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