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