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