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