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