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
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
61const char *B_SPECIFIER_ENTRY = "specifiers";
62const char *B_PROPERTY_ENTRY = "property";
63const char *B_PROPERTY_NAME_ENTRY = "name";
64
65extern "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
72BBlockCache *BMessage::sMsgCache = NULL;
73
74
75template<typename Type>
76static void
77print_to_stream_type(uint8 *pointer)
78{
79	Type *item = (Type *)pointer;
80	item->PrintToStream();
81}
82
83
84template<typename Type>
85static void
86print_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
96BMessage::BMessage()
97{
98	DEBUG_FUNCTION_ENTER;
99	_InitCommon(true);
100}
101
102
103BMessage::BMessage(BMessage *other)
104{
105	DEBUG_FUNCTION_ENTER;
106	_InitCommon(false);
107	*this = *other;
108}
109
110
111BMessage::BMessage(uint32 _what)
112{
113	DEBUG_FUNCTION_ENTER;
114	_InitCommon(true);
115	fHeader->what = what = _what;
116}
117
118
119BMessage::BMessage(const BMessage &other)
120{
121	DEBUG_FUNCTION_ENTER;
122	_InitCommon(false);
123	*this = other;
124}
125
126
127BMessage::~BMessage()
128{
129	DEBUG_FUNCTION_ENTER;
130	_Clear();
131}
132
133
134BMessage &
135BMessage::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
186void *
187BMessage::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
197void *
198BMessage::operator new(size_t, void *pointer)
199{
200	DEBUG_FUNCTION_ENTER2;
201	return pointer;
202}
203
204
205void
206BMessage::operator delete(void *pointer, size_t size)
207{
208	DEBUG_FUNCTION_ENTER2;
209	sMsgCache->Save(pointer, size);
210}
211
212
213bool
214BMessage::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
272status_t
273BMessage::_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
296status_t
297BMessage::_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
326status_t
327BMessage::_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
350status_t
351BMessage::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
392status_t
393BMessage::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
414status_t
415BMessage::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
433int32
434BMessage::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
451bool
452BMessage::IsEmpty() const
453{
454	DEBUG_FUNCTION_ENTER;
455	return fHeader->field_count == 0;
456}
457
458
459bool
460BMessage::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
481bool
482BMessage::IsReply() const
483{
484	DEBUG_FUNCTION_ENTER;
485	return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
486}
487
488
489void
490BMessage::PrintToStream() const
491{
492	_PrintToStream("");
493	printf("}\n");
494}
495
496
497void
498BMessage::_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=%lld"
602						", name=\"%s\", ", (int)ref.device,
603						(long long)ref.directory, 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
643status_t
644BMessage::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
687bool
688BMessage::WasDelivered() const
689{
690	DEBUG_FUNCTION_ENTER;
691	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
692}
693
694
695bool
696BMessage::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
704BMessenger
705BMessage::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
719const BMessage *
720BMessage::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
737bool
738BMessage::WasDropped() const
739{
740	DEBUG_FUNCTION_ENTER;
741	return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
742}
743
744
745BPoint
746BMessage::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
756ssize_t
757BMessage::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
765status_t
766BMessage::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
795status_t
796BMessage::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
834status_t
835BMessage::_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
859status_t
860BMessage::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
926status_t
927BMessage::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
991status_t
992BMessage::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
1004status_t
1005BMessage::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
1021status_t
1022BMessage::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
1045status_t
1046BMessage::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
1062status_t
1063BMessage::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
1076status_t
1077BMessage::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
1097status_t
1098BMessage::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
1128bool
1129BMessage::HasSpecifiers() const
1130{
1131	DEBUG_FUNCTION_ENTER;
1132	return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1133}
1134
1135
1136status_t
1137BMessage::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
1151status_t
1152BMessage::_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
1221uint32
1222BMessage::_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
1237status_t
1238BMessage::_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
1270status_t
1271BMessage::_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
1319status_t
1320BMessage::_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
1370status_t
1371BMessage::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
1429status_t
1430BMessage::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
1479status_t
1480BMessage::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
1496status_t
1497BMessage::MakeEmpty()
1498{
1499	DEBUG_FUNCTION_ENTER;
1500	_Clear();
1501	_InitHeader();
1502	return B_OK;
1503}
1504
1505
1506status_t
1507BMessage::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
1546status_t
1547BMessage::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
1598bool
1599BMessage::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
1618void BMessage::_ReservedMessage1(void) {};
1619void BMessage::_ReservedMessage2(void) {};
1620void BMessage::_ReservedMessage3(void) {};
1621
1622
1623/* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
1624
1625#define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
1626status_t																	\
1627BMessage::Add##typeName(const char *name, type val)							\
1628{																			\
1629	return AddData(name, typeCode, &val, sizeof(type), true);				\
1630}																			\
1631																			\
1632status_t																	\
1633BMessage::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																			\
1648status_t																	\
1649BMessage::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																			\
1664status_t																	\
1665BMessage::Replace##typeName(const char *name, type val)						\
1666{																			\
1667	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
1668}																			\
1669																			\
1670status_t																	\
1671BMessage::Replace##typeName(const char *name, int32 index, type val)		\
1672{																			\
1673	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
1674}																			\
1675																			\
1676bool																		\
1677BMessage::Has##typeName(const char *name, int32 index) const				\
1678{																			\
1679	return HasData(name, typeCode, index);									\
1680}
1681
1682DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
1683DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
1684DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
1685DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
1686DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
1687DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
1688DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
1689DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
1690DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
1691DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
1692DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
1693DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
1694DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
1695
1696#undef DEFINE_FUNCTIONS
1697
1698#define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
1699bool																		\
1700BMessage::Has##typeName(const char *name, int32 index) const				\
1701{																			\
1702	return HasData(name, typeCode, index);									\
1703}
1704
1705DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
1706DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
1707DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
1708DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
1709DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
1710
1711#undef DEFINE_HAS_FUNCTION
1712
1713#define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
1714type																		\
1715BMessage::Find##typeName(const char *name, int32 index) const				\
1716{																			\
1717	type val = initialize;													\
1718	Find##typeName(name, index, &val);										\
1719	return val;																\
1720}
1721
1722DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
1723DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
1724DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
1725DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
1726DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
1727DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
1728DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
1729DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
1730DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
1731DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
1732
1733#undef DEFINE_LAZY_FIND_FUNCTION
1734
1735status_t
1736BMessage::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
1742status_t
1743BMessage::AddString(const char *name, const BString &string)
1744{
1745	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
1746}
1747
1748
1749status_t
1750BMessage::AddPointer(const char *name, const void *pointer)
1751{
1752	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
1753}
1754
1755
1756status_t
1757BMessage::AddMessenger(const char *name, BMessenger messenger)
1758{
1759	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
1760}
1761
1762
1763status_t
1764BMessage::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
1778status_t
1779BMessage::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
1811status_t
1812BMessage::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
1840status_t
1841BMessage::FindString(const char *name, const char **string) const
1842{
1843	return FindString(name, 0, string);
1844}
1845
1846
1847status_t
1848BMessage::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
1855status_t
1856BMessage::FindString(const char *name, BString *string) const
1857{
1858	return FindString(name, 0, string);
1859}
1860
1861
1862status_t
1863BMessage::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
1878status_t
1879BMessage::FindPointer(const char *name, void **pointer) const
1880{
1881	return FindPointer(name, 0, pointer);
1882}
1883
1884
1885status_t
1886BMessage::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
1905status_t
1906BMessage::FindMessenger(const char *name, BMessenger *messenger) const
1907{
1908	return FindMessenger(name, 0, messenger);
1909}
1910
1911
1912status_t
1913BMessage::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
1933status_t
1934BMessage::FindRef(const char *name, entry_ref *ref) const
1935{
1936	return FindRef(name, 0, ref);
1937}
1938
1939
1940status_t
1941BMessage::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
1960status_t
1961BMessage::FindMessage(const char *name, BMessage *message) const
1962{
1963	return FindMessage(name, 0, message);
1964}
1965
1966
1967status_t
1968BMessage::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
1987status_t
1988BMessage::FindFlat(const char *name, BFlattenable *object) const
1989{
1990	return FindFlat(name, 0, object);
1991}
1992
1993
1994status_t
1995BMessage::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
2012status_t
2013BMessage::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
2020status_t
2021BMessage::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
2030status_t
2031BMessage::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
2040status_t
2041BMessage::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
2048status_t
2049BMessage::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
2056status_t
2057BMessage::ReplacePointer(const char *name, const void *pointer)
2058{
2059	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2060}
2061
2062
2063status_t
2064BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2065{
2066	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2067}
2068
2069
2070status_t
2071BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2072{
2073	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2074		sizeof(BMessenger));
2075}
2076
2077
2078status_t
2079BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2080{
2081	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2082		sizeof(BMessenger));
2083}
2084
2085
2086status_t
2087BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2088{
2089	return ReplaceRef(name, 0, ref);
2090}
2091
2092
2093status_t
2094BMessage::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
2108status_t
2109BMessage::ReplaceMessage(const char *name, const BMessage *message)
2110{
2111	return ReplaceMessage(name, 0, message);
2112}
2113
2114
2115status_t
2116BMessage::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
2133status_t
2134BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2135{
2136	return ReplaceFlat(name, 0, object);
2137}
2138
2139
2140status_t
2141BMessage::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
2158status_t
2159BMessage::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
2166bool
2167BMessage::HasFlat(const char *name, const BFlattenable *object) const
2168{
2169	return HasFlat(name, 0, object);
2170}
2171
2172
2173bool
2174BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2175	const
2176{
2177	return HasData(name, object->TypeCode(), index);
2178}
2179