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