vfs: check userland buffers before reading them.
[haiku.git] / src / kits / app / MessageAdapter.cpp
blob317d0e9dbceec88df89eb6f199656405d3a30392
1 /*
2 * Copyright 2005-2015, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Michael Lotz <mmlr@mlotz.ch>
8 */
11 #include <MessageAdapter.h>
12 #include <MessagePrivate.h>
13 #include <MessageUtils.h>
15 #include <stdlib.h>
18 namespace BPrivate {
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
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
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'
43 struct r5_message_header {
44 uint32 magic;
45 uint32 checksum;
46 int32 flattened_size;
47 int32 what;
48 uint8 flags;
49 } _PACKED;
52 struct dano_section_header {
53 uint32 code;
54 int32 size;
55 uint8 data[0];
56 } _PACKED;
59 struct dano_message_header {
60 int32 what;
61 int32 padding;
62 } _PACKED;
65 typedef struct offset_table_s {
66 int32 indexTable;
67 int32 endOfData;
68 int64 padding;
69 } OffsetTable;
72 struct dano_single_item {
73 type_code type;
74 int32 item_size;
75 uint8 name_length;
76 char name[0];
77 } _PACKED;
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;
88 struct dano_variable_size_array {
89 type_code type;
90 int32 padding;
91 uint8 name_length;
92 char name[0];
93 } _PACKED;
96 inline int32
97 pad_to_8(int32 value)
99 return (value + 7) & ~7;
103 /*static*/ ssize_t
104 MessageAdapter::FlattenedSize(uint32 format, const BMessage *from)
106 switch (format) {
107 case MESSAGE_FORMAT_R5:
108 case MESSAGE_FORMAT_R5_SWAPPED:
109 return _R5FlattenedSize(from);
112 return -1;
116 /*static*/ status_t
117 MessageAdapter::Flatten(uint32 format, const BMessage *from, char *buffer,
118 ssize_t *size)
120 switch (format) {
121 case MESSAGE_FORMAT_R5:
122 case MESSAGE_FORMAT_R5_SWAPPED:
123 return _FlattenR5Message(format, from, buffer, size);
126 return B_ERROR;
130 /*static*/ status_t
131 MessageAdapter::Flatten(uint32 format, const BMessage *from, BDataIO *stream,
132 ssize_t *size)
134 switch (format) {
135 case MESSAGE_FORMAT_R5:
136 case MESSAGE_FORMAT_R5_SWAPPED:
138 ssize_t flattenedSize = _R5FlattenedSize(from);
139 char *buffer = (char *)malloc(flattenedSize);
140 if (!buffer)
141 return B_NO_MEMORY;
143 status_t result = _FlattenR5Message(format, from, buffer,
144 &flattenedSize);
145 if (result < B_OK) {
146 free(buffer);
147 return result;
150 ssize_t written = stream->Write(buffer, flattenedSize);
151 if (written != flattenedSize) {
152 free(buffer);
153 return (written >= 0 ? B_ERROR : written);
156 if (size)
157 *size = flattenedSize;
159 free(buffer);
160 return B_OK;
164 return B_ERROR;
168 /*static*/ status_t
169 MessageAdapter::Unflatten(uint32 format, BMessage *into, const char *buffer)
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;
178 return _ConvertFromKMessage(&message, into);
181 try {
182 switch (format) {
183 case MESSAGE_FORMAT_R5:
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);
191 case MESSAGE_FORMAT_R5_SWAPPED:
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);
199 case MESSAGE_FORMAT_DANO:
200 case MESSAGE_FORMAT_DANO_SWAPPED:
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);
207 BMemoryIO stream(buffer + sizeof(uint32), size - sizeof(uint32));
208 return _UnflattenDanoMessage(format, into, &stream);
211 } catch (status_t error) {
212 into->MakeEmpty();
213 return error;
216 return B_NOT_A_MESSAGE;
220 /*static*/ status_t
221 MessageAdapter::Unflatten(uint32 format, BMessage *into, BDataIO *stream)
223 try {
224 switch (format) {
225 case MESSAGE_FORMAT_R5:
226 case MESSAGE_FORMAT_R5_SWAPPED:
227 return _UnflattenR5Message(format, into, stream);
229 case MESSAGE_FORMAT_DANO:
230 case MESSAGE_FORMAT_DANO_SWAPPED:
231 return _UnflattenDanoMessage(format, into, stream);
233 } catch (status_t error) {
234 into->MakeEmpty();
235 return error;
238 return B_NOT_A_MESSAGE;
242 /*static*/ status_t
243 MessageAdapter::ConvertToKMessage(const BMessage* from, KMessage& to)
245 if (from == NULL)
246 return B_BAD_VALUE;
248 BMessage::Private fromPrivate(const_cast<BMessage*>(from));
249 BMessage::message_header* header = fromPrivate.GetMessageHeader();
250 uint8* data = fromPrivate.GetMessageData();
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;
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;
276 return B_OK;
280 /*static*/ status_t
281 MessageAdapter::_ConvertFromKMessage(const KMessage *fromMessage,
282 BMessage *toMessage)
284 if (!fromMessage || !toMessage)
285 return B_BAD_VALUE;
287 // make empty and init what of the target message
288 toMessage->MakeEmpty();
289 toMessage->what = fromMessage->What();
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;
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;
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;
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);
326 } else {
327 result = toMessage->AddData(field.Name(), field.TypeCode(),
328 data, size, field.HasFixedElementSize(), 1);
331 if (result < B_OK)
332 return result;
337 return B_OK;
341 /*static*/ ssize_t
342 MessageAdapter::_R5FlattenedSize(const BMessage *from)
344 BMessage::Private messagePrivate((BMessage *)from);
345 BMessage::message_header* header = messagePrivate.GetMessageHeader();
347 // header size (variable, depending on the flags)
349 ssize_t flattenedSize = sizeof(r5_message_header);
351 if (header->target != B_NULL_TOKEN)
352 flattenedSize += sizeof(int32);
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;
360 // field size
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);
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
375 // item count
376 if (field->count > 1)
377 flattenedSize += (miniData ? sizeof(uint8) : sizeof(uint32));
379 // data size
380 flattenedSize += (miniData ? sizeof(uint8) : sizeof(size_t));
382 // name length and name
383 flattenedSize += 1 + min_c(field->name_length - 1, 255);
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;
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;
399 // pseudo field with flags 0
400 return flattenedSize + 1;
404 /*static*/ status_t
405 MessageAdapter::_FlattenR5Message(uint32 format, const BMessage *from,
406 char *buffer, ssize_t *size)
408 BMessage::Private messagePrivate((BMessage *)from);
409 BMessage::message_header *header = messagePrivate.GetMessageHeader();
410 uint8 *data = messagePrivate.GetMessageData();
412 r5_message_header *r5header = (r5_message_header *)buffer;
413 uint8 *pointer = (uint8 *)buffer + sizeof(r5_message_header);
415 r5header->magic = MESSAGE_FORMAT_R5;
416 r5header->what = from->what;
417 r5header->checksum = 0;
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;
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);
436 // big flags
437 *pointer = (header->reply_target == B_PREFERRED_TOKEN ? 1 : 0);
438 pointer++;
440 *pointer = (header->flags & MESSAGE_FLAG_REPLY_REQUIRED ? 1 : 0);
441 pointer++;
443 *pointer = (header->flags & MESSAGE_FLAG_REPLY_DONE ? 1 : 0);
444 pointer++;
446 *pointer = (header->flags & MESSAGE_FLAG_IS_REPLY ? 1 : 0);
447 pointer++;
449 flags |= R5_MESSAGE_FLAG_INCLUDE_REPLY;
452 if (header->flags & MESSAGE_FLAG_HAS_SPECIFIERS)
453 flags |= R5_MESSAGE_FLAG_SCRIPT_MESSAGE;
455 r5header->flags = flags;
457 // store the header size - used for the checksum later
458 ssize_t headerSize = (addr_t)pointer - (addr_t)buffer;
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;
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;
473 *pointer = flags;
474 pointer++;
476 *(type_code *)pointer = field->type;
477 pointer += sizeof(type_code);
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);
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);
499 // name
500 int32 nameLength = min_c(field->name_length - 1, 255);
501 *pointer = (uint8)nameLength;
502 pointer++;
504 strncpy((char *)pointer, (char *)data + field->offset, nameLength);
505 pointer += nameLength;
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;
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);
531 // terminate the fields with a pseudo field with flags 0 (not valid)
532 *pointer = 0;
533 pointer++;
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);
540 if (size)
541 *size = r5header->flattened_size;
543 return B_OK;
547 /*static*/ status_t
548 MessageAdapter::_UnflattenR5Message(uint32 format, BMessage *into,
549 BDataIO *stream)
551 into->MakeEmpty();
553 BMessage::Private messagePrivate(into);
554 BMessage::message_header *header = messagePrivate.GetMessageHeader();
556 TReadHelper reader(stream);
557 if (format == MESSAGE_FORMAT_R5_SWAPPED)
558 reader.SetSwap(true);
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));
565 header->what = into->what = r5header.what;
566 if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_TARGET)
567 reader(&header->target, sizeof(header->target));
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));
575 // big flags
576 uint8 bigFlag;
577 reader(bigFlag);
578 if (bigFlag)
579 header->reply_target = B_PREFERRED_TOKEN;
581 reader(bigFlag);
582 if (bigFlag)
583 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
585 reader(bigFlag);
586 if (bigFlag)
587 header->flags |= MESSAGE_FLAG_REPLY_DONE;
589 reader(bigFlag);
590 if (bigFlag)
591 header->flags |= MESSAGE_FLAG_IS_REPLY;
594 if (r5header.flags & R5_MESSAGE_FLAG_SCRIPT_MESSAGE)
595 header->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
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;
604 type_code type;
605 reader(type);
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;
618 int32 dataSize;
619 if (miniData) {
620 uint8 miniSize;
621 reader(miniSize);
622 dataSize = miniSize;
623 } else
624 reader(dataSize);
626 if (dataSize <= 0)
627 return B_ERROR;
629 // name
630 uint8 nameLength;
631 reader(nameLength);
633 char nameBuffer[256];
634 reader(nameBuffer, nameLength);
635 nameBuffer[nameLength] = '\0';
637 uint8 *buffer = (uint8 *)malloc(dataSize);
638 uint8 *pointer = buffer;
639 reader(buffer, dataSize);
641 status_t result = B_OK;
642 int32 itemSize = 0;
643 if (fixedSize)
644 itemSize = dataSize / itemCount;
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);
653 result = into->AddData(nameBuffer, type, pointer, itemSize,
654 fixedSize, itemCount);
656 if (result < B_OK) {
657 free(buffer);
658 return result;
661 if (fixedSize)
662 pointer += itemSize;
663 else {
664 pointer += pad_to_8(itemSize + sizeof(int32))
665 - sizeof(int32);
668 } else {
669 for (int32 i = 0; i < itemCount; i++) {
670 if (!fixedSize) {
671 itemSize = __swap_int32(*(int32 *)pointer);
672 pointer += sizeof(int32);
675 swap_data(type, pointer, itemSize, B_SWAP_ALWAYS);
676 result = into->AddData(nameBuffer, type, pointer, itemSize,
677 fixedSize, itemCount);
679 if (result < B_OK) {
680 free(buffer);
681 return result;
684 if (fixedSize)
685 pointer += itemSize;
686 else {
687 pointer += pad_to_8(itemSize + sizeof(int32))
688 - sizeof(int32);
693 free(buffer);
695 // flags of next field or termination byte
696 reader(flags);
699 return B_OK;
703 /*static*/ status_t
704 MessageAdapter::_UnflattenDanoMessage(uint32 format, BMessage *into,
705 BDataIO *stream)
707 into->MakeEmpty();
709 TReadHelper reader(stream);
710 if (format == MESSAGE_FORMAT_DANO_SWAPPED)
711 reader.SetSwap(true);
713 ssize_t size;
714 reader(size);
716 dano_message_header header;
717 reader(header);
718 into->what = header.what;
720 size -= sizeof(dano_section_header) + sizeof(dano_message_header);
721 int32 offset = 0;
723 while (offset < size) {
724 dano_section_header sectionHeader;
725 reader(sectionHeader);
727 // be safe. this shouldn't be necessary but in some testcases it was.
728 sectionHeader.size = pad_to_8(sectionHeader.size);
730 if (offset + sectionHeader.size > size || sectionHeader.size < 0)
731 return B_BAD_DATA;
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;
741 fieldBuffer = (uint8 *)malloc(fieldSize);
742 if (fieldBuffer == NULL)
743 throw (status_t)B_NO_MEMORY;
745 reader(fieldBuffer, fieldSize);
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;
755 case SECTION_SINGLE_ITEM_DATA:
757 dano_single_item *field = (dano_single_item *)fieldBuffer;
759 int32 dataOffset = sizeof(dano_single_item)
760 + field->name_length + 1;
761 dataOffset = pad_to_8(dataOffset);
763 if (offset + dataOffset + field->item_size > size)
764 return B_BAD_DATA;
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;
786 status_t result = into->AddData(field->name, field->type,
787 fieldBuffer + dataOffset, field->item_size, fixedSize);
789 if (result != B_OK) {
790 free(fieldBuffer);
791 throw result;
793 break;
796 case SECTION_FIXED_SIZE_ARRAY_DATA: {
797 dano_fixed_size_array *field
798 = (dano_fixed_size_array *)fieldBuffer;
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 */
806 if (offset + dataOffset + count * field->size_per_item > size)
807 return B_BAD_DATA;
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);
815 if (result != B_OK) {
816 free(fieldBuffer);
817 throw result;
820 dataOffset += field->size_per_item;
822 break;
825 case SECTION_VARIABLE_SIZE_ARRAY_DATA: {
826 dano_variable_size_array *field
827 = (dano_variable_size_array *)fieldBuffer;
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);
837 int32 *endPoints = (int32 *)(fieldBuffer + dataOffset
838 + totalSize);
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);
844 result = into->AddData(field->name, field->type,
845 fieldBuffer + dataOffset + itemOffset,
846 endPoints[i] - itemOffset, false, count);
848 if (result != B_OK) {
849 free(fieldBuffer);
850 throw result;
853 break;
857 free(fieldBuffer);
858 offset += sectionHeader.size;
861 return B_OK;
865 } // namespace BPrivate