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