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