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