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