xref: /haiku/src/build/libbe/app/Message.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2005-2011, 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 <MessengerPrivate.h>
16 #include <TokenSpace.h>
17 
18 #include <Application.h>
19 #include <AppMisc.h>
20 #include <BlockCache.h>
21 #include <Entry.h>
22 #include <MessageQueue.h>
23 #include <Messenger.h>
24 #include <Path.h>
25 #include <Point.h>
26 #include <Rect.h>
27 #include <String.h>
28 #include <StringList.h>
29 
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "tracing_config.h"
37 	// kernel tracing configuration
38 
39 //#define VERBOSE_DEBUG_OUTPUT
40 #ifdef VERBOSE_DEBUG_OUTPUT
41 #define DEBUG_FUNCTION_ENTER	\
42 	debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
43 		" data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
44 		find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \
45 		__LINE__, __PRETTY_FUNCTION__);
46 
47 #define DEBUG_FUNCTION_ENTER2	\
48 	debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
49 		__LINE__, __PRETTY_FUNCTION__);
50 #else
51 #define DEBUG_FUNCTION_ENTER	/* nothing */
52 #define DEBUG_FUNCTION_ENTER2	/* nothing */
53 #endif
54 
55 #if BMESSAGE_TRACING
56 #	define KTRACE(format...)	ktrace_printf(format)
57 #else
58 #	define KTRACE(format...)
59 #endif
60 
61 
62 const char *B_SPECIFIER_ENTRY = "specifiers";
63 const char *B_PROPERTY_ENTRY = "property";
64 const char *B_PROPERTY_NAME_ENTRY = "name";
65 
66 extern "C" {
67 	// private os function to set the owning team of an area
68 	status_t _kern_transfer_area(area_id area, void **_address,
69 		uint32 addressSpec, team_id target);
70 }
71 
72 
73 BBlockCache *BMessage::sMsgCache = NULL;
74 
75 
76 template<typename Type>
77 static void
78 print_to_stream_type(uint8 *pointer)
79 {
80 	Type *item = (Type *)pointer;
81 	item->PrintToStream();
82 }
83 
84 
85 template<typename Type>
86 static void
87 print_type(const char *format, uint8 *pointer)
88 {
89 	Type *item = (Type *)pointer;
90 	printf(format, *item, *item);
91 }
92 
93 
94 //	#pragma mark -
95 
96 
97 BMessage::BMessage()
98 {
99 	DEBUG_FUNCTION_ENTER;
100 	_InitCommon(true);
101 }
102 
103 
104 BMessage::BMessage(BMessage *other)
105 {
106 	DEBUG_FUNCTION_ENTER;
107 	_InitCommon(false);
108 	*this = *other;
109 }
110 
111 
112 BMessage::BMessage(uint32 _what)
113 {
114 	DEBUG_FUNCTION_ENTER;
115 	_InitCommon(true);
116 	fHeader->what = what = _what;
117 }
118 
119 
120 BMessage::BMessage(const BMessage &other)
121 {
122 	DEBUG_FUNCTION_ENTER;
123 	_InitCommon(false);
124 	*this = other;
125 }
126 
127 
128 BMessage::~BMessage()
129 {
130 	DEBUG_FUNCTION_ENTER;
131 	_Clear();
132 }
133 
134 
135 BMessage &
136 BMessage::operator=(const BMessage &other)
137 {
138 	DEBUG_FUNCTION_ENTER;
139 
140 	if (this == &other)
141 		return *this;
142 
143 	_Clear();
144 
145 	fHeader = (message_header *)malloc(sizeof(message_header));
146 	if (fHeader == NULL)
147 		return *this;
148 
149 	memcpy(fHeader, other.fHeader, sizeof(message_header));
150 
151 	// Clear some header flags inherited from the original message that don't
152 	// apply to the clone.
153 	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
154 		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
155 		| MESSAGE_FLAG_PASS_BY_AREA);
156 	// Note, that BeOS R5 seems to keep the reply info.
157 
158 	if (fHeader->field_count > 0) {
159 		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
160 		fFields = (field_header *)malloc(fieldsSize);
161 		if (fFields == NULL) {
162 			fHeader->field_count = 0;
163 			fHeader->data_size = 0;
164 		} else
165 			memcpy(fFields, other.fFields, fieldsSize);
166 	}
167 
168 	if (fHeader->data_size > 0) {
169 		fData = (uint8 *)malloc(fHeader->data_size);
170 		if (fData == NULL) {
171 			fHeader->field_count = 0;
172 			free(fFields);
173 			fFields = NULL;
174 		} else
175 			memcpy(fData, other.fData, fHeader->data_size);
176 	}
177 
178 	fHeader->what = what = other.what;
179 	fHeader->message_area = -1;
180 	fFieldsAvailable = 0;
181 	fDataAvailable = 0;
182 
183 	return *this;
184 }
185 
186 
187 void *
188 BMessage::operator new(size_t size)
189 {
190 	DEBUG_FUNCTION_ENTER2;
191 	if (!sMsgCache)
192 		sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE);
193 	void *pointer = sMsgCache->Get(size);
194 	return pointer;
195 }
196 
197 
198 void *
199 BMessage::operator new(size_t, void *pointer)
200 {
201 	DEBUG_FUNCTION_ENTER2;
202 	return pointer;
203 }
204 
205 
206 void
207 BMessage::operator delete(void *pointer, size_t size)
208 {
209 	DEBUG_FUNCTION_ENTER2;
210 	sMsgCache->Save(pointer, size);
211 }
212 
213 
214 bool
215 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
216 	bool deep) const
217 {
218 	if (this == &other)
219 		return true;
220 
221 	if (fHeader->field_count != other.fHeader->field_count)
222 		return false;
223 
224 	for (uint32 i = 0; i < fHeader->field_count; i++) {
225 		field_header *field = &fFields[i];
226 		field_header *otherField = NULL;
227 
228 		const char *name = (const char *)fData + field->offset;
229 		if (ignoreFieldOrder) {
230 			if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
231 				return false;
232 		} else {
233 			otherField = &other.fFields[i];
234 			if (otherField->name_length != field->name_length)
235 				return false;
236 
237 			const char *otherName = (const char *)other.fData
238 				+ otherField->offset;
239 			if (strncmp(name, otherName, field->name_length) != 0)
240 				return false;
241 		}
242 
243 		if (otherField->type != field->type || otherField->count != field->count)
244 			return false;
245 
246 		uint8 *data = fData + field->offset + field->name_length;
247 		uint8 *otherData = other.fData + otherField->offset
248 			+ otherField->name_length;
249 
250 		bool needsMemCompare = true;
251 		if (deep && field->type == B_MESSAGE_TYPE) {
252 			BMessage message, otherMessage;
253 			if (message.Unflatten((const char *)data) == B_OK
254 				&& otherMessage.Unflatten((const char *)otherData) == B_OK) {
255 				if (!message.HasSameData(ignoreFieldOrder, deep))
256 					return false;
257 				needsMemCompare = false;
258 			}
259 		}
260 
261 		if (needsMemCompare) {
262 			if (otherField->data_size != field->data_size)
263 				return false;
264 			if (memcmp(data, otherData, field->data_size) != 0)
265 				return false;
266 		}
267 	}
268 
269 	return true;
270 }
271 
272 
273 status_t
274 BMessage::_InitCommon(bool initHeader)
275 {
276 	DEBUG_FUNCTION_ENTER;
277 	what = 0;
278 
279 	fHeader = NULL;
280 	fFields = NULL;
281 	fData = NULL;
282 
283 	fFieldsAvailable = 0;
284 	fDataAvailable = 0;
285 
286 	fOriginal = NULL;
287 	fQueueLink = NULL;
288 
289 	if (initHeader)
290 		return _InitHeader();
291 
292 	fHeader = NULL;
293 	return B_OK;
294 }
295 
296 
297 status_t
298 BMessage::_InitHeader()
299 {
300 	DEBUG_FUNCTION_ENTER;
301 	if (fHeader == NULL) {
302 		fHeader = (message_header *)malloc(sizeof(message_header));
303 		if (fHeader == NULL)
304 			return B_NO_MEMORY;
305 	}
306 
307 	memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
308 
309 	fHeader->format = MESSAGE_FORMAT_HAIKU;
310 	fHeader->flags = MESSAGE_FLAG_VALID;
311 	fHeader->what = what;
312 	fHeader->current_specifier = -1;
313 	fHeader->message_area = -1;
314 
315 	fHeader->target = B_NULL_TOKEN;
316 	fHeader->reply_target = B_NULL_TOKEN;
317 	fHeader->reply_port = -1;
318 	fHeader->reply_team = -1;
319 
320 	// initializing the hash table to -1 because 0 is a valid index
321 	fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
322 	memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
323 	return B_OK;
324 }
325 
326 
327 status_t
328 BMessage::_Clear()
329 {
330 	DEBUG_FUNCTION_ENTER;
331 	if (fHeader != NULL) {
332 		free(fHeader);
333 		fHeader = NULL;
334 	}
335 
336 	free(fFields);
337 	fFields = NULL;
338 	free(fData);
339 	fData = NULL;
340 
341 	fFieldsAvailable = 0;
342 	fDataAvailable = 0;
343 
344 	delete fOriginal;
345 	fOriginal = NULL;
346 
347 	return B_OK;
348 }
349 
350 
351 status_t
352 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound,
353 	type_code *typeFound, int32 *countFound) const
354 {
355 	DEBUG_FUNCTION_ENTER;
356 	if (index < 0 || (uint32)index >= fHeader->field_count)
357 		return B_BAD_INDEX;
358 
359 	if (typeRequested == B_ANY_TYPE) {
360 		if (nameFound)
361 			*nameFound = (char *)fData + fFields[index].offset;
362 		if (typeFound)
363 			*typeFound = fFields[index].type;
364 		if (countFound)
365 			*countFound = fFields[index].count;
366 		return B_OK;
367 	}
368 
369 	int32 counter = -1;
370 	field_header *field = fFields;
371 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
372 		if (field->type == typeRequested)
373 			counter++;
374 
375 		if (counter == index) {
376 			if (nameFound)
377 				*nameFound = (char *)fData + field->offset;
378 			if (typeFound)
379 				*typeFound = field->type;
380 			if (countFound)
381 				*countFound = field->count;
382 			return B_OK;
383 		}
384 	}
385 
386 	if (counter == -1)
387 		return B_BAD_TYPE;
388 
389 	return B_BAD_INDEX;
390 }
391 
392 
393 status_t
394 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound)
395 	const
396 {
397 	DEBUG_FUNCTION_ENTER;
398 	if (countFound)
399 		*countFound = 0;
400 
401 	field_header *field = NULL;
402 	status_t result = _FindField(name, B_ANY_TYPE, &field);
403 	if (result < B_OK || field == NULL)
404 		return result;
405 
406 	if (typeFound)
407 		*typeFound = field->type;
408 	if (countFound)
409 		*countFound = field->count;
410 
411 	return B_OK;
412 }
413 
414 
415 status_t
416 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize)
417 	const
418 {
419 	DEBUG_FUNCTION_ENTER;
420 	field_header *field = NULL;
421 	status_t result = _FindField(name, B_ANY_TYPE, &field);
422 	if (result < B_OK || field == NULL)
423 		return result;
424 
425 	if (typeFound)
426 		*typeFound = field->type;
427 	if (fixedSize)
428 		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
429 
430 	return B_OK;
431 }
432 
433 
434 int32
435 BMessage::CountNames(type_code type) const
436 {
437 	DEBUG_FUNCTION_ENTER;
438 	if (type == B_ANY_TYPE)
439 		return fHeader->field_count;
440 
441 	int32 count = 0;
442 	field_header *field = fFields;
443 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
444 		if (field->type == type)
445 			count++;
446 	}
447 
448 	return count;
449 }
450 
451 
452 bool
453 BMessage::IsEmpty() const
454 {
455 	DEBUG_FUNCTION_ENTER;
456 	return fHeader->field_count == 0;
457 }
458 
459 
460 bool
461 BMessage::IsSystem() const
462 {
463 	DEBUG_FUNCTION_ENTER;
464 	char a = char(what >> 24);
465 	char b = char(what >> 16);
466 	char c = char(what >> 8);
467 	char d = char(what);
468 
469 	// The BeBook says:
470 	//		... we've adopted a strict convention for assigning values to all
471 	//		Be-defined constants.  The value assigned will always be formed by
472 	//		combining four characters into a multicharacter constant, with the
473 	//		characters limited to uppercase letters and the underbar
474 	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
475 	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
476 		return true;
477 
478 	return false;
479 }
480 
481 
482 bool
483 BMessage::IsReply() const
484 {
485 	DEBUG_FUNCTION_ENTER;
486 	return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
487 }
488 
489 
490 void
491 BMessage::PrintToStream() const
492 {
493 	_PrintToStream("");
494 	printf("}\n");
495 }
496 
497 
498 void
499 BMessage::_PrintToStream(const char* indent) const
500 {
501 	DEBUG_FUNCTION_ENTER;
502 
503 	int32 value = B_BENDIAN_TO_HOST_INT32(what);
504 	printf("BMessage(");
505 	if (isprint(*(char *)&value))
506 		printf("'%.4s'", (char *)&value);
507 	else
508 		printf("0x%" B_PRIx32, what);
509 	printf(") {\n");
510 
511 	if (fHeader == NULL || fFields == NULL || fData == NULL)
512 		return;
513 
514 	field_header *field = fFields;
515 	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
516 		value = B_BENDIAN_TO_HOST_INT32(field->type);
517 		ssize_t size = 0;
518 		if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
519 			size = field->data_size / field->count;
520 
521 		uint8 *pointer = fData + field->offset + field->name_length;
522 		for (uint32 j = 0; j < field->count; j++) {
523 			if (field->count == 1) {
524 				printf("%s        %s = ", indent,
525 					(char *)(fData + field->offset));
526 			} else {
527 				printf("%s        %s[%" B_PRIu32 "] = ", indent,
528 					(char *)(fData + field->offset), j);
529 			}
530 
531 			switch (field->type) {
532 				case B_RECT_TYPE:
533 					print_to_stream_type<BRect>(pointer);
534 					break;
535 
536 				case B_POINT_TYPE:
537 					print_to_stream_type<BPoint>(pointer);
538 					break;
539 
540 				case B_STRING_TYPE:
541 				{
542 					size = *(uint32 *)pointer;
543 					pointer += sizeof(uint32);
544 					printf("string(\"%s\", %ld bytes)\n", (char *)pointer,
545 						(long)size);
546 					break;
547 				}
548 
549 				case B_INT8_TYPE:
550 					print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
551 					break;
552 
553 				case B_UINT8_TYPE:
554 					print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n",
555 						pointer);
556 					break;
557 
558 				case B_INT16_TYPE:
559 					print_type<int16>("int16(0x%x or %d)\n", pointer);
560 					break;
561 
562 				case B_UINT16_TYPE:
563 					print_type<uint16>("uint16(0x%x or %u\n", pointer);
564 					break;
565 
566 				case B_INT32_TYPE:
567 					print_type<int32>("int32(0x%lx or %ld)\n", pointer);
568 					break;
569 
570 				case B_UINT32_TYPE:
571 					print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
572 					break;
573 
574 				case B_INT64_TYPE:
575 					print_type<int64>("int64(0x%Lx or %lld)\n", pointer);
576 					break;
577 
578 				case B_UINT64_TYPE:
579 					print_type<uint64>("uint64(0x%Lx or %lld\n", pointer);
580 					break;
581 
582 				case B_BOOL_TYPE:
583 					printf("bool(%s)\n", *((bool *)pointer) != 0
584 						? "true" : "false");
585 					break;
586 
587 				case B_FLOAT_TYPE:
588 					print_type<float>("float(%.4f)\n", pointer);
589 					break;
590 
591 				case B_DOUBLE_TYPE:
592 					print_type<double>("double(%.8f)\n", pointer);
593 					break;
594 
595 				case B_REF_TYPE:
596 				{
597 					size = *(uint32 *)pointer;
598 					pointer += sizeof(uint32);
599 					entry_ref ref;
600 					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
601 
602 					printf("entry_ref(device=%d, directory=%lld"
603 						", name=\"%s\", ", (int)ref.device,
604 						(long long)ref.directory, ref.name);
605 
606 					BPath path(&ref);
607 					printf("path=\"%s\")\n", path.Path());
608 					break;
609 				}
610 
611 				case B_MESSAGE_TYPE:
612 				{
613 					char buffer[1024];
614 					sprintf(buffer, "%s        ", indent);
615 
616 					BMessage message;
617 					size = *(uint32 *)pointer;
618 					pointer += sizeof(uint32);
619 					status_t result = message.Unflatten((const char *)pointer);
620 					if (result != B_OK) {
621 						printf("failed unflatten: %s\n", strerror(result));
622 						break;
623 					}
624 
625 					message._PrintToStream(buffer);
626 					printf("%s        }\n", indent);
627 					break;
628 				}
629 
630 				default:
631 				{
632 					printf("(type = '%.4s')(size = %ld)\n", (char *)&value,
633 						(long)size);
634 					break;
635 				}
636 			}
637 
638 			pointer += size;
639 		}
640 	}
641 }
642 
643 
644 status_t
645 BMessage::Rename(const char *oldEntry, const char *newEntry)
646 {
647 	DEBUG_FUNCTION_ENTER;
648 	if (oldEntry == NULL || newEntry == NULL)
649 		return B_BAD_VALUE;
650 
651 	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
652 	int32 *nextField = &fHeader->hash_table[hash];
653 
654 	while (*nextField >= 0) {
655 		field_header *field = &fFields[*nextField];
656 
657 		if (strncmp((const char *)(fData + field->offset), oldEntry,
658 			field->name_length) == 0) {
659 			// nextField points to the field for oldEntry, save it and unlink
660 			int32 index = *nextField;
661 			*nextField = field->next_field;
662 			field->next_field = -1;
663 
664 			hash = _HashName(newEntry) % fHeader->hash_table_size;
665 			nextField = &fHeader->hash_table[hash];
666 			while (*nextField >= 0)
667 				nextField = &fFields[*nextField].next_field;
668 			*nextField = index;
669 
670 			int32 newLength = strlen(newEntry) + 1;
671 			status_t result = _ResizeData(field->offset + 1,
672 				newLength - field->name_length);
673 			if (result < B_OK)
674 				return result;
675 
676 			memcpy(fData + field->offset, newEntry, newLength);
677 			field->name_length = newLength;
678 			return B_OK;
679 		}
680 
681 		nextField = &field->next_field;
682 	}
683 
684 	return B_NAME_NOT_FOUND;
685 }
686 
687 
688 bool
689 BMessage::WasDelivered() const
690 {
691 	DEBUG_FUNCTION_ENTER;
692 	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
693 }
694 
695 
696 bool
697 BMessage::IsSourceWaiting() const
698 {
699 	DEBUG_FUNCTION_ENTER;
700 	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
701 		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
702 }
703 
704 
705 BMessenger
706 BMessage::ReturnAddress() const
707 {
708 	DEBUG_FUNCTION_ENTER;
709 	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
710 		BMessenger messenger;
711 		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
712 			fHeader->reply_port, fHeader->reply_target);
713 		return messenger;
714 	}
715 
716 	return BMessenger();
717 }
718 
719 
720 const BMessage *
721 BMessage::Previous() const
722 {
723 	DEBUG_FUNCTION_ENTER;
724 	/* ToDo: test if the "_previous_" field is used in R5 */
725 	if (fOriginal == NULL) {
726 		fOriginal = new BMessage();
727 
728 		if (FindMessage("_previous_", fOriginal) != B_OK) {
729 			delete fOriginal;
730 			fOriginal = NULL;
731 		}
732 	}
733 
734 	return fOriginal;
735 }
736 
737 
738 bool
739 BMessage::WasDropped() const
740 {
741 	DEBUG_FUNCTION_ENTER;
742 	return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
743 }
744 
745 
746 BPoint
747 BMessage::DropPoint(BPoint *offset) const
748 {
749 	DEBUG_FUNCTION_ENTER;
750 	if (offset)
751 		*offset = FindPoint("_drop_offset_");
752 
753 	return FindPoint("_drop_point_");
754 }
755 
756 
757 ssize_t
758 BMessage::FlattenedSize() const
759 {
760 	DEBUG_FUNCTION_ENTER;
761 	return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
762 		+ fHeader->data_size;
763 }
764 
765 
766 status_t
767 BMessage::Flatten(char *buffer, ssize_t size) const
768 {
769 	DEBUG_FUNCTION_ENTER;
770 	if (buffer == NULL || size < 0)
771 		return B_BAD_VALUE;
772 
773 	if (fHeader == NULL)
774 		return B_NO_INIT;
775 
776 	/* we have to sync the what code as it is a public member */
777 	fHeader->what = what;
778 
779 	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
780 	buffer += sizeof(message_header);
781 	size -= sizeof(message_header);
782 
783 	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
784 	memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
785 	buffer += fieldsSize;
786 	size -= fieldsSize;
787 
788 	memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
789 	if ((size_t)size < fHeader->data_size)
790 		return B_BUFFER_OVERFLOW;
791 
792 	return B_OK;
793 }
794 
795 
796 status_t
797 BMessage::Flatten(BDataIO *stream, ssize_t *size) const
798 {
799 	DEBUG_FUNCTION_ENTER;
800 	if (stream == NULL)
801 		return B_BAD_VALUE;
802 
803 	if (fHeader == NULL)
804 		return B_NO_INIT;
805 
806 	/* we have to sync the what code as it is a public member */
807 	fHeader->what = what;
808 
809 	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
810 	if (result1 != sizeof(message_header))
811 		return result1 < 0 ? result1 : B_ERROR;
812 
813 	ssize_t result2 = 0;
814 	if (fHeader->field_count > 0) {
815 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
816 		result2 = stream->Write(fFields, fieldsSize);
817 		if (result2 != fieldsSize)
818 			return result2 < 0 ? result2 : B_ERROR;
819 	}
820 
821 	ssize_t result3 = 0;
822 	if (fHeader->data_size > 0) {
823 		result3 = stream->Write(fData, fHeader->data_size);
824 		if (result3 != (ssize_t)fHeader->data_size)
825 			return result3 < 0 ? result3 : B_ERROR;
826 	}
827 
828 	if (size)
829 		*size = result1 + result2 + result3;
830 
831 	return B_OK;
832 }
833 
834 
835 status_t
836 BMessage::_ValidateMessage()
837 {
838 	if (fHeader->field_count == 0)
839 		return B_OK;
840 
841 	if (fFields == NULL)
842 		return B_NO_INIT;
843 
844 	for (uint32 i = 0; i < fHeader->field_count; i++) {
845 		field_header *field = &fFields[i];
846 		if ((field->next_field >= 0
847 				&& (uint32)field->next_field > fHeader->field_count)
848 			|| (field->offset + field->name_length + field->data_size
849 				> fHeader->data_size)) {
850 			// the message is corrupt
851 			MakeEmpty();
852 			return B_BAD_VALUE;
853 		}
854 	}
855 
856 	return B_OK;
857 }
858 
859 
860 status_t
861 BMessage::Unflatten(const char *flatBuffer)
862 {
863 	DEBUG_FUNCTION_ENTER;
864 	if (flatBuffer == NULL)
865 		return B_BAD_VALUE;
866 
867 	uint32 format = *(uint32 *)flatBuffer;
868 	if (format != MESSAGE_FORMAT_HAIKU)
869 		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
870 
871 	// native message unflattening
872 
873 	_Clear();
874 
875 	fHeader = (message_header *)malloc(sizeof(message_header));
876 	if (fHeader == NULL)
877 		return B_NO_MEMORY;
878 
879 	memcpy(fHeader, flatBuffer, sizeof(message_header));
880 	flatBuffer += sizeof(message_header);
881 
882 	if (fHeader->format != MESSAGE_FORMAT_HAIKU
883 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
884 		_InitHeader();
885 		return B_BAD_VALUE;
886 	}
887 
888 	what = fHeader->what;
889 
890 	if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
891 		&& fHeader->message_area >= 0) {
892 //		status_t result = _Reference();
893 //		if (result != B_OK)
894 //			return result;
895 	} else {
896 		fHeader->message_area = -1;
897 
898 		if (fHeader->field_count > 0) {
899 			size_t fieldsSize = fHeader->field_count * sizeof(field_header);
900 			fFields = (field_header *)malloc(fieldsSize);
901 			if (fFields == NULL) {
902 				_InitHeader();
903 				return B_NO_MEMORY;
904 			}
905 
906 			memcpy(fFields, flatBuffer, fieldsSize);
907 			flatBuffer += fieldsSize;
908 		}
909 
910 		if (fHeader->data_size > 0) {
911 			fData = (uint8 *)malloc(fHeader->data_size);
912 			if (fData == NULL) {
913 				free(fFields);
914 				fFields = NULL;
915 				_InitHeader();
916 				return B_NO_MEMORY;
917 			}
918 
919 			memcpy(fData, flatBuffer, fHeader->data_size);
920 		}
921 	}
922 
923 	return _ValidateMessage();
924 }
925 
926 
927 status_t
928 BMessage::Unflatten(BDataIO *stream)
929 {
930 	DEBUG_FUNCTION_ENTER;
931 	if (stream == NULL)
932 		return B_BAD_VALUE;
933 
934 	uint32 format = 0;
935 	stream->Read(&format, sizeof(uint32));
936 	if (format != MESSAGE_FORMAT_HAIKU)
937 		return BPrivate::MessageAdapter::Unflatten(format, this, stream);
938 
939 	// native message unflattening
940 
941 	_Clear();
942 
943 	fHeader = (message_header *)malloc(sizeof(message_header));
944 	if (fHeader == NULL)
945 		return B_NO_MEMORY;
946 
947 	fHeader->format = format;
948 	uint8 *header = (uint8 *)fHeader;
949 	ssize_t result = stream->Read(header + sizeof(uint32),
950 		sizeof(message_header) - sizeof(uint32));
951 	if (result != sizeof(message_header) - sizeof(uint32)
952 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
953 		_InitHeader();
954 		return result < 0 ? result : B_BAD_VALUE;
955 	}
956 
957 	what = fHeader->what;
958 
959 	fHeader->message_area = -1;
960 
961 	if (fHeader->field_count > 0) {
962 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
963 		fFields = (field_header *)malloc(fieldsSize);
964 		if (fFields == NULL) {
965 			_InitHeader();
966 			return B_NO_MEMORY;
967 		}
968 
969 		result = stream->Read(fFields, fieldsSize);
970 		if (result != fieldsSize)
971 			return result < 0 ? result : B_BAD_VALUE;
972 	}
973 
974 	if (fHeader->data_size > 0) {
975 		fData = (uint8 *)malloc(fHeader->data_size);
976 		if (fData == NULL) {
977 			free(fFields);
978 			fFields = NULL;
979 			_InitHeader();
980 			return B_NO_MEMORY;
981 		}
982 
983 		result = stream->Read(fData, fHeader->data_size);
984 		if (result != (ssize_t)fHeader->data_size)
985 			return result < 0 ? result : B_BAD_VALUE;
986 	}
987 
988 	return _ValidateMessage();
989 }
990 
991 
992 status_t
993 BMessage::AddSpecifier(const char *property)
994 {
995 	DEBUG_FUNCTION_ENTER;
996 	BMessage message(B_DIRECT_SPECIFIER);
997 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
998 	if (result < B_OK)
999 		return result;
1000 
1001 	return AddSpecifier(&message);
1002 }
1003 
1004 
1005 status_t
1006 BMessage::AddSpecifier(const char *property, int32 index)
1007 {
1008 	DEBUG_FUNCTION_ENTER;
1009 	BMessage message(B_INDEX_SPECIFIER);
1010 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1011 	if (result < B_OK)
1012 		return result;
1013 
1014 	result = message.AddInt32("index", index);
1015 	if (result < B_OK)
1016 		return result;
1017 
1018 	return AddSpecifier(&message);
1019 }
1020 
1021 
1022 status_t
1023 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1024 {
1025 	DEBUG_FUNCTION_ENTER;
1026 	if (range < 0)
1027 		return B_BAD_VALUE;
1028 
1029 	BMessage message(B_RANGE_SPECIFIER);
1030 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1031 	if (result < B_OK)
1032 		return result;
1033 
1034 	result = message.AddInt32("index", index);
1035 	if (result < B_OK)
1036 		return result;
1037 
1038 	result = message.AddInt32("range", range);
1039 	if (result < B_OK)
1040 		return result;
1041 
1042 	return AddSpecifier(&message);
1043 }
1044 
1045 
1046 status_t
1047 BMessage::AddSpecifier(const char *property, const char *name)
1048 {
1049 	DEBUG_FUNCTION_ENTER;
1050 	BMessage message(B_NAME_SPECIFIER);
1051 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1052 	if (result < B_OK)
1053 		return result;
1054 
1055 	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1056 	if (result < B_OK)
1057 		return result;
1058 
1059 	return AddSpecifier(&message);
1060 }
1061 
1062 
1063 status_t
1064 BMessage::AddSpecifier(const BMessage *specifier)
1065 {
1066 	DEBUG_FUNCTION_ENTER;
1067 	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1068 	if (result < B_OK)
1069 		return result;
1070 
1071 	fHeader->current_specifier++;
1072 	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1073 	return B_OK;
1074 }
1075 
1076 
1077 status_t
1078 BMessage::SetCurrentSpecifier(int32 index)
1079 {
1080 	DEBUG_FUNCTION_ENTER;
1081 	if (index < 0)
1082 		return B_BAD_INDEX;
1083 
1084 	type_code type;
1085 	int32 count;
1086 	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1087 	if (result < B_OK)
1088 		return result;
1089 
1090 	if (index > count)
1091 		return B_BAD_INDEX;
1092 
1093 	fHeader->current_specifier = index;
1094 	return B_OK;
1095 }
1096 
1097 
1098 status_t
1099 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what,
1100 	const char **property) const
1101 {
1102 	DEBUG_FUNCTION_ENTER;
1103 
1104 	if (index != NULL)
1105 		*index = fHeader->current_specifier;
1106 
1107 	if (fHeader->current_specifier < 0
1108 		|| (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1109 		return B_BAD_SCRIPT_SYNTAX;
1110 
1111 	if (specifier) {
1112 		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1113 			specifier) < B_OK)
1114 			return B_BAD_SCRIPT_SYNTAX;
1115 
1116 		if (_what != NULL)
1117 			*_what = specifier->what;
1118 
1119 		if (property) {
1120 			if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1121 				return B_BAD_SCRIPT_SYNTAX;
1122 		}
1123 	}
1124 
1125 	return B_OK;
1126 }
1127 
1128 
1129 bool
1130 BMessage::HasSpecifiers() const
1131 {
1132 	DEBUG_FUNCTION_ENTER;
1133 	return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1134 }
1135 
1136 
1137 status_t
1138 BMessage::PopSpecifier()
1139 {
1140 	DEBUG_FUNCTION_ENTER;
1141 	if (fHeader->current_specifier < 0 ||
1142 		(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1143 		return B_BAD_VALUE;
1144 
1145 	if (fHeader->current_specifier >= 0)
1146 		fHeader->current_specifier--;
1147 
1148 	return B_OK;
1149 }
1150 
1151 
1152 status_t
1153 BMessage::_ResizeData(uint32 offset, int32 change)
1154 {
1155 	if (change == 0)
1156 		return B_OK;
1157 
1158 	/* optimize for the most usual case: appending data */
1159 	if (offset < fHeader->data_size) {
1160 		field_header *field = fFields;
1161 		for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1162 			if (field->offset >= offset)
1163 				field->offset += change;
1164 		}
1165 	}
1166 
1167 	if (change > 0) {
1168 		if (fDataAvailable >= (uint32)change) {
1169 			if (offset < fHeader->data_size) {
1170 				memmove(fData + offset + change, fData + offset,
1171 					fHeader->data_size - offset);
1172 			}
1173 
1174 			fDataAvailable -= change;
1175 			fHeader->data_size += change;
1176 			return B_OK;
1177 		}
1178 
1179 		size_t size = fHeader->data_size * 2;
1180 		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1181 		size = max_c(size, fHeader->data_size + change);
1182 
1183 		uint8 *newData = (uint8 *)realloc(fData, size);
1184 		if (size > 0 && newData == NULL)
1185 			return B_NO_MEMORY;
1186 
1187 		fData = newData;
1188 		if (offset < fHeader->data_size) {
1189 			memmove(fData + offset + change, fData + offset,
1190 				fHeader->data_size - offset);
1191 		}
1192 
1193 		fHeader->data_size += change;
1194 		fDataAvailable = size - fHeader->data_size;
1195 	} else {
1196 		ssize_t length = fHeader->data_size - offset + change;
1197 		if (length > 0)
1198 			memmove(fData + offset, fData + offset - change, length);
1199 
1200 		// change is negative
1201 		fHeader->data_size += change;
1202 		fDataAvailable -= change;
1203 
1204 		if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1205 			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1206 			ssize_t size = fHeader->data_size + available;
1207 			uint8 *newData = (uint8 *)realloc(fData, size);
1208 			if (size > 0 && newData == NULL) {
1209 				// this is strange, but not really fatal
1210 				return B_OK;
1211 			}
1212 
1213 			fData = newData;
1214 			fDataAvailable = available;
1215 		}
1216 	}
1217 
1218 	return B_OK;
1219 }
1220 
1221 
1222 uint32
1223 BMessage::_HashName(const char *name) const
1224 {
1225 	char ch;
1226 	uint32 result = 0;
1227 
1228 	while ((ch = *name++) != 0) {
1229 		result = (result << 7) ^ (result >> 24);
1230 		result ^= ch;
1231 	}
1232 
1233 	result ^= result << 12;
1234 	return result;
1235 }
1236 
1237 
1238 status_t
1239 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1240 {
1241 	if (name == NULL)
1242 		return B_BAD_VALUE;
1243 
1244 	if (fHeader == NULL || fFields == NULL || fData == NULL)
1245 		return B_NAME_NOT_FOUND;
1246 
1247 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1248 	int32 nextField = fHeader->hash_table[hash];
1249 
1250 	while (nextField >= 0) {
1251 		field_header *field = &fFields[nextField];
1252 		if ((field->flags & FIELD_FLAG_VALID) == 0)
1253 			break;
1254 
1255 		if (strncmp((const char *)(fData + field->offset), name,
1256 			field->name_length) == 0) {
1257 			if (type != B_ANY_TYPE && field->type != type)
1258 				return B_BAD_TYPE;
1259 
1260 			*result = field;
1261 			return B_OK;
1262 		}
1263 
1264 		nextField = field->next_field;
1265 	}
1266 
1267 	return B_NAME_NOT_FOUND;
1268 }
1269 
1270 
1271 status_t
1272 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1273 	field_header **result)
1274 {
1275 	if (fHeader == NULL)
1276 		return B_ERROR;
1277 
1278 	if (fFieldsAvailable <= 0) {
1279 		uint32 count = fHeader->field_count * 2 + 1;
1280 		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1281 
1282 		field_header *newFields = (field_header *)realloc(fFields,
1283 			count * sizeof(field_header));
1284 		if (count > 0 && newFields == NULL)
1285 			return B_NO_MEMORY;
1286 
1287 		fFields = newFields;
1288 		fFieldsAvailable = count - fHeader->field_count;
1289 	}
1290 
1291 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1292 	int32 *nextField = &fHeader->hash_table[hash];
1293 	while (*nextField >= 0)
1294 		nextField = &fFields[*nextField].next_field;
1295 	*nextField = fHeader->field_count;
1296 
1297 	field_header *field = &fFields[fHeader->field_count];
1298 	field->type = type;
1299 	field->count = 0;
1300 	field->data_size = 0;
1301 	field->next_field = -1;
1302 	field->offset = fHeader->data_size;
1303 	field->name_length = strlen(name) + 1;
1304 	status_t status = _ResizeData(field->offset, field->name_length);
1305 	if (status < B_OK)
1306 		return status;
1307 
1308 	memcpy(fData + field->offset, name, field->name_length);
1309 	field->flags = FIELD_FLAG_VALID;
1310 	if (isFixedSize)
1311 		field->flags |= FIELD_FLAG_FIXED_SIZE;
1312 
1313 	fFieldsAvailable--;
1314 	fHeader->field_count++;
1315 	*result = field;
1316 	return B_OK;
1317 }
1318 
1319 
1320 status_t
1321 BMessage::_RemoveField(field_header *field)
1322 {
1323 	status_t result = _ResizeData(field->offset, -(field->data_size
1324 		+ field->name_length));
1325 	if (result < B_OK)
1326 		return result;
1327 
1328 	int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1329 	int32 nextField = field->next_field;
1330 	if (nextField > index)
1331 		nextField--;
1332 
1333 	int32 *value = fHeader->hash_table;
1334 	for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1335 		if (*value > index)
1336 			*value -= 1;
1337 		else if (*value == index)
1338 			*value = nextField;
1339 	}
1340 
1341 	field_header *other = fFields;
1342 	for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1343 		if (other->next_field > index)
1344 			other->next_field--;
1345 		else if (other->next_field == index)
1346 			other->next_field = nextField;
1347 	}
1348 
1349 	size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1350 	memmove(fFields + index, fFields + index + 1, size);
1351 	fHeader->field_count--;
1352 	fFieldsAvailable++;
1353 
1354 	if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1355 		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1356 		size = (fHeader->field_count + available) * sizeof(field_header);
1357 		field_header *newFields = (field_header *)realloc(fFields, size);
1358 		if (size > 0 && newFields == NULL) {
1359 			// this is strange, but not really fatal
1360 			return B_OK;
1361 		}
1362 
1363 		fFields = newFields;
1364 		fFieldsAvailable = available;
1365 	}
1366 
1367 	return B_OK;
1368 }
1369 
1370 
1371 status_t
1372 BMessage::AddData(const char *name, type_code type, const void *data,
1373 	ssize_t numBytes, bool isFixedSize, int32 count)
1374 {
1375 	// Note that the "count" argument is only a hint at how many items
1376 	// the caller expects to add to this field. Since we do no item pre-
1377 	// allocation, we ignore this argument.
1378 	DEBUG_FUNCTION_ENTER;
1379 	if (numBytes <= 0 || data == NULL)
1380 		return B_BAD_VALUE;
1381 
1382 	field_header *field = NULL;
1383 	status_t result = _FindField(name, type, &field);
1384 	if (result == B_NAME_NOT_FOUND)
1385 		result = _AddField(name, type, isFixedSize, &field);
1386 
1387 	if (result < B_OK)
1388 		return result;
1389 
1390 	if (field == NULL)
1391 		return B_ERROR;
1392 
1393 	uint32 offset = field->offset + field->name_length + field->data_size;
1394 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1395 		if (field->count) {
1396 			ssize_t size = field->data_size / field->count;
1397 			if (size != numBytes)
1398 				return B_BAD_VALUE;
1399 		}
1400 
1401 		result = _ResizeData(offset, numBytes);
1402 		if (result < B_OK) {
1403 			if (field->count == 0)
1404 				_RemoveField(field);
1405 			return result;
1406 		}
1407 
1408 		memcpy(fData + offset, data, numBytes);
1409 		field->data_size += numBytes;
1410 	} else {
1411 		int32 change = numBytes + sizeof(uint32);
1412 		result = _ResizeData(offset, change);
1413 		if (result < B_OK) {
1414 			if (field->count == 0)
1415 				_RemoveField(field);
1416 			return result;
1417 		}
1418 
1419 		uint32 size = (uint32)numBytes;
1420 		memcpy(fData + offset, &size, sizeof(uint32));
1421 		memcpy(fData + offset + sizeof(uint32), data, size);
1422 		field->data_size += change;
1423 	}
1424 
1425 	field->count++;
1426 	return B_OK;
1427 }
1428 
1429 
1430 status_t
1431 BMessage::RemoveData(const char *name, int32 index)
1432 {
1433 	DEBUG_FUNCTION_ENTER;
1434 	if (index < 0)
1435 		return B_BAD_INDEX;
1436 
1437 	field_header *field = NULL;
1438 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1439 
1440 	if (result < B_OK)
1441 		return result;
1442 
1443 	if (field == NULL)
1444 		return B_ERROR;
1445 
1446 	if ((uint32)index >= field->count)
1447 		return B_BAD_INDEX;
1448 
1449 	if (field->count == 1)
1450 		return _RemoveField(field);
1451 
1452 	uint32 offset = field->offset + field->name_length;
1453 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1454 		ssize_t size = field->data_size / field->count;
1455 		result = _ResizeData(offset + index * size, -size);
1456 		if (result < B_OK)
1457 			return result;
1458 
1459 		field->data_size -= size;
1460 	} else {
1461 		uint8 *pointer = fData + offset;
1462 		for (int32 i = 0; i < index; i++) {
1463 			offset += *(uint32 *)pointer + sizeof(uint32);
1464 			pointer = fData + offset;
1465 		}
1466 
1467 		size_t currentSize = *(uint32 *)pointer + sizeof(uint32);
1468 		result = _ResizeData(offset, -currentSize);
1469 		if (result < B_OK)
1470 			return result;
1471 
1472 		field->data_size -= currentSize;
1473 	}
1474 
1475 	field->count--;
1476 	return B_OK;
1477 }
1478 
1479 
1480 status_t
1481 BMessage::RemoveName(const char *name)
1482 {
1483 	DEBUG_FUNCTION_ENTER;
1484 	field_header *field = NULL;
1485 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1486 
1487 	if (result < B_OK)
1488 		return result;
1489 
1490 	if (field == NULL)
1491 		return B_ERROR;
1492 
1493 	return _RemoveField(field);
1494 }
1495 
1496 
1497 status_t
1498 BMessage::MakeEmpty()
1499 {
1500 	DEBUG_FUNCTION_ENTER;
1501 	_Clear();
1502 	_InitHeader();
1503 	return B_OK;
1504 }
1505 
1506 
1507 status_t
1508 BMessage::FindData(const char *name, type_code type, int32 index,
1509 	const void **data, ssize_t *numBytes) const
1510 {
1511 	DEBUG_FUNCTION_ENTER;
1512 	if (data == NULL)
1513 		return B_BAD_VALUE;
1514 
1515 	*data = NULL;
1516 	field_header *field = NULL;
1517 	status_t result = _FindField(name, type, &field);
1518 
1519 	if (result < B_OK)
1520 		return result;
1521 
1522 	if (field == NULL)
1523 		return B_ERROR;
1524 
1525 	if (index < 0 || (uint32)index >= field->count)
1526 		return B_BAD_INDEX;
1527 
1528 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1529 		size_t bytes = field->data_size / field->count;
1530 		*data = fData + field->offset + field->name_length + index * bytes;
1531 		if (numBytes != NULL)
1532 			*numBytes = bytes;
1533 	} else {
1534 		uint8 *pointer = fData + field->offset + field->name_length;
1535 		for (int32 i = 0; i < index; i++)
1536 			pointer += *(uint32 *)pointer + sizeof(uint32);
1537 
1538 		*data = pointer + sizeof(uint32);
1539 		if (numBytes != NULL)
1540 			*numBytes = *(uint32 *)pointer;
1541 	}
1542 
1543 	return B_OK;
1544 }
1545 
1546 
1547 status_t
1548 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1549 	const void *data, ssize_t numBytes)
1550 {
1551 	DEBUG_FUNCTION_ENTER;
1552 	if (numBytes <= 0 || data == NULL)
1553 		return B_BAD_VALUE;
1554 
1555 	field_header *field = NULL;
1556 	status_t result = _FindField(name, type, &field);
1557 
1558 	if (result < B_OK)
1559 		return result;
1560 
1561 	if (field == NULL)
1562 		return B_ERROR;
1563 
1564 	if (index < 0 || (uint32)index >= field->count)
1565 		return B_BAD_INDEX;
1566 
1567 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1568 		ssize_t size = field->data_size / field->count;
1569 		if (size != numBytes)
1570 			return B_BAD_VALUE;
1571 
1572 		memcpy(fData + field->offset + field->name_length + index * size, data,
1573 			size);
1574 	} else {
1575 		uint32 offset = field->offset + field->name_length;
1576 		uint8 *pointer = fData + offset;
1577 
1578 		for (int32 i = 0; i < index; i++) {
1579 			offset += *(uint32 *)pointer + sizeof(uint32);
1580 			pointer = fData + offset;
1581 		}
1582 
1583 		size_t currentSize = *(uint32 *)pointer;
1584 		int32 change = numBytes - currentSize;
1585 		result = _ResizeData(offset, change);
1586 		if (result < B_OK)
1587 			return result;
1588 
1589 		uint32 newSize = (uint32)numBytes;
1590 		memcpy(fData + offset, &newSize, sizeof(uint32));
1591 		memcpy(fData + offset + sizeof(uint32), data, newSize);
1592 		field->data_size += change;
1593 	}
1594 
1595 	return B_OK;
1596 }
1597 
1598 
1599 bool
1600 BMessage::HasData(const char *name, type_code type, int32 index) const
1601 {
1602 	DEBUG_FUNCTION_ENTER;
1603 	field_header *field = NULL;
1604 	status_t result = _FindField(name, type, &field);
1605 
1606 	if (result < B_OK)
1607 		return false;
1608 
1609 	if (field == NULL)
1610 		return false;
1611 
1612 	if (index < 0 || (uint32)index >= field->count)
1613 		return false;
1614 
1615 	return true;
1616 }
1617 
1618 
1619 void BMessage::_ReservedMessage1(void) {};
1620 void BMessage::_ReservedMessage2(void) {};
1621 void BMessage::_ReservedMessage3(void) {};
1622 
1623 
1624 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
1625 
1626 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
1627 status_t																	\
1628 BMessage::Add##typeName(const char *name, type val)							\
1629 {																			\
1630 	return AddData(name, typeCode, &val, sizeof(type), true);				\
1631 }																			\
1632 																			\
1633 status_t																	\
1634 BMessage::Find##typeName(const char *name, type *p) const					\
1635 {																			\
1636 	void *ptr = NULL;														\
1637 	ssize_t bytes = 0;														\
1638 	status_t error = B_OK;													\
1639 																			\
1640 	*p = type();															\
1641 	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
1642 																			\
1643 	if (error == B_OK)														\
1644 		memcpy(p, ptr, sizeof(type));										\
1645 																			\
1646 	return error;															\
1647 }																			\
1648 																			\
1649 status_t																	\
1650 BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
1651 {																			\
1652 	void *ptr = NULL;														\
1653 	ssize_t bytes = 0;														\
1654 	status_t error = B_OK;													\
1655 																			\
1656 	*p = type();															\
1657 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
1658 																			\
1659 	if (error == B_OK)														\
1660 		memcpy(p, ptr, sizeof(type));										\
1661 																			\
1662 	return error;															\
1663 }																			\
1664 																			\
1665 status_t																	\
1666 BMessage::Replace##typeName(const char *name, type val)						\
1667 {																			\
1668 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
1669 }																			\
1670 																			\
1671 status_t																	\
1672 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
1673 {																			\
1674 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
1675 }																			\
1676 																			\
1677 bool																		\
1678 BMessage::Has##typeName(const char *name, int32 index) const				\
1679 {																			\
1680 	return HasData(name, typeCode, index);									\
1681 }
1682 
1683 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
1684 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
1685 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
1686 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
1687 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
1688 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
1689 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
1690 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
1691 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
1692 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
1693 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
1694 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
1695 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
1696 
1697 #undef DEFINE_FUNCTIONS
1698 
1699 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
1700 bool																		\
1701 BMessage::Has##typeName(const char *name, int32 index) const				\
1702 {																			\
1703 	return HasData(name, typeCode, index);									\
1704 }
1705 
1706 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
1707 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
1708 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
1709 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
1710 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
1711 
1712 #undef DEFINE_HAS_FUNCTION
1713 
1714 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
1715 type																		\
1716 BMessage::Find##typeName(const char *name, int32 index) const				\
1717 {																			\
1718 	type val = initialize;													\
1719 	Find##typeName(name, index, &val);										\
1720 	return val;																\
1721 }
1722 
1723 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
1724 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
1725 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
1726 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
1727 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
1728 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
1729 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
1730 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
1731 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
1732 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
1733 
1734 #undef DEFINE_LAZY_FIND_FUNCTION
1735 
1736 status_t
1737 BMessage::AddString(const char *name, const char *string)
1738 {
1739 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
1740 }
1741 
1742 
1743 status_t
1744 BMessage::AddString(const char *name, const BString &string)
1745 {
1746 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
1747 }
1748 
1749 
1750 status_t
1751 BMessage::AddStrings(const char *name, const BStringList &list)
1752 {
1753 	int32 count = list.CountStrings();
1754 	for (int32 i = 0; i < count; i++) {
1755 		status_t error = AddString(name, list.StringAt(i));
1756 		if (error != B_OK)
1757 			return error;
1758 	}
1759 
1760 	return B_OK;
1761 }
1762 
1763 
1764 status_t
1765 BMessage::AddPointer(const char *name, const void *pointer)
1766 {
1767 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
1768 }
1769 
1770 
1771 status_t
1772 BMessage::AddMessenger(const char *name, BMessenger messenger)
1773 {
1774 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
1775 }
1776 
1777 
1778 status_t
1779 BMessage::AddRef(const char *name, const entry_ref *ref)
1780 {
1781 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
1782 	char buffer[size];
1783 
1784 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
1785 
1786 	if (error >= B_OK)
1787 		error = AddData(name, B_REF_TYPE, buffer, size, false);
1788 
1789 	return error;
1790 }
1791 
1792 
1793 status_t
1794 BMessage::AddMessage(const char *name, const BMessage *message)
1795 {
1796 	if (message == NULL)
1797 		return B_BAD_VALUE;
1798 
1799 	// TODO: This and the following functions waste time by allocating and
1800 	// copying an extra buffer. Functions can be added that return a direct
1801 	// pointer into the message.
1802 
1803 	char stackBuffer[16384];
1804 	ssize_t size = message->FlattenedSize();
1805 
1806 	char* buffer;
1807 	if (size > (ssize_t)sizeof(stackBuffer)) {
1808 		buffer = (char *)malloc(size);
1809 		if (buffer == NULL)
1810 			return B_NO_MEMORY;
1811 	} else
1812 		buffer = stackBuffer;
1813 
1814 	status_t error = message->Flatten(buffer, size);
1815 
1816 	if (error >= B_OK)
1817 		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
1818 
1819 	if (buffer != stackBuffer)
1820 		free(buffer);
1821 
1822 	return error;
1823 }
1824 
1825 
1826 status_t
1827 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
1828 {
1829 	if (object == NULL)
1830 		return B_BAD_VALUE;
1831 
1832 	char stackBuffer[16384];
1833 	ssize_t size = object->FlattenedSize();
1834 
1835 	char* buffer;
1836 	if (size > (ssize_t)sizeof(stackBuffer)) {
1837 		buffer = (char *)malloc(size);
1838 		if (buffer == NULL)
1839 			return B_NO_MEMORY;
1840 	} else
1841 		buffer = stackBuffer;
1842 
1843 	status_t error = object->Flatten(buffer, size);
1844 
1845 	if (error >= B_OK)
1846 		error = AddData(name, object->TypeCode(), buffer, size, false);
1847 
1848 	if (buffer != stackBuffer)
1849 		free(buffer);
1850 
1851 	return error;
1852 }
1853 
1854 
1855 status_t
1856 BMessage::FindString(const char *name, const char **string) const
1857 {
1858 	return FindString(name, 0, string);
1859 }
1860 
1861 
1862 status_t
1863 BMessage::FindString(const char *name, int32 index, const char **string) const
1864 {
1865 	ssize_t bytes;
1866 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
1867 }
1868 
1869 
1870 status_t
1871 BMessage::FindString(const char *name, BString *string) const
1872 {
1873 	return FindString(name, 0, string);
1874 }
1875 
1876 
1877 status_t
1878 BMessage::FindString(const char *name, int32 index, BString *string) const
1879 {
1880 	if (string == NULL)
1881 		return B_BAD_VALUE;
1882 
1883 	const char *cstr;
1884 	status_t error = FindString(name, index, &cstr);
1885 	if (error < B_OK)
1886 		return error;
1887 
1888 	*string = cstr;
1889 	return B_OK;
1890 }
1891 
1892 
1893 status_t
1894 BMessage::FindStrings(const char *name, BStringList *list) const
1895 {
1896 	if (list == NULL)
1897 		return B_BAD_VALUE;
1898 
1899 	list->MakeEmpty();
1900 
1901 	// get the number of items
1902 	type_code type;
1903 	int32 count;
1904 	if (GetInfo(name, &type, &count) != B_OK)
1905 		return B_NAME_NOT_FOUND;
1906 
1907 	if (type != B_STRING_TYPE)
1908 		return B_BAD_DATA;
1909 
1910 	for (int32 i = 0; i < count; i++) {
1911 		BString string;
1912 		status_t error = FindString(name, i, &string);
1913 		if (error != B_OK)
1914 			return error;
1915 		if (!list->Add(string))
1916 			return B_NO_MEMORY;
1917 	}
1918 
1919 	return B_OK;
1920 }
1921 
1922 
1923 status_t
1924 BMessage::FindPointer(const char *name, void **pointer) const
1925 {
1926 	return FindPointer(name, 0, pointer);
1927 }
1928 
1929 
1930 status_t
1931 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
1932 {
1933 	if (pointer == NULL)
1934 		return B_BAD_VALUE;
1935 
1936 	void **data = NULL;
1937 	ssize_t size = 0;
1938 	status_t error = FindData(name, B_POINTER_TYPE, index,
1939 		(const void **)&data, &size);
1940 
1941 	if (error == B_OK)
1942 		*pointer = *data;
1943 	else
1944 		*pointer = NULL;
1945 
1946 	return error;
1947 }
1948 
1949 
1950 status_t
1951 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
1952 {
1953 	return FindMessenger(name, 0, messenger);
1954 }
1955 
1956 
1957 status_t
1958 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
1959 	const
1960 {
1961 	if (messenger == NULL)
1962 		return B_BAD_VALUE;
1963 
1964 	void *data = NULL;
1965 	ssize_t size = 0;
1966 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
1967 		(const void **)&data, &size);
1968 
1969 	if (error == B_OK)
1970 		memcpy(messenger, data, sizeof(BMessenger));
1971 	else
1972 		*messenger = BMessenger();
1973 
1974 	return error;
1975 }
1976 
1977 
1978 status_t
1979 BMessage::FindRef(const char *name, entry_ref *ref) const
1980 {
1981 	return FindRef(name, 0, ref);
1982 }
1983 
1984 
1985 status_t
1986 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
1987 {
1988 	if (ref == NULL)
1989 		return B_BAD_VALUE;
1990 
1991 	void *data = NULL;
1992 	ssize_t size = 0;
1993 	status_t error = FindData(name, B_REF_TYPE, index,
1994 		(const void **)&data, &size);
1995 
1996 	if (error == B_OK)
1997 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
1998 	else
1999 		*ref = entry_ref();
2000 
2001 	return error;
2002 }
2003 
2004 
2005 status_t
2006 BMessage::FindMessage(const char *name, BMessage *message) const
2007 {
2008 	return FindMessage(name, 0, message);
2009 }
2010 
2011 
2012 status_t
2013 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2014 {
2015 	if (message == NULL)
2016 		return B_BAD_VALUE;
2017 
2018 	void *data = NULL;
2019 	ssize_t size = 0;
2020 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
2021 		(const void **)&data, &size);
2022 
2023 	if (error == B_OK)
2024 		error = message->Unflatten((const char *)data);
2025 	else
2026 		*message = BMessage();
2027 
2028 	return error;
2029 }
2030 
2031 
2032 status_t
2033 BMessage::FindFlat(const char *name, BFlattenable *object) const
2034 {
2035 	return FindFlat(name, 0, object);
2036 }
2037 
2038 
2039 status_t
2040 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2041 {
2042 	if (object == NULL)
2043 		return B_BAD_VALUE;
2044 
2045 	void *data = NULL;
2046 	ssize_t numBytes = 0;
2047 	status_t error = FindData(name, object->TypeCode(), index,
2048 		(const void **)&data, &numBytes);
2049 
2050 	if (error == B_OK)
2051 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2052 
2053 	return error;
2054 }
2055 
2056 
2057 status_t
2058 BMessage::FindData(const char *name, type_code type, const void **data,
2059 	ssize_t *numBytes) const
2060 {
2061 	return FindData(name, type, 0, data, numBytes);
2062 }
2063 
2064 
2065 status_t
2066 BMessage::ReplaceString(const char *name, const char *string)
2067 {
2068 	if (string == NULL)
2069 		return B_BAD_VALUE;
2070 
2071 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2072 }
2073 
2074 
2075 status_t
2076 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2077 {
2078 	if (string == NULL)
2079 		return B_BAD_VALUE;
2080 
2081 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2082 }
2083 
2084 
2085 status_t
2086 BMessage::ReplaceString(const char *name, const BString &string)
2087 {
2088 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2089 		string.Length() + 1);
2090 }
2091 
2092 
2093 status_t
2094 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2095 {
2096 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2097 		string.Length() + 1);
2098 }
2099 
2100 
2101 status_t
2102 BMessage::ReplacePointer(const char *name, const void *pointer)
2103 {
2104 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2105 }
2106 
2107 
2108 status_t
2109 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2110 {
2111 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2112 }
2113 
2114 
2115 status_t
2116 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2117 {
2118 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2119 		sizeof(BMessenger));
2120 }
2121 
2122 
2123 status_t
2124 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2125 {
2126 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2127 		sizeof(BMessenger));
2128 }
2129 
2130 
2131 status_t
2132 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2133 {
2134 	return ReplaceRef(name, 0, ref);
2135 }
2136 
2137 
2138 status_t
2139 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2140 {
2141 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2142 	char buffer[size];
2143 
2144 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2145 
2146 	if (error >= B_OK)
2147 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2148 
2149 	return error;
2150 }
2151 
2152 
2153 status_t
2154 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2155 {
2156 	return ReplaceMessage(name, 0, message);
2157 }
2158 
2159 
2160 status_t
2161 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2162 {
2163 	if (message == NULL)
2164 		return B_BAD_VALUE;
2165 
2166 	ssize_t size = message->FlattenedSize();
2167 	char buffer[size];
2168 
2169 	status_t error = message->Flatten(buffer, size);
2170 
2171 	if (error >= B_OK)
2172 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2173 
2174 	return error;
2175 }
2176 
2177 
2178 status_t
2179 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2180 {
2181 	return ReplaceFlat(name, 0, object);
2182 }
2183 
2184 
2185 status_t
2186 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2187 {
2188 	if (object == NULL)
2189 		return B_BAD_VALUE;
2190 
2191 	ssize_t size = object->FlattenedSize();
2192 	char buffer[size];
2193 
2194 	status_t error = object->Flatten(buffer, size);
2195 
2196 	if (error >= B_OK)
2197 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2198 
2199 	return error;
2200 }
2201 
2202 
2203 status_t
2204 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2205 	ssize_t numBytes)
2206 {
2207 	return ReplaceData(name, type, 0, data, numBytes);
2208 }
2209 
2210 
2211 bool
2212 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2213 {
2214 	return HasFlat(name, 0, object);
2215 }
2216 
2217 
2218 bool
2219 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2220 	const
2221 {
2222 	return HasData(name, object->TypeCode(), index);
2223 }
2224