xref: /haiku/src/kits/app/Message.cpp (revision 0e50eab75e25d0d82090e22dbff766dfaa6f5e86)
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 		try {
1044 			if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped)
1045 				return BPrivate::unflatten_r5_message(format, this, flatBuffer);
1046 
1047 			if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped) {
1048 				BMemoryIO stream(flatBuffer + sizeof(uint32),
1049 					BPrivate::dano_message_flattened_size(flatBuffer));
1050 				return BPrivate::unflatten_dano_message(format, stream, *this);
1051 			}
1052 		} catch (status_t error) {
1053 			MakeEmpty();
1054 			return error;
1055 		}
1056 
1057 		return B_NOT_A_MESSAGE;
1058 	}
1059 
1060 	// native message unflattening
1061 
1062 	_Clear();
1063 
1064 	fHeader = (message_header *)malloc(sizeof(message_header));
1065 	if (!fHeader)
1066 		return B_NO_MEMORY;
1067 
1068 	memcpy(fHeader, flatBuffer, sizeof(message_header));
1069 	flatBuffer += sizeof(message_header);
1070 
1071 	if (fHeader->format != kMessageMagicHaiku
1072 		|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
1073 		free(fHeader);
1074 		fHeader = NULL;
1075 		_InitHeader();
1076 		return B_BAD_VALUE;
1077 	}
1078 
1079 	fHeader->fields_available = 0;
1080 	fHeader->data_available = 0;
1081 	what = fHeader->what;
1082 
1083 	if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
1084 		status_t result = _Reference(fHeader);
1085 		if (result < B_OK)
1086 			return result;
1087 	} else {
1088 		fHeader->shared_area = -1;
1089 
1090 		if (fHeader->fields_size > 0) {
1091 			fFields = (field_header *)malloc(fHeader->fields_size);
1092 			if (!fFields)
1093 				return B_NO_MEMORY;
1094 
1095 			memcpy(fFields, flatBuffer, fHeader->fields_size);
1096 			flatBuffer += fHeader->fields_size;
1097 		}
1098 
1099 		if (fHeader->data_size > 0) {
1100 			fData = (uint8 *)malloc(fHeader->data_size);
1101 			if (!fData)
1102 				return B_NO_MEMORY;
1103 
1104 			memcpy(fData, flatBuffer, fHeader->data_size);
1105 		}
1106 	}
1107 
1108 	/*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
1109 		|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
1110 		debug_printf("checksum mismatch 1\n");
1111 		_Clear();
1112 		_InitHeader();
1113 		return B_BAD_VALUE;
1114 	}*/
1115 
1116 	return B_OK;
1117 }
1118 
1119 
1120 status_t
1121 BMessage::Unflatten(BDataIO *stream)
1122 {
1123 	DEBUG_FUNCTION_ENTER;
1124 	if (!stream)
1125 		return B_BAD_VALUE;
1126 
1127 	uint32 format = 0;
1128 	stream->Read(&format, sizeof(uint32));
1129 	if (format != kMessageMagicHaiku) {
1130 		try {
1131 			if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped)
1132 				return BPrivate::unflatten_r5_message(format, this, stream);
1133 
1134 			if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped)
1135 				return BPrivate::unflatten_dano_message(format, *stream, *this);
1136 		} catch (status_t error) {
1137 			MakeEmpty();
1138 			return error;
1139 		}
1140 
1141 		return B_NOT_A_MESSAGE;
1142 	}
1143 
1144 	// native message unflattening
1145 
1146 	_Clear();
1147 
1148 	fHeader = (message_header *)malloc(sizeof(message_header));
1149 	if (!fHeader)
1150 		return B_NO_MEMORY;
1151 
1152 	fHeader->format = format;
1153 	uint8 *header = (uint8 *)fHeader;
1154 	ssize_t result = stream->Read(header + sizeof(uint32),
1155 		sizeof(message_header) - sizeof(uint32));
1156 	result -= sizeof(message_header) - sizeof(uint32);
1157 
1158 	if (result != B_OK || fHeader->format != kMessageMagicHaiku
1159 		|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
1160 		free(fHeader);
1161 		fHeader = NULL;
1162 		_InitHeader();
1163 		return B_BAD_VALUE;
1164 	}
1165 
1166 	fHeader->fields_available = 0;
1167 	fHeader->data_available = 0;
1168 	what = fHeader->what;
1169 
1170 	if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
1171 		result = _Reference(fHeader);
1172 		if (result < B_OK)
1173 			return result;
1174 	} else {
1175 		fHeader->shared_area = -1;
1176 
1177 		if (result == B_OK && fHeader->fields_size > 0) {
1178 			fFields = (field_header *)malloc(fHeader->fields_size);
1179 			if (!fFields)
1180 				return B_NO_MEMORY;
1181 
1182 			result = stream->Read(fFields, fHeader->fields_size);
1183 			result -= fHeader->fields_size;
1184 		}
1185 
1186 		if (result == B_OK && fHeader->data_size > 0) {
1187 			fData = (uint8 *)malloc(fHeader->data_size);
1188 			if (!fData)
1189 				return B_NO_MEMORY;
1190 
1191 			result = stream->Read(fData, fHeader->data_size);
1192 			result -= fHeader->data_size;
1193 		}
1194 
1195 		if (result < B_OK)
1196 			return B_BAD_VALUE;
1197 	}
1198 
1199 	/*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
1200 		|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
1201 		debug_printf("checksum mismatch 2\n");
1202 		_Clear();
1203 		_InitHeader();
1204 		return B_BAD_VALUE;
1205 	}*/
1206 
1207 	return B_OK;
1208 }
1209 
1210 
1211 status_t
1212 BMessage::AddSpecifier(const char *property)
1213 {
1214 	DEBUG_FUNCTION_ENTER;
1215 	BMessage message(B_DIRECT_SPECIFIER);
1216 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1217 	if (result < B_OK)
1218 		return result;
1219 
1220 	return AddSpecifier(&message);
1221 }
1222 
1223 
1224 status_t
1225 BMessage::AddSpecifier(const char *property, int32 index)
1226 {
1227 	DEBUG_FUNCTION_ENTER;
1228 	BMessage message(B_INDEX_SPECIFIER);
1229 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1230 	if (result < B_OK)
1231 		return result;
1232 
1233 	result = message.AddInt32("index", index);
1234 	if (result < B_OK)
1235 		return result;
1236 
1237 	return AddSpecifier(&message);
1238 }
1239 
1240 
1241 status_t
1242 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1243 {
1244 	DEBUG_FUNCTION_ENTER;
1245 	if (range < 0)
1246 		return B_BAD_VALUE;
1247 
1248 	BMessage message(B_RANGE_SPECIFIER);
1249 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1250 	if (result < B_OK)
1251 		return result;
1252 
1253 	result = message.AddInt32("index", index);
1254 	if (result < B_OK)
1255 		return result;
1256 
1257 	result = message.AddInt32("range", range);
1258 	if (result < B_OK)
1259 		return result;
1260 
1261 	return AddSpecifier(&message);
1262 }
1263 
1264 
1265 status_t
1266 BMessage::AddSpecifier(const char *property, const char *name)
1267 {
1268 	DEBUG_FUNCTION_ENTER;
1269 	BMessage message(B_NAME_SPECIFIER);
1270 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1271 	if (result < B_OK)
1272 		return result;
1273 
1274 	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1275 	if (result < B_OK)
1276 		return result;
1277 
1278 	return AddSpecifier(&message);
1279 }
1280 
1281 
1282 status_t
1283 BMessage::AddSpecifier(const BMessage *specifier)
1284 {
1285 	DEBUG_FUNCTION_ENTER;
1286 	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1287 	if (result < B_OK)
1288 		return result;
1289 
1290 	fHeader->current_specifier++;
1291 	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1292 	return B_OK;
1293 }
1294 
1295 
1296 status_t
1297 BMessage::SetCurrentSpecifier(int32 index)
1298 {
1299 	DEBUG_FUNCTION_ENTER;
1300 	if (index < 0)
1301 		return B_BAD_INDEX;
1302 
1303 	type_code type;
1304 	int32 count;
1305 	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1306 	if (result < B_OK)
1307 		return result;
1308 
1309 	if (index > count)
1310 		return B_BAD_INDEX;
1311 
1312 	fHeader->current_specifier = index;
1313 	return B_OK;
1314 }
1315 
1316 
1317 status_t
1318 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *what,
1319 	const char **property) const
1320 {
1321 	DEBUG_FUNCTION_ENTER;
1322 	if (fHeader->current_specifier < 0
1323 		|| !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
1324 		return B_BAD_SCRIPT_SYNTAX;
1325 
1326 	if (index)
1327 		*index = fHeader->current_specifier;
1328 
1329 	if (specifier) {
1330 		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1331 			specifier) < B_OK)
1332 			return B_BAD_SCRIPT_SYNTAX;
1333 
1334 		if (what)
1335 			*what = specifier->what;
1336 
1337 		if (property) {
1338 			if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1339 				return B_BAD_SCRIPT_SYNTAX;
1340 		}
1341 	}
1342 
1343 	return B_OK;
1344 }
1345 
1346 
1347 bool
1348 BMessage::HasSpecifiers() const
1349 {
1350 	DEBUG_FUNCTION_ENTER;
1351 	return fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS;
1352 }
1353 
1354 
1355 status_t
1356 BMessage::PopSpecifier()
1357 {
1358 	DEBUG_FUNCTION_ENTER;
1359 	if (fHeader->current_specifier < 0 ||
1360 		!(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
1361 		return B_BAD_VALUE;
1362 
1363 	if (fHeader->current_specifier >= 0)
1364 		fHeader->current_specifier--;
1365 
1366 	return B_OK;
1367 }
1368 
1369 
1370 status_t
1371 BMessage::_ResizeData(int32 offset, int32 change)
1372 {
1373 	if (change == 0)
1374 		return B_OK;
1375 
1376 	/* optimize for the most usual case: appending data */
1377 	if (offset < fHeader->data_size) {
1378 		field_header *field = fFields;
1379 		for (int32 i = 0; i < fHeader->field_count; i++, field++) {
1380 			if (field->offset >= offset)
1381 				field->offset += change;
1382 		}
1383 	}
1384 
1385 	if (change > 0) {
1386 		if (fHeader->data_available >= change) {
1387 			if (offset < fHeader->data_size) {
1388 				memmove(fData + offset + change, fData + offset,
1389 					fHeader->data_size - offset);
1390 			}
1391 
1392 			fHeader->data_available -= change;
1393 			fHeader->data_size += change;
1394 			return B_OK;
1395 		}
1396 
1397 		ssize_t size = fHeader->data_size * 2;
1398 		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1399 		size = max_c(size, fHeader->data_size + change);
1400 
1401 		fData = (uint8 *)realloc(fData, size);
1402 		if (!fData)
1403 			return B_NO_MEMORY;
1404 
1405 		if (offset < fHeader->data_size) {
1406 			memmove(fData + offset + change, fData + offset,
1407 				fHeader->data_size - offset);
1408 		}
1409 
1410 		fHeader->data_size += change;
1411 		fHeader->data_available = size - fHeader->data_size;
1412 	} else {
1413 		ssize_t length = fHeader->data_size - offset + change;
1414 		if (length > 0)
1415 			memmove(fData + offset, fData + offset - change, length);
1416 
1417 		fHeader->data_size += change;
1418 		fHeader->data_available -= change;
1419 
1420 		if (fHeader->data_available > MAX_DATA_PREALLOCATION) {
1421 			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1422 			fData = (uint8 *)realloc(fData, fHeader->data_size + available);
1423 			if (!fData)
1424 				return B_NO_MEMORY;
1425 
1426 			fHeader->data_available = available;
1427 		}
1428 	}
1429 
1430 	return B_OK;
1431 }
1432 
1433 
1434 uint32
1435 BMessage::_HashName(const char *name) const
1436 {
1437 	char ch;
1438 	uint32 result = 0;
1439 
1440 	while ((ch = *name++) != 0) {
1441 		result = (result << 7) ^ (result >> 24);
1442 		result ^= ch;
1443 	}
1444 
1445 	result ^= result << 12;
1446 	return result;
1447 }
1448 
1449 
1450 status_t
1451 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1452 {
1453 	if (!name)
1454 		return B_BAD_VALUE;
1455 
1456 	if (!fHeader || !fFields || !fData)
1457 		return B_NAME_NOT_FOUND;
1458 
1459 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1460 	int32 nextField = fHeader->hash_table[hash];
1461 
1462 	while (nextField >= 0) {
1463 		field_header *field = &fFields[nextField];
1464 
1465 		if (strncmp((const char *)(fData + field->offset), name,
1466 			field->name_length) == 0) {
1467 			if (type != B_ANY_TYPE && field->type != type)
1468 				return B_BAD_TYPE;
1469 
1470 			*result = field;
1471 			return B_OK;
1472 		}
1473 
1474 		nextField = field->next_field;
1475 	}
1476 
1477 	return B_NAME_NOT_FOUND;
1478 }
1479 
1480 
1481 status_t
1482 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1483 	field_header **result)
1484 {
1485 	if (!fHeader)
1486 		return B_ERROR;
1487 
1488 	if (fHeader->fields_available <= 0) {
1489 		int32 count = fHeader->field_count * 2 + 1;
1490 		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1491 
1492 		fFields = (field_header *)realloc(fFields, count * sizeof(field_header));
1493 		if (!fFields)
1494 			return B_NO_MEMORY;
1495 
1496 		fHeader->fields_available = count - fHeader->field_count;
1497 	}
1498 
1499 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1500 
1501 	int32 *nextField = &fHeader->hash_table[hash];
1502 	while (*nextField >= 0)
1503 		nextField = &fFields[*nextField].next_field;
1504 	*nextField = fHeader->field_count;
1505 
1506 	field_header *field = &fFields[fHeader->field_count];
1507 	field->type = type;
1508 	field->flags = FIELD_FLAG_VALID;
1509 	if (isFixedSize)
1510 		field->flags |= FIELD_FLAG_FIXED_SIZE;
1511 
1512 	field->count = 0;
1513 	field->data_size = 0;
1514 	field->allocated = 0;
1515 	field->next_field = -1;
1516 	field->offset = fHeader->data_size;
1517 	field->name_length = strlen(name) + 1;
1518 	_ResizeData(field->offset, field->name_length);
1519 	memcpy(fData + field->offset, name, field->name_length);
1520 
1521 	fHeader->fields_available--;
1522 	fHeader->fields_size += sizeof(field_header);
1523 	fHeader->field_count++;
1524 	*result = field;
1525 	return B_OK;
1526 }
1527 
1528 
1529 status_t
1530 BMessage::_RemoveField(field_header *field)
1531 {
1532 	int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1533 	int32 nextField = field->next_field;
1534 	if (nextField > index)
1535 		nextField--;
1536 
1537 	int32 *value = fHeader->hash_table;
1538 	for (int32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1539 		if (*value > index)
1540 			*value -= 1;
1541 		else if (*value == index)
1542 			*value = nextField;
1543 	}
1544 
1545 	field_header *other = fFields;
1546 	for (int32 i = 0; i < fHeader->field_count; i++, other++) {
1547 		if (other->next_field > index)
1548 			other->next_field--;
1549 		else if (other->next_field == index)
1550 			other->next_field = nextField;
1551 	}
1552 
1553 	_ResizeData(field->offset, -(field->data_size + field->name_length));
1554 
1555 	ssize_t size = fHeader->fields_size - (index + 1) * sizeof(field_header);
1556 	memmove(fFields + index, fFields + index + 1, size);
1557 	fHeader->fields_size -= sizeof(field_header);
1558 	fHeader->field_count--;
1559 	fHeader->fields_available++;
1560 
1561 	if (fHeader->fields_available > MAX_FIELD_PREALLOCATION) {
1562 		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1563 		fFields = (field_header *)realloc(fFields, fHeader->fields_size
1564 			+ available * sizeof(field_header));
1565 		if (!fFields)
1566 			return B_NO_MEMORY;
1567 
1568 		fHeader->fields_available = available;
1569 	}
1570 
1571 	return B_OK;
1572 }
1573 
1574 
1575 status_t
1576 BMessage::AddData(const char *name, type_code type, const void *data,
1577 	ssize_t numBytes, bool isFixedSize, int32 count)
1578 {
1579 	DEBUG_FUNCTION_ENTER;
1580 	if (numBytes <= 0 || !data)
1581 		return B_BAD_VALUE;
1582 
1583 	if (fClonedArea >= B_OK)
1584 		_CopyForWrite();
1585 
1586 	field_header *field = NULL;
1587 	status_t result = _FindField(name, type, &field);
1588 	if (result == B_NAME_NOT_FOUND)
1589 		result = _AddField(name, type, isFixedSize, &field);
1590 
1591 	if (result < B_OK || !field)
1592 		return result;
1593 
1594 	uint32 offset = field->offset + field->name_length + field->data_size;
1595 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1596 		if (field->count) {
1597 			ssize_t size = field->data_size / field->count;
1598 			if (size != numBytes)
1599 				return B_BAD_VALUE;
1600 		}
1601 
1602 		_ResizeData(offset, numBytes);
1603 		memcpy(fData + offset, data, numBytes);
1604 		field->data_size += numBytes;
1605 	} else {
1606 		int32 change = numBytes + sizeof(numBytes);
1607 		_ResizeData(offset, change);
1608 		memcpy(fData + offset, &numBytes, sizeof(numBytes));
1609 		memcpy(fData + offset + sizeof(numBytes), data, numBytes);
1610 		field->data_size += change;
1611 	}
1612 
1613 	field->count++;
1614 	return B_OK;
1615 }
1616 
1617 
1618 status_t
1619 BMessage::RemoveData(const char *name, int32 index)
1620 {
1621 	DEBUG_FUNCTION_ENTER;
1622 	if (index < 0)
1623 		return B_BAD_VALUE;
1624 
1625 	if (fClonedArea >= B_OK)
1626 		_CopyForWrite();
1627 
1628 	field_header *field = NULL;
1629 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1630 
1631 	if (result < B_OK)
1632 		return result;
1633 
1634 	if (!field)
1635 		return B_ERROR;
1636 
1637 	if (index >= field->count)
1638 		return B_BAD_INDEX;
1639 
1640 	if (field->count == 1)
1641 		return _RemoveField(field);
1642 
1643 	uint32 offset = field->offset + field->name_length;
1644 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1645 		ssize_t size = field->data_size / field->count;
1646 		_ResizeData(offset + index * size, -size);
1647 		field->data_size -= size;
1648 	} else {
1649 		uint8 *pointer = fData + offset;
1650 
1651 		for (int32 i = 0; i < index; i++) {
1652 			offset += *(ssize_t *)pointer + sizeof(ssize_t);
1653 			pointer = fData + offset;
1654 		}
1655 
1656 		ssize_t currentSize = *(ssize_t *)pointer + sizeof(ssize_t);
1657 		_ResizeData(offset, -currentSize);
1658 		field->data_size -= currentSize;
1659 	}
1660 
1661 	field->count--;
1662 	return B_OK;
1663 }
1664 
1665 
1666 status_t
1667 BMessage::RemoveName(const char *name)
1668 {
1669 	DEBUG_FUNCTION_ENTER;
1670 	if (fClonedArea >= B_OK)
1671 		_CopyForWrite();
1672 
1673 	field_header *field = NULL;
1674 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1675 
1676 	if (result < B_OK)
1677 		return result;
1678 
1679 	if (!field)
1680 		return B_ERROR;
1681 
1682 	return _RemoveField(field);
1683 }
1684 
1685 
1686 status_t
1687 BMessage::MakeEmpty()
1688 {
1689 	DEBUG_FUNCTION_ENTER;
1690 	_Clear();
1691 	_InitHeader();
1692 	return B_OK;
1693 }
1694 
1695 
1696 status_t
1697 BMessage::FindData(const char *name, type_code type, int32 index,
1698 	const void **data, ssize_t *numBytes) const
1699 {
1700 	DEBUG_FUNCTION_ENTER;
1701 	if (!data || !numBytes)
1702 		return B_BAD_VALUE;
1703 
1704 	*data = NULL;
1705 	field_header *field = NULL;
1706 	status_t result = _FindField(name, type, &field);
1707 
1708 	if (result < B_OK)
1709 		return result;
1710 
1711 	if (!field)
1712 		return B_ERROR;
1713 
1714 	if (index >= field->count)
1715 		return B_BAD_INDEX;
1716 
1717 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1718 		*numBytes = field->data_size / field->count;
1719 		*data = fData + field->offset + field->name_length + index * *numBytes;
1720 	} else {
1721 		uint8 *pointer = fData + field->offset + field->name_length;
1722 
1723 		for (int32 i = 0; i < index; i++)
1724 			pointer += *(ssize_t *)pointer + sizeof(ssize_t);
1725 
1726 		*numBytes = *(ssize_t *)pointer;
1727 		*data = pointer + sizeof(ssize_t);
1728 	}
1729 
1730 	return B_OK;
1731 }
1732 
1733 
1734 status_t
1735 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1736 	const void *data, ssize_t numBytes)
1737 {
1738 	DEBUG_FUNCTION_ENTER;
1739 	if (numBytes <= 0 || !data)
1740 		return B_BAD_VALUE;
1741 
1742 	if (fClonedArea >= B_OK)
1743 		_CopyForWrite();
1744 
1745 	field_header *field = NULL;
1746 	status_t result = _FindField(name, type, &field);
1747 
1748 	if (result < B_OK)
1749 		return result;
1750 
1751 	if (!field)
1752 		return B_ERROR;
1753 
1754 	if (index >= field->count)
1755 		return B_BAD_INDEX;
1756 
1757 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1758 		ssize_t size = field->data_size / field->count;
1759 		if (size != numBytes)
1760 			return B_BAD_VALUE;
1761 
1762 		memcpy(fData + field->offset + field->name_length + index * size, data,
1763 			size);
1764 	} else {
1765 		uint32 offset = field->offset + field->name_length;
1766 		uint8 *pointer = fData + offset;
1767 
1768 		for (int32 i = 0; i < index; i++) {
1769 			offset += *(ssize_t *)pointer + sizeof(ssize_t);
1770 			pointer = fData + offset;
1771 		}
1772 
1773 		ssize_t currentSize = *(ssize_t *)pointer;
1774 		int32 change = numBytes - currentSize;
1775 		_ResizeData(offset, change);
1776 		memcpy(fData + offset, &numBytes, sizeof(numBytes));
1777 		memcpy(fData + offset + sizeof(numBytes), data, numBytes);
1778 		field->data_size += change;
1779 	}
1780 
1781 	return B_OK;
1782 }
1783 
1784 
1785 bool
1786 BMessage::HasData(const char *name, type_code type, int32 index) const
1787 {
1788 	DEBUG_FUNCTION_ENTER;
1789 	field_header *field = NULL;
1790 	status_t result = _FindField(name, type, &field);
1791 
1792 	if (result < B_OK)
1793 		return false;
1794 
1795 	if (!field)
1796 		return false;
1797 
1798 	if (index >= field->count)
1799 		return false;
1800 
1801 	return true;
1802 }
1803 
1804 
1805 /* Static functions for cache initialization and cleanup */
1806 void
1807 BMessage::_StaticInit()
1808 {
1809 	DEBUG_FUNCTION_ENTER2;
1810 	sReplyPorts[0] = create_port(1, "tmp_rport0");
1811 	sReplyPorts[1] = create_port(1, "tmp_rport1");
1812 	sReplyPorts[2] = create_port(1, "tmp_rport2");
1813 
1814 	sReplyPortInUse[0] = 0;
1815 	sReplyPortInUse[1] = 0;
1816 	sReplyPortInUse[2] = 0;
1817 
1818 	sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
1819 }
1820 
1821 
1822 void
1823 BMessage::_StaticCleanup()
1824 {
1825 	DEBUG_FUNCTION_ENTER2;
1826 	delete_port(sReplyPorts[0]);
1827 	sReplyPorts[0] = -1;
1828 	delete_port(sReplyPorts[1]);
1829 	sReplyPorts[1] = -1;
1830 	delete_port(sReplyPorts[2]);
1831 	sReplyPorts[2] = -1;
1832 }
1833 
1834 
1835 void
1836 BMessage::_StaticCacheCleanup()
1837 {
1838 	DEBUG_FUNCTION_ENTER2;
1839 	delete sMsgCache;
1840 	sMsgCache = NULL;
1841 }
1842 
1843 
1844 int32
1845 BMessage::_StaticGetCachedReplyPort()
1846 {
1847 	DEBUG_FUNCTION_ENTER2;
1848 	int index = -1;
1849 	for (int32 i = 0; i < sNumReplyPorts; i++) {
1850 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
1851 		if (old == 0) {
1852 			// This entry is free
1853 			index = i;
1854 			break;
1855 		} else {
1856 			// This entry is being used.
1857 			atomic_add(&(sReplyPortInUse[i]), -1);
1858 		}
1859 	}
1860 
1861 	return index;
1862 }
1863 
1864 
1865 status_t
1866 BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
1867 	bool replyRequired, BMessenger &replyTo) const
1868 {
1869 	DEBUG_FUNCTION_ENTER;
1870 	ssize_t size = 0;
1871 	char *buffer = NULL;
1872 	message_header *header = NULL;
1873 	status_t result;
1874 
1875 	if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
1876 		result = _FlattenToArea(&header);
1877 		buffer = (char *)header;
1878 		size = sizeof(message_header);
1879 
1880 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
1881 		port_info info;
1882 		get_port_info(port, &info);
1883 		void *address = NULL;
1884 		_kern_transfer_area(header->shared_area, &address, B_ANY_ADDRESS,
1885 			info.team);
1886 #endif
1887 	} else {
1888 		size = _NativeFlattenedSize();
1889 		buffer = (char *)malloc(size);
1890 		result = _NativeFlatten(buffer, size);
1891 		header = (message_header *)buffer;
1892 	}
1893 
1894 	if (result < B_OK)
1895 		return result;
1896 
1897 	if (!replyTo.IsValid()) {
1898 		BMessenger::Private(replyTo).SetTo(header->reply_team,
1899 			header->reply_port, header->reply_target);
1900 
1901 		if (!replyTo.IsValid())
1902 			replyTo = be_app_messenger;
1903 	}
1904 
1905 	BMessenger::Private replyToPrivate(replyTo);
1906 
1907 	if (replyRequired)
1908 		header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
1909 	else
1910 		header->flags &= ~MESSAGE_FLAG_REPLY_REQUIRED;
1911 
1912 	header->target = token;
1913 	header->reply_team = replyToPrivate.Team();
1914 	header->reply_port = replyToPrivate.Port();
1915 	header->reply_target = replyToPrivate.Token();
1916 	header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
1917 
1918 	do {
1919 		result = write_port_etc(port, kPortMessageCode, (void *)buffer, size,
1920 			B_RELATIVE_TIMEOUT, timeout);
1921 	} while (result == B_INTERRUPTED);
1922 
1923 	if (result == B_OK && IsSourceWaiting()) {
1924 		// the forwarded message will handle the reply - we must not do
1925 		// this anymore
1926 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
1927 	}
1928 
1929 	free(buffer);
1930 	return result;
1931 }
1932 
1933 
1934 status_t
1935 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
1936 	BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
1937 {
1938 	if (IsSourceWaiting()) {
1939 		// we can't forward this message synchronously when it's already
1940 		// waiting for a reply
1941 		return B_ERROR;
1942 	}
1943 
1944 	DEBUG_FUNCTION_ENTER;
1945 	const int32 cachedReplyPort = _StaticGetCachedReplyPort();
1946 	port_id replyPort = B_BAD_PORT_ID;
1947 	status_t result = B_OK;
1948 
1949 	if (cachedReplyPort < B_OK) {
1950 		// All the cached reply ports are in use; create a new one
1951 		replyPort = create_port(1 /* for one message */, "tmp_reply_port");
1952 		if (replyPort < B_OK)
1953 			return replyPort;
1954 	} else {
1955 		assert(cachedReplyPort < sNumReplyPorts);
1956 		replyPort = sReplyPorts[cachedReplyPort];
1957 	}
1958 
1959 	team_id team = B_BAD_TEAM_ID;
1960 	if (be_app != NULL)
1961 		team = be_app->Team();
1962 	else {
1963 		port_info portInfo;
1964 		result = get_port_info(replyPort, &portInfo);
1965 		if (result < B_OK)
1966 			goto error;
1967 
1968 		team = portInfo.team;
1969 	}
1970 
1971 	result = set_port_owner(replyPort, portOwner);
1972 	if (result < B_OK)
1973 		goto error;
1974 
1975 	// tests if the queue of the reply port is really empty
1976 #if 0
1977 	port_info portInfo;
1978 	if (get_port_info(replyPort, &portInfo) == B_OK
1979 		&& portInfo.queue_count > 0)
1980 		debugger("reply port not empty!");
1981 #endif
1982 
1983 	{
1984 		BMessenger replyTarget;
1985 		BMessenger::Private(replyTarget).SetTo(team, replyPort,
1986 			B_PREFERRED_TOKEN);
1987 		result = _SendMessage(port, token, sendTimeout, true, replyTarget);
1988 	}
1989 
1990 	if (result < B_OK)
1991 		goto error;
1992 
1993 	int32 code;
1994 	result = handle_reply(replyPort, &code, replyTimeout, reply);
1995 	if (result < B_OK && cachedReplyPort >= 0) {
1996 		delete_port(replyPort);
1997 		sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
1998 	}
1999 
2000 error:
2001 	if (cachedReplyPort >= 0) {
2002 		// Reclaim ownership of cached port
2003 		set_port_owner(replyPort, team);
2004 		// Flag as available
2005 		atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2006 		return result;
2007 	}
2008 
2009 	delete_port(replyPort);
2010 	return result;
2011 }
2012 
2013 
2014 status_t
2015 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
2016 	int32 token, bigtime_t timeout)
2017 {
2018 	DEBUG_FUNCTION_ENTER2;
2019 	if (!data)
2020 		return B_BAD_VALUE;
2021 
2022 	uint32 magic = *(uint32 *)data;
2023 
2024 	if (magic == kMessageMagicHaiku || magic == kMessageMagicHaikuSwapped) {
2025 		message_header *header = (message_header *)data;
2026 		header->target = token;
2027 		header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2028 	} else if (magic == kMessageMagicR5) {
2029 		uint8 *header = (uint8 *)data;
2030 		header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2031 			+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2032 			+ sizeof(uint8) /* flags */;
2033 		*(int32 *)header = token;
2034 	} else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) {
2035 		KMessage::Header *header = (KMessage::Header *)data;
2036 		header->targetToken = token;
2037 	} else {
2038 		return B_NOT_A_MESSAGE;
2039 	}
2040 
2041 	// send the message
2042 	status_t result;
2043 
2044 	do {
2045 		result = write_port_etc(port, kPortMessageCode, data, size,
2046 			B_RELATIVE_TIMEOUT, timeout);
2047 	} while (result == B_INTERRUPTED);
2048 
2049 	return result;
2050 }
2051 
2052 
2053 static status_t
2054 handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout,
2055 	BMessage *reply)
2056 {
2057 	DEBUG_FUNCTION_ENTER2;
2058 	ssize_t size;
2059 	do {
2060 		size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
2061 	} while (size == B_INTERRUPTED);
2062 
2063 	if (size < B_OK)
2064 		return size;
2065 
2066 	status_t result;
2067 	char *buffer = (char *)malloc(size);
2068 	do {
2069 		result = read_port(replyPort, _code, buffer, size);
2070 	} while (result == B_INTERRUPTED);
2071 
2072 	if (result < B_OK || *_code != kPortMessageCode) {
2073 		free(buffer);
2074 		return result < B_OK ? result : B_ERROR;
2075 	}
2076 
2077 	result = reply->Unflatten(buffer);
2078 	free(buffer);
2079 	return result;
2080 }
2081 
2082 
2083 static status_t
2084 convert_message(const KMessage *fromMessage, BMessage *toMessage)
2085 {
2086 	DEBUG_FUNCTION_ENTER2;
2087 	if (!fromMessage || !toMessage)
2088 		return B_BAD_VALUE;
2089 
2090 	// make empty and init what of the target message
2091 	toMessage->MakeEmpty();
2092 	toMessage->what = fromMessage->What();
2093 
2094 	BMessage::Private toPrivate(toMessage);
2095 	toPrivate.SetTarget(fromMessage->TargetToken());
2096 	toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(),
2097 		fromMessage->ReplyToken());
2098 
2099 	// iterate through the fields and import them in the target message
2100 	KMessageField field;
2101 	while (fromMessage->GetNextField(&field) == B_OK) {
2102 		int32 elementCount = field.CountElements();
2103 		if (elementCount > 0) {
2104 			for (int32 i = 0; i < elementCount; i++) {
2105 				int32 size;
2106 				const void *data = field.ElementAt(i, &size);
2107 				status_t result;
2108 
2109 				if (field.TypeCode() == B_MESSAGE_TYPE) {
2110 					// message type: if it's a KMessage, convert it
2111 					KMessage message;
2112 					if (message.SetTo(data, size) == B_OK) {
2113 						BMessage bMessage;
2114 						result = convert_message(&message, &bMessage);
2115 						if (result < B_OK)
2116 							return result;
2117 
2118 						result = toMessage->AddMessage(field.Name(), &bMessage);
2119 					} else {
2120 						// just add it
2121 						result = toMessage->AddData(field.Name(),
2122 							field.TypeCode(), data, size,
2123 							field.HasFixedElementSize(), 1);
2124 					}
2125 				} else {
2126 					result = toMessage->AddData(field.Name(), field.TypeCode(),
2127 						data, size, field.HasFixedElementSize(), 1);
2128 				}
2129 
2130 				if (result < B_OK)
2131 					return result;
2132 			}
2133 		}
2134 	}
2135 
2136 	return B_OK;
2137 }
2138 
2139 
2140 void BMessage::_ReservedMessage1(void) {};
2141 void BMessage::_ReservedMessage2(void) {};
2142 void BMessage::_ReservedMessage3(void) {};
2143 
2144 
2145 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2146 
2147 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
2148 status_t																	\
2149 BMessage::Add##typeName(const char *name, type val)							\
2150 {																			\
2151 	return AddData(name, typeCode, &val, sizeof(type), true);				\
2152 }																			\
2153 																			\
2154 status_t																	\
2155 BMessage::Find##typeName(const char *name, type *p) const					\
2156 {																			\
2157 	void *ptr = NULL;														\
2158 	ssize_t bytes = 0;														\
2159 	status_t error = B_OK;													\
2160 																			\
2161 	*p = type();															\
2162 	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
2163 																			\
2164 	if (error == B_OK)														\
2165 		memcpy(p, ptr, sizeof(type));										\
2166 																			\
2167 	return error;															\
2168 }																			\
2169 																			\
2170 status_t																	\
2171 BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
2172 {																			\
2173 	void *ptr = NULL;														\
2174 	ssize_t bytes = 0;														\
2175 	status_t error = B_OK;													\
2176 																			\
2177 	*p = type();															\
2178 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
2179 																			\
2180 	if (error == B_OK)														\
2181 		memcpy(p, ptr, sizeof(type));										\
2182 																			\
2183 	return error;															\
2184 }																			\
2185 																			\
2186 status_t																	\
2187 BMessage::Replace##typeName(const char *name, type val)						\
2188 {																			\
2189 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
2190 }																			\
2191 																			\
2192 status_t																	\
2193 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
2194 {																			\
2195 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
2196 }																			\
2197 																			\
2198 bool																		\
2199 BMessage::Has##typeName(const char *name, int32 index) const				\
2200 {																			\
2201 	return HasData(name, typeCode, index);									\
2202 }
2203 
2204 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2205 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2206 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2207 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2208 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2209 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2210 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2211 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2212 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2213 
2214 #undef DEFINE_FUNCTIONS
2215 
2216 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2217 bool																		\
2218 BMessage::Has##typeName(const char *name, int32 index) const				\
2219 {																			\
2220 	return HasData(name, typeCode, index);									\
2221 }
2222 
2223 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2224 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2225 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2226 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2227 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2228 
2229 #undef DEFINE_HAS_FUNCTION
2230 
2231 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2232 type																		\
2233 BMessage::Find##typeName(const char *name, int32 index) const				\
2234 {																			\
2235 	type val = initialize;													\
2236 	Find##typeName(name, index, &val);										\
2237 	return val;																\
2238 }
2239 
2240 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2241 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2242 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
2243 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2244 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2245 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2246 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2247 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2248 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2249 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2250 
2251 #undef DEFINE_LAZY_FIND_FUNCTION
2252 
2253 status_t
2254 BMessage::AddString(const char *name, const char *string)
2255 {
2256 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
2257 }
2258 
2259 
2260 status_t
2261 BMessage::AddString(const char *name, const BString &string)
2262 {
2263 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
2264 }
2265 
2266 
2267 status_t
2268 BMessage::AddPointer(const char *name, const void *pointer)
2269 {
2270 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2271 }
2272 
2273 
2274 status_t
2275 BMessage::AddMessenger(const char *name, BMessenger messenger)
2276 {
2277 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2278 }
2279 
2280 
2281 status_t
2282 BMessage::AddRef(const char *name, const entry_ref *ref)
2283 {
2284 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2285 	char buffer[size];
2286 
2287 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2288 
2289 	if (error >= B_OK)
2290 		error = AddData(name, B_REF_TYPE, buffer, size, false);
2291 
2292 	return error;
2293 }
2294 
2295 
2296 status_t
2297 BMessage::AddMessage(const char *name, const BMessage *message)
2298 {
2299 	/* ToDo: This and the following functions waste time by allocating and
2300 	copying an extra buffer. Functions can be added that return a direct
2301 	pointer into the message. */
2302 
2303 	ssize_t size = message->FlattenedSize();
2304 	char buffer[size];
2305 
2306 	status_t error = message->Flatten(buffer, size);
2307 
2308 	if (error >= B_OK)
2309 		error = AddData(name, B_MESSAGE_TYPE, &buffer, size, false);
2310 
2311 	return error;
2312 }
2313 
2314 
2315 status_t
2316 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
2317 {
2318 	ssize_t size = object->FlattenedSize();
2319 	char buffer[size];
2320 
2321 	status_t error = object->Flatten(buffer, size);
2322 
2323 	if (error >= B_OK)
2324 		error = AddData(name, object->TypeCode(), &buffer, size, false);
2325 
2326 	return error;
2327 }
2328 
2329 
2330 status_t
2331 BMessage::FindString(const char *name, const char **string) const
2332 {
2333 	return FindString(name, 0, string);
2334 }
2335 
2336 
2337 status_t
2338 BMessage::FindString(const char *name, int32 index, const char **string) const
2339 {
2340 	ssize_t bytes;
2341 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
2342 }
2343 
2344 
2345 status_t
2346 BMessage::FindString(const char *name, BString *string) const
2347 {
2348 	return FindString(name, 0, string);
2349 }
2350 
2351 
2352 status_t
2353 BMessage::FindString(const char *name, int32 index, BString *string) const
2354 {
2355 	const char *cstr;
2356 	status_t error = FindString(name, index, &cstr);
2357 	if (error < B_OK)
2358 		return error;
2359 
2360 	*string = cstr;
2361 	return B_OK;
2362 }
2363 
2364 
2365 status_t
2366 BMessage::FindPointer(const char *name, void **pointer) const
2367 {
2368 	return FindPointer(name, 0, pointer);
2369 }
2370 
2371 
2372 status_t
2373 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
2374 {
2375 	void **data = NULL;
2376 	ssize_t size = 0;
2377 	status_t error = FindData(name, B_POINTER_TYPE, index,
2378 		(const void **)&data, &size);
2379 
2380 	if (error == B_OK)
2381 		*pointer = *data;
2382 	else
2383 		*pointer = NULL;
2384 
2385 	return error;
2386 }
2387 
2388 
2389 status_t
2390 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
2391 {
2392 	return FindMessenger(name, 0, messenger);
2393 }
2394 
2395 
2396 status_t
2397 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
2398 	const
2399 {
2400 	void *data = NULL;
2401 	ssize_t size = 0;
2402 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2403 		(const void **)&data, &size);
2404 
2405 	if (error == B_OK)
2406 		memcpy(messenger, data, sizeof(BMessenger));
2407 	else
2408 		*messenger = BMessenger();
2409 
2410 	return error;
2411 }
2412 
2413 
2414 status_t
2415 BMessage::FindRef(const char *name, entry_ref *ref) const
2416 {
2417 	return FindRef(name, 0, ref);
2418 }
2419 
2420 
2421 status_t
2422 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
2423 {
2424 	void *data = NULL;
2425 	ssize_t size = 0;
2426 	status_t error = FindData(name, B_REF_TYPE, index,
2427 		(const void **)&data, &size);
2428 
2429 	if (error == B_OK)
2430 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
2431 	else
2432 		*ref = entry_ref();
2433 
2434 	return error;
2435 }
2436 
2437 
2438 status_t
2439 BMessage::FindMessage(const char *name, BMessage *message) const
2440 {
2441 	return FindMessage(name, 0, message);
2442 }
2443 
2444 
2445 status_t
2446 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2447 {
2448 	void *data = NULL;
2449 	ssize_t size = 0;
2450 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
2451 		(const void **)&data, &size);
2452 
2453 	if (error == B_OK)
2454 		error = message->Unflatten((const char *)data);
2455 	else
2456 		*message = BMessage();
2457 
2458 	return error;
2459 }
2460 
2461 
2462 status_t
2463 BMessage::FindFlat(const char *name, BFlattenable *object) const
2464 {
2465 	return FindFlat(name, 0, object);
2466 }
2467 
2468 
2469 status_t
2470 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2471 {
2472 	void *data = NULL;
2473 	ssize_t numBytes = 0;
2474 	status_t error = FindData(name, object->TypeCode(), index,
2475 		(const void **)&data, &numBytes);
2476 
2477 	if (error == B_OK)
2478 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2479 
2480 	return error;
2481 }
2482 
2483 
2484 status_t
2485 BMessage::FindData(const char *name, type_code type, const void **data,
2486 	ssize_t *numBytes) const
2487 {
2488 	return FindData(name, type, 0, data, numBytes);
2489 }
2490 
2491 
2492 status_t
2493 BMessage::ReplaceString(const char *name, const char *string)
2494 {
2495 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2496 }
2497 
2498 
2499 status_t
2500 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2501 {
2502 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2503 }
2504 
2505 
2506 status_t
2507 BMessage::ReplaceString(const char *name, const BString &string)
2508 {
2509 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2510 		string.Length() + 1);
2511 }
2512 
2513 
2514 status_t
2515 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2516 {
2517 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2518 		string.Length() + 1);
2519 }
2520 
2521 
2522 status_t
2523 BMessage::ReplacePointer(const char *name, const void *pointer)
2524 {
2525 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2526 }
2527 
2528 
2529 status_t
2530 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2531 {
2532 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2533 }
2534 
2535 
2536 status_t
2537 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2538 {
2539 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2540 		sizeof(BMessenger));
2541 }
2542 
2543 
2544 status_t
2545 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2546 {
2547 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2548 		sizeof(BMessenger));
2549 }
2550 
2551 
2552 status_t
2553 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2554 {
2555 	return ReplaceRef(name, 0, ref);
2556 }
2557 
2558 
2559 status_t
2560 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2561 {
2562 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2563 	char buffer[size];
2564 
2565 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2566 
2567 	if (error >= B_OK)
2568 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2569 
2570 	return error;
2571 }
2572 
2573 
2574 status_t
2575 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2576 {
2577 	return ReplaceMessage(name, 0, message);
2578 }
2579 
2580 
2581 status_t
2582 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2583 {
2584 	ssize_t size = message->FlattenedSize();
2585 	char buffer[size];
2586 
2587 	status_t error = message->Flatten(buffer, size);
2588 
2589 	if (error >= B_OK)
2590 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2591 
2592 	return error;
2593 }
2594 
2595 
2596 status_t
2597 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2598 {
2599 	return ReplaceFlat(name, 0, object);
2600 }
2601 
2602 
2603 status_t
2604 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2605 {
2606 	ssize_t size = object->FlattenedSize();
2607 	char buffer[size];
2608 
2609 	status_t error = object->Flatten(buffer, size);
2610 
2611 	if (error >= B_OK)
2612 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2613 
2614 	return error;
2615 }
2616 
2617 
2618 status_t
2619 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2620 	ssize_t numBytes)
2621 {
2622 	return ReplaceData(name, type, 0, data, numBytes);
2623 }
2624 
2625 
2626 bool
2627 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2628 {
2629 	return HasFlat(name, 0, object);
2630 }
2631 
2632 
2633 bool
2634 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2635 	const
2636 {
2637 	return HasData(name, object->TypeCode(), index);
2638 }
2639