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