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