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