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