1 /* 2 * Copyright 2005-2007, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Michael Lotz <mmlr@mlotz.ch> 8 */ 9 #include <MessageAdapter.h> 10 #include <MessagePrivate.h> 11 #include <MessageUtils.h> 12 13 #include <stdlib.h> 14 15 16 namespace BPrivate { 17 18 #define R5_MESSAGE_FLAG_VALID 0x01 19 #define R5_MESSAGE_FLAG_INCLUDE_TARGET 0x02 20 #define R5_MESSAGE_FLAG_INCLUDE_REPLY 0x04 21 #define R5_MESSAGE_FLAG_SCRIPT_MESSAGE 0x08 22 23 #define R5_FIELD_FLAG_VALID 0x01 24 #define R5_FIELD_FLAG_MINI_DATA 0x02 25 #define R5_FIELD_FLAG_FIXED_SIZE 0x04 26 #define R5_FIELD_FLAG_SINGLE_ITEM 0x08 27 28 29 enum { 30 SECTION_MESSAGE_HEADER = 'FOB2', 31 SECTION_OFFSET_TABLE = 'STof', 32 SECTION_TARGET_INFORMATION = 'ENwh', 33 SECTION_SINGLE_ITEM_DATA = 'SGDa', 34 SECTION_FIXED_SIZE_ARRAY_DATA = 'FADa', 35 SECTION_VARIABLE_SIZE_ARRAY_DATA = 'VADa', 36 SECTION_SORTED_INDEX_TABLE = 'DXIn', 37 SECTION_END_OF_DATA = 'DDEn' 38 }; 39 40 41 struct r5_message_header { 42 uint32 magic; 43 uint32 checksum; 44 int32 flattened_size; 45 int32 what; 46 uint8 flags; 47 } _PACKED; 48 49 50 struct dano_section_header { 51 uint32 code; 52 int32 size; 53 uint8 data[0]; 54 } _PACKED; 55 56 57 struct dano_message_header { 58 int32 what; 59 int32 padding; 60 } _PACKED; 61 62 63 typedef struct offset_table_s { 64 int32 indexTable; 65 int32 endOfData; 66 int64 padding; 67 } OffsetTable; 68 69 70 struct dano_single_item { 71 type_code type; 72 int32 item_size; 73 uint8 name_length; 74 char name[0]; 75 } _PACKED; 76 77 78 struct dano_fixed_size_array { 79 type_code type; 80 int32 size_per_item; 81 uint8 name_length; 82 char name[0]; 83 } _PACKED; 84 85 86 struct dano_variable_size_array { 87 type_code type; 88 int32 padding; 89 uint8 name_length; 90 char name[0]; 91 } _PACKED; 92 93 94 inline int32 95 pad_to_8(int32 value) 96 { 97 return (value + 7) & ~7; 98 } 99 100 101 ssize_t 102 MessageAdapter::FlattenedSize(uint32 format, const BMessage *from) 103 { 104 switch (format) { 105 case MESSAGE_FORMAT_R5: 106 case MESSAGE_FORMAT_R5_SWAPPED: 107 return _R5FlattenedSize(from); 108 } 109 110 return -1; 111 } 112 113 114 status_t 115 MessageAdapter::Flatten(uint32 format, const BMessage *from, char *buffer, 116 ssize_t *size) 117 { 118 switch (format) { 119 case MESSAGE_FORMAT_R5: 120 case MESSAGE_FORMAT_R5_SWAPPED: 121 return _FlattenR5Message(format, from, buffer, size); 122 } 123 124 return B_ERROR; 125 } 126 127 128 status_t 129 MessageAdapter::Flatten(uint32 format, const BMessage *from, BDataIO *stream, 130 ssize_t *size) 131 { 132 switch (format) { 133 case MESSAGE_FORMAT_R5: 134 case MESSAGE_FORMAT_R5_SWAPPED: 135 { 136 ssize_t flattenedSize = _R5FlattenedSize(from); 137 char *buffer = (char *)malloc(flattenedSize); 138 if (!buffer) 139 return B_NO_MEMORY; 140 141 status_t result = _FlattenR5Message(format, from, buffer, 142 &flattenedSize); 143 if (result < B_OK) { 144 free(buffer); 145 return result; 146 } 147 148 ssize_t written = stream->Write(buffer, flattenedSize); 149 if (written != flattenedSize) { 150 free(buffer); 151 return (written >= 0 ? B_ERROR : written); 152 } 153 154 if (size) 155 *size = flattenedSize; 156 157 free(buffer); 158 return B_OK; 159 } 160 } 161 162 return B_ERROR; 163 } 164 165 166 status_t 167 MessageAdapter::Unflatten(uint32 format, BMessage *into, const char *buffer) 168 { 169 if (format == KMessage::kMessageHeaderMagic) { 170 KMessage message; 171 status_t result = message.SetTo(buffer, 172 ((KMessage::Header *)buffer)->size); 173 if (result != B_OK) 174 return result; 175 176 return _ConvertKMessage(&message, into); 177 } 178 179 try { 180 switch (format) { 181 case MESSAGE_FORMAT_R5: 182 { 183 r5_message_header *header = (r5_message_header *)buffer; 184 BMemoryIO stream(buffer + sizeof(uint32), 185 header->flattened_size - sizeof(uint32)); 186 return _UnflattenR5Message(format, into, &stream); 187 } 188 189 case MESSAGE_FORMAT_R5_SWAPPED: 190 { 191 r5_message_header *header = (r5_message_header *)buffer; 192 BMemoryIO stream(buffer + sizeof(uint32), 193 __swap_int32(header->flattened_size) - sizeof(uint32)); 194 return _UnflattenR5Message(format, into, &stream); 195 } 196 197 case MESSAGE_FORMAT_DANO: 198 case MESSAGE_FORMAT_DANO_SWAPPED: 199 { 200 dano_section_header *header = (dano_section_header *)buffer; 201 ssize_t size = header->size; 202 if (header->code == MESSAGE_FORMAT_DANO_SWAPPED) 203 size = __swap_int32(size); 204 205 BMemoryIO stream(buffer + sizeof(uint32), size - sizeof(uint32)); 206 return _UnflattenDanoMessage(format, into, &stream); 207 } 208 } 209 } catch (status_t error) { 210 into->MakeEmpty(); 211 return error; 212 } 213 214 return B_NOT_A_MESSAGE; 215 } 216 217 218 status_t 219 MessageAdapter::Unflatten(uint32 format, BMessage *into, BDataIO *stream) 220 { 221 try { 222 switch (format) { 223 case MESSAGE_FORMAT_R5: 224 case MESSAGE_FORMAT_R5_SWAPPED: 225 return _UnflattenR5Message(format, into, stream); 226 227 case MESSAGE_FORMAT_DANO: 228 case MESSAGE_FORMAT_DANO_SWAPPED: 229 return _UnflattenDanoMessage(format, into, stream); 230 } 231 } catch (status_t error) { 232 into->MakeEmpty(); 233 return error; 234 } 235 236 return B_NOT_A_MESSAGE; 237 } 238 239 240 status_t 241 MessageAdapter::_ConvertKMessage(const KMessage *fromMessage, 242 BMessage *toMessage) 243 { 244 if (!fromMessage || !toMessage) 245 return B_BAD_VALUE; 246 247 // make empty and init what of the target message 248 toMessage->MakeEmpty(); 249 toMessage->what = fromMessage->What(); 250 251 BMessage::Private toPrivate(toMessage); 252 toPrivate.SetTarget(fromMessage->TargetToken()); 253 toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(), 254 fromMessage->ReplyToken()); 255 256 // iterate through the fields and import them in the target message 257 KMessageField field; 258 while (fromMessage->GetNextField(&field) == B_OK) { 259 int32 elementCount = field.CountElements(); 260 if (elementCount > 0) { 261 for (int32 i = 0; i < elementCount; i++) { 262 int32 size; 263 const void *data = field.ElementAt(i, &size); 264 status_t result; 265 266 if (field.TypeCode() == B_MESSAGE_TYPE) { 267 // message type: if it's a KMessage, convert it 268 KMessage message; 269 if (message.SetTo(data, size) == B_OK) { 270 BMessage bMessage; 271 result = _ConvertKMessage(&message, &bMessage); 272 if (result < B_OK) 273 return result; 274 275 result = toMessage->AddMessage(field.Name(), &bMessage); 276 } else { 277 // just add it 278 result = toMessage->AddData(field.Name(), 279 field.TypeCode(), data, size, 280 field.HasFixedElementSize(), 1); 281 } 282 } else { 283 result = toMessage->AddData(field.Name(), field.TypeCode(), 284 data, size, field.HasFixedElementSize(), 1); 285 } 286 287 if (result < B_OK) 288 return result; 289 } 290 } 291 } 292 293 return B_OK; 294 } 295 296 297 ssize_t 298 MessageAdapter::_R5FlattenedSize(const BMessage *from) 299 { 300 BMessage::Private messagePrivate((BMessage *)from); 301 BMessage::message_header* header = messagePrivate.GetMessageHeader(); 302 303 // header size (variable, depending on the flags) 304 305 ssize_t flattenedSize = sizeof(r5_message_header); 306 307 if (header->target != B_NULL_TOKEN) 308 flattenedSize += sizeof(int32); 309 310 if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN 311 && header->reply_team >= 0) { 312 // reply info + big flags 313 flattenedSize += sizeof(port_id) + sizeof(int32) + sizeof(team_id) + 4; 314 } 315 316 // field size 317 318 uint8 *data = messagePrivate.GetMessageData(); 319 BMessage::field_header *field = messagePrivate.GetMessageFields(); 320 for (uint32 i = 0; i < header->field_count; i++, field++) { 321 // flags and type 322 flattenedSize += 1 + sizeof(type_code); 323 324 #if 0 325 bool miniData = field->dataSize <= 255 && field->count <= 255; 326 #else 327 // TODO: we don't know the R5 dataSize yet (padding) 328 bool miniData = false; 329 #endif 330 331 // item count 332 if (field->count > 1) 333 flattenedSize += (miniData ? sizeof(uint8) : sizeof(uint32)); 334 335 // data size 336 flattenedSize += (miniData ? sizeof(uint8) : sizeof(size_t)); 337 338 // name length and name 339 flattenedSize += 1 + min_c(field->name_length - 1, 255); 340 341 // data 342 if (field->flags & FIELD_FLAG_FIXED_SIZE) 343 flattenedSize += field->data_size; 344 else { 345 uint8 *source = data + field->offset + field->name_length; 346 347 for (uint32 i = 0; i < field->count; i++) { 348 ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t); 349 flattenedSize += pad_to_8(itemSize); 350 source += itemSize; 351 } 352 } 353 } 354 355 // pseudo field with flags 0 356 return flattenedSize + 1; 357 } 358 359 360 status_t 361 MessageAdapter::_FlattenR5Message(uint32 format, const BMessage *from, 362 char *buffer, ssize_t *size) 363 { 364 BMessage::Private messagePrivate((BMessage *)from); 365 BMessage::message_header *header = messagePrivate.GetMessageHeader(); 366 uint8 *data = messagePrivate.GetMessageData(); 367 368 r5_message_header *r5header = (r5_message_header *)buffer; 369 uint8 *pointer = (uint8 *)buffer + sizeof(r5_message_header); 370 371 r5header->magic = MESSAGE_FORMAT_R5; 372 r5header->what = from->what; 373 r5header->checksum = 0; 374 375 uint8 flags = R5_MESSAGE_FLAG_VALID; 376 if (header->target != B_NULL_TOKEN) { 377 *(int32 *)pointer = header->target; 378 pointer += sizeof(int32); 379 flags |= R5_MESSAGE_FLAG_INCLUDE_TARGET; 380 } 381 382 if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN 383 && header->reply_team >= 0) { 384 // reply info 385 *(port_id *)pointer = header->reply_port; 386 pointer += sizeof(port_id); 387 *(int32 *)pointer = header->reply_target; 388 pointer += sizeof(int32); 389 *(team_id *)pointer = header->reply_team; 390 pointer += sizeof(team_id); 391 392 // big flags 393 *pointer = (header->reply_target == B_PREFERRED_TOKEN ? 1 : 0); 394 pointer++; 395 396 *pointer = (header->flags & MESSAGE_FLAG_REPLY_REQUIRED ? 1 : 0); 397 pointer++; 398 399 *pointer = (header->flags & MESSAGE_FLAG_REPLY_DONE ? 1 : 0); 400 pointer++; 401 402 *pointer = (header->flags & MESSAGE_FLAG_IS_REPLY ? 1 : 0); 403 pointer++; 404 405 flags |= R5_MESSAGE_FLAG_INCLUDE_REPLY; 406 } 407 408 if (header->flags & MESSAGE_FLAG_HAS_SPECIFIERS) 409 flags |= R5_MESSAGE_FLAG_SCRIPT_MESSAGE; 410 411 r5header->flags = flags; 412 413 // store the header size - used for the checksum later 414 ssize_t headerSize = (addr_t)pointer - (addr_t)buffer; 415 416 // collect and add the data 417 BMessage::field_header *field = messagePrivate.GetMessageFields(); 418 for (uint32 i = 0; i < header->field_count; i++, field++) { 419 flags = R5_FIELD_FLAG_VALID; 420 421 if (field->count == 1) 422 flags |= R5_FIELD_FLAG_SINGLE_ITEM; 423 // TODO: we don't really know the data size now (padding missing) 424 // if (field->data_size <= 255 && field->count <= 255) 425 // flags |= R5_FIELD_FLAG_MINI_DATA; 426 if (field->flags & FIELD_FLAG_FIXED_SIZE) 427 flags |= R5_FIELD_FLAG_FIXED_SIZE; 428 429 *pointer = flags; 430 pointer++; 431 432 *(type_code *)pointer = field->type; 433 pointer += sizeof(type_code); 434 435 if (!(flags & R5_FIELD_FLAG_SINGLE_ITEM)) { 436 if (flags & R5_FIELD_FLAG_MINI_DATA) { 437 *pointer = (uint8)field->count; 438 pointer++; 439 } else { 440 *(int32 *)pointer = field->count; 441 pointer += sizeof(int32); 442 } 443 } 444 445 // we may have to adjust this to account for padding later 446 uint8 *fieldSize = pointer; 447 if (flags & R5_FIELD_FLAG_MINI_DATA) { 448 *pointer = (uint8)field->data_size; 449 pointer++; 450 } else { 451 *(ssize_t *)pointer = field->data_size; 452 pointer += sizeof(ssize_t); 453 } 454 455 // name 456 int32 nameLength = min_c(field->name_length - 1, 255); 457 *pointer = (uint8)nameLength; 458 pointer++; 459 460 strncpy((char *)pointer, (char *)data + field->offset, nameLength); 461 pointer += nameLength; 462 463 // data 464 uint8 *source = data + field->offset + field->name_length; 465 if (flags & R5_FIELD_FLAG_FIXED_SIZE) { 466 memcpy(pointer, source, field->data_size); 467 pointer += field->data_size; 468 } else { 469 uint8 *previous = pointer; 470 for (uint32 i = 0; i < field->count; i++) { 471 ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t); 472 memcpy(pointer, source, itemSize); 473 ssize_t paddedSize = pad_to_8(itemSize); 474 memset(pointer + itemSize, 0, paddedSize - itemSize); 475 pointer += paddedSize; 476 source += itemSize; 477 } 478 479 // adjust the field size to the padded value 480 if (flags & R5_FIELD_FLAG_MINI_DATA) 481 *fieldSize = (uint8)(pointer - previous); 482 else 483 *(ssize_t *)fieldSize = (pointer - previous); 484 } 485 } 486 487 // terminate the fields with a pseudo field with flags 0 (not valid) 488 *pointer = 0; 489 pointer++; 490 491 // calculate the flattened size from the pointers 492 r5header->flattened_size = (addr_t)pointer - (addr_t)buffer; 493 r5header->checksum = CalculateChecksum((uint8 *)(buffer + 8), 494 headerSize - 8); 495 496 if (size) 497 *size = r5header->flattened_size; 498 499 return B_OK; 500 } 501 502 503 status_t 504 MessageAdapter::_UnflattenR5Message(uint32 format, BMessage *into, 505 BDataIO *stream) 506 { 507 into->MakeEmpty(); 508 509 BMessage::Private messagePrivate(into); 510 BMessage::message_header *header = messagePrivate.GetMessageHeader(); 511 512 TReadHelper reader(stream); 513 if (format == MESSAGE_FORMAT_R5_SWAPPED) 514 reader.SetSwap(true); 515 516 // the stream is already advanced by the size of the "format" 517 r5_message_header r5header; 518 reader(((uint8 *)&r5header) + sizeof(uint32), 519 sizeof(r5header) - sizeof(uint32)); 520 521 header->what = into->what = r5header.what; 522 if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_TARGET) 523 reader(&header->target, sizeof(header->target)); 524 525 if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_REPLY) { 526 // reply info 527 reader(&header->reply_port, sizeof(header->reply_port)); 528 reader(&header->reply_target, sizeof(header->reply_target)); 529 reader(&header->reply_team, sizeof(header->reply_team)); 530 531 // big flags 532 uint8 bigFlag; 533 reader(bigFlag); 534 if (bigFlag) 535 header->reply_target = B_PREFERRED_TOKEN; 536 537 reader(bigFlag); 538 if (bigFlag) 539 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 540 541 reader(bigFlag); 542 if (bigFlag) 543 header->flags |= MESSAGE_FLAG_REPLY_DONE; 544 545 reader(bigFlag); 546 if (bigFlag) 547 header->flags |= MESSAGE_FLAG_IS_REPLY; 548 } 549 550 if (r5header.flags & R5_MESSAGE_FLAG_SCRIPT_MESSAGE) 551 header->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 552 553 uint8 flags; 554 reader(flags); 555 while (flags & R5_FIELD_FLAG_VALID) { 556 bool fixedSize = flags & R5_FIELD_FLAG_FIXED_SIZE; 557 bool miniData = flags & R5_FIELD_FLAG_MINI_DATA; 558 bool singleItem = flags & R5_FIELD_FLAG_SINGLE_ITEM; 559 560 type_code type; 561 reader(type); 562 563 int32 itemCount; 564 if (!singleItem) { 565 if (miniData) { 566 uint8 miniCount; 567 reader(miniCount); 568 itemCount = miniCount; 569 } else 570 reader(itemCount); 571 } else 572 itemCount = 1; 573 574 int32 dataSize; 575 if (miniData) { 576 uint8 miniSize; 577 reader(miniSize); 578 dataSize = miniSize; 579 } else 580 reader(dataSize); 581 582 if (dataSize <= 0) 583 return B_ERROR; 584 585 // name 586 uint8 nameLength; 587 reader(nameLength); 588 589 char nameBuffer[256]; 590 reader(nameBuffer, nameLength); 591 nameBuffer[nameLength] = '\0'; 592 593 uint8 *buffer = (uint8 *)malloc(dataSize); 594 uint8 *pointer = buffer; 595 reader(buffer, dataSize); 596 597 status_t result = B_OK; 598 int32 itemSize = 0; 599 if (fixedSize) 600 itemSize = dataSize / itemCount; 601 602 if (format == MESSAGE_FORMAT_R5) { 603 for (int32 i = 0; i < itemCount; i++) { 604 if (!fixedSize) { 605 itemSize = *(int32 *)pointer; 606 pointer += sizeof(int32); 607 } 608 609 result = into->AddData(nameBuffer, type, pointer, itemSize, 610 fixedSize, itemCount); 611 612 if (result < B_OK) { 613 free(buffer); 614 return result; 615 } 616 617 if (fixedSize) 618 pointer += itemSize; 619 else 620 pointer += pad_to_8(itemSize + sizeof(int32)) - sizeof(int32); 621 } 622 } else { 623 for (int32 i = 0; i < itemCount; i++) { 624 if (!fixedSize) { 625 itemSize = __swap_int32(*(int32 *)pointer); 626 pointer += sizeof(int32); 627 } 628 629 swap_data(type, pointer, itemSize, B_SWAP_ALWAYS); 630 result = into->AddData(nameBuffer, type, pointer, itemSize, 631 fixedSize, itemCount); 632 633 if (result < B_OK) { 634 free(buffer); 635 return result; 636 } 637 638 if (fixedSize) 639 pointer += itemSize; 640 else 641 pointer += pad_to_8(itemSize + sizeof(int32)) - sizeof(int32); 642 } 643 } 644 645 free(buffer); 646 647 // flags of next field or termination byte 648 reader(flags); 649 } 650 651 return B_OK; 652 } 653 654 655 status_t 656 MessageAdapter::_UnflattenDanoMessage(uint32 format, BMessage *into, 657 BDataIO *stream) 658 { 659 into->MakeEmpty(); 660 661 TReadHelper reader(stream); 662 if (format == MESSAGE_FORMAT_DANO_SWAPPED) 663 reader.SetSwap(true); 664 665 ssize_t size; 666 reader(size); 667 668 dano_message_header header; 669 reader(header); 670 into->what = header.what; 671 672 size -= sizeof(dano_section_header) + sizeof(dano_message_header); 673 int32 offset = 0; 674 675 while (offset < size) { 676 dano_section_header sectionHeader; 677 reader(sectionHeader); 678 679 // be safe. this shouldn't be necessary but in some testcases it was. 680 sectionHeader.size = pad_to_8(sectionHeader.size); 681 682 if (offset + sectionHeader.size > size || sectionHeader.size < 0) 683 return B_BAD_DATA; 684 685 ssize_t fieldSize = sectionHeader.size - sizeof(dano_section_header); 686 uint8 *fieldBuffer = NULL; 687 if (fieldSize <= 0) { 688 // there may be no data. we shouldn't fail because of that 689 offset += sectionHeader.size; 690 continue; 691 } 692 693 fieldBuffer = (uint8 *)malloc(fieldSize); 694 if (fieldBuffer == NULL) 695 throw (status_t)B_NO_MEMORY; 696 697 reader(fieldBuffer, fieldSize); 698 699 switch (sectionHeader.code) { 700 case SECTION_OFFSET_TABLE: 701 case SECTION_TARGET_INFORMATION: 702 case SECTION_SORTED_INDEX_TABLE: 703 case SECTION_END_OF_DATA: 704 // discard 705 break; 706 707 case SECTION_SINGLE_ITEM_DATA: { 708 dano_single_item *field = (dano_single_item *)fieldBuffer; 709 710 int32 dataOffset = sizeof(dano_single_item) 711 + field->name_length + 1; 712 dataOffset = pad_to_8(dataOffset); 713 714 if (offset + dataOffset + field->item_size > size) 715 return B_BAD_DATA; 716 717 // support for fixed size is not possible with a single item 718 bool fixedSize = false; 719 switch (field->type) { 720 case B_RECT_TYPE: 721 case B_POINT_TYPE: 722 case B_INT8_TYPE: 723 case B_INT16_TYPE: 724 case B_INT32_TYPE: 725 case B_INT64_TYPE: 726 case B_BOOL_TYPE: 727 case B_FLOAT_TYPE: 728 case B_DOUBLE_TYPE: 729 case B_POINTER_TYPE: 730 case B_MESSENGER_TYPE: 731 fixedSize = true; 732 break; 733 default: 734 break; 735 } 736 737 status_t result = into->AddData(field->name, field->type, 738 fieldBuffer + dataOffset, field->item_size, fixedSize); 739 740 if (result < B_OK) { 741 free(fieldBuffer); 742 throw result; 743 } 744 break; 745 } 746 747 case SECTION_FIXED_SIZE_ARRAY_DATA: { 748 dano_fixed_size_array *field 749 = (dano_fixed_size_array *)fieldBuffer; 750 751 int32 dataOffset = sizeof(dano_fixed_size_array) 752 + field->name_length + 1; 753 dataOffset = pad_to_8(dataOffset); 754 int32 count = *(int32 *)(fieldBuffer + dataOffset); 755 dataOffset += 8; /* count and padding */ 756 757 if (offset + dataOffset + count * field->size_per_item > size) 758 return B_BAD_DATA; 759 760 status_t result = B_OK; 761 for (int32 i = 0; i < count; i++) { 762 result = into->AddData(field->name, field->type, 763 fieldBuffer + dataOffset, field->size_per_item, true, 764 count); 765 766 if (result < B_OK) { 767 free(fieldBuffer); 768 throw result; 769 } 770 771 dataOffset += field->size_per_item; 772 } 773 break; 774 } 775 776 case SECTION_VARIABLE_SIZE_ARRAY_DATA: { 777 dano_variable_size_array *field 778 = (dano_variable_size_array *)fieldBuffer; 779 780 int32 dataOffset = sizeof(dano_variable_size_array) 781 + field->name_length + 1; 782 dataOffset = pad_to_8(dataOffset); 783 int32 count = *(int32 *)(fieldBuffer + dataOffset); 784 dataOffset += sizeof(int32); 785 ssize_t totalSize = *(ssize_t *)(fieldBuffer + dataOffset); 786 dataOffset += sizeof(ssize_t); 787 788 int32 *endPoints = (int32 *)(fieldBuffer + dataOffset 789 + totalSize); 790 791 status_t result = B_OK; 792 for (int32 i = 0; i < count; i++) { 793 int32 itemOffset = (i > 0 ? pad_to_8(endPoints[i - 1]) : 0); 794 795 result = into->AddData(field->name, field->type, 796 fieldBuffer + dataOffset + itemOffset, 797 endPoints[i] - itemOffset, false, count); 798 799 if (result < B_OK) { 800 free(fieldBuffer); 801 throw result; 802 } 803 } 804 break; 805 } 806 } 807 808 free(fieldBuffer); 809 offset += sectionHeader.size; 810 } 811 812 return B_OK; 813 } 814 815 } // namespace BPrivate 816