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