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