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