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