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