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	void* ptr = NULL;														\
2442	ssize_t bytes = 0;														\
2443	status_t error = B_OK;													\
2444																			\
2445	*p = type();															\
2446	error = FindData(name, typeCode, 0, (const void**)&ptr, &bytes);		\
2447																			\
2448	if (error == B_OK)														\
2449		memcpy(p, ptr, sizeof(type));										\
2450																			\
2451	return error;															\
2452}																			\
2453																			\
2454																			\
2455status_t																	\
2456BMessage::Find##typeName(const char* name, int32 index, type* p) const		\
2457{																			\
2458	void* ptr = NULL;														\
2459	ssize_t bytes = 0;														\
2460	status_t error = B_OK;													\
2461																			\
2462	*p = type();															\
2463	error = FindData(name, typeCode, index, (const void**)&ptr, &bytes);	\
2464																			\
2465	if (error == B_OK)														\
2466		memcpy(p, ptr, sizeof(type));										\
2467																			\
2468	return error;															\
2469}																			\
2470																			\
2471																			\
2472status_t																	\
2473BMessage::Replace##typeName(const char* name, type value)					\
2474{																			\
2475	return ReplaceData(name, typeCode, 0, &value, sizeof(type));			\
2476}																			\
2477																			\
2478																			\
2479status_t																	\
2480BMessage::Replace##typeName(const char* name, int32 index, type value)		\
2481{																			\
2482	return ReplaceData(name, typeCode, index, &value, sizeof(type));		\
2483}																			\
2484																			\
2485																			\
2486bool																		\
2487BMessage::Has##typeName(const char* name, int32 index) const				\
2488{																			\
2489	return HasData(name, typeCode, index);									\
2490}
2491
2492DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2493DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2494DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2495DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2496DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2497DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2498DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2499DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2500DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2501DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2502DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2503DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2504DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2505DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2506DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2507
2508#undef DEFINE_FUNCTIONS
2509
2510#define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2511bool																		\
2512BMessage::Has##typeName(const char* name, int32 index) const				\
2513{																			\
2514	return HasData(name, typeCode, index);									\
2515}
2516
2517
2518DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE);
2519DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2520DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2521DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2522DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2523DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2524
2525#undef DEFINE_HAS_FUNCTION
2526
2527
2528#define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2529type																		\
2530BMessage::Find##typeName(const char* name, int32 index) const				\
2531{																			\
2532	type val = initialize;													\
2533	Find##typeName(name, index, &val);										\
2534	return val;																\
2535}
2536
2537
2538DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2539DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2540DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL);
2541DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2542DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2543DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2544DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2545DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2546DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2547DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2548
2549#undef DEFINE_LAZY_FIND_FUNCTION
2550
2551
2552#define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode)					\
2553type																		\
2554BMessage::Get##typeName(const char* name, type defaultValue) const			\
2555{																			\
2556	return Get##typeName(name, 0, defaultValue);							\
2557}																			\
2558																			\
2559																			\
2560type																		\
2561BMessage::Get##typeName(const char* name, int32 index,						\
2562	type defaultValue) const												\
2563{																			\
2564	type value;																\
2565	if (Find##typeName(name, index, &value) == B_OK)						\
2566		return value;														\
2567																			\
2568	return defaultValue;													\
2569}																			\
2570																			\
2571																			\
2572status_t																	\
2573BMessage::Set##typeName(const char* name, type value)						\
2574{																			\
2575	return SetData(name, typeCode, &value, sizeof(type));					\
2576}																			\
2577
2578
2579DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2580DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2581DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2582DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2583DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2584DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2585DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2586DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2587DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2588DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2589DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2590DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2591
2592#undef DEFINE_SET_GET_FUNCTION
2593
2594
2595const void*
2596BMessage::GetPointer(const char* name, const void* defaultValue) const
2597{
2598	return GetPointer(name, 0, defaultValue);
2599}
2600
2601
2602const void*
2603BMessage::GetPointer(const char* name, int32 index,
2604	const void* defaultValue) const
2605{
2606	void* value;
2607	if (FindPointer(name, index, &value) == B_OK)
2608		return value;
2609
2610	return defaultValue;
2611}
2612
2613
2614status_t
2615BMessage::SetPointer(const char* name, const void* value)
2616{
2617	return SetData(name, B_POINTER_TYPE, &value, sizeof(void*));
2618}
2619
2620
2621#define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode)		\
2622type																		\
2623BMessage::Get##typeName(const char* name, const type& defaultValue) const	\
2624{																			\
2625	return Get##typeName(name, 0, defaultValue);							\
2626}																			\
2627																			\
2628																			\
2629type																		\
2630BMessage::Get##typeName(const char* name, int32 index,						\
2631	const type& defaultValue) const											\
2632{																			\
2633	type value;																\
2634	if (Find##typeName(name, index, &value) == B_OK)						\
2635		return value;														\
2636																			\
2637	return defaultValue;													\
2638}																			\
2639																			\
2640																			\
2641status_t																	\
2642BMessage::Set##typeName(const char* name, const type& value)				\
2643{																			\
2644	return SetData(name, typeCode, &value, sizeof(type));					\
2645}																			\
2646
2647
2648DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2649DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2650DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2651
2652#undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS
2653
2654
2655status_t
2656BMessage::AddAlignment(const char* name, const BAlignment& alignment)
2657{
2658	int32 data[2] = { alignment.horizontal, alignment.vertical };
2659	return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data));
2660}
2661
2662
2663status_t
2664BMessage::AddString(const char* name, const char* string)
2665{
2666	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0,
2667		false);
2668}
2669
2670
2671status_t
2672BMessage::AddString(const char* name, const BString& string)
2673{
2674	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1,
2675		false);
2676}
2677
2678
2679status_t
2680BMessage::AddStrings(const char* name, const BStringList& list)
2681{
2682	int32 count = list.CountStrings();
2683	for (int32 i = 0; i < count; i++) {
2684		status_t error = AddString(name, list.StringAt(i));
2685		if (error != B_OK)
2686			return error;
2687	}
2688
2689	return B_OK;
2690}
2691
2692
2693status_t
2694BMessage::AddPointer(const char* name, const void* pointer)
2695{
2696	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2697}
2698
2699
2700status_t
2701BMessage::AddMessenger(const char* name, BMessenger messenger)
2702{
2703	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2704}
2705
2706
2707status_t
2708BMessage::AddRef(const char* name, const entry_ref* ref)
2709{
2710	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2711	char buffer[size];
2712
2713	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2714
2715	if (error >= B_OK)
2716		error = AddData(name, B_REF_TYPE, buffer, size, false);
2717
2718	return error;
2719}
2720
2721
2722status_t
2723BMessage::AddMessage(const char* name, const BMessage* message)
2724{
2725	if (message == NULL)
2726		return B_BAD_VALUE;
2727
2728	// TODO: This and the following functions waste time by allocating and
2729	// copying an extra buffer. Functions can be added that return a direct
2730	// pointer into the message.
2731
2732	char stackBuffer[16384];
2733	ssize_t size = message->FlattenedSize();
2734
2735	char* buffer;
2736	if (size > (ssize_t)sizeof(stackBuffer)) {
2737		buffer = (char*)malloc(size);
2738		if (buffer == NULL)
2739			return B_NO_MEMORY;
2740	} else
2741		buffer = stackBuffer;
2742
2743	status_t error = message->Flatten(buffer, size);
2744
2745	if (error >= B_OK)
2746		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2747
2748	if (buffer != stackBuffer)
2749		free(buffer);
2750
2751	return error;
2752}
2753
2754
2755status_t
2756BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
2757{
2758	return AddFlat(name, (const BFlattenable*)object, count);
2759}
2760
2761
2762status_t
2763BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count)
2764{
2765	if (object == NULL)
2766		return B_BAD_VALUE;
2767
2768	char stackBuffer[16384];
2769	ssize_t size = object->FlattenedSize();
2770
2771	char* buffer;
2772	if (size > (ssize_t)sizeof(stackBuffer)) {
2773		buffer = (char*)malloc(size);
2774		if (buffer == NULL)
2775			return B_NO_MEMORY;
2776	} else
2777		buffer = stackBuffer;
2778
2779	status_t error = object->Flatten(buffer, size);
2780
2781	if (error >= B_OK)
2782		error = AddData(name, object->TypeCode(), buffer, size, false);
2783
2784	if (buffer != stackBuffer)
2785		free(buffer);
2786
2787	return error;
2788}
2789
2790
2791status_t
2792BMessage::Append(const BMessage& other)
2793{
2794	field_header* field = other.fFields;
2795	for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) {
2796		const char* name = (const char*)(other.fData + field->offset);
2797		const void* data = (const void*)(other.fData + field->offset
2798			+ field->name_length);
2799		bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
2800		size_t size = field->data_size / field->count;
2801
2802		for (uint32 j = 0; j < field->count; j++) {
2803			if (!isFixed) {
2804				size = *(uint32*)data;
2805				data = (const void*)((const char*)data + sizeof(uint32));
2806			}
2807
2808			status_t status = AddData(name, field->type, data, size,
2809				isFixed, 1);
2810			if (status != B_OK)
2811				return status;
2812
2813			data = (const void*)((const char*)data + size);
2814		}
2815	}
2816	return B_OK;
2817}
2818
2819
2820status_t
2821BMessage::FindAlignment(const char* name, BAlignment* alignment) const
2822{
2823	return FindAlignment(name, 0, alignment);
2824}
2825
2826
2827status_t
2828BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment)
2829	const
2830{
2831	if (!alignment)
2832		return B_BAD_VALUE;
2833
2834	int32* data;
2835	ssize_t bytes;
2836
2837	status_t err = FindData(name, B_ALIGNMENT_TYPE, index,
2838		(const void**)&data, &bytes);
2839
2840	if (err == B_OK) {
2841		if (bytes != sizeof(int32[2]))
2842			return B_ERROR;
2843
2844		alignment->horizontal = (enum alignment)(*data);
2845		alignment->vertical = (vertical_alignment)*(data + 1);
2846	}
2847
2848	return err;
2849}
2850
2851
2852status_t
2853BMessage::FindString(const char* name, const char** string) const
2854{
2855	return FindString(name, 0, string);
2856}
2857
2858
2859status_t
2860BMessage::FindString(const char* name, int32 index, const char** string) const
2861{
2862	ssize_t bytes;
2863	return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes);
2864}
2865
2866
2867status_t
2868BMessage::FindString(const char* name, BString* string) const
2869{
2870	return FindString(name, 0, string);
2871}
2872
2873
2874status_t
2875BMessage::FindString(const char* name, int32 index, BString* string) const
2876{
2877	if (string == NULL)
2878		return B_BAD_VALUE;
2879
2880	const char* value;
2881	status_t error = FindString(name, index, &value);
2882
2883	// Find*() clobbers the object even on failure
2884	string->SetTo(value);
2885	return error;
2886}
2887
2888
2889status_t
2890BMessage::FindStrings(const char* name, BStringList* list) const
2891{
2892	if (list == NULL)
2893		return B_BAD_VALUE;
2894
2895	list->MakeEmpty();
2896
2897	// get the number of items
2898	type_code type;
2899	int32 count;
2900	if (GetInfo(name, &type, &count) != B_OK)
2901		return B_NAME_NOT_FOUND;
2902
2903	if (type != B_STRING_TYPE)
2904		return B_BAD_DATA;
2905
2906	for (int32 i = 0; i < count; i++) {
2907		BString string;
2908		status_t error = FindString(name, i, &string);
2909		if (error != B_OK)
2910			return error;
2911		if (!list->Add(string))
2912			return B_NO_MEMORY;
2913	}
2914
2915	return B_OK;
2916}
2917
2918
2919status_t
2920BMessage::FindPointer(const char* name, void** pointer) const
2921{
2922	return FindPointer(name, 0, pointer);
2923}
2924
2925
2926status_t
2927BMessage::FindPointer(const char* name, int32 index, void** pointer) const
2928{
2929	if (pointer == NULL)
2930		return B_BAD_VALUE;
2931
2932	void** data = NULL;
2933	ssize_t size = 0;
2934	status_t error = FindData(name, B_POINTER_TYPE, index,
2935		(const void**)&data, &size);
2936
2937	if (error == B_OK)
2938		*pointer = *data;
2939	else
2940		*pointer = NULL;
2941
2942	return error;
2943}
2944
2945
2946status_t
2947BMessage::FindMessenger(const char* name, BMessenger* messenger) const
2948{
2949	return FindMessenger(name, 0, messenger);
2950}
2951
2952
2953status_t
2954BMessage::FindMessenger(const char* name, int32 index,
2955	BMessenger* messenger) const
2956{
2957	if (messenger == NULL)
2958		return B_BAD_VALUE;
2959
2960	void* data = NULL;
2961	ssize_t size = 0;
2962	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2963		(const void**)&data, &size);
2964
2965	if (error == B_OK)
2966		memcpy(messenger, data, sizeof(BMessenger));
2967	else
2968		*messenger = BMessenger();
2969
2970	return error;
2971}
2972
2973
2974status_t
2975BMessage::FindRef(const char* name, entry_ref* ref) const
2976{
2977	return FindRef(name, 0, ref);
2978}
2979
2980
2981status_t
2982BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
2983{
2984	if (ref == NULL)
2985		return B_BAD_VALUE;
2986
2987	void* data = NULL;
2988	ssize_t size = 0;
2989	status_t error = FindData(name, B_REF_TYPE, index,
2990		(const void**)&data, &size);
2991
2992	if (error == B_OK)
2993		error = BPrivate::entry_ref_unflatten(ref, (char*)data, size);
2994	else
2995		*ref = entry_ref();
2996
2997	return error;
2998}
2999
3000
3001status_t
3002BMessage::FindMessage(const char* name, BMessage* message) const
3003{
3004	return FindMessage(name, 0, message);
3005}
3006
3007
3008status_t
3009BMessage::FindMessage(const char* name, int32 index, BMessage* message) const
3010{
3011	if (message == NULL)
3012		return B_BAD_VALUE;
3013
3014	void* data = NULL;
3015	ssize_t size = 0;
3016	status_t error = FindData(name, B_MESSAGE_TYPE, index,
3017		(const void**)&data, &size);
3018
3019	if (error == B_OK)
3020		error = message->Unflatten((const char*)data);
3021	else
3022		*message = BMessage();
3023
3024	return error;
3025}
3026
3027
3028status_t
3029BMessage::FindFlat(const char* name, BFlattenable* object) const
3030{
3031	return FindFlat(name, 0, object);
3032}
3033
3034
3035status_t
3036BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const
3037{
3038	if (object == NULL)
3039		return B_BAD_VALUE;
3040
3041	void* data = NULL;
3042	ssize_t numBytes = 0;
3043	status_t error = FindData(name, object->TypeCode(), index,
3044		(const void**)&data, &numBytes);
3045
3046	if (error == B_OK)
3047		error = object->Unflatten(object->TypeCode(), data, numBytes);
3048
3049	return error;
3050}
3051
3052
3053status_t
3054BMessage::FindData(const char* name, type_code type, const void** data,
3055	ssize_t* numBytes) const
3056{
3057	return FindData(name, type, 0, data, numBytes);
3058}
3059
3060
3061status_t
3062BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment)
3063{
3064	int32 data[2] = {alignment.horizontal, alignment.vertical};
3065	return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data));
3066}
3067
3068
3069status_t
3070BMessage::ReplaceAlignment(const char* name, int32 index,
3071	const BAlignment& alignment)
3072{
3073	int32 data[2] = {alignment.horizontal, alignment.vertical};
3074	return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data));
3075}
3076
3077
3078status_t
3079BMessage::ReplaceString(const char* name, const char* string)
3080{
3081	if (string == NULL)
3082		return B_BAD_VALUE;
3083
3084	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
3085}
3086
3087
3088status_t
3089BMessage::ReplaceString(const char* name, int32 index, const char* string)
3090{
3091	if (string == NULL)
3092		return B_BAD_VALUE;
3093
3094	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
3095}
3096
3097
3098status_t
3099BMessage::ReplaceString(const char* name, const BString& string)
3100{
3101	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
3102		string.Length() + 1);
3103}
3104
3105
3106status_t
3107BMessage::ReplaceString(const char* name, int32 index, const BString& string)
3108{
3109	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
3110		string.Length() + 1);
3111}
3112
3113
3114status_t
3115BMessage::ReplacePointer(const char* name, const void* pointer)
3116{
3117	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
3118}
3119
3120
3121status_t
3122BMessage::ReplacePointer(const char* name, int32 index, const void* pointer)
3123{
3124	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
3125}
3126
3127
3128status_t
3129BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
3130{
3131	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
3132		sizeof(BMessenger));
3133}
3134
3135
3136status_t
3137BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
3138{
3139	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
3140		sizeof(BMessenger));
3141}
3142
3143
3144status_t
3145BMessage::ReplaceRef(const char* name, const entry_ref* ref)
3146{
3147	return ReplaceRef(name, 0, ref);
3148}
3149
3150
3151status_t
3152BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
3153{
3154	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
3155	char buffer[size];
3156
3157	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
3158
3159	if (error >= B_OK)
3160		error = ReplaceData(name, B_REF_TYPE, index, buffer, size);
3161
3162	return error;
3163}
3164
3165
3166status_t
3167BMessage::ReplaceMessage(const char* name, const BMessage* message)
3168{
3169	return ReplaceMessage(name, 0, message);
3170}
3171
3172
3173status_t
3174BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message)
3175{
3176	if (message == NULL)
3177		return B_BAD_VALUE;
3178
3179	ssize_t size = message->FlattenedSize();
3180	char buffer[size];
3181
3182	status_t error = message->Flatten(buffer, size);
3183
3184	if (error >= B_OK)
3185		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
3186
3187	return error;
3188}
3189
3190
3191status_t
3192BMessage::ReplaceFlat(const char* name, BFlattenable* object)
3193{
3194	return ReplaceFlat(name, 0, object);
3195}
3196
3197
3198status_t
3199BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
3200{
3201	if (object == NULL)
3202		return B_BAD_VALUE;
3203
3204	ssize_t size = object->FlattenedSize();
3205	char buffer[size];
3206
3207	status_t error = object->Flatten(buffer, size);
3208
3209	if (error >= B_OK)
3210		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
3211
3212	return error;
3213}
3214
3215
3216status_t
3217BMessage::ReplaceData(const char* name, type_code type, const void* data,
3218	ssize_t numBytes)
3219{
3220	return ReplaceData(name, type, 0, data, numBytes);
3221}
3222
3223
3224bool
3225BMessage::HasFlat(const char* name, const BFlattenable* object) const
3226{
3227	return HasFlat(name, 0, object);
3228}
3229
3230
3231bool
3232BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object)
3233	const
3234{
3235	return HasData(name, object->TypeCode(), index);
3236}
3237
3238
3239const char*
3240BMessage::GetString(const char* name, const char* defaultValue) const
3241{
3242	return GetString(name, 0, defaultValue);
3243}
3244
3245
3246const char*
3247BMessage::GetString(const char* name, int32 index,
3248	const char* defaultValue) const
3249{
3250	const char* value;
3251	if (FindString(name, index, &value) == B_OK)
3252		return value;
3253
3254	return defaultValue;
3255}
3256
3257
3258status_t
3259BMessage::SetString(const char* name, const BString& value)
3260{
3261	return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1,
3262		false);
3263}
3264
3265
3266status_t
3267BMessage::SetString(const char* name, const char* value)
3268{
3269	return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false);
3270}
3271
3272
3273status_t
3274BMessage::SetData(const char* name, type_code type, const void* data,
3275	ssize_t numBytes, bool fixedSize, int count)
3276{
3277	if (numBytes <= 0 || data == NULL)
3278		return B_BAD_VALUE;
3279
3280	if (ReplaceData(name, type, data, numBytes) == B_OK)
3281		return B_OK;
3282
3283	return AddData(name, type, data, numBytes, fixedSize, count);
3284}
3285