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