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