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