xref: /haiku/src/build/libbe/app/Message.cpp (revision 6490c5b6211c94ec48c03c12b90e8603fe268d1b)
1 /*
2  * Copyright 2005-2009, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 
10 #include <Message.h>
11 #include <MessageAdapter.h>
12 #include <MessagePrivate.h>
13 #include <MessageUtils.h>
14 
15 #include <MessengerPrivate.h>
16 #include <TokenSpace.h>
17 
18 #include <Application.h>
19 #include <AppMisc.h>
20 #include <BlockCache.h>
21 #include <Entry.h>
22 #include <MessageQueue.h>
23 #include <Messenger.h>
24 #include <Path.h>
25 #include <Point.h>
26 #include <Rect.h>
27 #include <String.h>
28 
29 #include <assert.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "tracing_config.h"
36 	// kernel tracing configuration
37 
38 //#define VERBOSE_DEBUG_OUTPUT
39 #ifdef VERBOSE_DEBUG_OUTPUT
40 #define DEBUG_FUNCTION_ENTER	\
41 	debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
42 		" data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
43 		find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \
44 		__LINE__, __PRETTY_FUNCTION__);
45 
46 #define DEBUG_FUNCTION_ENTER2	\
47 	debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
48 		__LINE__, __PRETTY_FUNCTION__);
49 #else
50 #define DEBUG_FUNCTION_ENTER	/* nothing */
51 #define DEBUG_FUNCTION_ENTER2	/* nothing */
52 #endif
53 
54 #if BMESSAGE_TRACING
55 #	define KTRACE(format...)	ktrace_printf(format)
56 #else
57 #	define KTRACE(format...)
58 #endif
59 
60 
61 const char *B_SPECIFIER_ENTRY = "specifiers";
62 const char *B_PROPERTY_ENTRY = "property";
63 const char *B_PROPERTY_NAME_ENTRY = "name";
64 
65 extern "C" {
66 	// private os function to set the owning team of an area
67 	status_t _kern_transfer_area(area_id area, void **_address,
68 		uint32 addressSpec, team_id target);
69 }
70 
71 
72 BBlockCache *BMessage::sMsgCache = NULL;
73 
74 
75 template<typename Type>
76 static void
77 print_to_stream_type(uint8 *pointer)
78 {
79 	Type *item = (Type *)pointer;
80 	item->PrintToStream();
81 }
82 
83 
84 template<typename Type>
85 static void
86 print_type(const char *format, uint8 *pointer)
87 {
88 	Type *item = (Type *)pointer;
89 	printf(format, *item, *item);
90 }
91 
92 
93 //	#pragma mark -
94 
95 
96 BMessage::BMessage()
97 {
98 	DEBUG_FUNCTION_ENTER;
99 	_InitCommon(true);
100 }
101 
102 
103 BMessage::BMessage(BMessage *other)
104 {
105 	DEBUG_FUNCTION_ENTER;
106 	_InitCommon(false);
107 	*this = *other;
108 }
109 
110 
111 BMessage::BMessage(uint32 _what)
112 {
113 	DEBUG_FUNCTION_ENTER;
114 	_InitCommon(true);
115 	fHeader->what = what = _what;
116 }
117 
118 
119 BMessage::BMessage(const BMessage &other)
120 {
121 	DEBUG_FUNCTION_ENTER;
122 	_InitCommon(false);
123 	*this = other;
124 }
125 
126 
127 BMessage::~BMessage()
128 {
129 	DEBUG_FUNCTION_ENTER;
130 	_Clear();
131 }
132 
133 
134 BMessage &
135 BMessage::operator=(const BMessage &other)
136 {
137 	DEBUG_FUNCTION_ENTER;
138 
139     if (this == &other)
140         return *this;
141 
142 	_Clear();
143 
144 	fHeader = (message_header *)malloc(sizeof(message_header));
145 	if (fHeader == NULL)
146 		return *this;
147 
148 	memcpy(fHeader, other.fHeader, sizeof(message_header));
149 
150 	// Clear some header flags inherited from the original message that don't
151 	// apply to the clone.
152 	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
153 		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
154 		| MESSAGE_FLAG_PASS_BY_AREA);
155 	// Note, that BeOS R5 seems to keep the reply info.
156 
157 	if (fHeader->field_count > 0) {
158 		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
159 		fFields = (field_header *)malloc(fieldsSize);
160 		if (fFields == NULL) {
161 			fHeader->field_count = 0;
162 			fHeader->data_size = 0;
163 		} else
164 			memcpy(fFields, other.fFields, fieldsSize);
165 	}
166 
167 	if (fHeader->data_size > 0) {
168 		fData = (uint8 *)malloc(fHeader->data_size);
169 		if (fData == NULL) {
170 			fHeader->field_count = 0;
171 			free(fFields);
172 			fFields = NULL;
173 		} else
174 			memcpy(fData, other.fData, fHeader->data_size);
175 	}
176 
177 	fHeader->what = what = other.what;
178 	fHeader->message_area = -1;
179 	fFieldsAvailable = 0;
180 	fDataAvailable = 0;
181 
182 	return *this;
183 }
184 
185 
186 void *
187 BMessage::operator new(size_t size)
188 {
189 	DEBUG_FUNCTION_ENTER2;
190 	if (!sMsgCache)
191 		sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE);
192 	void *pointer = sMsgCache->Get(size);
193 	return pointer;
194 }
195 
196 
197 void *
198 BMessage::operator new(size_t, void *pointer)
199 {
200 	DEBUG_FUNCTION_ENTER2;
201 	return pointer;
202 }
203 
204 
205 void
206 BMessage::operator delete(void *pointer, size_t size)
207 {
208 	DEBUG_FUNCTION_ENTER2;
209 	sMsgCache->Save(pointer, size);
210 }
211 
212 
213 bool
214 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
215 	bool deep) const
216 {
217 	if (this == &other)
218 		return true;
219 
220 	if (fHeader->field_count != other.fHeader->field_count)
221 		return false;
222 
223 	for (uint32 i = 0; i < fHeader->field_count; i++) {
224 		field_header *field = &fFields[i];
225 		field_header *otherField = NULL;
226 
227 		const char *name = (const char *)fData + field->offset;
228 		if (ignoreFieldOrder) {
229 			if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
230 				return false;
231 		} else {
232 			otherField = &other.fFields[i];
233 			if (otherField->name_length != field->name_length)
234 				return false;
235 
236 			const char *otherName = (const char *)other.fData
237 				+ otherField->offset;
238 			if (strncmp(name, otherName, field->name_length) != 0)
239 				return false;
240 		}
241 
242 		if (otherField->type != field->type || otherField->count != field->count)
243 			return false;
244 
245 		uint8 *data = fData + field->offset + field->name_length;
246 		uint8 *otherData = other.fData + otherField->offset
247 			+ otherField->name_length;
248 
249 		bool needsMemCompare = true;
250 		if (deep && field->type == B_MESSAGE_TYPE) {
251 			BMessage message, otherMessage;
252 			if (message.Unflatten((const char *)data) == B_OK
253 				&& otherMessage.Unflatten((const char *)otherData) == B_OK) {
254 				if (!message.HasSameData(ignoreFieldOrder, deep))
255 					return false;
256 				needsMemCompare = false;
257 			}
258 		}
259 
260 		if (needsMemCompare) {
261 			if (otherField->data_size != field->data_size)
262 				return false;
263 			if (memcmp(data, otherData, field->data_size) != 0)
264 				return false;
265 		}
266 	}
267 
268 	return true;
269 }
270 
271 
272 status_t
273 BMessage::_InitCommon(bool initHeader)
274 {
275 	DEBUG_FUNCTION_ENTER;
276 	what = 0;
277 
278 	fHeader = NULL;
279 	fFields = NULL;
280 	fData = NULL;
281 
282 	fFieldsAvailable = 0;
283 	fDataAvailable = 0;
284 
285 	fOriginal = NULL;
286 	fQueueLink = NULL;
287 
288 	if (initHeader)
289 		return _InitHeader();
290 
291 	fHeader = NULL;
292 	return B_OK;
293 }
294 
295 
296 status_t
297 BMessage::_InitHeader()
298 {
299 	DEBUG_FUNCTION_ENTER;
300 	if (fHeader == NULL) {
301 		fHeader = (message_header *)malloc(sizeof(message_header));
302 		if (fHeader == NULL)
303 			return B_NO_MEMORY;
304 	}
305 
306 	memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
307 
308 	fHeader->format = MESSAGE_FORMAT_HAIKU;
309 	fHeader->flags = MESSAGE_FLAG_VALID;
310 	fHeader->what = what;
311 	fHeader->current_specifier = -1;
312 	fHeader->message_area = -1;
313 
314 	fHeader->target = B_NULL_TOKEN;
315 	fHeader->reply_target = B_NULL_TOKEN;
316 	fHeader->reply_port = -1;
317 	fHeader->reply_team = -1;
318 
319 	// initializing the hash table to -1 because 0 is a valid index
320 	fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
321 	memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
322 	return B_OK;
323 }
324 
325 
326 status_t
327 BMessage::_Clear()
328 {
329 	DEBUG_FUNCTION_ENTER;
330 	if (fHeader != NULL) {
331 		free(fHeader);
332 		fHeader = NULL;
333 	}
334 
335 	free(fFields);
336 	fFields = NULL;
337 	free(fData);
338 	fData = NULL;
339 
340 	fFieldsAvailable = 0;
341 	fDataAvailable = 0;
342 
343 	delete fOriginal;
344 	fOriginal = NULL;
345 
346 	return B_OK;
347 }
348 
349 
350 status_t
351 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound,
352 	type_code *typeFound, int32 *countFound) const
353 {
354 	DEBUG_FUNCTION_ENTER;
355 	if (index < 0 || (uint32)index >= fHeader->field_count)
356 		return B_BAD_INDEX;
357 
358 	if (typeRequested == B_ANY_TYPE) {
359 		if (nameFound)
360 			*nameFound = (char *)fData + fFields[index].offset;
361 		if (typeFound)
362 			*typeFound = fFields[index].type;
363 		if (countFound)
364 			*countFound = fFields[index].count;
365 		return B_OK;
366 	}
367 
368 	int32 counter = -1;
369 	field_header *field = fFields;
370 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
371 		if (field->type == typeRequested)
372 			counter++;
373 
374 		if (counter == index) {
375 			if (nameFound)
376 				*nameFound = (char *)fData + field->offset;
377 			if (typeFound)
378 				*typeFound = field->type;
379 			if (countFound)
380 				*countFound = field->count;
381 			return B_OK;
382 		}
383 	}
384 
385 	if (counter == -1)
386 		return B_BAD_TYPE;
387 
388 	return B_BAD_INDEX;
389 }
390 
391 
392 status_t
393 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound)
394 	const
395 {
396 	DEBUG_FUNCTION_ENTER;
397 	if (countFound)
398 		*countFound = 0;
399 
400 	field_header *field = NULL;
401 	status_t result = _FindField(name, B_ANY_TYPE, &field);
402 	if (result < B_OK || field == NULL)
403 		return result;
404 
405 	if (typeFound)
406 		*typeFound = field->type;
407 	if (countFound)
408 		*countFound = field->count;
409 
410 	return B_OK;
411 }
412 
413 
414 status_t
415 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize)
416 	const
417 {
418 	DEBUG_FUNCTION_ENTER;
419 	field_header *field = NULL;
420 	status_t result = _FindField(name, B_ANY_TYPE, &field);
421 	if (result < B_OK || field == NULL)
422 		return result;
423 
424 	if (typeFound)
425 		*typeFound = field->type;
426 	if (fixedSize)
427 		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
428 
429 	return B_OK;
430 }
431 
432 
433 int32
434 BMessage::CountNames(type_code type) const
435 {
436 	DEBUG_FUNCTION_ENTER;
437 	if (type == B_ANY_TYPE)
438 		return fHeader->field_count;
439 
440 	int32 count = 0;
441 	field_header *field = fFields;
442 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
443 		if (field->type == type)
444 			count++;
445 	}
446 
447 	return count;
448 }
449 
450 
451 bool
452 BMessage::IsEmpty() const
453 {
454 	DEBUG_FUNCTION_ENTER;
455 	return fHeader->field_count == 0;
456 }
457 
458 
459 bool
460 BMessage::IsSystem() const
461 {
462 	DEBUG_FUNCTION_ENTER;
463 	char a = char(what >> 24);
464 	char b = char(what >> 16);
465 	char c = char(what >> 8);
466 	char d = char(what);
467 
468 	// The BeBook says:
469 	//		... we've adopted a strict convention for assigning values to all
470 	//		Be-defined constants.  The value assigned will always be formed by
471 	//		combining four characters into a multicharacter constant, with the
472 	//		characters limited to uppercase letters and the underbar
473 	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
474 	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
475 		return true;
476 
477 	return false;
478 }
479 
480 
481 bool
482 BMessage::IsReply() const
483 {
484 	DEBUG_FUNCTION_ENTER;
485 	return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
486 }
487 
488 
489 void
490 BMessage::PrintToStream() const
491 {
492 	_PrintToStream("");
493 	printf("}\n");
494 }
495 
496 
497 void
498 BMessage::_PrintToStream(const char* indent) const
499 {
500 	DEBUG_FUNCTION_ENTER;
501 
502 	int32 value = B_BENDIAN_TO_HOST_INT32(what);
503 	printf("BMessage(");
504 	if (isprint(*(char *)&value))
505 		printf("'%.4s'", (char *)&value);
506 	else
507 		printf("0x%" B_PRIx32, what);
508 	printf(") {\n");
509 
510 	if (fHeader == NULL || fFields == NULL || fData == NULL)
511 		return;
512 
513 	field_header *field = fFields;
514 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
515 		value = B_BENDIAN_TO_HOST_INT32(field->type);
516 		ssize_t size = 0;
517 		if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
518 			size = field->data_size / field->count;
519 
520 		uint8 *pointer = fData + field->offset + field->name_length;
521 		for (uint32 j = 0; j < field->count; j++) {
522 			if (field->count == 1) {
523 				printf("%s        %s = ", indent,
524 					(char *)(fData + field->offset));
525 			} else {
526 				printf("%s        %s[%" B_PRIu32 "] = ", indent,
527 					(char *)(fData + field->offset), j);
528 			}
529 
530 			switch (field->type) {
531 				case B_RECT_TYPE:
532 					print_to_stream_type<BRect>(pointer);
533 					break;
534 
535 				case B_POINT_TYPE:
536 					print_to_stream_type<BPoint>(pointer);
537 					break;
538 
539 				case B_STRING_TYPE:
540 				{
541 					size = *(uint32 *)pointer;
542 					pointer += sizeof(uint32);
543 					printf("string(\"%s\", %ld bytes)\n", (char *)pointer,
544 						(long)size);
545 					break;
546 				}
547 
548 				case B_INT8_TYPE:
549 					print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
550 					break;
551 
552 				case B_UINT8_TYPE:
553 					print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n",
554 						pointer);
555 					break;
556 
557 				case B_INT16_TYPE:
558 					print_type<int16>("int16(0x%x or %d)\n", pointer);
559 					break;
560 
561 				case B_UINT16_TYPE:
562 					print_type<uint16>("uint16(0x%x or %u\n", pointer);
563 					break;
564 
565 				case B_INT32_TYPE:
566 					print_type<int32>("int32(0x%lx or %ld)\n", pointer);
567 					break;
568 
569 				case B_UINT32_TYPE:
570 					print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
571 					break;
572 
573 				case B_INT64_TYPE:
574 					print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
575 					break;
576 
577 				case B_UINT64_TYPE:
578 					print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
579 					break;
580 
581 				case B_BOOL_TYPE:
582 					printf("bool(%s)\n", *((bool *)pointer) != 0
583 						? "true" : "false");
584 					break;
585 
586 				case B_FLOAT_TYPE:
587 					print_type<float>("float(%.4f)\n", pointer);
588 					break;
589 
590 				case B_DOUBLE_TYPE:
591 					print_type<double>("double(%.8f)\n", pointer);
592 					break;
593 
594 				case B_REF_TYPE:
595 				{
596 					size = *(uint32 *)pointer;
597 					pointer += sizeof(uint32);
598 					entry_ref ref;
599 					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
600 
601 					printf("entry_ref(device=%d, directory=%" B_PRIdINO
602 						", name=\"%s\", ", (int)ref.device, ref.directory,
603 						ref.name);
604 
605 					BPath path(&ref);
606 					printf("path=\"%s\")\n", path.Path());
607 					break;
608 				}
609 
610 				case B_MESSAGE_TYPE:
611 				{
612 					char buffer[1024];
613 					sprintf(buffer, "%s        ", indent);
614 
615 					BMessage message;
616 					size = *(uint32 *)pointer;
617 					pointer += sizeof(uint32);
618 					status_t result = message.Unflatten((const char *)pointer);
619 					if (result != B_OK) {
620 						printf("failed unflatten: %s\n", strerror(result));
621 						break;
622 					}
623 
624 					message._PrintToStream(buffer);
625 					printf("%s        }\n", indent);
626 					break;
627 				}
628 
629 				default:
630 				{
631 					printf("(type = '%.4s')(size = %ld)\n", (char *)&value,
632 						(long)size);
633 					break;
634 				}
635 			}
636 
637 			pointer += size;
638 		}
639 	}
640 }
641 
642 
643 status_t
644 BMessage::Rename(const char *oldEntry, const char *newEntry)
645 {
646 	DEBUG_FUNCTION_ENTER;
647 	if (oldEntry == NULL || newEntry == NULL)
648 		return B_BAD_VALUE;
649 
650 	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
651 	int32 *nextField = &fHeader->hash_table[hash];
652 
653 	while (*nextField >= 0) {
654 		field_header *field = &fFields[*nextField];
655 
656 		if (strncmp((const char *)(fData + field->offset), oldEntry,
657 			field->name_length) == 0) {
658 			// nextField points to the field for oldEntry, save it and unlink
659 			int32 index = *nextField;
660 			*nextField = field->next_field;
661 			field->next_field = -1;
662 
663 			hash = _HashName(newEntry) % fHeader->hash_table_size;
664 			nextField = &fHeader->hash_table[hash];
665 			while (*nextField >= 0)
666 				nextField = &fFields[*nextField].next_field;
667 			*nextField = index;
668 
669 			int32 newLength = strlen(newEntry) + 1;
670 			status_t result = _ResizeData(field->offset + 1,
671 				newLength - field->name_length);
672 			if (result < B_OK)
673 				return result;
674 
675 			memcpy(fData + field->offset, newEntry, newLength);
676 			field->name_length = newLength;
677 			return B_OK;
678 		}
679 
680 		nextField = &field->next_field;
681 	}
682 
683 	return B_NAME_NOT_FOUND;
684 }
685 
686 
687 bool
688 BMessage::WasDelivered() const
689 {
690 	DEBUG_FUNCTION_ENTER;
691 	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
692 }
693 
694 
695 bool
696 BMessage::IsSourceWaiting() const
697 {
698 	DEBUG_FUNCTION_ENTER;
699 	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
700 		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
701 }
702 
703 
704 BMessenger
705 BMessage::ReturnAddress() const
706 {
707 	DEBUG_FUNCTION_ENTER;
708 	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
709 		BMessenger messenger;
710 		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
711 			fHeader->reply_port, fHeader->reply_target);
712 		return messenger;
713 	}
714 
715 	return BMessenger();
716 }
717 
718 
719 const BMessage *
720 BMessage::Previous() const
721 {
722 	DEBUG_FUNCTION_ENTER;
723 	/* ToDo: test if the "_previous_" field is used in R5 */
724 	if (fOriginal == NULL) {
725 		fOriginal = new BMessage();
726 
727 		if (FindMessage("_previous_", fOriginal) != B_OK) {
728 			delete fOriginal;
729 			fOriginal = NULL;
730 		}
731 	}
732 
733 	return fOriginal;
734 }
735 
736 
737 bool
738 BMessage::WasDropped() const
739 {
740 	DEBUG_FUNCTION_ENTER;
741 	return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
742 }
743 
744 
745 BPoint
746 BMessage::DropPoint(BPoint *offset) const
747 {
748 	DEBUG_FUNCTION_ENTER;
749 	if (offset)
750 		*offset = FindPoint("_drop_offset_");
751 
752 	return FindPoint("_drop_point_");
753 }
754 
755 
756 ssize_t
757 BMessage::FlattenedSize() const
758 {
759 	DEBUG_FUNCTION_ENTER;
760 	return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
761 		+ fHeader->data_size;
762 }
763 
764 
765 status_t
766 BMessage::Flatten(char *buffer, ssize_t size) const
767 {
768 	DEBUG_FUNCTION_ENTER;
769 	if (buffer == NULL || size < 0)
770 		return B_BAD_VALUE;
771 
772 	if (fHeader == NULL)
773 		return B_NO_INIT;
774 
775 	/* we have to sync the what code as it is a public member */
776 	fHeader->what = what;
777 
778 	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
779 	buffer += sizeof(message_header);
780 	size -= sizeof(message_header);
781 
782 	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
783 	memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
784 	buffer += fieldsSize;
785 	size -= fieldsSize;
786 
787 	memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
788 	if ((size_t)size < fHeader->data_size)
789 		return B_BUFFER_OVERFLOW;
790 
791 	return B_OK;
792 }
793 
794 
795 status_t
796 BMessage::Flatten(BDataIO *stream, ssize_t *size) const
797 {
798 	DEBUG_FUNCTION_ENTER;
799 	if (stream == NULL)
800 		return B_BAD_VALUE;
801 
802 	if (fHeader == NULL)
803 		return B_NO_INIT;
804 
805 	/* we have to sync the what code as it is a public member */
806 	fHeader->what = what;
807 
808 	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
809 	if (result1 != sizeof(message_header))
810 		return result1 < 0 ? result1 : B_ERROR;
811 
812 	ssize_t result2 = 0;
813 	if (fHeader->field_count > 0) {
814 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
815 		result2 = stream->Write(fFields, fieldsSize);
816 		if (result2 != fieldsSize)
817 			return result2 < 0 ? result2 : B_ERROR;
818 	}
819 
820 	ssize_t result3 = 0;
821 	if (fHeader->data_size > 0) {
822 		result3 = stream->Write(fData, fHeader->data_size);
823 		if (result3 != (ssize_t)fHeader->data_size)
824 			return result3 < 0 ? result3 : B_ERROR;
825 	}
826 
827 	if (size)
828 		*size = result1 + result2 + result3;
829 
830 	return B_OK;
831 }
832 
833 
834 status_t
835 BMessage::_ValidateMessage()
836 {
837 	if (fHeader->field_count == 0)
838 		return B_OK;
839 
840 	if (fFields == NULL)
841 		return B_NO_INIT;
842 
843 	for (uint32 i = 0; i < fHeader->field_count; i++) {
844 		field_header *field = &fFields[i];
845 		if ((field->next_field >= 0
846 				&& (uint32)field->next_field > fHeader->field_count)
847 			|| (field->offset + field->name_length + field->data_size
848 				> fHeader->data_size)) {
849 			// the message is corrupt
850 			MakeEmpty();
851 			return B_BAD_VALUE;
852 		}
853 	}
854 
855 	return B_OK;
856 }
857 
858 
859 status_t
860 BMessage::Unflatten(const char *flatBuffer)
861 {
862 	DEBUG_FUNCTION_ENTER;
863 	if (flatBuffer == NULL)
864 		return B_BAD_VALUE;
865 
866 	uint32 format = *(uint32 *)flatBuffer;
867 	if (format != MESSAGE_FORMAT_HAIKU)
868 		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
869 
870 	// native message unflattening
871 
872 	_Clear();
873 
874 	fHeader = (message_header *)malloc(sizeof(message_header));
875 	if (fHeader == NULL)
876 		return B_NO_MEMORY;
877 
878 	memcpy(fHeader, flatBuffer, sizeof(message_header));
879 	flatBuffer += sizeof(message_header);
880 
881 	if (fHeader->format != MESSAGE_FORMAT_HAIKU
882 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
883 		_InitHeader();
884 		return B_BAD_VALUE;
885 	}
886 
887 	what = fHeader->what;
888 
889 	if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
890 		&& fHeader->message_area >= 0) {
891 //		status_t result = _Reference();
892 //		if (result != B_OK)
893 //			return result;
894 	} else {
895 		fHeader->message_area = -1;
896 
897 		if (fHeader->field_count > 0) {
898 			size_t fieldsSize = fHeader->field_count * sizeof(field_header);
899 			fFields = (field_header *)malloc(fieldsSize);
900 			if (fFields == NULL) {
901 				_InitHeader();
902 				return B_NO_MEMORY;
903 			}
904 
905 			memcpy(fFields, flatBuffer, fieldsSize);
906 			flatBuffer += fieldsSize;
907 		}
908 
909 		if (fHeader->data_size > 0) {
910 			fData = (uint8 *)malloc(fHeader->data_size);
911 			if (fData == NULL) {
912 				free(fFields);
913 				fFields = NULL;
914 				_InitHeader();
915 				return B_NO_MEMORY;
916 			}
917 
918 			memcpy(fData, flatBuffer, fHeader->data_size);
919 		}
920 	}
921 
922 	return _ValidateMessage();
923 }
924 
925 
926 status_t
927 BMessage::Unflatten(BDataIO *stream)
928 {
929 	DEBUG_FUNCTION_ENTER;
930 	if (stream == NULL)
931 		return B_BAD_VALUE;
932 
933 	uint32 format = 0;
934 	stream->Read(&format, sizeof(uint32));
935 	if (format != MESSAGE_FORMAT_HAIKU)
936 		return BPrivate::MessageAdapter::Unflatten(format, this, stream);
937 
938 	// native message unflattening
939 
940 	_Clear();
941 
942 	fHeader = (message_header *)malloc(sizeof(message_header));
943 	if (fHeader == NULL)
944 		return B_NO_MEMORY;
945 
946 	fHeader->format = format;
947 	uint8 *header = (uint8 *)fHeader;
948 	ssize_t result = stream->Read(header + sizeof(uint32),
949 		sizeof(message_header) - sizeof(uint32));
950 	if (result != sizeof(message_header) - sizeof(uint32)
951 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
952 		_InitHeader();
953 		return result < 0 ? result : B_BAD_VALUE;
954 	}
955 
956 	what = fHeader->what;
957 
958 	fHeader->message_area = -1;
959 
960 	if (fHeader->field_count > 0) {
961 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
962 		fFields = (field_header *)malloc(fieldsSize);
963 		if (fFields == NULL) {
964 			_InitHeader();
965 			return B_NO_MEMORY;
966 		}
967 
968 		result = stream->Read(fFields, fieldsSize);
969 		if (result != fieldsSize)
970 			return result < 0 ? result : B_BAD_VALUE;
971 	}
972 
973 	if (fHeader->data_size > 0) {
974 		fData = (uint8 *)malloc(fHeader->data_size);
975 		if (fData == NULL) {
976 			free(fFields);
977 			fFields = NULL;
978 			_InitHeader();
979 			return B_NO_MEMORY;
980 		}
981 
982 		result = stream->Read(fData, fHeader->data_size);
983 		if (result != (ssize_t)fHeader->data_size)
984 			return result < 0 ? result : B_BAD_VALUE;
985 	}
986 
987 	return _ValidateMessage();
988 }
989 
990 
991 status_t
992 BMessage::AddSpecifier(const char *property)
993 {
994 	DEBUG_FUNCTION_ENTER;
995 	BMessage message(B_DIRECT_SPECIFIER);
996 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
997 	if (result < B_OK)
998 		return result;
999 
1000 	return AddSpecifier(&message);
1001 }
1002 
1003 
1004 status_t
1005 BMessage::AddSpecifier(const char *property, int32 index)
1006 {
1007 	DEBUG_FUNCTION_ENTER;
1008 	BMessage message(B_INDEX_SPECIFIER);
1009 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1010 	if (result < B_OK)
1011 		return result;
1012 
1013 	result = message.AddInt32("index", index);
1014 	if (result < B_OK)
1015 		return result;
1016 
1017 	return AddSpecifier(&message);
1018 }
1019 
1020 
1021 status_t
1022 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1023 {
1024 	DEBUG_FUNCTION_ENTER;
1025 	if (range < 0)
1026 		return B_BAD_VALUE;
1027 
1028 	BMessage message(B_RANGE_SPECIFIER);
1029 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1030 	if (result < B_OK)
1031 		return result;
1032 
1033 	result = message.AddInt32("index", index);
1034 	if (result < B_OK)
1035 		return result;
1036 
1037 	result = message.AddInt32("range", range);
1038 	if (result < B_OK)
1039 		return result;
1040 
1041 	return AddSpecifier(&message);
1042 }
1043 
1044 
1045 status_t
1046 BMessage::AddSpecifier(const char *property, const char *name)
1047 {
1048 	DEBUG_FUNCTION_ENTER;
1049 	BMessage message(B_NAME_SPECIFIER);
1050 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1051 	if (result < B_OK)
1052 		return result;
1053 
1054 	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1055 	if (result < B_OK)
1056 		return result;
1057 
1058 	return AddSpecifier(&message);
1059 }
1060 
1061 
1062 status_t
1063 BMessage::AddSpecifier(const BMessage *specifier)
1064 {
1065 	DEBUG_FUNCTION_ENTER;
1066 	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1067 	if (result < B_OK)
1068 		return result;
1069 
1070 	fHeader->current_specifier++;
1071 	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1072 	return B_OK;
1073 }
1074 
1075 
1076 status_t
1077 BMessage::SetCurrentSpecifier(int32 index)
1078 {
1079 	DEBUG_FUNCTION_ENTER;
1080 	if (index < 0)
1081 		return B_BAD_INDEX;
1082 
1083 	type_code type;
1084 	int32 count;
1085 	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1086 	if (result < B_OK)
1087 		return result;
1088 
1089 	if (index > count)
1090 		return B_BAD_INDEX;
1091 
1092 	fHeader->current_specifier = index;
1093 	return B_OK;
1094 }
1095 
1096 
1097 status_t
1098 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what,
1099 	const char **property) const
1100 {
1101 	DEBUG_FUNCTION_ENTER;
1102 
1103 	if (index != NULL)
1104 		*index = fHeader->current_specifier;
1105 
1106 	if (fHeader->current_specifier < 0
1107 		|| (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1108 		return B_BAD_SCRIPT_SYNTAX;
1109 
1110 	if (specifier) {
1111 		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1112 			specifier) < B_OK)
1113 			return B_BAD_SCRIPT_SYNTAX;
1114 
1115 		if (_what != NULL)
1116 			*_what = specifier->what;
1117 
1118 		if (property) {
1119 			if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1120 				return B_BAD_SCRIPT_SYNTAX;
1121 		}
1122 	}
1123 
1124 	return B_OK;
1125 }
1126 
1127 
1128 bool
1129 BMessage::HasSpecifiers() const
1130 {
1131 	DEBUG_FUNCTION_ENTER;
1132 	return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1133 }
1134 
1135 
1136 status_t
1137 BMessage::PopSpecifier()
1138 {
1139 	DEBUG_FUNCTION_ENTER;
1140 	if (fHeader->current_specifier < 0 ||
1141 		(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1142 		return B_BAD_VALUE;
1143 
1144 	if (fHeader->current_specifier >= 0)
1145 		fHeader->current_specifier--;
1146 
1147 	return B_OK;
1148 }
1149 
1150 
1151 status_t
1152 BMessage::_ResizeData(uint32 offset, int32 change)
1153 {
1154 	if (change == 0)
1155 		return B_OK;
1156 
1157 	/* optimize for the most usual case: appending data */
1158 	if (offset < fHeader->data_size) {
1159 		field_header *field = fFields;
1160 		for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1161 			if (field->offset >= offset)
1162 				field->offset += change;
1163 		}
1164 	}
1165 
1166 	if (change > 0) {
1167 		if (fDataAvailable >= (uint32)change) {
1168 			if (offset < fHeader->data_size) {
1169 				memmove(fData + offset + change, fData + offset,
1170 					fHeader->data_size - offset);
1171 			}
1172 
1173 			fDataAvailable -= change;
1174 			fHeader->data_size += change;
1175 			return B_OK;
1176 		}
1177 
1178 		size_t size = fHeader->data_size * 2;
1179 		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1180 		size = max_c(size, fHeader->data_size + change);
1181 
1182 		uint8 *newData = (uint8 *)realloc(fData, size);
1183 		if (size > 0 && newData == NULL)
1184 			return B_NO_MEMORY;
1185 
1186 		fData = newData;
1187 		if (offset < fHeader->data_size) {
1188 			memmove(fData + offset + change, fData + offset,
1189 				fHeader->data_size - offset);
1190 		}
1191 
1192 		fHeader->data_size += change;
1193 		fDataAvailable = size - fHeader->data_size;
1194 	} else {
1195 		ssize_t length = fHeader->data_size - offset + change;
1196 		if (length > 0)
1197 			memmove(fData + offset, fData + offset - change, length);
1198 
1199 		// change is negative
1200 		fHeader->data_size += change;
1201 		fDataAvailable -= change;
1202 
1203 		if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1204 			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1205 			ssize_t size = fHeader->data_size + available;
1206 			uint8 *newData = (uint8 *)realloc(fData, size);
1207 			if (size > 0 && newData == NULL) {
1208 				// this is strange, but not really fatal
1209 				return B_OK;
1210 			}
1211 
1212 			fData = newData;
1213 			fDataAvailable = available;
1214 		}
1215 	}
1216 
1217 	return B_OK;
1218 }
1219 
1220 
1221 uint32
1222 BMessage::_HashName(const char *name) const
1223 {
1224 	char ch;
1225 	uint32 result = 0;
1226 
1227 	while ((ch = *name++) != 0) {
1228 		result = (result << 7) ^ (result >> 24);
1229 		result ^= ch;
1230 	}
1231 
1232 	result ^= result << 12;
1233 	return result;
1234 }
1235 
1236 
1237 status_t
1238 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1239 {
1240 	if (name == NULL)
1241 		return B_BAD_VALUE;
1242 
1243 	if (fHeader == NULL || fFields == NULL || fData == NULL)
1244 		return B_NAME_NOT_FOUND;
1245 
1246 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1247 	int32 nextField = fHeader->hash_table[hash];
1248 
1249 	while (nextField >= 0) {
1250 		field_header *field = &fFields[nextField];
1251 		if ((field->flags & FIELD_FLAG_VALID) == 0)
1252 			break;
1253 
1254 		if (strncmp((const char *)(fData + field->offset), name,
1255 			field->name_length) == 0) {
1256 			if (type != B_ANY_TYPE && field->type != type)
1257 				return B_BAD_TYPE;
1258 
1259 			*result = field;
1260 			return B_OK;
1261 		}
1262 
1263 		nextField = field->next_field;
1264 	}
1265 
1266 	return B_NAME_NOT_FOUND;
1267 }
1268 
1269 
1270 status_t
1271 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1272 	field_header **result)
1273 {
1274 	if (fHeader == NULL)
1275 		return B_ERROR;
1276 
1277 	if (fFieldsAvailable <= 0) {
1278 		uint32 count = fHeader->field_count * 2 + 1;
1279 		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1280 
1281 		field_header *newFields = (field_header *)realloc(fFields,
1282 			count * sizeof(field_header));
1283 		if (count > 0 && newFields == NULL)
1284 			return B_NO_MEMORY;
1285 
1286 		fFields = newFields;
1287 		fFieldsAvailable = count - fHeader->field_count;
1288 	}
1289 
1290 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1291 	int32 *nextField = &fHeader->hash_table[hash];
1292 	while (*nextField >= 0)
1293 		nextField = &fFields[*nextField].next_field;
1294 	*nextField = fHeader->field_count;
1295 
1296 	field_header *field = &fFields[fHeader->field_count];
1297 	field->type = type;
1298 	field->count = 0;
1299 	field->data_size = 0;
1300 	field->next_field = -1;
1301 	field->offset = fHeader->data_size;
1302 	field->name_length = strlen(name) + 1;
1303 	status_t status = _ResizeData(field->offset, field->name_length);
1304 	if (status < B_OK)
1305 		return status;
1306 
1307 	memcpy(fData + field->offset, name, field->name_length);
1308 	field->flags = FIELD_FLAG_VALID;
1309 	if (isFixedSize)
1310 		field->flags |= FIELD_FLAG_FIXED_SIZE;
1311 
1312 	fFieldsAvailable--;
1313 	fHeader->field_count++;
1314 	*result = field;
1315 	return B_OK;
1316 }
1317 
1318 
1319 status_t
1320 BMessage::_RemoveField(field_header *field)
1321 {
1322 	status_t result = _ResizeData(field->offset, -(field->data_size
1323 		+ field->name_length));
1324 	if (result < B_OK)
1325 		return result;
1326 
1327 	int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1328 	int32 nextField = field->next_field;
1329 	if (nextField > index)
1330 		nextField--;
1331 
1332 	int32 *value = fHeader->hash_table;
1333 	for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1334 		if (*value > index)
1335 			*value -= 1;
1336 		else if (*value == index)
1337 			*value = nextField;
1338 	}
1339 
1340 	field_header *other = fFields;
1341 	for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1342 		if (other->next_field > index)
1343 			other->next_field--;
1344 		else if (other->next_field == index)
1345 			other->next_field = nextField;
1346 	}
1347 
1348 	size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1349 	memmove(fFields + index, fFields + index + 1, size);
1350 	fHeader->field_count--;
1351 	fFieldsAvailable++;
1352 
1353 	if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1354 		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1355 		size = (fHeader->field_count + available) * sizeof(field_header);
1356 		field_header *newFields = (field_header *)realloc(fFields, size);
1357 		if (size > 0 && newFields == NULL) {
1358 			// this is strange, but not really fatal
1359 			return B_OK;
1360 		}
1361 
1362 		fFields = newFields;
1363 		fFieldsAvailable = available;
1364 	}
1365 
1366 	return B_OK;
1367 }
1368 
1369 
1370 status_t
1371 BMessage::AddData(const char *name, type_code type, const void *data,
1372 	ssize_t numBytes, bool isFixedSize, int32 count)
1373 {
1374 	// Note that the "count" argument is only a hint at how many items
1375 	// the caller expects to add to this field. Since we do no item pre-
1376 	// allocation, we ignore this argument.
1377 	DEBUG_FUNCTION_ENTER;
1378 	if (numBytes <= 0 || data == NULL)
1379 		return B_BAD_VALUE;
1380 
1381 	field_header *field = NULL;
1382 	status_t result = _FindField(name, type, &field);
1383 	if (result == B_NAME_NOT_FOUND)
1384 		result = _AddField(name, type, isFixedSize, &field);
1385 
1386 	if (result < B_OK)
1387 		return result;
1388 
1389 	if (field == NULL)
1390 		return B_ERROR;
1391 
1392 	uint32 offset = field->offset + field->name_length + field->data_size;
1393 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1394 		if (field->count) {
1395 			ssize_t size = field->data_size / field->count;
1396 			if (size != numBytes)
1397 				return B_BAD_VALUE;
1398 		}
1399 
1400 		result = _ResizeData(offset, numBytes);
1401 		if (result < B_OK) {
1402 			if (field->count == 0)
1403 				_RemoveField(field);
1404 			return result;
1405 		}
1406 
1407 		memcpy(fData + offset, data, numBytes);
1408 		field->data_size += numBytes;
1409 	} else {
1410 		int32 change = numBytes + sizeof(uint32);
1411 		result = _ResizeData(offset, change);
1412 		if (result < B_OK) {
1413 			if (field->count == 0)
1414 				_RemoveField(field);
1415 			return result;
1416 		}
1417 
1418 		uint32 size = (uint32)numBytes;
1419 		memcpy(fData + offset, &size, sizeof(uint32));
1420 		memcpy(fData + offset + sizeof(uint32), data, size);
1421 		field->data_size += change;
1422 	}
1423 
1424 	field->count++;
1425 	return B_OK;
1426 }
1427 
1428 
1429 status_t
1430 BMessage::RemoveData(const char *name, int32 index)
1431 {
1432 	DEBUG_FUNCTION_ENTER;
1433 	if (index < 0)
1434 		return B_BAD_INDEX;
1435 
1436 	field_header *field = NULL;
1437 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1438 
1439 	if (result < B_OK)
1440 		return result;
1441 
1442 	if (field == NULL)
1443 		return B_ERROR;
1444 
1445 	if ((uint32)index >= field->count)
1446 		return B_BAD_INDEX;
1447 
1448 	if (field->count == 1)
1449 		return _RemoveField(field);
1450 
1451 	uint32 offset = field->offset + field->name_length;
1452 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1453 		ssize_t size = field->data_size / field->count;
1454 		result = _ResizeData(offset + index * size, -size);
1455 		if (result < B_OK)
1456 			return result;
1457 
1458 		field->data_size -= size;
1459 	} else {
1460 		uint8 *pointer = fData + offset;
1461 		for (int32 i = 0; i < index; i++) {
1462 			offset += *(uint32 *)pointer + sizeof(uint32);
1463 			pointer = fData + offset;
1464 		}
1465 
1466 		size_t currentSize = *(uint32 *)pointer + sizeof(uint32);
1467 		result = _ResizeData(offset, -currentSize);
1468 		if (result < B_OK)
1469 			return result;
1470 
1471 		field->data_size -= currentSize;
1472 	}
1473 
1474 	field->count--;
1475 	return B_OK;
1476 }
1477 
1478 
1479 status_t
1480 BMessage::RemoveName(const char *name)
1481 {
1482 	DEBUG_FUNCTION_ENTER;
1483 	field_header *field = NULL;
1484 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1485 
1486 	if (result < B_OK)
1487 		return result;
1488 
1489 	if (field == NULL)
1490 		return B_ERROR;
1491 
1492 	return _RemoveField(field);
1493 }
1494 
1495 
1496 status_t
1497 BMessage::MakeEmpty()
1498 {
1499 	DEBUG_FUNCTION_ENTER;
1500 	_Clear();
1501 	_InitHeader();
1502 	return B_OK;
1503 }
1504 
1505 
1506 status_t
1507 BMessage::FindData(const char *name, type_code type, int32 index,
1508 	const void **data, ssize_t *numBytes) const
1509 {
1510 	DEBUG_FUNCTION_ENTER;
1511 	if (data == NULL)
1512 		return B_BAD_VALUE;
1513 
1514 	*data = NULL;
1515 	field_header *field = NULL;
1516 	status_t result = _FindField(name, type, &field);
1517 
1518 	if (result < B_OK)
1519 		return result;
1520 
1521 	if (field == NULL)
1522 		return B_ERROR;
1523 
1524 	if (index < 0 || (uint32)index >= field->count)
1525 		return B_BAD_INDEX;
1526 
1527 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1528 		size_t bytes = field->data_size / field->count;
1529 		*data = fData + field->offset + field->name_length + index * bytes;
1530 		if (numBytes != NULL)
1531 			*numBytes = bytes;
1532 	} else {
1533 		uint8 *pointer = fData + field->offset + field->name_length;
1534 		for (int32 i = 0; i < index; i++)
1535 			pointer += *(uint32 *)pointer + sizeof(uint32);
1536 
1537 		*data = pointer + sizeof(uint32);
1538 		if (numBytes != NULL)
1539 			*numBytes = *(uint32 *)pointer;
1540 	}
1541 
1542 	return B_OK;
1543 }
1544 
1545 
1546 status_t
1547 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1548 	const void *data, ssize_t numBytes)
1549 {
1550 	DEBUG_FUNCTION_ENTER;
1551 	if (numBytes <= 0 || data == NULL)
1552 		return B_BAD_VALUE;
1553 
1554 	field_header *field = NULL;
1555 	status_t result = _FindField(name, type, &field);
1556 
1557 	if (result < B_OK)
1558 		return result;
1559 
1560 	if (field == NULL)
1561 		return B_ERROR;
1562 
1563 	if (index < 0 || (uint32)index >= field->count)
1564 		return B_BAD_INDEX;
1565 
1566 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1567 		ssize_t size = field->data_size / field->count;
1568 		if (size != numBytes)
1569 			return B_BAD_VALUE;
1570 
1571 		memcpy(fData + field->offset + field->name_length + index * size, data,
1572 			size);
1573 	} else {
1574 		uint32 offset = field->offset + field->name_length;
1575 		uint8 *pointer = fData + offset;
1576 
1577 		for (int32 i = 0; i < index; i++) {
1578 			offset += *(uint32 *)pointer + sizeof(uint32);
1579 			pointer = fData + offset;
1580 		}
1581 
1582 		size_t currentSize = *(uint32 *)pointer;
1583 		int32 change = numBytes - currentSize;
1584 		result = _ResizeData(offset, change);
1585 		if (result < B_OK)
1586 			return result;
1587 
1588 		uint32 newSize = (uint32)numBytes;
1589 		memcpy(fData + offset, &newSize, sizeof(uint32));
1590 		memcpy(fData + offset + sizeof(uint32), data, newSize);
1591 		field->data_size += change;
1592 	}
1593 
1594 	return B_OK;
1595 }
1596 
1597 
1598 bool
1599 BMessage::HasData(const char *name, type_code type, int32 index) const
1600 {
1601 	DEBUG_FUNCTION_ENTER;
1602 	field_header *field = NULL;
1603 	status_t result = _FindField(name, type, &field);
1604 
1605 	if (result < B_OK)
1606 		return false;
1607 
1608 	if (field == NULL)
1609 		return false;
1610 
1611 	if (index < 0 || (uint32)index >= field->count)
1612 		return false;
1613 
1614 	return true;
1615 }
1616 
1617 
1618 void BMessage::_ReservedMessage1(void) {};
1619 void BMessage::_ReservedMessage2(void) {};
1620 void BMessage::_ReservedMessage3(void) {};
1621 
1622 
1623 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
1624 
1625 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
1626 status_t																	\
1627 BMessage::Add##typeName(const char *name, type val)							\
1628 {																			\
1629 	return AddData(name, typeCode, &val, sizeof(type), true);				\
1630 }																			\
1631 																			\
1632 status_t																	\
1633 BMessage::Find##typeName(const char *name, type *p) const					\
1634 {																			\
1635 	void *ptr = NULL;														\
1636 	ssize_t bytes = 0;														\
1637 	status_t error = B_OK;													\
1638 																			\
1639 	*p = type();															\
1640 	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
1641 																			\
1642 	if (error == B_OK)														\
1643 		memcpy(p, ptr, sizeof(type));										\
1644 																			\
1645 	return error;															\
1646 }																			\
1647 																			\
1648 status_t																	\
1649 BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
1650 {																			\
1651 	void *ptr = NULL;														\
1652 	ssize_t bytes = 0;														\
1653 	status_t error = B_OK;													\
1654 																			\
1655 	*p = type();															\
1656 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
1657 																			\
1658 	if (error == B_OK)														\
1659 		memcpy(p, ptr, sizeof(type));										\
1660 																			\
1661 	return error;															\
1662 }																			\
1663 																			\
1664 status_t																	\
1665 BMessage::Replace##typeName(const char *name, type val)						\
1666 {																			\
1667 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
1668 }																			\
1669 																			\
1670 status_t																	\
1671 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
1672 {																			\
1673 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
1674 }																			\
1675 																			\
1676 bool																		\
1677 BMessage::Has##typeName(const char *name, int32 index) const				\
1678 {																			\
1679 	return HasData(name, typeCode, index);									\
1680 }
1681 
1682 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
1683 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
1684 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
1685 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
1686 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
1687 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
1688 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
1689 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
1690 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
1691 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
1692 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
1693 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
1694 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
1695 
1696 #undef DEFINE_FUNCTIONS
1697 
1698 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
1699 bool																		\
1700 BMessage::Has##typeName(const char *name, int32 index) const				\
1701 {																			\
1702 	return HasData(name, typeCode, index);									\
1703 }
1704 
1705 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
1706 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
1707 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
1708 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
1709 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
1710 
1711 #undef DEFINE_HAS_FUNCTION
1712 
1713 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
1714 type																		\
1715 BMessage::Find##typeName(const char *name, int32 index) const				\
1716 {																			\
1717 	type val = initialize;													\
1718 	Find##typeName(name, index, &val);										\
1719 	return val;																\
1720 }
1721 
1722 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
1723 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
1724 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
1725 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
1726 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
1727 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
1728 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
1729 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
1730 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
1731 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
1732 
1733 #undef DEFINE_LAZY_FIND_FUNCTION
1734 
1735 status_t
1736 BMessage::AddString(const char *name, const char *string)
1737 {
1738 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
1739 }
1740 
1741 
1742 status_t
1743 BMessage::AddString(const char *name, const BString &string)
1744 {
1745 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
1746 }
1747 
1748 
1749 status_t
1750 BMessage::AddPointer(const char *name, const void *pointer)
1751 {
1752 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
1753 }
1754 
1755 
1756 status_t
1757 BMessage::AddMessenger(const char *name, BMessenger messenger)
1758 {
1759 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
1760 }
1761 
1762 
1763 status_t
1764 BMessage::AddRef(const char *name, const entry_ref *ref)
1765 {
1766 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
1767 	char buffer[size];
1768 
1769 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
1770 
1771 	if (error >= B_OK)
1772 		error = AddData(name, B_REF_TYPE, buffer, size, false);
1773 
1774 	return error;
1775 }
1776 
1777 
1778 status_t
1779 BMessage::AddMessage(const char *name, const BMessage *message)
1780 {
1781 	if (message == NULL)
1782 		return B_BAD_VALUE;
1783 
1784 	// TODO: This and the following functions waste time by allocating and
1785 	// copying an extra buffer. Functions can be added that return a direct
1786 	// pointer into the message.
1787 
1788 	char stackBuffer[16384];
1789 	ssize_t size = message->FlattenedSize();
1790 
1791 	char* buffer;
1792 	if (size > (ssize_t)sizeof(stackBuffer)) {
1793 		buffer = (char *)malloc(size);
1794 		if (buffer == NULL)
1795 			return B_NO_MEMORY;
1796 	} else
1797 		buffer = stackBuffer;
1798 
1799 	status_t error = message->Flatten(buffer, size);
1800 
1801 	if (error >= B_OK)
1802 		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
1803 
1804 	if (buffer != stackBuffer)
1805 		free(buffer);
1806 
1807 	return error;
1808 }
1809 
1810 
1811 status_t
1812 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
1813 {
1814 	if (object == NULL)
1815 		return B_BAD_VALUE;
1816 
1817 	char stackBuffer[16384];
1818 	ssize_t size = object->FlattenedSize();
1819 
1820 	char* buffer;
1821 	if (size > (ssize_t)sizeof(stackBuffer)) {
1822 		buffer = (char *)malloc(size);
1823 		if (buffer == NULL)
1824 			return B_NO_MEMORY;
1825 	} else
1826 		buffer = stackBuffer;
1827 
1828 	status_t error = object->Flatten(buffer, size);
1829 
1830 	if (error >= B_OK)
1831 		error = AddData(name, object->TypeCode(), buffer, size, false);
1832 
1833 	if (buffer != stackBuffer)
1834 		free(buffer);
1835 
1836 	return error;
1837 }
1838 
1839 
1840 status_t
1841 BMessage::FindString(const char *name, const char **string) const
1842 {
1843 	return FindString(name, 0, string);
1844 }
1845 
1846 
1847 status_t
1848 BMessage::FindString(const char *name, int32 index, const char **string) const
1849 {
1850 	ssize_t bytes;
1851 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
1852 }
1853 
1854 
1855 status_t
1856 BMessage::FindString(const char *name, BString *string) const
1857 {
1858 	return FindString(name, 0, string);
1859 }
1860 
1861 
1862 status_t
1863 BMessage::FindString(const char *name, int32 index, BString *string) const
1864 {
1865 	if (string == NULL)
1866 		return B_BAD_VALUE;
1867 
1868 	const char *cstr;
1869 	status_t error = FindString(name, index, &cstr);
1870 	if (error < B_OK)
1871 		return error;
1872 
1873 	*string = cstr;
1874 	return B_OK;
1875 }
1876 
1877 
1878 status_t
1879 BMessage::FindPointer(const char *name, void **pointer) const
1880 {
1881 	return FindPointer(name, 0, pointer);
1882 }
1883 
1884 
1885 status_t
1886 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
1887 {
1888 	if (pointer == NULL)
1889 		return B_BAD_VALUE;
1890 
1891 	void **data = NULL;
1892 	ssize_t size = 0;
1893 	status_t error = FindData(name, B_POINTER_TYPE, index,
1894 		(const void **)&data, &size);
1895 
1896 	if (error == B_OK)
1897 		*pointer = *data;
1898 	else
1899 		*pointer = NULL;
1900 
1901 	return error;
1902 }
1903 
1904 
1905 status_t
1906 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
1907 {
1908 	return FindMessenger(name, 0, messenger);
1909 }
1910 
1911 
1912 status_t
1913 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
1914 	const
1915 {
1916 	if (messenger == NULL)
1917 		return B_BAD_VALUE;
1918 
1919 	void *data = NULL;
1920 	ssize_t size = 0;
1921 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
1922 		(const void **)&data, &size);
1923 
1924 	if (error == B_OK)
1925 		memcpy(messenger, data, sizeof(BMessenger));
1926 	else
1927 		*messenger = BMessenger();
1928 
1929 	return error;
1930 }
1931 
1932 
1933 status_t
1934 BMessage::FindRef(const char *name, entry_ref *ref) const
1935 {
1936 	return FindRef(name, 0, ref);
1937 }
1938 
1939 
1940 status_t
1941 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
1942 {
1943 	if (ref == NULL)
1944 		return B_BAD_VALUE;
1945 
1946 	void *data = NULL;
1947 	ssize_t size = 0;
1948 	status_t error = FindData(name, B_REF_TYPE, index,
1949 		(const void **)&data, &size);
1950 
1951 	if (error == B_OK)
1952 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
1953 	else
1954 		*ref = entry_ref();
1955 
1956 	return error;
1957 }
1958 
1959 
1960 status_t
1961 BMessage::FindMessage(const char *name, BMessage *message) const
1962 {
1963 	return FindMessage(name, 0, message);
1964 }
1965 
1966 
1967 status_t
1968 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
1969 {
1970 	if (message == NULL)
1971 		return B_BAD_VALUE;
1972 
1973 	void *data = NULL;
1974 	ssize_t size = 0;
1975 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
1976 		(const void **)&data, &size);
1977 
1978 	if (error == B_OK)
1979 		error = message->Unflatten((const char *)data);
1980 	else
1981 		*message = BMessage();
1982 
1983 	return error;
1984 }
1985 
1986 
1987 status_t
1988 BMessage::FindFlat(const char *name, BFlattenable *object) const
1989 {
1990 	return FindFlat(name, 0, object);
1991 }
1992 
1993 
1994 status_t
1995 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
1996 {
1997 	if (object == NULL)
1998 		return B_BAD_VALUE;
1999 
2000 	void *data = NULL;
2001 	ssize_t numBytes = 0;
2002 	status_t error = FindData(name, object->TypeCode(), index,
2003 		(const void **)&data, &numBytes);
2004 
2005 	if (error == B_OK)
2006 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2007 
2008 	return error;
2009 }
2010 
2011 
2012 status_t
2013 BMessage::FindData(const char *name, type_code type, const void **data,
2014 	ssize_t *numBytes) const
2015 {
2016 	return FindData(name, type, 0, data, numBytes);
2017 }
2018 
2019 
2020 status_t
2021 BMessage::ReplaceString(const char *name, const char *string)
2022 {
2023 	if (string == NULL)
2024 		return B_BAD_VALUE;
2025 
2026 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2027 }
2028 
2029 
2030 status_t
2031 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2032 {
2033 	if (string == NULL)
2034 		return B_BAD_VALUE;
2035 
2036 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2037 }
2038 
2039 
2040 status_t
2041 BMessage::ReplaceString(const char *name, const BString &string)
2042 {
2043 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2044 		string.Length() + 1);
2045 }
2046 
2047 
2048 status_t
2049 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2050 {
2051 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2052 		string.Length() + 1);
2053 }
2054 
2055 
2056 status_t
2057 BMessage::ReplacePointer(const char *name, const void *pointer)
2058 {
2059 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2060 }
2061 
2062 
2063 status_t
2064 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2065 {
2066 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2067 }
2068 
2069 
2070 status_t
2071 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2072 {
2073 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2074 		sizeof(BMessenger));
2075 }
2076 
2077 
2078 status_t
2079 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2080 {
2081 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2082 		sizeof(BMessenger));
2083 }
2084 
2085 
2086 status_t
2087 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2088 {
2089 	return ReplaceRef(name, 0, ref);
2090 }
2091 
2092 
2093 status_t
2094 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2095 {
2096 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2097 	char buffer[size];
2098 
2099 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2100 
2101 	if (error >= B_OK)
2102 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2103 
2104 	return error;
2105 }
2106 
2107 
2108 status_t
2109 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2110 {
2111 	return ReplaceMessage(name, 0, message);
2112 }
2113 
2114 
2115 status_t
2116 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2117 {
2118 	if (message == NULL)
2119 		return B_BAD_VALUE;
2120 
2121 	ssize_t size = message->FlattenedSize();
2122 	char buffer[size];
2123 
2124 	status_t error = message->Flatten(buffer, size);
2125 
2126 	if (error >= B_OK)
2127 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2128 
2129 	return error;
2130 }
2131 
2132 
2133 status_t
2134 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2135 {
2136 	return ReplaceFlat(name, 0, object);
2137 }
2138 
2139 
2140 status_t
2141 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2142 {
2143 	if (object == NULL)
2144 		return B_BAD_VALUE;
2145 
2146 	ssize_t size = object->FlattenedSize();
2147 	char buffer[size];
2148 
2149 	status_t error = object->Flatten(buffer, size);
2150 
2151 	if (error >= B_OK)
2152 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2153 
2154 	return error;
2155 }
2156 
2157 
2158 status_t
2159 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2160 	ssize_t numBytes)
2161 {
2162 	return ReplaceData(name, type, 0, data, numBytes);
2163 }
2164 
2165 
2166 bool
2167 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2168 {
2169 	return HasFlat(name, 0, object);
2170 }
2171 
2172 
2173 bool
2174 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2175 	const
2176 {
2177 	return HasData(name, object->TypeCode(), index);
2178 }
2179