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