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