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 (uint32 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 (uint32 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 (uint32 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 (uint32 i = 0; i < field->count; i++) { 470 ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t); 471 memcpy(pointer, source, itemSize); 472 ssize_t paddedSize = pad_to_8(itemSize); 473 memset(pointer + itemSize, 0, paddedSize - itemSize); 474 pointer += paddedSize; 475 source += itemSize; 476 } 477 478 // adjust the field size to the padded value 479 if (flags & R5_FIELD_FLAG_MINI_DATA) 480 *fieldSize = (uint8)(pointer - previous); 481 else 482 *(ssize_t *)fieldSize = (pointer - previous); 483 } 484 } 485 486 // terminate the fields with a pseudo field with flags 0 (not valid) 487 *pointer = 0; 488 pointer++; 489 490 // calculate the flattened size from the pointers 491 r5header->flattened_size = (uint32)pointer - (uint32)buffer; 492 r5header->checksum = CalculateChecksum((uint8 *)(buffer + 8), 493 headerSize - 8); 494 495 if (size) 496 *size = r5header->flattened_size; 497 498 return B_OK; 499 } 500 501 502 status_t 503 MessageAdapter::_UnflattenR5Message(uint32 format, BMessage *into, 504 BDataIO *stream) 505 { 506 into->MakeEmpty(); 507 508 BMessage::Private messagePrivate(into); 509 BMessage::message_header *header = messagePrivate.GetMessageHeader(); 510 511 TReadHelper reader(stream); 512 if (format == MESSAGE_FORMAT_R5_SWAPPED) 513 reader.SetSwap(true); 514 515 // the stream is already advanced by the size of the "format" 516 r5_message_header r5header; 517 reader(((uint8 *)&r5header) + sizeof(uint32), 518 sizeof(r5header) - sizeof(uint32)); 519 520 header->what = into->what = r5header.what; 521 if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_TARGET) 522 reader(&header->target, sizeof(header->target)); 523 524 if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_REPLY) { 525 // reply info 526 reader(&header->reply_port, sizeof(header->reply_port)); 527 reader(&header->reply_target, sizeof(header->reply_target)); 528 reader(&header->reply_team, sizeof(header->reply_team)); 529 530 // big flags 531 uint8 bigFlag; 532 reader(bigFlag); 533 if (bigFlag) 534 header->reply_target = B_PREFERRED_TOKEN; 535 536 reader(bigFlag); 537 if (bigFlag) 538 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 539 540 reader(bigFlag); 541 if (bigFlag) 542 header->flags |= MESSAGE_FLAG_REPLY_DONE; 543 544 reader(bigFlag); 545 if (bigFlag) 546 header->flags |= MESSAGE_FLAG_IS_REPLY; 547 } 548 549 if (r5header.flags & R5_MESSAGE_FLAG_SCRIPT_MESSAGE) 550 header->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 551 552 uint8 flags; 553 reader(flags); 554 while (flags & R5_FIELD_FLAG_VALID) { 555 bool fixedSize = flags & R5_FIELD_FLAG_FIXED_SIZE; 556 bool miniData = flags & R5_FIELD_FLAG_MINI_DATA; 557 bool singleItem = flags & R5_FIELD_FLAG_SINGLE_ITEM; 558 559 type_code type; 560 reader(type); 561 562 int32 itemCount; 563 if (!singleItem) { 564 if (miniData) { 565 uint8 miniCount; 566 reader(miniCount); 567 itemCount = miniCount; 568 } else 569 reader(itemCount); 570 } else 571 itemCount = 1; 572 573 ssize_t dataSize; 574 if (miniData) { 575 uint8 miniSize; 576 reader(miniSize); 577 dataSize = miniSize; 578 } else 579 reader(dataSize); 580 581 if (dataSize <= 0) 582 return B_ERROR; 583 584 // name 585 uint8 nameLength; 586 reader(nameLength); 587 588 char nameBuffer[256]; 589 reader(nameBuffer, nameLength); 590 nameBuffer[nameLength] = '\0'; 591 592 uint8 *buffer = (uint8 *)malloc(dataSize); 593 uint8 *pointer = buffer; 594 reader(buffer, dataSize); 595 596 status_t result = B_OK; 597 ssize_t itemSize = 0; 598 if (fixedSize) 599 itemSize = dataSize / itemCount; 600 601 if (format == MESSAGE_FORMAT_R5) { 602 for (int32 i = 0; i < itemCount; i++) { 603 if (!fixedSize) { 604 itemSize = *(ssize_t *)pointer; 605 pointer += sizeof(ssize_t); 606 } 607 608 result = into->AddData(nameBuffer, type, pointer, itemSize, 609 fixedSize, itemCount); 610 611 if (result < B_OK) { 612 free(buffer); 613 return result; 614 } 615 616 if (fixedSize) 617 pointer += itemSize; 618 else 619 pointer += pad_to_8(itemSize + sizeof(ssize_t)) - sizeof(ssize_t); 620 } 621 } else { 622 for (int32 i = 0; i < itemCount; i++) { 623 if (!fixedSize) { 624 itemSize = __swap_int32(*(ssize_t *)pointer); 625 pointer += sizeof(ssize_t); 626 } 627 628 swap_data(type, pointer, itemSize, B_SWAP_ALWAYS); 629 result = into->AddData(nameBuffer, type, pointer, itemSize, 630 fixedSize, itemCount); 631 632 if (result < B_OK) { 633 free(buffer); 634 return result; 635 } 636 637 if (fixedSize) 638 pointer += itemSize; 639 else 640 pointer += pad_to_8(itemSize + sizeof(ssize_t)) - sizeof(ssize_t); 641 } 642 } 643 644 free(buffer); 645 646 // flags of next field or termination byte 647 reader(flags); 648 } 649 650 return B_OK; 651 } 652 653 654 status_t 655 MessageAdapter::_UnflattenDanoMessage(uint32 format, BMessage *into, 656 BDataIO *stream) 657 { 658 into->MakeEmpty(); 659 660 TReadHelper reader(stream); 661 if (format == MESSAGE_FORMAT_DANO_SWAPPED) 662 reader.SetSwap(true); 663 664 ssize_t size; 665 reader(size); 666 667 dano_message_header header; 668 reader(header); 669 into->what = header.what; 670 671 size -= sizeof(dano_section_header) + sizeof(dano_message_header); 672 int32 offset = 0; 673 674 while (offset < size) { 675 dano_section_header sectionHeader; 676 reader(sectionHeader); 677 678 // be safe. this shouldn't be necessary but in some testcases it was. 679 sectionHeader.size = pad_to_8(sectionHeader.size); 680 681 if (offset + sectionHeader.size > size || sectionHeader.size < 0) 682 return B_BAD_DATA; 683 684 ssize_t fieldSize = sectionHeader.size - sizeof(dano_section_header); 685 uint8 *fieldBuffer = NULL; 686 if (fieldSize <= 0) { 687 // there may be no data. we shouldn't fail because of that 688 offset += sectionHeader.size; 689 continue; 690 } 691 692 fieldBuffer = (uint8 *)malloc(fieldSize); 693 if (fieldBuffer == NULL) 694 throw (status_t)B_NO_MEMORY; 695 696 reader(fieldBuffer, fieldSize); 697 698 switch (sectionHeader.code) { 699 case SECTION_OFFSET_TABLE: 700 case SECTION_TARGET_INFORMATION: 701 case SECTION_SORTED_INDEX_TABLE: 702 case SECTION_END_OF_DATA: 703 // discard 704 break; 705 706 case SECTION_SINGLE_ITEM_DATA: { 707 dano_single_item *field = (dano_single_item *)fieldBuffer; 708 709 int32 dataOffset = sizeof(dano_single_item) 710 + field->name_length + 1; 711 dataOffset = pad_to_8(dataOffset); 712 713 if (offset + dataOffset + field->item_size > size) 714 return B_BAD_DATA; 715 716 // support for fixed size is not possible with a single item 717 bool fixedSize = false; 718 switch (field->type) { 719 case B_RECT_TYPE: 720 case B_POINT_TYPE: 721 case B_INT8_TYPE: 722 case B_INT16_TYPE: 723 case B_INT32_TYPE: 724 case B_INT64_TYPE: 725 case B_BOOL_TYPE: 726 case B_FLOAT_TYPE: 727 case B_DOUBLE_TYPE: 728 case B_POINTER_TYPE: 729 case B_MESSENGER_TYPE: 730 fixedSize = true; 731 break; 732 default: 733 break; 734 } 735 736 status_t result = into->AddData(field->name, field->type, 737 fieldBuffer + dataOffset, field->item_size, fixedSize); 738 739 if (result < B_OK) { 740 free(fieldBuffer); 741 throw result; 742 } 743 break; 744 } 745 746 case SECTION_FIXED_SIZE_ARRAY_DATA: { 747 dano_fixed_size_array *field 748 = (dano_fixed_size_array *)fieldBuffer; 749 750 int32 dataOffset = sizeof(dano_fixed_size_array) 751 + field->name_length + 1; 752 dataOffset = pad_to_8(dataOffset); 753 int32 count = *(int32 *)(fieldBuffer + dataOffset); 754 dataOffset += 8; /* count and padding */ 755 756 if (offset + dataOffset + count * field->size_per_item > size) 757 return B_BAD_DATA; 758 759 status_t result = B_OK; 760 for (int32 i = 0; i < count; i++) { 761 result = into->AddData(field->name, field->type, 762 fieldBuffer + dataOffset, field->size_per_item, true, 763 count); 764 765 if (result < B_OK) { 766 free(fieldBuffer); 767 throw result; 768 } 769 770 dataOffset += field->size_per_item; 771 } 772 break; 773 } 774 775 case SECTION_VARIABLE_SIZE_ARRAY_DATA: { 776 dano_variable_size_array *field 777 = (dano_variable_size_array *)fieldBuffer; 778 779 int32 dataOffset = sizeof(dano_variable_size_array) 780 + field->name_length + 1; 781 dataOffset = pad_to_8(dataOffset); 782 int32 count = *(int32 *)(fieldBuffer + dataOffset); 783 dataOffset += sizeof(int32); 784 ssize_t totalSize = *(ssize_t *)(fieldBuffer + dataOffset); 785 dataOffset += sizeof(ssize_t); 786 787 int32 *endPoints = (int32 *)(fieldBuffer + dataOffset 788 + totalSize); 789 790 status_t result = B_OK; 791 for (int32 i = 0; i < count; i++) { 792 int32 itemOffset = (i > 0 ? pad_to_8(endPoints[i - 1]) : 0); 793 794 result = into->AddData(field->name, field->type, 795 fieldBuffer + dataOffset + itemOffset, 796 endPoints[i] - itemOffset, false, count); 797 798 if (result < B_OK) { 799 free(fieldBuffer); 800 throw result; 801 } 802 } 803 break; 804 } 805 } 806 807 free(fieldBuffer); 808 offset += sectionHeader.size; 809 } 810 811 return B_OK; 812 } 813 814 } // namespace BPrivate 815