1/*
2 * Copyright 2005-2017 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 <DirectMessageTarget.h>
16#include <MessengerPrivate.h>
17#include <TokenSpace.h>
18#include <util/KMessage.h>
19
20#include <Alignment.h>
21#include <Application.h>
22#include <AppMisc.h>
23#include <BlockCache.h>
24#include <Entry.h>
25#include <GraphicsDefs.h>
26#include <MessageQueue.h>
27#include <Messenger.h>
28#include <Path.h>
29#include <Point.h>
30#include <Rect.h>
31#include <String.h>
32#include <StringList.h>
33
34#include <assert.h>
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include "tracing_config.h"
41	// kernel tracing configuration
42
43//#define VERBOSE_DEBUG_OUTPUT
44#ifdef VERBOSE_DEBUG_OUTPUT
45#define DEBUG_FUNCTION_ENTER	\
46	debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
47		" data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
48		find_thread(NULL), this, fHeader, fFields, fData, what, (char*)&what, \
49		__LINE__, __PRETTY_FUNCTION__);
50
51#define DEBUG_FUNCTION_ENTER2	\
52	debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
53		__LINE__, __PRETTY_FUNCTION__);
54#else
55#define DEBUG_FUNCTION_ENTER	/* nothing */
56#define DEBUG_FUNCTION_ENTER2	/* nothing */
57#endif
58
59#if BMESSAGE_TRACING
60#	define KTRACE(format...)	ktrace_printf(format)
61#else
62#	define KTRACE(format...)	;
63#endif
64
65
66const char* B_SPECIFIER_ENTRY = "specifiers";
67const char* B_PROPERTY_ENTRY = "property";
68const char* B_PROPERTY_NAME_ENTRY = "name";
69
70
71static status_t handle_reply(port_id replyPort, int32* pCode,
72	bigtime_t timeout, BMessage* reply);
73
74
75extern "C" {
76	// private os function to set the owning team of an area
77	status_t _kern_transfer_area(area_id area, void** _address,
78		uint32 addressSpec, team_id target);
79}
80
81
82BBlockCache* BMessage::sMsgCache = NULL;
83port_id BMessage::sReplyPorts[sNumReplyPorts];
84int32 BMessage::sReplyPortInUse[sNumReplyPorts];
85
86
87template<typename Type>
88static void
89print_to_stream_type(uint8* pointer)
90{
91	Type* item = (Type*)pointer;
92	item->PrintToStream();
93}
94
95
96template<typename Type>
97static void
98print_type(const char* format, uint8* pointer)
99{
100	Type* item = (Type*)pointer;
101	printf(format,* item,* item);
102}
103
104
105template<typename Type>
106static void
107print_type3(const char* format, uint8* pointer)
108{
109	Type* item = (Type*)pointer;
110	printf(format, *item, *item, *item);
111}
112
113
114static status_t
115handle_reply(port_id replyPort, int32* _code, bigtime_t timeout,
116	BMessage* reply)
117{
118	DEBUG_FUNCTION_ENTER2;
119	ssize_t size;
120	do {
121		size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
122	} while (size == B_INTERRUPTED);
123
124	if (size < 0)
125		return size;
126
127	status_t result;
128	char* buffer = (char*)malloc(size);
129	if (buffer == NULL)
130		return B_NO_MEMORY;
131
132	do {
133		result = read_port(replyPort, _code, buffer, size);
134	} while (result == B_INTERRUPTED);
135
136	if (result < 0 || *_code != kPortMessageCode) {
137		free(buffer);
138		return result < 0 ? result : B_ERROR;
139	}
140
141	result = reply->Unflatten(buffer);
142	free(buffer);
143	return result;
144}
145
146
147//	#pragma mark -
148
149
150BMessage::BMessage()
151{
152	DEBUG_FUNCTION_ENTER;
153	_InitCommon(true);
154}
155
156
157BMessage::BMessage(BMessage* other)
158{
159	DEBUG_FUNCTION_ENTER;
160	_InitCommon(false);
161	*this = *other;
162}
163
164
165BMessage::BMessage(uint32 _what)
166{
167	DEBUG_FUNCTION_ENTER;
168	if (_InitCommon(true))
169		fHeader->what = _what;
170	what = _what;
171}
172
173
174BMessage::BMessage(const BMessage& other)
175{
176	DEBUG_FUNCTION_ENTER;
177	_InitCommon(false);
178	*this = other;
179}
180
181
182BMessage::~BMessage()
183{
184	DEBUG_FUNCTION_ENTER;
185	_Clear();
186}
187
188
189BMessage&
190BMessage::operator=(const BMessage& other)
191{
192	DEBUG_FUNCTION_ENTER;
193
194	if (this == &other)
195		return *this;
196
197	_Clear();
198
199	fHeader = (message_header*)malloc(sizeof(message_header));
200	if (fHeader == NULL)
201		return *this;
202
203	if (other.fHeader == NULL)
204		return *this;
205
206	memcpy(fHeader, other.fHeader, sizeof(message_header));
207
208	// Clear some header flags inherited from the original message that don't
209	// apply to the clone.
210	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
211		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
212		| MESSAGE_FLAG_PASS_BY_AREA);
213	// Note, that BeOS R5 seems to keep the reply info.
214
215	if (fHeader->field_count > 0) {
216		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
217		if (other.fFields != NULL)
218			fFields = (field_header*)malloc(fieldsSize);
219
220		if (fFields == NULL) {
221			fHeader->field_count = 0;
222			fHeader->data_size = 0;
223		} else if (other.fFields != NULL)
224			memcpy(fFields, other.fFields, fieldsSize);
225	}
226
227	if (fHeader->data_size > 0) {
228		if (other.fData != NULL)
229			fData = (uint8*)malloc(fHeader->data_size);
230
231		if (fData == NULL) {
232			fHeader->field_count = 0;
233			free(fFields);
234			fFields = NULL;
235		} else if (other.fData != NULL)
236			memcpy(fData, other.fData, fHeader->data_size);
237	}
238
239	fHeader->what = what = other.what;
240	fHeader->message_area = -1;
241	fFieldsAvailable = 0;
242	fDataAvailable = 0;
243
244	return *this;
245}
246
247
248void*
249BMessage::operator new(size_t size)
250{
251	DEBUG_FUNCTION_ENTER2;
252	return sMsgCache->Get(size);
253}
254
255
256void*
257BMessage::operator new(size_t size, const std::nothrow_t& noThrow)
258{
259	DEBUG_FUNCTION_ENTER2;
260	return sMsgCache->Get(size);
261}
262
263
264void*
265BMessage::operator new(size_t, void* pointer)
266{
267	DEBUG_FUNCTION_ENTER2;
268	return pointer;
269}
270
271
272void
273BMessage::operator delete(void* pointer, size_t size)
274{
275	DEBUG_FUNCTION_ENTER2;
276	if (pointer == NULL)
277		return;
278	sMsgCache->Save(pointer, size);
279}
280
281
282bool
283BMessage::HasSameData(const BMessage& other, bool ignoreFieldOrder,
284	bool deep) const
285{
286	if (this == &other)
287		return true;
288
289	if (fHeader == NULL)
290		return other.fHeader == NULL;
291
292	if (fHeader->field_count != other.fHeader->field_count)
293		return false;
294
295	for (uint32 i = 0; i < fHeader->field_count; i++) {
296		field_header* field = &fFields[i];
297		field_header* otherField = NULL;
298
299		const char* name = (const char*)fData + field->offset;
300		if (ignoreFieldOrder) {
301			if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
302				return false;
303		} else {
304			otherField = &other.fFields[i];
305			if (otherField->name_length != field->name_length)
306				return false;
307
308			const char* otherName = (const char*)other.fData
309				+ otherField->offset;
310			if (strncmp(name, otherName, field->name_length) != 0)
311				return false;
312		}
313
314		if (otherField->type != field->type
315			|| otherField->count != field->count) {
316			return false;
317		}
318
319		uint8* data = fData + field->offset + field->name_length;
320		uint8* otherData = other.fData + otherField->offset
321			+ otherField->name_length;
322
323		bool needsMemCompare = true;
324		if (deep && field->type == B_MESSAGE_TYPE) {
325			BMessage message, otherMessage;
326			if (message.Unflatten((const char*)data) == B_OK
327				&& otherMessage.Unflatten((const char*)otherData) == B_OK) {
328				if (!message.HasSameData(ignoreFieldOrder, deep))
329					return false;
330				needsMemCompare = false;
331			}
332		}
333
334		if (needsMemCompare) {
335			if (otherField->data_size != field->data_size)
336				return false;
337			if (memcmp(data, otherData, field->data_size) != 0)
338				return false;
339		}
340	}
341
342	return true;
343}
344
345
346status_t
347BMessage::_InitCommon(bool initHeader)
348{
349	DEBUG_FUNCTION_ENTER;
350	what = 0;
351
352	fHeader = NULL;
353	fFields = NULL;
354	fData = NULL;
355
356	fFieldsAvailable = 0;
357	fDataAvailable = 0;
358
359	fOriginal = NULL;
360	fQueueLink = NULL;
361
362	fArchivingPointer = NULL;
363
364	if (initHeader)
365		return _InitHeader();
366
367	return B_OK;
368}
369
370
371status_t
372BMessage::_InitHeader()
373{
374	DEBUG_FUNCTION_ENTER;
375	if (fHeader == NULL) {
376		fHeader = (message_header*)malloc(sizeof(message_header));
377		if (fHeader == NULL)
378			return B_NO_MEMORY;
379	}
380
381	memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
382
383	fHeader->format = MESSAGE_FORMAT_HAIKU;
384	fHeader->flags = MESSAGE_FLAG_VALID;
385	fHeader->what = what;
386	fHeader->current_specifier = -1;
387	fHeader->message_area = -1;
388
389	fHeader->target = B_NULL_TOKEN;
390	fHeader->reply_target = B_NULL_TOKEN;
391	fHeader->reply_port = -1;
392	fHeader->reply_team = -1;
393
394	// initializing the hash table to -1 because 0 is a valid index
395	fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
396	memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
397	return B_OK;
398}
399
400
401status_t
402BMessage::_Clear()
403{
404	DEBUG_FUNCTION_ENTER;
405	if (fHeader != NULL) {
406		// We're going to destroy all information of this message. If there's
407		// still someone waiting for a reply to this message, we have to send
408		// one now.
409		if (IsSourceWaiting())
410			SendReply(B_NO_REPLY);
411
412		if (fHeader->message_area >= 0)
413			_Dereference();
414
415		free(fHeader);
416		fHeader = NULL;
417	}
418
419	free(fFields);
420	fFields = NULL;
421	free(fData);
422	fData = NULL;
423
424	fArchivingPointer = NULL;
425
426	fFieldsAvailable = 0;
427	fDataAvailable = 0;
428
429	delete fOriginal;
430	fOriginal = NULL;
431
432	return B_OK;
433}
434
435
436status_t
437BMessage::GetInfo(type_code typeRequested, int32 index, char** nameFound,
438	type_code* typeFound, int32* countFound) const
439{
440	DEBUG_FUNCTION_ENTER;
441	if (fHeader == NULL)
442		return B_NO_INIT;
443
444	if (index < 0 || (uint32)index >= fHeader->field_count)
445		return B_BAD_INDEX;
446
447	if (typeRequested == B_ANY_TYPE) {
448		if (nameFound != NULL)
449			*nameFound = (char*)fData + fFields[index].offset;
450		if (typeFound != NULL)
451			*typeFound = fFields[index].type;
452		if (countFound != NULL)
453			*countFound = fFields[index].count;
454		return B_OK;
455	}
456
457	int32 counter = -1;
458	field_header* field = fFields;
459	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
460		if (field->type == typeRequested)
461			counter++;
462
463		if (counter == index) {
464			if (nameFound != NULL)
465				*nameFound = (char*)fData + field->offset;
466			if (typeFound != NULL)
467				*typeFound = field->type;
468			if (countFound != NULL)
469				*countFound = field->count;
470			return B_OK;
471		}
472	}
473
474	if (counter == -1)
475		return B_BAD_TYPE;
476
477	return B_BAD_INDEX;
478}
479
480
481status_t
482BMessage::GetInfo(const char* name, type_code* typeFound,
483	int32* countFound) const
484{
485	DEBUG_FUNCTION_ENTER;
486	if (countFound != NULL)
487		*countFound = 0;
488
489	field_header* field = NULL;
490	status_t result = _FindField(name, B_ANY_TYPE, &field);
491	if (result != B_OK)
492		return result;
493
494	if (typeFound != NULL)
495		*typeFound = field->type;
496	if (countFound != NULL)
497		*countFound = field->count;
498
499	return B_OK;
500}
501
502
503status_t
504BMessage::GetInfo(const char* name, type_code* typeFound, bool* fixedSize)
505	const
506{
507	DEBUG_FUNCTION_ENTER;
508	field_header* field = NULL;
509	status_t result = _FindField(name, B_ANY_TYPE, &field);
510	if (result != B_OK)
511		return result;
512
513	if (typeFound != NULL)
514		*typeFound = field->type;
515	if (fixedSize != NULL)
516		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
517
518	return B_OK;
519}
520
521
522status_t
523BMessage::GetInfo(const char* name, type_code* typeFound, int32* countFound,
524	bool* fixedSize) const
525{
526	DEBUG_FUNCTION_ENTER;
527	field_header* field = NULL;
528	status_t result = _FindField(name, B_ANY_TYPE, &field);
529	if (result != B_OK)
530		return result;
531
532	if (typeFound != NULL)
533		*typeFound = field->type;
534	if (countFound != NULL)
535		*countFound = field->count;
536	if (fixedSize != NULL)
537		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
538
539	return B_OK;
540}
541
542
543int32
544BMessage::CountNames(type_code type) const
545{
546	DEBUG_FUNCTION_ENTER;
547	if (fHeader == NULL)
548		return 0;
549
550	if (type == B_ANY_TYPE)
551		return fHeader->field_count;
552
553	int32 count = 0;
554	field_header* field = fFields;
555	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
556		if (field->type == type)
557			count++;
558	}
559
560	return count;
561}
562
563
564bool
565BMessage::IsEmpty() const
566{
567	DEBUG_FUNCTION_ENTER;
568	return fHeader == NULL || fHeader->field_count == 0;
569}
570
571
572bool
573BMessage::IsSystem() const
574{
575	DEBUG_FUNCTION_ENTER;
576	char a = char(what >> 24);
577	char b = char(what >> 16);
578	char c = char(what >> 8);
579	char d = char(what);
580
581	// The BeBook says:
582	//		... we've adopted a strict convention for assigning values to all
583	//		Be-defined constants.  The value assigned will always be formed by
584	//		combining four characters into a multicharacter constant, with the
585	//		characters limited to uppercase letters and the underbar
586	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
587	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
588		return true;
589
590	return false;
591}
592
593
594bool
595BMessage::IsReply() const
596{
597	DEBUG_FUNCTION_ENTER;
598	return fHeader != NULL && (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
599}
600
601
602void
603BMessage::PrintToStream() const
604{
605	_PrintToStream("");
606	printf("}\n");
607}
608
609
610void
611BMessage::_PrintToStream(const char* indent) const
612{
613	DEBUG_FUNCTION_ENTER;
614
615	int32 value = B_BENDIAN_TO_HOST_INT32(what);
616	printf("BMessage(");
617	if (isprint(*(char*)&value))
618		printf("'%.4s'", (char*)&value);
619	else
620		printf("0x%" B_PRIx32, what);
621	printf(") {\n");
622
623	if (fHeader == NULL || fFields == NULL || fData == NULL)
624		return;
625
626	field_header* field = fFields;
627	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
628		value = B_BENDIAN_TO_HOST_INT32(field->type);
629		ssize_t size = 0;
630		if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
631			size = field->data_size / field->count;
632
633		uint8* pointer = fData + field->offset + field->name_length;
634		for (uint32 j = 0; j < field->count; j++) {
635			if (field->count == 1) {
636				printf("%s        %s = ", indent,
637					(char*)(fData + field->offset));
638			} else {
639				printf("%s        %s[%" B_PRIu32 "] = ", indent,
640					(char*)(fData + field->offset), j);
641			}
642
643			if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) {
644				size = *(uint32*)pointer;
645				pointer += sizeof(uint32);
646			}
647
648			switch (field->type) {
649				case B_RECT_TYPE:
650					print_to_stream_type<BRect>(pointer);
651					break;
652
653				case B_POINT_TYPE:
654					print_to_stream_type<BPoint>(pointer);
655					break;
656
657				case B_STRING_TYPE:
658					printf("string(\"%.*s\", %ld bytes)\n", (int)size,
659						(char*)pointer, (long)size);
660					break;
661
662				case B_INT8_TYPE:
663					print_type3<int8>("int8(0x%hx or %d or '%c')\n",
664						pointer);
665					break;
666
667				case B_UINT8_TYPE:
668					print_type3<uint8>("uint8(0x%hx or %u or '%c')\n",
669						pointer);
670					break;
671
672				case B_INT16_TYPE:
673					print_type<int16>("int16(0x%x or %d)\n", pointer);
674					break;
675
676				case B_UINT16_TYPE:
677					print_type<uint16>("uint16(0x%x or %u\n", pointer);
678					break;
679
680				case B_INT32_TYPE:
681					print_type<int32>("int32(0x%lx or %ld)\n", pointer);
682					break;
683
684				case B_UINT32_TYPE:
685					print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
686					break;
687
688				case B_INT64_TYPE:
689					print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
690					break;
691
692				case B_UINT64_TYPE:
693					print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
694					break;
695
696				case B_BOOL_TYPE:
697					printf("bool(%s)\n", *((bool*)pointer) != 0
698						? "true" : "false");
699					break;
700
701				case B_FLOAT_TYPE:
702					print_type<float>("float(%.4f)\n", pointer);
703					break;
704
705				case B_DOUBLE_TYPE:
706					print_type<double>("double(%.8f)\n", pointer);
707					break;
708
709				case B_REF_TYPE:
710				{
711					entry_ref ref;
712					BPrivate::entry_ref_unflatten(&ref, (char*)pointer, size);
713
714					printf("entry_ref(device=%d, directory=%" B_PRIdINO
715						", name=\"%s\", ", (int)ref.device, ref.directory,
716						ref.name);
717
718					BPath path(&ref);
719					printf("path=\"%s\")\n", path.Path());
720					break;
721				}
722
723				case B_MESSAGE_TYPE:
724				{
725					char buffer[1024];
726					snprintf(buffer, sizeof(buffer), "%s        ", indent);
727
728					BMessage message;
729					status_t result = message.Unflatten((const char*)pointer);
730					if (result != B_OK) {
731						printf("failed unflatten: %s\n", strerror(result));
732						break;
733					}
734
735					message._PrintToStream(buffer);
736					printf("%s        }\n", indent);
737					break;
738				}
739
740				case B_RGB_32_BIT_TYPE:
741				{
742					rgb_color* color = (rgb_color*)pointer;
743					printf("rgb_color(%u, %u, %u, %u)\n", color->red,
744						color->green, color->blue, color->alpha);
745					break;
746				}
747
748				default:
749				{
750					printf("(type = '%.4s')(size = %ld)\n", (char*)&value,
751						(long)size);
752					break;
753				}
754			}
755
756			pointer += size;
757		}
758	}
759}
760
761
762status_t
763BMessage::Rename(const char* oldEntry, const char* newEntry)
764{
765	DEBUG_FUNCTION_ENTER;
766	if (oldEntry == NULL || newEntry == NULL)
767		return B_BAD_VALUE;
768
769	if (fHeader == NULL)
770		return B_NO_INIT;
771
772	status_t result;
773	if (fHeader->message_area >= 0) {
774		result = _CopyForWrite();
775		if (result != B_OK)
776			return result;
777	}
778
779	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
780	int32* nextField = &fHeader->hash_table[hash];
781
782	while (*nextField >= 0) {
783		field_header* field = &fFields[*nextField];
784
785		if (strncmp((const char*)(fData + field->offset), oldEntry,
786			field->name_length) == 0) {
787			// nextField points to the field for oldEntry, save it and unlink
788			int32 index = *nextField;
789			*nextField = field->next_field;
790			field->next_field = -1;
791
792			hash = _HashName(newEntry) % fHeader->hash_table_size;
793			nextField = &fHeader->hash_table[hash];
794			while (*nextField >= 0)
795				nextField = &fFields[*nextField].next_field;
796			*nextField = index;
797
798			int32 newLength = strlen(newEntry) + 1;
799			result = _ResizeData(field->offset + 1,
800				newLength - field->name_length);
801			if (result != B_OK)
802				return result;
803
804			memcpy(fData + field->offset, newEntry, newLength);
805			field->name_length = newLength;
806			return B_OK;
807		}
808
809		nextField = &field->next_field;
810	}
811
812	return B_NAME_NOT_FOUND;
813}
814
815
816bool
817BMessage::WasDelivered() const
818{
819	DEBUG_FUNCTION_ENTER;
820	return fHeader != NULL
821		&& (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
822}
823
824
825bool
826BMessage::IsSourceWaiting() const
827{
828	DEBUG_FUNCTION_ENTER;
829	return fHeader != NULL
830		&& (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
831		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
832}
833
834
835bool
836BMessage::IsSourceRemote() const
837{
838	DEBUG_FUNCTION_ENTER;
839	return fHeader != NULL
840		&& (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0
841		&& fHeader->reply_team != BPrivate::current_team();
842}
843
844
845BMessenger
846BMessage::ReturnAddress() const
847{
848	DEBUG_FUNCTION_ENTER;
849	if (fHeader == NULL || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
850		return BMessenger();
851
852	BMessenger messenger;
853	BMessenger::Private(messenger).SetTo(fHeader->reply_team,
854		fHeader->reply_port, fHeader->reply_target);
855	return messenger;
856}
857
858
859const BMessage*
860BMessage::Previous() const
861{
862	DEBUG_FUNCTION_ENTER;
863	/* ToDo: test if the "_previous_" field is used in R5 */
864	if (fOriginal == NULL) {
865		fOriginal = new BMessage();
866
867		if (FindMessage("_previous_", fOriginal) != B_OK) {
868			delete fOriginal;
869			fOriginal = NULL;
870		}
871	}
872
873	return fOriginal;
874}
875
876
877bool
878BMessage::WasDropped() const
879{
880	DEBUG_FUNCTION_ENTER;
881	return fHeader != NULL
882		&& (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
883}
884
885
886BPoint
887BMessage::DropPoint(BPoint* offset) const
888{
889	DEBUG_FUNCTION_ENTER;
890	if (offset != NULL)
891		*offset = FindPoint("_drop_offset_");
892
893	return FindPoint("_drop_point_");
894}
895
896
897status_t
898BMessage::SendReply(uint32 command, BHandler* replyTo)
899{
900	DEBUG_FUNCTION_ENTER;
901	BMessage message(command);
902	return SendReply(&message, replyTo);
903}
904
905
906status_t
907BMessage::SendReply(BMessage* reply, BHandler* replyTo, bigtime_t timeout)
908{
909	DEBUG_FUNCTION_ENTER;
910	BMessenger messenger(replyTo);
911	return SendReply(reply, messenger, timeout);
912}
913
914
915status_t
916BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
917{
918	DEBUG_FUNCTION_ENTER;
919	if (fHeader == NULL)
920		return B_NO_INIT;
921
922	BMessenger messenger;
923	BMessenger::Private messengerPrivate(messenger);
924	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
925		fHeader->reply_target);
926	if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0)
927		reply->fHeader->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE;
928
929	if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
930		if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
931			return B_DUPLICATE_REPLY;
932
933		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
934		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
935		status_t result = messenger.SendMessage(reply, replyTo, timeout);
936		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
937
938		if (result != B_OK && set_port_owner(messengerPrivate.Port(),
939				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
940			delete_port(messengerPrivate.Port());
941		}
942
943		return result;
944	}
945
946	// no reply required
947	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
948		return B_BAD_REPLY;
949
950	reply->AddMessage("_previous_", this);
951	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
952	status_t result = messenger.SendMessage(reply, replyTo, timeout);
953	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
954	reply->RemoveName("_previous_");
955	return result;
956}
957
958
959status_t
960BMessage::SendReply(uint32 command, BMessage* replyToReply)
961{
962	DEBUG_FUNCTION_ENTER;
963	BMessage message(command);
964	return SendReply(&message, replyToReply);
965}
966
967
968status_t
969BMessage::SendReply(BMessage* reply, BMessage* replyToReply,
970	bigtime_t sendTimeout, bigtime_t replyTimeout)
971{
972	DEBUG_FUNCTION_ENTER;
973	if (fHeader == NULL)
974		return B_NO_INIT;
975
976	BMessenger messenger;
977	BMessenger::Private messengerPrivate(messenger);
978	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
979		fHeader->reply_target);
980
981	if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
982		if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
983			return B_DUPLICATE_REPLY;
984
985		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
986		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
987		status_t result = messenger.SendMessage(reply, replyToReply,
988			sendTimeout, replyTimeout);
989		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
990
991		if (result != B_OK) {
992			if (set_port_owner(messengerPrivate.Port(),
993				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
994				delete_port(messengerPrivate.Port());
995			}
996		}
997
998		return result;
999	}
1000
1001	// no reply required
1002	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1003		return B_BAD_REPLY;
1004
1005	reply->AddMessage("_previous_", this);
1006	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY
1007		| (fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE);
1008	status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
1009		replyTimeout);
1010	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
1011	reply->RemoveName("_previous_");
1012	return result;
1013}
1014
1015
1016ssize_t
1017BMessage::FlattenedSize() const
1018{
1019	DEBUG_FUNCTION_ENTER;
1020	if (fHeader == NULL)
1021		return B_NO_INIT;
1022
1023	return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
1024		+ fHeader->data_size;
1025}
1026
1027
1028status_t
1029BMessage::Flatten(char* buffer, ssize_t size) const
1030{
1031	DEBUG_FUNCTION_ENTER;
1032	if (buffer == NULL || size < 0)
1033		return B_BAD_VALUE;
1034
1035	if (fHeader == NULL)
1036		return B_NO_INIT;
1037
1038	if (size < FlattenedSize())
1039		return B_BUFFER_OVERFLOW;
1040
1041	/* we have to sync the what code as it is a public member */
1042	fHeader->what = what;
1043
1044	memcpy(buffer, fHeader, sizeof(message_header));
1045	buffer += sizeof(message_header);
1046
1047	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1048	memcpy(buffer, fFields, fieldsSize);
1049	buffer += fieldsSize;
1050
1051	memcpy(buffer, fData, fHeader->data_size);
1052
1053	return B_OK;
1054}
1055
1056
1057status_t
1058BMessage::Flatten(BDataIO* stream, ssize_t* size) const
1059{
1060	DEBUG_FUNCTION_ENTER;
1061	if (stream == NULL)
1062		return B_BAD_VALUE;
1063
1064	if (fHeader == NULL)
1065		return B_NO_INIT;
1066
1067	/* we have to sync the what code as it is a public member */
1068	fHeader->what = what;
1069
1070	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
1071	if (result1 != sizeof(message_header))
1072		return result1 < 0 ? result1 : B_ERROR;
1073
1074	ssize_t result2 = 0;
1075	if (fHeader->field_count > 0) {
1076		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1077		result2 = stream->Write(fFields, fieldsSize);
1078		if (result2 != fieldsSize)
1079			return result2 < 0 ? result2 : B_ERROR;
1080	}
1081
1082	ssize_t result3 = 0;
1083	if (fHeader->data_size > 0) {
1084		result3 = stream->Write(fData, fHeader->data_size);
1085		if (result3 != (ssize_t)fHeader->data_size)
1086			return result3 < 0 ? result3 : B_ERROR;
1087	}
1088
1089	if (size)
1090		*size = result1 + result2 + result3;
1091
1092	return B_OK;
1093}
1094
1095
1096/*	The concept of message sending by area:
1097
1098	The traditional way of sending a message is to send it by flattening it to
1099	a buffer, pushing it through a port, reading it into the outputbuffer and
1100	unflattening it from there (copying the data again). While this works ok
1101	for small messages it does not make any sense for larger ones and may even
1102	hit some port capacity limit.
1103	Often in the life of a BMessage, it will be sent to someone. Almost as
1104	often the one receiving the message will not need to change the message
1105	in any way, but uses it "read only" to get information from it. This means
1106	that all that copying is pretty pointless in the first place since we
1107	could simply pass the original buffers on.
1108	It's obviously not exactly as simple as this, since we cannot just use the
1109	memory of one application in another - but we can share areas with
1110	eachother.
1111	Therefore instead of flattening into a buffer, we copy the message data
1112	into an area, put this information into the message header and only push
1113	this through the port. The receiving looper then builds a BMessage from
1114	the header, that only references the data in the area (not copying it),
1115	allowing read only access to it.
1116	Only if write access is necessary the message will be copyed from the area
1117	to its own buffers (like in the unflatten step before).
1118	The double copying is reduced to a single copy in most cases and we safe
1119	the slower route of moving the data through a port.
1120	Additionally we save us the reference counting with the use of areas that
1121	are reference counted internally. So we don't have to worry about leaving
1122	an area behind or deleting one that is still in use.
1123*/
1124
1125status_t
1126BMessage::_FlattenToArea(message_header** _header) const
1127{
1128	DEBUG_FUNCTION_ENTER;
1129	if (fHeader == NULL)
1130		return B_NO_INIT;
1131
1132	message_header* header = (message_header*)malloc(sizeof(message_header));
1133	if (header == NULL)
1134		return B_NO_MEMORY;
1135
1136	memcpy(header, fHeader, sizeof(message_header));
1137
1138	header->what = what;
1139	header->message_area = -1;
1140	*_header = header;
1141
1142	if (header->field_count == 0 && header->data_size == 0)
1143		return B_OK;
1144
1145	char* address = NULL;
1146	size_t fieldsSize = header->field_count * sizeof(field_header);
1147	size_t size = fieldsSize + header->data_size;
1148	size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
1149	area_id area = create_area("BMessage data", (void**)&address,
1150		B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1151
1152	if (area < 0) {
1153		free(header);
1154		*_header = NULL;
1155		return area;
1156	}
1157
1158	memcpy(address, fFields, fieldsSize);
1159	memcpy(address + fieldsSize, fData, fHeader->data_size);
1160	header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
1161	header->message_area = area;
1162	return B_OK;
1163}
1164
1165
1166status_t
1167BMessage::_Reference()
1168{
1169	DEBUG_FUNCTION_ENTER;
1170	if (fHeader == NULL)
1171		return B_NO_INIT;
1172
1173	fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
1174
1175	/* if there is no data at all we don't need the area */
1176	if (fHeader->field_count == 0 && fHeader->data_size == 0)
1177		return B_OK;
1178
1179	area_info areaInfo;
1180	status_t result = get_area_info(fHeader->message_area, &areaInfo);
1181	if (result != B_OK)
1182		return result;
1183
1184	if (areaInfo.team != BPrivate::current_team())
1185		return B_BAD_VALUE;
1186
1187	set_area_protection(fHeader->message_area, B_READ_AREA);
1188
1189	uint8* address = (uint8*)areaInfo.address;
1190
1191	fFields = (field_header*)address;
1192	fData = address + fHeader->field_count * sizeof(field_header);
1193	return B_OK;
1194}
1195
1196
1197status_t
1198BMessage::_Dereference()
1199{
1200	DEBUG_FUNCTION_ENTER;
1201	if (fHeader == NULL)
1202		return B_NO_INIT;
1203
1204	delete_area(fHeader->message_area);
1205	fHeader->message_area = -1;
1206	fFields = NULL;
1207	fData = NULL;
1208	return B_OK;
1209}
1210
1211
1212status_t
1213BMessage::_CopyForWrite()
1214{
1215	DEBUG_FUNCTION_ENTER;
1216	if (fHeader == NULL)
1217		return B_NO_INIT;
1218
1219	field_header* newFields = NULL;
1220	uint8* newData = NULL;
1221
1222	if (fHeader->field_count > 0) {
1223		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1224		newFields = (field_header*)malloc(fieldsSize);
1225		if (newFields == NULL)
1226			return B_NO_MEMORY;
1227
1228		memcpy(newFields, fFields, fieldsSize);
1229	}
1230
1231	if (fHeader->data_size > 0) {
1232		newData = (uint8*)malloc(fHeader->data_size);
1233		if (newData == NULL) {
1234			free(newFields);
1235			return B_NO_MEMORY;
1236		}
1237
1238		memcpy(newData, fData, fHeader->data_size);
1239	}
1240
1241	_Dereference();
1242
1243	fFieldsAvailable = 0;
1244	fDataAvailable = 0;
1245
1246	fFields = newFields;
1247	fData = newData;
1248	return B_OK;
1249}
1250
1251
1252status_t
1253BMessage::_ValidateMessage()
1254{
1255	DEBUG_FUNCTION_ENTER;
1256	if (fHeader == NULL)
1257		return B_NO_INIT;
1258
1259	if (fHeader->field_count == 0)
1260		return B_OK;
1261
1262	if (fFields == NULL)
1263		return B_NO_INIT;
1264
1265	for (uint32 i = 0; i < fHeader->field_count; i++) {
1266		field_header* field = &fFields[i];
1267		if ((field->next_field >= 0
1268				&& (uint32)field->next_field > fHeader->field_count)
1269			|| (field->offset + field->name_length + field->data_size
1270				> fHeader->data_size)) {
1271			// the message is corrupt
1272			MakeEmpty();
1273			return B_BAD_VALUE;
1274		}
1275	}
1276
1277	return B_OK;
1278}
1279
1280
1281status_t
1282BMessage::Unflatten(const char* flatBuffer)
1283{
1284	DEBUG_FUNCTION_ENTER;
1285	if (flatBuffer == NULL)
1286		return B_BAD_VALUE;
1287
1288	uint32 format = *(uint32*)flatBuffer;
1289	if (format != MESSAGE_FORMAT_HAIKU)
1290		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
1291
1292	BMemoryIO io(flatBuffer, SSIZE_MAX);
1293	return Unflatten(&io);
1294}
1295
1296
1297status_t
1298BMessage::Unflatten(BDataIO* stream)
1299{
1300	DEBUG_FUNCTION_ENTER;
1301	if (stream == NULL)
1302		return B_BAD_VALUE;
1303
1304	uint32 format = 0;
1305	stream->Read(&format, sizeof(uint32));
1306	if (format != MESSAGE_FORMAT_HAIKU)
1307		return BPrivate::MessageAdapter::Unflatten(format, this, stream);
1308
1309	// native message unflattening
1310
1311	_Clear();
1312
1313	fHeader = (message_header*)malloc(sizeof(message_header));
1314	if (fHeader == NULL)
1315		return B_NO_MEMORY;
1316
1317	fHeader->format = format;
1318	uint8* header = (uint8*)fHeader;
1319	ssize_t result = stream->Read(header + sizeof(uint32),
1320		sizeof(message_header) - sizeof(uint32));
1321	if (result != sizeof(message_header) - sizeof(uint32)
1322		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
1323		_InitHeader();
1324		return result < 0 ? result : B_BAD_VALUE;
1325	}
1326
1327	what = fHeader->what;
1328
1329	if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
1330		&& fHeader->message_area >= 0) {
1331		status_t result = _Reference();
1332		if (result != B_OK) {
1333			_InitHeader();
1334			return result;
1335		}
1336	} else {
1337		fHeader->message_area = -1;
1338
1339		if (fHeader->field_count > 0) {
1340			ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1341			fFields = (field_header*)malloc(fieldsSize);
1342			if (fFields == NULL) {
1343				_InitHeader();
1344				return B_NO_MEMORY;
1345			}
1346
1347			result = stream->Read(fFields, fieldsSize);
1348			if (result != fieldsSize)
1349				return result < 0 ? result : B_BAD_VALUE;
1350		}
1351
1352		if (fHeader->data_size > 0) {
1353			fData = (uint8*)malloc(fHeader->data_size);
1354			if (fData == NULL) {
1355				free(fFields);
1356				fFields = NULL;
1357				_InitHeader();
1358				return B_NO_MEMORY;
1359			}
1360
1361			result = stream->Read(fData, fHeader->data_size);
1362			if (result != (ssize_t)fHeader->data_size)
1363				return result < 0 ? result : B_BAD_VALUE;
1364		}
1365	}
1366
1367	return _ValidateMessage();
1368}
1369
1370
1371status_t
1372BMessage::AddSpecifier(const char* property)
1373{
1374	DEBUG_FUNCTION_ENTER;
1375	BMessage message(B_DIRECT_SPECIFIER);
1376	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1377	if (result != B_OK)
1378		return result;
1379
1380	return AddSpecifier(&message);
1381}
1382
1383
1384status_t
1385BMessage::AddSpecifier(const char* property, int32 index)
1386{
1387	DEBUG_FUNCTION_ENTER;
1388	BMessage message(B_INDEX_SPECIFIER);
1389	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1390	if (result != B_OK)
1391		return result;
1392
1393	result = message.AddInt32("index", index);
1394	if (result != B_OK)
1395		return result;
1396
1397	return AddSpecifier(&message);
1398}
1399
1400
1401status_t
1402BMessage::AddSpecifier(const char* property, int32 index, int32 range)
1403{
1404	DEBUG_FUNCTION_ENTER;
1405	if (range < 0)
1406		return B_BAD_VALUE;
1407
1408	BMessage message(B_RANGE_SPECIFIER);
1409	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1410	if (result != B_OK)
1411		return result;
1412
1413	result = message.AddInt32("index", index);
1414	if (result != B_OK)
1415		return result;
1416
1417	result = message.AddInt32("range", range);
1418	if (result != B_OK)
1419		return result;
1420
1421	return AddSpecifier(&message);
1422}
1423
1424
1425status_t
1426BMessage::AddSpecifier(const char* property, const char* name)
1427{
1428	DEBUG_FUNCTION_ENTER;
1429	BMessage message(B_NAME_SPECIFIER);
1430	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1431	if (result != B_OK)
1432		return result;
1433
1434	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1435	if (result != B_OK)
1436		return result;
1437
1438	return AddSpecifier(&message);
1439}
1440
1441
1442status_t
1443BMessage::AddSpecifier(const BMessage* specifier)
1444{
1445	DEBUG_FUNCTION_ENTER;
1446	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1447	if (result != B_OK)
1448		return result;
1449
1450	fHeader->current_specifier++;
1451	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1452	return B_OK;
1453}
1454
1455
1456status_t
1457BMessage::SetCurrentSpecifier(int32 index)
1458{
1459	DEBUG_FUNCTION_ENTER;
1460	if (index < 0)
1461		return B_BAD_INDEX;
1462
1463	type_code type;
1464	int32 count;
1465	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1466	if (result != B_OK)
1467		return result;
1468
1469	if (index >= count)
1470		return B_BAD_INDEX;
1471
1472	fHeader->current_specifier = index;
1473	return B_OK;
1474}
1475
1476
1477status_t
1478BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what,
1479	const char** property) const
1480{
1481	DEBUG_FUNCTION_ENTER;
1482	if (fHeader == NULL)
1483		return B_NO_INIT;
1484
1485	if (index != NULL)
1486		*index = fHeader->current_specifier;
1487
1488	if (fHeader->current_specifier < 0
1489		|| (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1490		return B_BAD_SCRIPT_SYNTAX;
1491
1492	if (specifier) {
1493		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1494			specifier) != B_OK)
1495			return B_BAD_SCRIPT_SYNTAX;
1496
1497		if (_what != NULL)
1498			*_what = specifier->what;
1499
1500		if (property) {
1501			if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK)
1502				return B_BAD_SCRIPT_SYNTAX;
1503		}
1504	}
1505
1506	return B_OK;
1507}
1508
1509
1510bool
1511BMessage::HasSpecifiers() const
1512{
1513	DEBUG_FUNCTION_ENTER;
1514	return fHeader != NULL
1515		&& (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1516}
1517
1518
1519status_t
1520BMessage::PopSpecifier()
1521{
1522	DEBUG_FUNCTION_ENTER;
1523	if (fHeader == NULL)
1524		return B_NO_INIT;
1525
1526	if (fHeader->current_specifier < 0 ||
1527		(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1528		return B_BAD_VALUE;
1529
1530	if (fHeader->current_specifier >= 0)
1531		fHeader->current_specifier--;
1532
1533	return B_OK;
1534}
1535
1536
1537void
1538BMessage::_UpdateOffsets(uint32 offset, int32 change)
1539{
1540	// Update the header to match the new position of the fields
1541	if (offset < fHeader->data_size) {
1542		field_header* field = fFields;
1543		for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1544			if (field->offset >= offset)
1545				field->offset += change;
1546		}
1547	}
1548}
1549
1550
1551status_t
1552BMessage::_ResizeData(uint32 offset, int32 change)
1553{
1554	if (change == 0)
1555		return B_OK;
1556
1557	/* optimize for the most usual case: appending data */
1558
1559	if (change > 0) {
1560		// We need to make the field bigger
1561		// check if there is enough free space allocated
1562		if (fDataAvailable >= (uint32)change) {
1563			// In this case, we just need to move the data after the growing
1564			// field to get the space at the right place
1565			if (offset < fHeader->data_size) {
1566				memmove(fData + offset + change, fData + offset,
1567					fHeader->data_size - offset);
1568			}
1569
1570			_UpdateOffsets(offset, change);
1571
1572			fDataAvailable -= change;
1573			fHeader->data_size += change;
1574			return B_OK;
1575		}
1576
1577		// We need to grow the buffer. We try to optimize reallocations by
1578		// preallocating space for more fields.
1579		size_t size = fHeader->data_size * 2;
1580		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1581		size = max_c(size, fHeader->data_size + change);
1582
1583		uint8* newData = (uint8*)realloc(fData, size);
1584		if (size > 0 && newData == NULL)
1585			return B_NO_MEMORY;
1586
1587		fData = newData;
1588		if (offset < fHeader->data_size) {
1589			memmove(fData + offset + change, fData + offset,
1590				fHeader->data_size - offset);
1591		}
1592
1593		fHeader->data_size += change;
1594		fDataAvailable = size - fHeader->data_size;
1595	} else {
1596		ssize_t length = fHeader->data_size - offset + change;
1597		if (length > 0)
1598			memmove(fData + offset, fData + offset - change, length);
1599
1600		// change is negative
1601		fHeader->data_size += change;
1602		fDataAvailable -= change;
1603
1604		if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1605			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1606			ssize_t size = fHeader->data_size + available;
1607			uint8* newData = (uint8*)realloc(fData, size);
1608			if (size > 0 && newData == NULL) {
1609				// this is strange, but not really fatal
1610				_UpdateOffsets(offset, change);
1611				return B_OK;
1612			}
1613
1614			fData = newData;
1615			fDataAvailable = available;
1616		}
1617	}
1618
1619	_UpdateOffsets(offset, change);
1620	return B_OK;
1621}
1622
1623
1624uint32
1625BMessage::_HashName(const char* name) const
1626{
1627	char ch;
1628	uint32 result = 0;
1629
1630	while ((ch = *name++) != 0) {
1631		result = (result << 7) ^ (result >> 24);
1632		result ^= ch;
1633	}
1634
1635	result ^= result << 12;
1636	return result;
1637}
1638
1639
1640status_t
1641BMessage::_FindField(const char* name, type_code type, field_header** result)
1642	const
1643{
1644	if (name == NULL)
1645		return B_BAD_VALUE;
1646
1647	if (fHeader == NULL)
1648		return B_NO_INIT;
1649
1650	if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
1651		return B_NAME_NOT_FOUND;
1652
1653	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1654	int32 nextField = fHeader->hash_table[hash];
1655
1656	while (nextField >= 0) {
1657		field_header* field = &fFields[nextField];
1658		if ((field->flags & FIELD_FLAG_VALID) == 0)
1659			break;
1660
1661		if (strncmp((const char*)(fData + field->offset), name,
1662			field->name_length) == 0) {
1663			if (type != B_ANY_TYPE && field->type != type)
1664				return B_BAD_TYPE;
1665
1666			*result = field;
1667			return B_OK;
1668		}
1669
1670		nextField = field->next_field;
1671	}
1672
1673	return B_NAME_NOT_FOUND;
1674}
1675
1676
1677status_t
1678BMessage::_AddField(const char* name, type_code type, bool isFixedSize,
1679	field_header** result)
1680{
1681	if (fHeader == NULL)
1682		return B_NO_INIT;
1683
1684	if (fFieldsAvailable <= 0) {
1685		uint32 count = fHeader->field_count * 2 + 1;
1686		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1687
1688		field_header* newFields = (field_header*)realloc(fFields,
1689			count * sizeof(field_header));
1690		if (count > 0 && newFields == NULL)
1691			return B_NO_MEMORY;
1692
1693		fFields = newFields;
1694		fFieldsAvailable = count - fHeader->field_count;
1695	}
1696
1697	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1698	int32* nextField = &fHeader->hash_table[hash];
1699	while (*nextField >= 0)
1700		nextField = &fFields[*nextField].next_field;
1701	*nextField = fHeader->field_count;
1702
1703	field_header* field = &fFields[fHeader->field_count];
1704	field->type = type;
1705	field->count = 0;
1706	field->data_size = 0;
1707	field->next_field = -1;
1708	field->offset = fHeader->data_size;
1709	field->name_length = strlen(name) + 1;
1710	status_t status = _ResizeData(field->offset, field->name_length);
1711	if (status != B_OK)
1712		return status;
1713
1714	memcpy(fData + field->offset, name, field->name_length);
1715	field->flags = FIELD_FLAG_VALID;
1716	if (isFixedSize)
1717		field->flags |= FIELD_FLAG_FIXED_SIZE;
1718
1719	fFieldsAvailable--;
1720	fHeader->field_count++;
1721	*result = field;
1722	return B_OK;
1723}
1724
1725
1726status_t
1727BMessage::_RemoveField(field_header* field)
1728{
1729	status_t result = _ResizeData(field->offset, -(field->data_size
1730		+ field->name_length));
1731	if (result != B_OK)
1732		return result;
1733
1734	int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header);
1735	int32 nextField = field->next_field;
1736	if (nextField > index)
1737		nextField--;
1738
1739	int32* value = fHeader->hash_table;
1740	for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1741		if (*value > index)
1742			*value -= 1;
1743		else if (*value == index)
1744			*value = nextField;
1745	}
1746
1747	field_header* other = fFields;
1748	for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1749		if (other->next_field > index)
1750			other->next_field--;
1751		else if (other->next_field == index)
1752			other->next_field = nextField;
1753	}
1754
1755	size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1756	memmove(fFields + index, fFields + index + 1, size);
1757	fHeader->field_count--;
1758	fFieldsAvailable++;
1759
1760	if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1761		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1762		size = (fHeader->field_count + available) * sizeof(field_header);
1763		field_header* newFields = (field_header*)realloc(fFields, size);
1764		if (size > 0 && newFields == NULL) {
1765			// this is strange, but not really fatal
1766			return B_OK;
1767		}
1768
1769		fFields = newFields;
1770		fFieldsAvailable = available;
1771	}
1772
1773	return B_OK;
1774}
1775
1776
1777status_t
1778BMessage::AddData(const char* name, type_code type, const void* data,
1779	ssize_t numBytes, bool isFixedSize, int32 count)
1780{
1781	// Note that the "count" argument is only a hint at how many items
1782	// the caller expects to add to this field. Since we do no item pre-
1783	// allocation, we ignore this argument.
1784	DEBUG_FUNCTION_ENTER;
1785	if (numBytes <= 0 || data == NULL)
1786		return B_BAD_VALUE;
1787
1788	if (fHeader == NULL)
1789		return B_NO_INIT;
1790
1791	status_t result;
1792	if (fHeader->message_area >= 0) {
1793		result = _CopyForWrite();
1794		if (result != B_OK)
1795			return result;
1796	}
1797
1798	field_header* field = NULL;
1799	result = _FindField(name, type, &field);
1800	if (result == B_NAME_NOT_FOUND)
1801		result = _AddField(name, type, isFixedSize, &field);
1802
1803	if (result != B_OK)
1804		return result;
1805
1806	if (field == NULL)
1807		return B_ERROR;
1808
1809	uint32 offset = field->offset + field->name_length + field->data_size;
1810	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1811		if (field->count) {
1812			ssize_t size = field->data_size / field->count;
1813			if (size != numBytes)
1814				return B_BAD_VALUE;
1815		}
1816
1817		result = _ResizeData(offset, numBytes);
1818		if (result != B_OK) {
1819			if (field->count == 0)
1820				_RemoveField(field);
1821			return result;
1822		}
1823
1824		memcpy(fData + offset, data, numBytes);
1825		field->data_size += numBytes;
1826	} else {
1827		int32 change = numBytes + sizeof(uint32);
1828		result = _ResizeData(offset, change);
1829		if (result != B_OK) {
1830			if (field->count == 0)
1831				_RemoveField(field);
1832			return result;
1833		}
1834
1835		uint32 size = (uint32)numBytes;
1836		memcpy(fData + offset, &size, sizeof(uint32));
1837		memcpy(fData + offset + sizeof(uint32), data, size);
1838		field->data_size += change;
1839	}
1840
1841	field->count++;
1842	return B_OK;
1843}
1844
1845
1846status_t
1847BMessage::RemoveData(const char* name, int32 index)
1848{
1849	DEBUG_FUNCTION_ENTER;
1850	if (index < 0)
1851		return B_BAD_INDEX;
1852
1853	if (fHeader == NULL)
1854		return B_NO_INIT;
1855
1856	status_t result;
1857	if (fHeader->message_area >= 0) {
1858		result = _CopyForWrite();
1859		if (result != B_OK)
1860			return result;
1861	}
1862
1863	field_header* field = NULL;
1864	result = _FindField(name, B_ANY_TYPE, &field);
1865	if (result != B_OK)
1866		return result;
1867
1868	if ((uint32)index >= field->count)
1869		return B_BAD_INDEX;
1870
1871	if (field->count == 1)
1872		return _RemoveField(field);
1873
1874	uint32 offset = field->offset + field->name_length;
1875	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1876		ssize_t size = field->data_size / field->count;
1877		result = _ResizeData(offset + index * size, -size);
1878		if (result != B_OK)
1879			return result;
1880
1881		field->data_size -= size;
1882	} else {
1883		uint8* pointer = fData + offset;
1884		for (int32 i = 0; i < index; i++) {
1885			offset += *(uint32*)pointer + sizeof(uint32);
1886			pointer = fData + offset;
1887		}
1888
1889		size_t currentSize = *(uint32*)pointer + sizeof(uint32);
1890		result = _ResizeData(offset, -currentSize);
1891		if (result != B_OK)
1892			return result;
1893
1894		field->data_size -= currentSize;
1895	}
1896
1897	field->count--;
1898	return B_OK;
1899}
1900
1901
1902status_t
1903BMessage::RemoveName(const char* name)
1904{
1905	DEBUG_FUNCTION_ENTER;
1906	if (fHeader == NULL)
1907		return B_NO_INIT;
1908
1909	status_t result;
1910	if (fHeader->message_area >= 0) {
1911		result = _CopyForWrite();
1912		if (result != B_OK)
1913			return result;
1914	}
1915
1916	field_header* field = NULL;
1917	result = _FindField(name, B_ANY_TYPE, &field);
1918	if (result != B_OK)
1919		return result;
1920
1921	return _RemoveField(field);
1922}
1923
1924
1925status_t
1926BMessage::MakeEmpty()
1927{
1928	DEBUG_FUNCTION_ENTER;
1929	_Clear();
1930	return _InitHeader();
1931}
1932
1933
1934status_t
1935BMessage::FindData(const char* name, type_code type, int32 index,
1936	const void** data, ssize_t* numBytes) const
1937{
1938	DEBUG_FUNCTION_ENTER;
1939	if (data == NULL)
1940		return B_BAD_VALUE;
1941
1942	*data = NULL;
1943	field_header* field = NULL;
1944	status_t result = _FindField(name, type, &field);
1945	if (result != B_OK)
1946		return result;
1947
1948	if (index < 0 || (uint32)index >= field->count)
1949		return B_BAD_INDEX;
1950
1951	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1952		size_t bytes = field->data_size / field->count;
1953		*data = fData + field->offset + field->name_length + index * bytes;
1954		if (numBytes != NULL)
1955			*numBytes = bytes;
1956	} else {
1957		uint8* pointer = fData + field->offset + field->name_length;
1958		for (int32 i = 0; i < index; i++)
1959			pointer += *(uint32*)pointer + sizeof(uint32);
1960
1961		*data = pointer + sizeof(uint32);
1962		if (numBytes != NULL)
1963			*numBytes = *(uint32*)pointer;
1964	}
1965
1966	return B_OK;
1967}
1968
1969
1970status_t
1971BMessage::ReplaceData(const char* name, type_code type, int32 index,
1972	const void* data, ssize_t numBytes)
1973{
1974	DEBUG_FUNCTION_ENTER;
1975	if (numBytes <= 0 || data == NULL)
1976		return B_BAD_VALUE;
1977
1978	status_t result;
1979	if (fHeader->message_area >= 0) {
1980		result = _CopyForWrite();
1981		if (result != B_OK)
1982			return result;
1983	}
1984
1985	field_header* field = NULL;
1986	result = _FindField(name, type, &field);
1987	if (result != B_OK)
1988		return result;
1989
1990	if (index < 0 || (uint32)index >= field->count)
1991		return B_BAD_INDEX;
1992
1993	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1994		ssize_t size = field->data_size / field->count;
1995		if (size != numBytes)
1996			return B_BAD_VALUE;
1997
1998		memcpy(fData + field->offset + field->name_length + index * size, data,
1999			size);
2000	} else {
2001		uint32 offset = field->offset + field->name_length;
2002		uint8* pointer = fData + offset;
2003
2004		for (int32 i = 0; i < index; i++) {
2005			offset += *(uint32*)pointer + sizeof(uint32);
2006			pointer = fData + offset;
2007		}
2008
2009		size_t currentSize = *(uint32*)pointer;
2010		int32 change = numBytes - currentSize;
2011		result = _ResizeData(offset, change);
2012		if (result != B_OK)
2013			return result;
2014
2015		uint32 newSize = (uint32)numBytes;
2016		memcpy(fData + offset, &newSize, sizeof(uint32));
2017		memcpy(fData + offset + sizeof(uint32), data, newSize);
2018		field->data_size += change;
2019	}
2020
2021	return B_OK;
2022}
2023
2024
2025bool
2026BMessage::HasData(const char* name, type_code type, int32 index) const
2027{
2028	DEBUG_FUNCTION_ENTER;
2029	field_header* field = NULL;
2030	status_t result = _FindField(name, type, &field);
2031	if (result != B_OK)
2032		return false;
2033
2034	if (index < 0 || (uint32)index >= field->count)
2035		return false;
2036
2037	return true;
2038}
2039
2040
2041/* Static functions for cache initialization and cleanup */
2042void
2043BMessage::_StaticInit()
2044{
2045	DEBUG_FUNCTION_ENTER2;
2046	sReplyPorts[0] = create_port(1, "tmp_rport0");
2047	sReplyPorts[1] = create_port(1, "tmp_rport1");
2048	sReplyPorts[2] = create_port(1, "tmp_rport2");
2049
2050	sReplyPortInUse[0] = 0;
2051	sReplyPortInUse[1] = 0;
2052	sReplyPortInUse[2] = 0;
2053
2054	sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
2055}
2056
2057
2058void
2059BMessage::_StaticReInitForkedChild()
2060{
2061	DEBUG_FUNCTION_ENTER2;
2062
2063	// overwrite the inherited ports with a set of our own
2064	sReplyPorts[0] = create_port(1, "tmp_rport0");
2065	sReplyPorts[1] = create_port(1, "tmp_rport1");
2066	sReplyPorts[2] = create_port(1, "tmp_rport2");
2067
2068	sReplyPortInUse[0] = 0;
2069	sReplyPortInUse[1] = 0;
2070	sReplyPortInUse[2] = 0;
2071}
2072
2073
2074void
2075BMessage::_StaticCleanup()
2076{
2077	DEBUG_FUNCTION_ENTER2;
2078	delete_port(sReplyPorts[0]);
2079	sReplyPorts[0] = -1;
2080	delete_port(sReplyPorts[1]);
2081	sReplyPorts[1] = -1;
2082	delete_port(sReplyPorts[2]);
2083	sReplyPorts[2] = -1;
2084}
2085
2086
2087void
2088BMessage::_StaticCacheCleanup()
2089{
2090	DEBUG_FUNCTION_ENTER2;
2091	delete sMsgCache;
2092	sMsgCache = NULL;
2093}
2094
2095
2096int32
2097BMessage::_StaticGetCachedReplyPort()
2098{
2099	DEBUG_FUNCTION_ENTER2;
2100	int index = -1;
2101	for (int32 i = 0; i < sNumReplyPorts; i++) {
2102		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2103		if (old == 0) {
2104			// This entry is free
2105			index = i;
2106			break;
2107		} else {
2108			// This entry is being used.
2109			atomic_add(&(sReplyPortInUse[i]), -1);
2110		}
2111	}
2112
2113	return index;
2114}
2115
2116
2117status_t
2118BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2119	bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const
2120{
2121	DEBUG_FUNCTION_ENTER;
2122	ssize_t size = 0;
2123	char* buffer = NULL;
2124	message_header* header = NULL;
2125	status_t result = B_OK;
2126
2127	BPrivate::BDirectMessageTarget* direct = NULL;
2128	BMessage* copy = NULL;
2129	if (portOwner == BPrivate::current_team())
2130		BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
2131
2132	if (direct != NULL) {
2133		// We have a direct local message target - we can just enqueue the
2134		// message in its message queue. This will also prevent possible
2135		// deadlocks when the queue is full.
2136		copy = new BMessage(*this);
2137		if (copy != NULL) {
2138			header = copy->fHeader;
2139			header->flags = fHeader->flags;
2140		} else {
2141			direct->Release();
2142			return B_NO_MEMORY;
2143		}
2144#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2145	} else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) {
2146		KMessage toMessage;
2147		result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage);
2148		if (result != B_OK)
2149			return result;
2150
2151		return toMessage.SendTo(port, token);
2152	} else if (fHeader->data_size > B_PAGE_SIZE * 10) {
2153		// ToDo: bind the above size to the max port message size
2154		// use message passing by area for such a large message
2155		result = _FlattenToArea(&header);
2156		if (result != B_OK)
2157			return result;
2158
2159		buffer = (char*)header;
2160		size = sizeof(message_header);
2161
2162		if (header->message_area >= 0) {
2163			team_id target = portOwner;
2164			if (target < 0) {
2165				port_info info;
2166				result = get_port_info(port, &info);
2167				if (result != B_OK) {
2168					free(header);
2169					return result;
2170				}
2171				target = info.team;
2172			}
2173
2174			void* address = NULL;
2175			area_id transfered = _kern_transfer_area(header->message_area,
2176				&address, B_ANY_ADDRESS, target);
2177			if (transfered < 0) {
2178				delete_area(header->message_area);
2179				free(header);
2180				return transfered;
2181			}
2182
2183			header->message_area = transfered;
2184		}
2185#endif
2186	} else {
2187		size = FlattenedSize();
2188		buffer = (char*)malloc(size);
2189		if (buffer == NULL)
2190			return B_NO_MEMORY;
2191
2192		result = Flatten(buffer, size);
2193		if (result != B_OK) {
2194			free(buffer);
2195			return result;
2196		}
2197
2198		header = (message_header*)buffer;
2199	}
2200
2201	if (!replyTo.IsValid()) {
2202		BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2203			fHeader->reply_port, fHeader->reply_target);
2204
2205		if (!replyTo.IsValid())
2206			replyTo = be_app_messenger;
2207	}
2208
2209	BMessenger::Private replyToPrivate(replyTo);
2210
2211	if (replyRequired) {
2212		header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2213		header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2214	}
2215
2216	header->target = token;
2217	header->reply_team = replyToPrivate.Team();
2218	header->reply_port = replyToPrivate.Port();
2219	header->reply_target = replyToPrivate.Token();
2220	header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2221
2222	if (direct == NULL) {
2223		KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2224			"message: '%c%c%c%c'", portOwner, port, token,
2225			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2226
2227		do {
2228			result = write_port_etc(port, kPortMessageCode, (void*)buffer,
2229				size, B_RELATIVE_TIMEOUT, timeout);
2230		} while (result == B_INTERRUPTED);
2231	}
2232
2233	if (result == B_OK && IsSourceWaiting()) {
2234		// the forwarded message will handle the reply - we must not do
2235		// this anymore
2236		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2237	}
2238
2239	// we need to do this last because it is possible our
2240	// message might be destroyed after it's enqueued in the
2241	// target looper. Thus we don't want to do any ops that depend on
2242	// members of this after the enqueue.
2243	if (direct != NULL) {
2244		KTRACE("BMessage send direct: port: %ld, token: %ld, "
2245			"message: '%c%c%c%c'", port, token,
2246			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2247
2248		// this is a local message transmission
2249		direct->AddMessage(copy);
2250		if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2251			// there is currently no message waiting, and we need to wakeup the
2252			// looper
2253			write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2254		}
2255		direct->Release();
2256	}
2257
2258	free(buffer);
2259	return result;
2260}
2261
2262
2263// Sends a message and waits synchronously for a reply.
2264status_t
2265BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2266	BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2267{
2268	if (IsSourceWaiting()) {
2269		// we can't forward this message synchronously when it's already
2270		// waiting for a reply
2271		return B_ERROR;
2272	}
2273
2274	DEBUG_FUNCTION_ENTER;
2275	const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2276	port_id replyPort = B_BAD_PORT_ID;
2277	status_t result = B_OK;
2278
2279	if (cachedReplyPort < 0) {
2280		// All the cached reply ports are in use; create a new one
2281		replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2282		if (replyPort < 0)
2283			return replyPort;
2284	} else {
2285		assert(cachedReplyPort < sNumReplyPorts);
2286		replyPort = sReplyPorts[cachedReplyPort];
2287	}
2288
2289	bool recreateCachedPort = false;
2290
2291	team_id team = B_BAD_TEAM_ID;
2292	if (be_app != NULL)
2293		team = be_app->Team();
2294	else {
2295		port_info portInfo;
2296		result = get_port_info(replyPort, &portInfo);
2297		if (result != B_OK)
2298			goto error;
2299
2300		team = portInfo.team;
2301	}
2302
2303	result = set_port_owner(replyPort, portOwner);
2304	if (result != B_OK)
2305		goto error;
2306
2307	// tests if the queue of the reply port is really empty
2308#if 0
2309	port_info portInfo;
2310	if (get_port_info(replyPort, &portInfo) == B_OK
2311		&& portInfo.queue_count > 0) {
2312		debugger("reply port not empty!");
2313		printf("  reply port not empty! %ld message(s) in queue\n",
2314			portInfo.queue_count);
2315
2316		// fetch and print the messages
2317		for (int32 i = 0; i < portInfo.queue_count; i++) {
2318			char buffer[1024];
2319			int32 code;
2320			ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2321			if (size < 0) {
2322				printf("failed to read message from reply port\n");
2323				continue;
2324			}
2325			if (size >= (ssize_t)sizeof(buffer)) {
2326				printf("message from reply port too big\n");
2327				continue;
2328			}
2329
2330			BMemoryIO stream(buffer, size);
2331			BMessage reply;
2332			if (reply.Unflatten(&stream) != B_OK) {
2333				printf("failed to unflatten message from reply port\n");
2334				continue;
2335			}
2336
2337			printf("message %ld from reply port:\n", i);
2338			reply.PrintToStream();
2339		}
2340	}
2341#endif
2342
2343	{
2344		BMessenger replyTarget;
2345		BMessenger::Private(replyTarget).SetTo(team, replyPort,
2346			B_PREFERRED_TOKEN);
2347		// TODO: replying could also use a BDirectMessageTarget like mechanism
2348		// for local targets
2349		result = _SendMessage(port, -1, token, sendTimeout, true,
2350			replyTarget);
2351	}
2352
2353	if (result != B_OK)
2354		goto error;
2355
2356	int32 code;
2357	result = handle_reply(replyPort, &code, replyTimeout, reply);
2358	if (result != B_OK && cachedReplyPort >= 0) {
2359		delete_port(replyPort);
2360		recreateCachedPort = true;
2361	}
2362
2363error:
2364	if (cachedReplyPort >= 0) {
2365		// Reclaim ownership of cached port, if possible
2366		if (!recreateCachedPort && set_port_owner(replyPort, team) == B_OK) {
2367			// Flag as available
2368			atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2369		} else
2370			sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2371
2372		return result;
2373	}
2374
2375	delete_port(replyPort);
2376	return result;
2377}
2378
2379
2380status_t
2381BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port,
2382	int32 token, bigtime_t timeout)
2383{
2384	DEBUG_FUNCTION_ENTER2;
2385	if (data == NULL)
2386		return B_BAD_VALUE;
2387
2388	uint32 magic = *(uint32*)data;
2389
2390	if (magic == MESSAGE_FORMAT_HAIKU
2391		|| magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2392		message_header* header = (message_header*)data;
2393		header->target = token;
2394		header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2395	} else if (magic == MESSAGE_FORMAT_R5) {
2396		uint8* header = (uint8*)data;
2397		header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2398			+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2399			+ sizeof(uint8) /* flags */;
2400		*(int32*)header = token;
2401	} else if (((KMessage::Header*)data)->magic
2402			== KMessage::kMessageHeaderMagic) {
2403		KMessage::Header* header = (KMessage::Header*)data;
2404		header->targetToken = token;
2405	} else {
2406		return B_NOT_A_MESSAGE;
2407	}
2408
2409	// send the message
2410	status_t result;
2411
2412	do {
2413		result = write_port_etc(port, kPortMessageCode, data, size,
2414			B_RELATIVE_TIMEOUT, timeout);
2415	} while (result == B_INTERRUPTED);
2416
2417	return result;
2418}
2419
2420
2421void BMessage::_ReservedMessage1() {}
2422void BMessage::_ReservedMessage2() {}
2423void BMessage::_ReservedMessage3() {}
2424
2425
2426// #pragma mark - Macro definitions for data access methods
2427
2428
2429/* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2430
2431#define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
2432status_t																	\
2433BMessage::Add##typeName(const char* name, type val)							\
2434{																			\
2435	return AddData(name, typeCode, &val, sizeof(type), true);				\
2436}																			\
2437																			\
2438																			\
2439status_t																	\
2440BMessage::Find##typeName(const char* name, type* p) const					\
2441{																			\
2442	return Find##typeName(name, 0, p);										\
2443}																			\
2444																			\
2445																			\
2446status_t																	\
2447BMessage::Find##typeName(const char* name, int32 index, type* p) const		\
2448{																			\
2449	type* ptr = NULL;														\
2450	ssize_t bytes = 0;														\
2451	status_t error = B_OK;													\
2452																			\
2453	*p = type();															\
2454	error = FindData(name, typeCode, index, (const void**)&ptr, &bytes);	\
2455																			\
2456	if (error == B_OK)														\
2457		*p = *ptr;															\
2458																			\
2459	return error;															\
2460}																			\
2461																			\
2462																			\
2463status_t																	\
2464BMessage::Replace##typeName(const char* name, type value)					\
2465{																			\
2466	return ReplaceData(name, typeCode, 0, &value, sizeof(type));			\
2467}																			\
2468																			\
2469																			\
2470status_t																	\
2471BMessage::Replace##typeName(const char* name, int32 index, type value)		\
2472{																			\
2473	return ReplaceData(name, typeCode, index, &value, sizeof(type));		\
2474}																			\
2475																			\
2476																			\
2477bool																		\
2478BMessage::Has##typeName(const char* name, int32 index) const				\
2479{																			\
2480	return HasData(name, typeCode, index);									\
2481}
2482
2483DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2484DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2485DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2486DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2487DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2488DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2489DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2490DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2491DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2492DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2493DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2494DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2495DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2496DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2497DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2498
2499#undef DEFINE_FUNCTIONS
2500
2501#define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2502bool																		\
2503BMessage::Has##typeName(const char* name, int32 index) const				\
2504{																			\
2505	return HasData(name, typeCode, index);									\
2506}
2507
2508
2509DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE);
2510DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2511DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2512DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2513DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2514DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2515
2516#undef DEFINE_HAS_FUNCTION
2517
2518
2519#define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2520type																		\
2521BMessage::Find##typeName(const char* name, int32 index) const				\
2522{																			\
2523	type val = initialize;													\
2524	Find##typeName(name, index, &val);										\
2525	return val;																\
2526}
2527
2528
2529DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2530DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2531DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL);
2532DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2533DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2534DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2535DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2536DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2537DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2538DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2539
2540#undef DEFINE_LAZY_FIND_FUNCTION
2541
2542
2543#define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode)					\
2544type																		\
2545BMessage::Get##typeName(const char* name, type defaultValue) const			\
2546{																			\
2547	return Get##typeName(name, 0, defaultValue);							\
2548}																			\
2549																			\
2550																			\
2551type																		\
2552BMessage::Get##typeName(const char* name, int32 index,						\
2553	type defaultValue) const												\
2554{																			\
2555	type value;																\
2556	if (Find##typeName(name, index, &value) == B_OK)						\
2557		return value;														\
2558																			\
2559	return defaultValue;													\
2560}																			\
2561																			\
2562																			\
2563status_t																	\
2564BMessage::Set##typeName(const char* name, type value)						\
2565{																			\
2566	return SetData(name, typeCode, &value, sizeof(type));					\
2567}																			\
2568
2569
2570DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2571DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2572DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2573DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2574DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2575DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2576DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2577DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2578DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2579DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2580DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2581DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2582
2583#undef DEFINE_SET_GET_FUNCTION
2584
2585
2586const void*
2587BMessage::GetPointer(const char* name, const void* defaultValue) const
2588{
2589	return GetPointer(name, 0, defaultValue);
2590}
2591
2592
2593const void*
2594BMessage::GetPointer(const char* name, int32 index,
2595	const void* defaultValue) const
2596{
2597	void* value;
2598	if (FindPointer(name, index, &value) == B_OK)
2599		return value;
2600
2601	return defaultValue;
2602}
2603
2604
2605status_t
2606BMessage::SetPointer(const char* name, const void* value)
2607{
2608	return SetData(name, B_POINTER_TYPE, &value, sizeof(void*));
2609}
2610
2611
2612#define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode)		\
2613type																		\
2614BMessage::Get##typeName(const char* name, const type& defaultValue) const	\
2615{																			\
2616	return Get##typeName(name, 0, defaultValue);							\
2617}																			\
2618																			\
2619																			\
2620type																		\
2621BMessage::Get##typeName(const char* name, int32 index,						\
2622	const type& defaultValue) const											\
2623{																			\
2624	type value;																\
2625	if (Find##typeName(name, index, &value) == B_OK)						\
2626		return value;														\
2627																			\
2628	return defaultValue;													\
2629}																			\
2630																			\
2631																			\
2632status_t																	\
2633BMessage::Set##typeName(const char* name, const type& value)				\
2634{																			\
2635	return SetData(name, typeCode, &value, sizeof(type));					\
2636}																			\
2637
2638
2639DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2640DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2641DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2642
2643#undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS
2644
2645
2646status_t
2647BMessage::AddAlignment(const char* name, const BAlignment& alignment)
2648{
2649	int32 data[2] = { alignment.horizontal, alignment.vertical };
2650	return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data));
2651}
2652
2653
2654status_t
2655BMessage::AddString(const char* name, const char* string)
2656{
2657	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0,
2658		false);
2659}
2660
2661
2662status_t
2663BMessage::AddString(const char* name, const BString& string)
2664{
2665	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1,
2666		false);
2667}
2668
2669
2670status_t
2671BMessage::AddStrings(const char* name, const BStringList& list)
2672{
2673	int32 count = list.CountStrings();
2674	for (int32 i = 0; i < count; i++) {
2675		status_t error = AddString(name, list.StringAt(i));
2676		if (error != B_OK)
2677			return error;
2678	}
2679
2680	return B_OK;
2681}
2682
2683
2684status_t
2685BMessage::AddPointer(const char* name, const void* pointer)
2686{
2687	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2688}
2689
2690
2691status_t
2692BMessage::AddMessenger(const char* name, BMessenger messenger)
2693{
2694	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2695}
2696
2697
2698status_t
2699BMessage::AddRef(const char* name, const entry_ref* ref)
2700{
2701	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2702	char buffer[size];
2703
2704	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2705
2706	if (error >= B_OK)
2707		error = AddData(name, B_REF_TYPE, buffer, size, false);
2708
2709	return error;
2710}
2711
2712
2713status_t
2714BMessage::AddMessage(const char* name, const BMessage* message)
2715{
2716	if (message == NULL)
2717		return B_BAD_VALUE;
2718
2719	// TODO: This and the following functions waste time by allocating and
2720	// copying an extra buffer. Functions can be added that return a direct
2721	// pointer into the message.
2722
2723	char stackBuffer[16384];
2724	ssize_t size = message->FlattenedSize();
2725
2726	char* buffer;
2727	if (size > (ssize_t)sizeof(stackBuffer)) {
2728		buffer = (char*)malloc(size);
2729		if (buffer == NULL)
2730			return B_NO_MEMORY;
2731	} else
2732		buffer = stackBuffer;
2733
2734	status_t error = message->Flatten(buffer, size);
2735
2736	if (error >= B_OK)
2737		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2738
2739	if (buffer != stackBuffer)
2740		free(buffer);
2741
2742	return error;
2743}
2744
2745
2746status_t
2747BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
2748{
2749	return AddFlat(name, (const BFlattenable*)object, count);
2750}
2751
2752
2753status_t
2754BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count)
2755{
2756	if (object == NULL)
2757		return B_BAD_VALUE;
2758
2759	char stackBuffer[16384];
2760	ssize_t size = object->FlattenedSize();
2761
2762	char* buffer;
2763	if (size > (ssize_t)sizeof(stackBuffer)) {
2764		buffer = (char*)malloc(size);
2765		if (buffer == NULL)
2766			return B_NO_MEMORY;
2767	} else
2768		buffer = stackBuffer;
2769
2770	status_t error = object->Flatten(buffer, size);
2771
2772	if (error >= B_OK)
2773		error = AddData(name, object->TypeCode(), buffer, size, false);
2774
2775	if (buffer != stackBuffer)
2776		free(buffer);
2777
2778	return error;
2779}
2780
2781
2782status_t
2783BMessage::Append(const BMessage& other)
2784{
2785	field_header* field = other.fFields;
2786	for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) {
2787		const char* name = (const char*)(other.fData + field->offset);
2788		const void* data = (const void*)(other.fData + field->offset
2789			+ field->name_length);
2790		bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
2791		size_t size = field->data_size / field->count;
2792
2793		for (uint32 j = 0; j < field->count; j++) {
2794			if (!isFixed) {
2795				size = *(uint32*)data;
2796				data = (const void*)((const char*)data + sizeof(uint32));
2797			}
2798
2799			status_t status = AddData(name, field->type, data, size,
2800				isFixed, 1);
2801			if (status != B_OK)
2802				return status;
2803
2804			data = (const void*)((const char*)data + size);
2805		}
2806	}
2807	return B_OK;
2808}
2809
2810
2811status_t
2812BMessage::FindAlignment(const char* name, BAlignment* alignment) const
2813{
2814	return FindAlignment(name, 0, alignment);
2815}
2816
2817
2818status_t
2819BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment)
2820	const
2821{
2822	if (!alignment)
2823		return B_BAD_VALUE;
2824
2825	int32* data;
2826	ssize_t bytes;
2827
2828	status_t err = FindData(name, B_ALIGNMENT_TYPE, index,
2829		(const void**)&data, &bytes);
2830
2831	if (err == B_OK) {
2832		if (bytes != sizeof(int32[2]))
2833			return B_ERROR;
2834
2835		alignment->horizontal = (enum alignment)(*data);
2836		alignment->vertical = (vertical_alignment)*(data + 1);
2837	}
2838
2839	return err;
2840}
2841
2842
2843status_t
2844BMessage::FindString(const char* name, const char** string) const
2845{
2846	return FindString(name, 0, string);
2847}
2848
2849
2850status_t
2851BMessage::FindString(const char* name, int32 index, const char** string) const
2852{
2853	ssize_t bytes;
2854	return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes);
2855}
2856
2857
2858status_t
2859BMessage::FindString(const char* name, BString* string) const
2860{
2861	return FindString(name, 0, string);
2862}
2863
2864
2865status_t
2866BMessage::FindString(const char* name, int32 index, BString* string) const
2867{
2868	if (string == NULL)
2869		return B_BAD_VALUE;
2870
2871	const char* value;
2872	status_t error = FindString(name, index, &value);
2873
2874	// Find*() clobbers the object even on failure
2875	string->SetTo(value);
2876	return error;
2877}
2878
2879
2880status_t
2881BMessage::FindStrings(const char* name, BStringList* list) const
2882{
2883	if (list == NULL)
2884		return B_BAD_VALUE;
2885
2886	list->MakeEmpty();
2887
2888	// get the number of items
2889	type_code type;
2890	int32 count;
2891	if (GetInfo(name, &type, &count) != B_OK)
2892		return B_NAME_NOT_FOUND;
2893
2894	if (type != B_STRING_TYPE)
2895		return B_BAD_DATA;
2896
2897	for (int32 i = 0; i < count; i++) {
2898		BString string;
2899		status_t error = FindString(name, i, &string);
2900		if (error != B_OK)
2901			return error;
2902		if (!list->Add(string))
2903			return B_NO_MEMORY;
2904	}
2905
2906	return B_OK;
2907}
2908
2909
2910status_t
2911BMessage::FindPointer(const char* name, void** pointer) const
2912{
2913	return FindPointer(name, 0, pointer);
2914}
2915
2916
2917status_t
2918BMessage::FindPointer(const char* name, int32 index, void** pointer) const
2919{
2920	if (pointer == NULL)
2921		return B_BAD_VALUE;
2922
2923	void** data = NULL;
2924	ssize_t size = 0;
2925	status_t error = FindData(name, B_POINTER_TYPE, index,
2926		(const void**)&data, &size);
2927
2928	if (error == B_OK)
2929		*pointer = *data;
2930	else
2931		*pointer = NULL;
2932
2933	return error;
2934}
2935
2936
2937status_t
2938BMessage::FindMessenger(const char* name, BMessenger* messenger) const
2939{
2940	return FindMessenger(name, 0, messenger);
2941}
2942
2943
2944status_t
2945BMessage::FindMessenger(const char* name, int32 index,
2946	BMessenger* messenger) const
2947{
2948	if (messenger == NULL)
2949		return B_BAD_VALUE;
2950
2951	BMessenger* data = NULL;
2952	ssize_t size = 0;
2953	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2954		(const void**)&data, &size);
2955
2956	if (error == B_OK)
2957		*messenger = *data;
2958	else
2959		*messenger = BMessenger();
2960
2961	return error;
2962}
2963
2964
2965status_t
2966BMessage::FindRef(const char* name, entry_ref* ref) const
2967{
2968	return FindRef(name, 0, ref);
2969}
2970
2971
2972status_t
2973BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
2974{
2975	if (ref == NULL)
2976		return B_BAD_VALUE;
2977
2978	void* data = NULL;
2979	ssize_t size = 0;
2980	status_t error = FindData(name, B_REF_TYPE, index,
2981		(const void**)&data, &size);
2982
2983	if (error == B_OK)
2984		error = BPrivate::entry_ref_unflatten(ref, (char*)data, size);
2985	else
2986		*ref = entry_ref();
2987
2988	return error;
2989}
2990
2991
2992status_t
2993BMessage::FindMessage(const char* name, BMessage* message) const
2994{
2995	return FindMessage(name, 0, message);
2996}
2997
2998
2999status_t
3000BMessage::FindMessage(const char* name, int32 index, BMessage* message) const
3001{
3002	if (message == NULL)
3003		return B_BAD_VALUE;
3004
3005	void* data = NULL;
3006	ssize_t size = 0;
3007	status_t error = FindData(name, B_MESSAGE_TYPE, index,
3008		(const void**)&data, &size);
3009
3010	if (error == B_OK)
3011		error = message->Unflatten((const char*)data);
3012	else
3013		*message = BMessage();
3014
3015	return error;
3016}
3017
3018
3019status_t
3020BMessage::FindFlat(const char* name, BFlattenable* object) const
3021{
3022	return FindFlat(name, 0, object);
3023}
3024
3025
3026status_t
3027BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const
3028{
3029	if (object == NULL)
3030		return B_BAD_VALUE;
3031
3032	void* data = NULL;
3033	ssize_t numBytes = 0;
3034	status_t error = FindData(name, object->TypeCode(), index,
3035		(const void**)&data, &numBytes);
3036
3037	if (error == B_OK)
3038		error = object->Unflatten(object->TypeCode(), data, numBytes);
3039
3040	return error;
3041}
3042
3043
3044status_t
3045BMessage::FindData(const char* name, type_code type, const void** data,
3046	ssize_t* numBytes) const
3047{
3048	return FindData(name, type, 0, data, numBytes);
3049}
3050
3051
3052status_t
3053BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment)
3054{
3055	int32 data[2] = {alignment.horizontal, alignment.vertical};
3056	return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data));
3057}
3058
3059
3060status_t
3061BMessage::ReplaceAlignment(const char* name, int32 index,
3062	const BAlignment& alignment)
3063{
3064	int32 data[2] = {alignment.horizontal, alignment.vertical};
3065	return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data));
3066}
3067
3068
3069status_t
3070BMessage::ReplaceString(const char* name, const char* string)
3071{
3072	if (string == NULL)
3073		return B_BAD_VALUE;
3074
3075	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
3076}
3077
3078
3079status_t
3080BMessage::ReplaceString(const char* name, int32 index, const char* string)
3081{
3082	if (string == NULL)
3083		return B_BAD_VALUE;
3084
3085	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
3086}
3087
3088
3089status_t
3090BMessage::ReplaceString(const char* name, const BString& string)
3091{
3092	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
3093		string.Length() + 1);
3094}
3095
3096
3097status_t
3098BMessage::ReplaceString(const char* name, int32 index, const BString& string)
3099{
3100	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
3101		string.Length() + 1);
3102}
3103
3104
3105status_t
3106BMessage::ReplacePointer(const char* name, const void* pointer)
3107{
3108	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
3109}
3110
3111
3112status_t
3113BMessage::ReplacePointer(const char* name, int32 index, const void* pointer)
3114{
3115	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
3116}
3117
3118
3119status_t
3120BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
3121{
3122	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
3123		sizeof(BMessenger));
3124}
3125
3126
3127status_t
3128BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
3129{
3130	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
3131		sizeof(BMessenger));
3132}
3133
3134
3135status_t
3136BMessage::ReplaceRef(const char* name, const entry_ref* ref)
3137{
3138	return ReplaceRef(name, 0, ref);
3139}
3140
3141
3142status_t
3143BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
3144{
3145	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
3146	char buffer[size];
3147
3148	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
3149
3150	if (error >= B_OK)
3151		error = ReplaceData(name, B_REF_TYPE, index, buffer, size);
3152
3153	return error;
3154}
3155
3156
3157status_t
3158BMessage::ReplaceMessage(const char* name, const BMessage* message)
3159{
3160	return ReplaceMessage(name, 0, message);
3161}
3162
3163
3164status_t
3165BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message)
3166{
3167	if (message == NULL)
3168		return B_BAD_VALUE;
3169
3170	ssize_t size = message->FlattenedSize();
3171	char buffer[size];
3172
3173	status_t error = message->Flatten(buffer, size);
3174
3175	if (error >= B_OK)
3176		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
3177
3178	return error;
3179}
3180
3181
3182status_t
3183BMessage::ReplaceFlat(const char* name, BFlattenable* object)
3184{
3185	return ReplaceFlat(name, 0, object);
3186}
3187
3188
3189status_t
3190BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
3191{
3192	if (object == NULL)
3193		return B_BAD_VALUE;
3194
3195	ssize_t size = object->FlattenedSize();
3196	char buffer[size];
3197
3198	status_t error = object->Flatten(buffer, size);
3199
3200	if (error >= B_OK)
3201		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
3202
3203	return error;
3204}
3205
3206
3207status_t
3208BMessage::ReplaceData(const char* name, type_code type, const void* data,
3209	ssize_t numBytes)
3210{
3211	return ReplaceData(name, type, 0, data, numBytes);
3212}
3213
3214
3215bool
3216BMessage::HasFlat(const char* name, const BFlattenable* object) const
3217{
3218	return HasFlat(name, 0, object);
3219}
3220
3221
3222bool
3223BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object)
3224	const
3225{
3226	return HasData(name, object->TypeCode(), index);
3227}
3228
3229
3230const char*
3231BMessage::GetString(const char* name, const char* defaultValue) const
3232{
3233	return GetString(name, 0, defaultValue);
3234}
3235
3236
3237const char*
3238BMessage::GetString(const char* name, int32 index,
3239	const char* defaultValue) const
3240{
3241	const char* value;
3242	if (FindString(name, index, &value) == B_OK)
3243		return value;
3244
3245	return defaultValue;
3246}
3247
3248
3249status_t
3250BMessage::SetString(const char* name, const BString& value)
3251{
3252	return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1,
3253		false);
3254}
3255
3256
3257status_t
3258BMessage::SetString(const char* name, const char* value)
3259{
3260	return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false);
3261}
3262
3263
3264status_t
3265BMessage::SetData(const char* name, type_code type, const void* data,
3266	ssize_t numBytes, bool fixedSize, int count)
3267{
3268	if (numBytes <= 0 || data == NULL)
3269		return B_BAD_VALUE;
3270
3271	if (ReplaceData(name, type, data, numBytes) == B_OK)
3272		return B_OK;
3273
3274	return AddData(name, type, data, numBytes, fixedSize, count);
3275}
3276