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