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