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