xref: /haiku/src/kits/app/MessageAdapter.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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