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