btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / build / libbe / app / Message.cpp
bloba49839a4cc58a22a6ffd42ce50c8e733baf256a9
1 /*
2 * Copyright 2005-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
10 #include <Message.h>
11 #include <MessageAdapter.h>
12 #include <MessagePrivate.h>
13 #include <MessageUtils.h>
15 #include <MessengerPrivate.h>
16 #include <TokenSpace.h>
18 #include <Application.h>
19 #include <AppMisc.h>
20 #include <BlockCache.h>
21 #include <Entry.h>
22 #include <MessageQueue.h>
23 #include <Messenger.h>
24 #include <Path.h>
25 #include <Point.h>
26 #include <Rect.h>
27 #include <String.h>
28 #include <StringList.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #include "tracing_config.h"
37 // kernel tracing configuration
39 //#define VERBOSE_DEBUG_OUTPUT
40 #ifdef VERBOSE_DEBUG_OUTPUT
41 #define DEBUG_FUNCTION_ENTER \
42 debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
43 " data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
44 find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \
45 __LINE__, __PRETTY_FUNCTION__);
47 #define DEBUG_FUNCTION_ENTER2 \
48 debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
49 __LINE__, __PRETTY_FUNCTION__);
50 #else
51 #define DEBUG_FUNCTION_ENTER /* nothing */
52 #define DEBUG_FUNCTION_ENTER2 /* nothing */
53 #endif
55 #if BMESSAGE_TRACING
56 # define KTRACE(format...) ktrace_printf(format)
57 #else
58 # define KTRACE(format...)
59 #endif
62 const char *B_SPECIFIER_ENTRY = "specifiers";
63 const char *B_PROPERTY_ENTRY = "property";
64 const char *B_PROPERTY_NAME_ENTRY = "name";
66 extern "C" {
67 // private os function to set the owning team of an area
68 status_t _kern_transfer_area(area_id area, void **_address,
69 uint32 addressSpec, team_id target);
73 BBlockCache *BMessage::sMsgCache = NULL;
76 template<typename Type>
77 static void
78 print_to_stream_type(uint8 *pointer)
80 Type *item = (Type *)pointer;
81 item->PrintToStream();
85 template<typename Type>
86 static void
87 print_type(const char *format, uint8 *pointer)
89 Type *item = (Type *)pointer;
90 printf(format, *item, *item);
94 // #pragma mark -
97 BMessage::BMessage()
99 DEBUG_FUNCTION_ENTER;
100 _InitCommon(true);
104 BMessage::BMessage(BMessage *other)
106 DEBUG_FUNCTION_ENTER;
107 _InitCommon(false);
108 *this = *other;
112 BMessage::BMessage(uint32 _what)
114 DEBUG_FUNCTION_ENTER;
115 _InitCommon(true);
116 fHeader->what = what = _what;
120 BMessage::BMessage(const BMessage &other)
122 DEBUG_FUNCTION_ENTER;
123 _InitCommon(false);
124 *this = other;
128 BMessage::~BMessage()
130 DEBUG_FUNCTION_ENTER;
131 _Clear();
135 BMessage &
136 BMessage::operator=(const BMessage &other)
138 DEBUG_FUNCTION_ENTER;
140 if (this == &other)
141 return *this;
143 _Clear();
145 fHeader = (message_header *)malloc(sizeof(message_header));
146 if (fHeader == NULL)
147 return *this;
149 memcpy(fHeader, other.fHeader, sizeof(message_header));
151 // Clear some header flags inherited from the original message that don't
152 // apply to the clone.
153 fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
154 | MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
155 | MESSAGE_FLAG_PASS_BY_AREA);
156 // Note, that BeOS R5 seems to keep the reply info.
158 if (fHeader->field_count > 0) {
159 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
160 fFields = (field_header *)malloc(fieldsSize);
161 if (fFields == NULL) {
162 fHeader->field_count = 0;
163 fHeader->data_size = 0;
164 } else
165 memcpy(fFields, other.fFields, fieldsSize);
168 if (fHeader->data_size > 0) {
169 fData = (uint8 *)malloc(fHeader->data_size);
170 if (fData == NULL) {
171 fHeader->field_count = 0;
172 free(fFields);
173 fFields = NULL;
174 } else
175 memcpy(fData, other.fData, fHeader->data_size);
178 fHeader->what = what = other.what;
179 fHeader->message_area = -1;
180 fFieldsAvailable = 0;
181 fDataAvailable = 0;
183 return *this;
187 void *
188 BMessage::operator new(size_t size)
190 DEBUG_FUNCTION_ENTER2;
191 if (!sMsgCache)
192 sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE);
193 void *pointer = sMsgCache->Get(size);
194 return pointer;
198 void *
199 BMessage::operator new(size_t, void *pointer)
201 DEBUG_FUNCTION_ENTER2;
202 return pointer;
206 void
207 BMessage::operator delete(void *pointer, size_t size)
209 DEBUG_FUNCTION_ENTER2;
210 sMsgCache->Save(pointer, size);
214 bool
215 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
216 bool deep) const
218 if (this == &other)
219 return true;
221 if (fHeader->field_count != other.fHeader->field_count)
222 return false;
224 for (uint32 i = 0; i < fHeader->field_count; i++) {
225 field_header *field = &fFields[i];
226 field_header *otherField = NULL;
228 const char *name = (const char *)fData + field->offset;
229 if (ignoreFieldOrder) {
230 if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
231 return false;
232 } else {
233 otherField = &other.fFields[i];
234 if (otherField->name_length != field->name_length)
235 return false;
237 const char *otherName = (const char *)other.fData
238 + otherField->offset;
239 if (strncmp(name, otherName, field->name_length) != 0)
240 return false;
243 if (otherField->type != field->type || otherField->count != field->count)
244 return false;
246 uint8 *data = fData + field->offset + field->name_length;
247 uint8 *otherData = other.fData + otherField->offset
248 + otherField->name_length;
250 bool needsMemCompare = true;
251 if (deep && field->type == B_MESSAGE_TYPE) {
252 BMessage message, otherMessage;
253 if (message.Unflatten((const char *)data) == B_OK
254 && otherMessage.Unflatten((const char *)otherData) == B_OK) {
255 if (!message.HasSameData(ignoreFieldOrder, deep))
256 return false;
257 needsMemCompare = false;
261 if (needsMemCompare) {
262 if (otherField->data_size != field->data_size)
263 return false;
264 if (memcmp(data, otherData, field->data_size) != 0)
265 return false;
269 return true;
273 status_t
274 BMessage::_InitCommon(bool initHeader)
276 DEBUG_FUNCTION_ENTER;
277 what = 0;
279 fHeader = NULL;
280 fFields = NULL;
281 fData = NULL;
283 fFieldsAvailable = 0;
284 fDataAvailable = 0;
286 fOriginal = NULL;
287 fQueueLink = NULL;
289 if (initHeader)
290 return _InitHeader();
292 fHeader = NULL;
293 return B_OK;
297 status_t
298 BMessage::_InitHeader()
300 DEBUG_FUNCTION_ENTER;
301 if (fHeader == NULL) {
302 fHeader = (message_header *)malloc(sizeof(message_header));
303 if (fHeader == NULL)
304 return B_NO_MEMORY;
307 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
309 fHeader->format = MESSAGE_FORMAT_HAIKU;
310 fHeader->flags = MESSAGE_FLAG_VALID;
311 fHeader->what = what;
312 fHeader->current_specifier = -1;
313 fHeader->message_area = -1;
315 fHeader->target = B_NULL_TOKEN;
316 fHeader->reply_target = B_NULL_TOKEN;
317 fHeader->reply_port = -1;
318 fHeader->reply_team = -1;
320 // initializing the hash table to -1 because 0 is a valid index
321 fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
322 memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
323 return B_OK;
327 status_t
328 BMessage::_Clear()
330 DEBUG_FUNCTION_ENTER;
331 if (fHeader != NULL) {
332 free(fHeader);
333 fHeader = NULL;
336 free(fFields);
337 fFields = NULL;
338 free(fData);
339 fData = NULL;
341 fFieldsAvailable = 0;
342 fDataAvailable = 0;
344 delete fOriginal;
345 fOriginal = NULL;
347 return B_OK;
351 status_t
352 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound,
353 type_code *typeFound, int32 *countFound) const
355 DEBUG_FUNCTION_ENTER;
356 if (index < 0 || (uint32)index >= fHeader->field_count)
357 return B_BAD_INDEX;
359 if (typeRequested == B_ANY_TYPE) {
360 if (nameFound)
361 *nameFound = (char *)fData + fFields[index].offset;
362 if (typeFound)
363 *typeFound = fFields[index].type;
364 if (countFound)
365 *countFound = fFields[index].count;
366 return B_OK;
369 int32 counter = -1;
370 field_header *field = fFields;
371 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
372 if (field->type == typeRequested)
373 counter++;
375 if (counter == index) {
376 if (nameFound)
377 *nameFound = (char *)fData + field->offset;
378 if (typeFound)
379 *typeFound = field->type;
380 if (countFound)
381 *countFound = field->count;
382 return B_OK;
386 if (counter == -1)
387 return B_BAD_TYPE;
389 return B_BAD_INDEX;
393 status_t
394 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound)
395 const
397 DEBUG_FUNCTION_ENTER;
398 if (countFound)
399 *countFound = 0;
401 field_header *field = NULL;
402 status_t result = _FindField(name, B_ANY_TYPE, &field);
403 if (result < B_OK || field == NULL)
404 return result;
406 if (typeFound)
407 *typeFound = field->type;
408 if (countFound)
409 *countFound = field->count;
411 return B_OK;
415 status_t
416 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize)
417 const
419 DEBUG_FUNCTION_ENTER;
420 field_header *field = NULL;
421 status_t result = _FindField(name, B_ANY_TYPE, &field);
422 if (result < B_OK || field == NULL)
423 return result;
425 if (typeFound)
426 *typeFound = field->type;
427 if (fixedSize)
428 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
430 return B_OK;
434 int32
435 BMessage::CountNames(type_code type) const
437 DEBUG_FUNCTION_ENTER;
438 if (type == B_ANY_TYPE)
439 return fHeader->field_count;
441 int32 count = 0;
442 field_header *field = fFields;
443 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
444 if (field->type == type)
445 count++;
448 return count;
452 bool
453 BMessage::IsEmpty() const
455 DEBUG_FUNCTION_ENTER;
456 return fHeader->field_count == 0;
460 bool
461 BMessage::IsSystem() const
463 DEBUG_FUNCTION_ENTER;
464 char a = char(what >> 24);
465 char b = char(what >> 16);
466 char c = char(what >> 8);
467 char d = char(what);
469 // The BeBook says:
470 // ... we've adopted a strict convention for assigning values to all
471 // Be-defined constants. The value assigned will always be formed by
472 // combining four characters into a multicharacter constant, with the
473 // characters limited to uppercase letters and the underbar
474 // Between that and what's in AppDefs.h, this algo seems like a safe bet:
475 if (a == '_' && isupper(b) && isupper(c) && isupper(d))
476 return true;
478 return false;
482 bool
483 BMessage::IsReply() const
485 DEBUG_FUNCTION_ENTER;
486 return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
490 void
491 BMessage::PrintToStream() const
493 _PrintToStream("");
494 printf("}\n");
498 void
499 BMessage::_PrintToStream(const char* indent) const
501 DEBUG_FUNCTION_ENTER;
503 int32 value = B_BENDIAN_TO_HOST_INT32(what);
504 printf("BMessage(");
505 if (isprint(*(char *)&value))
506 printf("'%.4s'", (char *)&value);
507 else
508 printf("0x%" B_PRIx32, what);
509 printf(") {\n");
511 if (fHeader == NULL || fFields == NULL || fData == NULL)
512 return;
514 field_header *field = fFields;
515 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
516 value = B_BENDIAN_TO_HOST_INT32(field->type);
517 ssize_t size = 0;
518 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
519 size = field->data_size / field->count;
521 uint8 *pointer = fData + field->offset + field->name_length;
522 for (uint32 j = 0; j < field->count; j++) {
523 if (field->count == 1) {
524 printf("%s %s = ", indent,
525 (char *)(fData + field->offset));
526 } else {
527 printf("%s %s[%" B_PRIu32 "] = ", indent,
528 (char *)(fData + field->offset), j);
531 switch (field->type) {
532 case B_RECT_TYPE:
533 print_to_stream_type<BRect>(pointer);
534 break;
536 case B_POINT_TYPE:
537 print_to_stream_type<BPoint>(pointer);
538 break;
540 case B_STRING_TYPE:
542 size = *(uint32 *)pointer;
543 pointer += sizeof(uint32);
544 printf("string(\"%s\", %ld bytes)\n", (char *)pointer,
545 (long)size);
546 break;
549 case B_INT8_TYPE:
550 print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
551 break;
553 case B_UINT8_TYPE:
554 print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n",
555 pointer);
556 break;
558 case B_INT16_TYPE:
559 print_type<int16>("int16(0x%x or %d)\n", pointer);
560 break;
562 case B_UINT16_TYPE:
563 print_type<uint16>("uint16(0x%x or %u\n", pointer);
564 break;
566 case B_INT32_TYPE:
567 print_type<int32>("int32(0x%lx or %ld)\n", pointer);
568 break;
570 case B_UINT32_TYPE:
571 print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
572 break;
574 case B_INT64_TYPE:
575 print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
576 break;
578 case B_UINT64_TYPE:
579 print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
580 break;
582 case B_BOOL_TYPE:
583 printf("bool(%s)\n", *((bool *)pointer) != 0
584 ? "true" : "false");
585 break;
587 case B_FLOAT_TYPE:
588 print_type<float>("float(%.4f)\n", pointer);
589 break;
591 case B_DOUBLE_TYPE:
592 print_type<double>("double(%.8f)\n", pointer);
593 break;
595 case B_REF_TYPE:
597 size = *(uint32 *)pointer;
598 pointer += sizeof(uint32);
599 entry_ref ref;
600 BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
602 printf("entry_ref(device=%d, directory=%lld"
603 ", name=\"%s\", ", (int)ref.device,
604 (long long)ref.directory, ref.name);
606 BPath path(&ref);
607 printf("path=\"%s\")\n", path.Path());
608 break;
611 case B_MESSAGE_TYPE:
613 char buffer[1024];
614 sprintf(buffer, "%s ", indent);
616 BMessage message;
617 size = *(uint32 *)pointer;
618 pointer += sizeof(uint32);
619 status_t result = message.Unflatten((const char *)pointer);
620 if (result != B_OK) {
621 printf("failed unflatten: %s\n", strerror(result));
622 break;
625 message._PrintToStream(buffer);
626 printf("%s }\n", indent);
627 break;
630 default:
632 printf("(type = '%.4s')(size = %ld)\n", (char *)&value,
633 (long)size);
634 break;
638 pointer += size;
644 status_t
645 BMessage::Rename(const char *oldEntry, const char *newEntry)
647 DEBUG_FUNCTION_ENTER;
648 if (oldEntry == NULL || newEntry == NULL)
649 return B_BAD_VALUE;
651 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
652 int32 *nextField = &fHeader->hash_table[hash];
654 while (*nextField >= 0) {
655 field_header *field = &fFields[*nextField];
657 if (strncmp((const char *)(fData + field->offset), oldEntry,
658 field->name_length) == 0) {
659 // nextField points to the field for oldEntry, save it and unlink
660 int32 index = *nextField;
661 *nextField = field->next_field;
662 field->next_field = -1;
664 hash = _HashName(newEntry) % fHeader->hash_table_size;
665 nextField = &fHeader->hash_table[hash];
666 while (*nextField >= 0)
667 nextField = &fFields[*nextField].next_field;
668 *nextField = index;
670 int32 newLength = strlen(newEntry) + 1;
671 status_t result = _ResizeData(field->offset + 1,
672 newLength - field->name_length);
673 if (result < B_OK)
674 return result;
676 memcpy(fData + field->offset, newEntry, newLength);
677 field->name_length = newLength;
678 return B_OK;
681 nextField = &field->next_field;
684 return B_NAME_NOT_FOUND;
688 bool
689 BMessage::WasDelivered() const
691 DEBUG_FUNCTION_ENTER;
692 return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
696 bool
697 BMessage::IsSourceWaiting() const
699 DEBUG_FUNCTION_ENTER;
700 return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
701 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
705 BMessenger
706 BMessage::ReturnAddress() const
708 DEBUG_FUNCTION_ENTER;
709 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
710 BMessenger messenger;
711 BMessenger::Private(messenger).SetTo(fHeader->reply_team,
712 fHeader->reply_port, fHeader->reply_target);
713 return messenger;
716 return BMessenger();
720 const BMessage *
721 BMessage::Previous() const
723 DEBUG_FUNCTION_ENTER;
724 /* ToDo: test if the "_previous_" field is used in R5 */
725 if (fOriginal == NULL) {
726 fOriginal = new BMessage();
728 if (FindMessage("_previous_", fOriginal) != B_OK) {
729 delete fOriginal;
730 fOriginal = NULL;
734 return fOriginal;
738 bool
739 BMessage::WasDropped() const
741 DEBUG_FUNCTION_ENTER;
742 return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
746 BPoint
747 BMessage::DropPoint(BPoint *offset) const
749 DEBUG_FUNCTION_ENTER;
750 if (offset)
751 *offset = FindPoint("_drop_offset_");
753 return FindPoint("_drop_point_");
757 ssize_t
758 BMessage::FlattenedSize() const
760 DEBUG_FUNCTION_ENTER;
761 return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
762 + fHeader->data_size;
766 status_t
767 BMessage::Flatten(char *buffer, ssize_t size) const
769 DEBUG_FUNCTION_ENTER;
770 if (buffer == NULL || size < 0)
771 return B_BAD_VALUE;
773 if (fHeader == NULL)
774 return B_NO_INIT;
776 /* we have to sync the what code as it is a public member */
777 fHeader->what = what;
779 memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
780 buffer += sizeof(message_header);
781 size -= sizeof(message_header);
783 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
784 memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
785 buffer += fieldsSize;
786 size -= fieldsSize;
788 memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
789 if ((size_t)size < fHeader->data_size)
790 return B_BUFFER_OVERFLOW;
792 return B_OK;
796 status_t
797 BMessage::Flatten(BDataIO *stream, ssize_t *size) const
799 DEBUG_FUNCTION_ENTER;
800 if (stream == NULL)
801 return B_BAD_VALUE;
803 if (fHeader == NULL)
804 return B_NO_INIT;
806 /* we have to sync the what code as it is a public member */
807 fHeader->what = what;
809 ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
810 if (result1 != sizeof(message_header))
811 return result1 < 0 ? result1 : B_ERROR;
813 ssize_t result2 = 0;
814 if (fHeader->field_count > 0) {
815 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
816 result2 = stream->Write(fFields, fieldsSize);
817 if (result2 != fieldsSize)
818 return result2 < 0 ? result2 : B_ERROR;
821 ssize_t result3 = 0;
822 if (fHeader->data_size > 0) {
823 result3 = stream->Write(fData, fHeader->data_size);
824 if (result3 != (ssize_t)fHeader->data_size)
825 return result3 < 0 ? result3 : B_ERROR;
828 if (size)
829 *size = result1 + result2 + result3;
831 return B_OK;
835 status_t
836 BMessage::_ValidateMessage()
838 if (fHeader->field_count == 0)
839 return B_OK;
841 if (fFields == NULL)
842 return B_NO_INIT;
844 for (uint32 i = 0; i < fHeader->field_count; i++) {
845 field_header *field = &fFields[i];
846 if ((field->next_field >= 0
847 && (uint32)field->next_field > fHeader->field_count)
848 || (field->offset + field->name_length + field->data_size
849 > fHeader->data_size)) {
850 // the message is corrupt
851 MakeEmpty();
852 return B_BAD_VALUE;
856 return B_OK;
860 status_t
861 BMessage::Unflatten(const char *flatBuffer)
863 DEBUG_FUNCTION_ENTER;
864 if (flatBuffer == NULL)
865 return B_BAD_VALUE;
867 uint32 format = *(uint32 *)flatBuffer;
868 if (format != MESSAGE_FORMAT_HAIKU)
869 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
871 // native message unflattening
873 _Clear();
875 fHeader = (message_header *)malloc(sizeof(message_header));
876 if (fHeader == NULL)
877 return B_NO_MEMORY;
879 memcpy(fHeader, flatBuffer, sizeof(message_header));
880 flatBuffer += sizeof(message_header);
882 if (fHeader->format != MESSAGE_FORMAT_HAIKU
883 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
884 _InitHeader();
885 return B_BAD_VALUE;
888 what = fHeader->what;
890 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
891 && fHeader->message_area >= 0) {
892 // status_t result = _Reference();
893 // if (result != B_OK)
894 // return result;
895 } else {
896 fHeader->message_area = -1;
898 if (fHeader->field_count > 0) {
899 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
900 fFields = (field_header *)malloc(fieldsSize);
901 if (fFields == NULL) {
902 _InitHeader();
903 return B_NO_MEMORY;
906 memcpy(fFields, flatBuffer, fieldsSize);
907 flatBuffer += fieldsSize;
910 if (fHeader->data_size > 0) {
911 fData = (uint8 *)malloc(fHeader->data_size);
912 if (fData == NULL) {
913 free(fFields);
914 fFields = NULL;
915 _InitHeader();
916 return B_NO_MEMORY;
919 memcpy(fData, flatBuffer, fHeader->data_size);
923 return _ValidateMessage();
927 status_t
928 BMessage::Unflatten(BDataIO *stream)
930 DEBUG_FUNCTION_ENTER;
931 if (stream == NULL)
932 return B_BAD_VALUE;
934 uint32 format = 0;
935 stream->Read(&format, sizeof(uint32));
936 if (format != MESSAGE_FORMAT_HAIKU)
937 return BPrivate::MessageAdapter::Unflatten(format, this, stream);
939 // native message unflattening
941 _Clear();
943 fHeader = (message_header *)malloc(sizeof(message_header));
944 if (fHeader == NULL)
945 return B_NO_MEMORY;
947 fHeader->format = format;
948 uint8 *header = (uint8 *)fHeader;
949 ssize_t result = stream->Read(header + sizeof(uint32),
950 sizeof(message_header) - sizeof(uint32));
951 if (result != sizeof(message_header) - sizeof(uint32)
952 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
953 _InitHeader();
954 return result < 0 ? result : B_BAD_VALUE;
957 what = fHeader->what;
959 fHeader->message_area = -1;
961 if (fHeader->field_count > 0) {
962 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
963 fFields = (field_header *)malloc(fieldsSize);
964 if (fFields == NULL) {
965 _InitHeader();
966 return B_NO_MEMORY;
969 result = stream->Read(fFields, fieldsSize);
970 if (result != fieldsSize)
971 return result < 0 ? result : B_BAD_VALUE;
974 if (fHeader->data_size > 0) {
975 fData = (uint8 *)malloc(fHeader->data_size);
976 if (fData == NULL) {
977 free(fFields);
978 fFields = NULL;
979 _InitHeader();
980 return B_NO_MEMORY;
983 result = stream->Read(fData, fHeader->data_size);
984 if (result != (ssize_t)fHeader->data_size)
985 return result < 0 ? result : B_BAD_VALUE;
988 return _ValidateMessage();
992 status_t
993 BMessage::AddSpecifier(const char *property)
995 DEBUG_FUNCTION_ENTER;
996 BMessage message(B_DIRECT_SPECIFIER);
997 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
998 if (result < B_OK)
999 return result;
1001 return AddSpecifier(&message);
1005 status_t
1006 BMessage::AddSpecifier(const char *property, int32 index)
1008 DEBUG_FUNCTION_ENTER;
1009 BMessage message(B_INDEX_SPECIFIER);
1010 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1011 if (result < B_OK)
1012 return result;
1014 result = message.AddInt32("index", index);
1015 if (result < B_OK)
1016 return result;
1018 return AddSpecifier(&message);
1022 status_t
1023 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1025 DEBUG_FUNCTION_ENTER;
1026 if (range < 0)
1027 return B_BAD_VALUE;
1029 BMessage message(B_RANGE_SPECIFIER);
1030 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1031 if (result < B_OK)
1032 return result;
1034 result = message.AddInt32("index", index);
1035 if (result < B_OK)
1036 return result;
1038 result = message.AddInt32("range", range);
1039 if (result < B_OK)
1040 return result;
1042 return AddSpecifier(&message);
1046 status_t
1047 BMessage::AddSpecifier(const char *property, const char *name)
1049 DEBUG_FUNCTION_ENTER;
1050 BMessage message(B_NAME_SPECIFIER);
1051 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1052 if (result < B_OK)
1053 return result;
1055 result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1056 if (result < B_OK)
1057 return result;
1059 return AddSpecifier(&message);
1063 status_t
1064 BMessage::AddSpecifier(const BMessage *specifier)
1066 DEBUG_FUNCTION_ENTER;
1067 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1068 if (result < B_OK)
1069 return result;
1071 fHeader->current_specifier++;
1072 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1073 return B_OK;
1077 status_t
1078 BMessage::SetCurrentSpecifier(int32 index)
1080 DEBUG_FUNCTION_ENTER;
1081 if (index < 0)
1082 return B_BAD_INDEX;
1084 type_code type;
1085 int32 count;
1086 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1087 if (result < B_OK)
1088 return result;
1090 if (index > count)
1091 return B_BAD_INDEX;
1093 fHeader->current_specifier = index;
1094 return B_OK;
1098 status_t
1099 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what,
1100 const char **property) const
1102 DEBUG_FUNCTION_ENTER;
1104 if (index != NULL)
1105 *index = fHeader->current_specifier;
1107 if (fHeader->current_specifier < 0
1108 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1109 return B_BAD_SCRIPT_SYNTAX;
1111 if (specifier) {
1112 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1113 specifier) < B_OK)
1114 return B_BAD_SCRIPT_SYNTAX;
1116 if (_what != NULL)
1117 *_what = specifier->what;
1119 if (property) {
1120 if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1121 return B_BAD_SCRIPT_SYNTAX;
1125 return B_OK;
1129 bool
1130 BMessage::HasSpecifiers() const
1132 DEBUG_FUNCTION_ENTER;
1133 return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1137 status_t
1138 BMessage::PopSpecifier()
1140 DEBUG_FUNCTION_ENTER;
1141 if (fHeader->current_specifier < 0 ||
1142 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1143 return B_BAD_VALUE;
1145 if (fHeader->current_specifier >= 0)
1146 fHeader->current_specifier--;
1148 return B_OK;
1152 status_t
1153 BMessage::_ResizeData(uint32 offset, int32 change)
1155 if (change == 0)
1156 return B_OK;
1158 /* optimize for the most usual case: appending data */
1159 if (offset < fHeader->data_size) {
1160 field_header *field = fFields;
1161 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1162 if (field->offset >= offset)
1163 field->offset += change;
1167 if (change > 0) {
1168 if (fDataAvailable >= (uint32)change) {
1169 if (offset < fHeader->data_size) {
1170 memmove(fData + offset + change, fData + offset,
1171 fHeader->data_size - offset);
1174 fDataAvailable -= change;
1175 fHeader->data_size += change;
1176 return B_OK;
1179 size_t size = fHeader->data_size * 2;
1180 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1181 size = max_c(size, fHeader->data_size + change);
1183 uint8 *newData = (uint8 *)realloc(fData, size);
1184 if (size > 0 && newData == NULL)
1185 return B_NO_MEMORY;
1187 fData = newData;
1188 if (offset < fHeader->data_size) {
1189 memmove(fData + offset + change, fData + offset,
1190 fHeader->data_size - offset);
1193 fHeader->data_size += change;
1194 fDataAvailable = size - fHeader->data_size;
1195 } else {
1196 ssize_t length = fHeader->data_size - offset + change;
1197 if (length > 0)
1198 memmove(fData + offset, fData + offset - change, length);
1200 // change is negative
1201 fHeader->data_size += change;
1202 fDataAvailable -= change;
1204 if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1205 ssize_t available = MAX_DATA_PREALLOCATION / 2;
1206 ssize_t size = fHeader->data_size + available;
1207 uint8 *newData = (uint8 *)realloc(fData, size);
1208 if (size > 0 && newData == NULL) {
1209 // this is strange, but not really fatal
1210 return B_OK;
1213 fData = newData;
1214 fDataAvailable = available;
1218 return B_OK;
1222 uint32
1223 BMessage::_HashName(const char *name) const
1225 char ch;
1226 uint32 result = 0;
1228 while ((ch = *name++) != 0) {
1229 result = (result << 7) ^ (result >> 24);
1230 result ^= ch;
1233 result ^= result << 12;
1234 return result;
1238 status_t
1239 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1241 if (name == NULL)
1242 return B_BAD_VALUE;
1244 if (fHeader == NULL || fFields == NULL || fData == NULL)
1245 return B_NAME_NOT_FOUND;
1247 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1248 int32 nextField = fHeader->hash_table[hash];
1250 while (nextField >= 0) {
1251 field_header *field = &fFields[nextField];
1252 if ((field->flags & FIELD_FLAG_VALID) == 0)
1253 break;
1255 if (strncmp((const char *)(fData + field->offset), name,
1256 field->name_length) == 0) {
1257 if (type != B_ANY_TYPE && field->type != type)
1258 return B_BAD_TYPE;
1260 *result = field;
1261 return B_OK;
1264 nextField = field->next_field;
1267 return B_NAME_NOT_FOUND;
1271 status_t
1272 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1273 field_header **result)
1275 if (fHeader == NULL)
1276 return B_ERROR;
1278 if (fFieldsAvailable <= 0) {
1279 uint32 count = fHeader->field_count * 2 + 1;
1280 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1282 field_header *newFields = (field_header *)realloc(fFields,
1283 count * sizeof(field_header));
1284 if (count > 0 && newFields == NULL)
1285 return B_NO_MEMORY;
1287 fFields = newFields;
1288 fFieldsAvailable = count - fHeader->field_count;
1291 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1292 int32 *nextField = &fHeader->hash_table[hash];
1293 while (*nextField >= 0)
1294 nextField = &fFields[*nextField].next_field;
1295 *nextField = fHeader->field_count;
1297 field_header *field = &fFields[fHeader->field_count];
1298 field->type = type;
1299 field->count = 0;
1300 field->data_size = 0;
1301 field->next_field = -1;
1302 field->offset = fHeader->data_size;
1303 field->name_length = strlen(name) + 1;
1304 status_t status = _ResizeData(field->offset, field->name_length);
1305 if (status < B_OK)
1306 return status;
1308 memcpy(fData + field->offset, name, field->name_length);
1309 field->flags = FIELD_FLAG_VALID;
1310 if (isFixedSize)
1311 field->flags |= FIELD_FLAG_FIXED_SIZE;
1313 fFieldsAvailable--;
1314 fHeader->field_count++;
1315 *result = field;
1316 return B_OK;
1320 status_t
1321 BMessage::_RemoveField(field_header *field)
1323 status_t result = _ResizeData(field->offset, -(field->data_size
1324 + field->name_length));
1325 if (result < B_OK)
1326 return result;
1328 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1329 int32 nextField = field->next_field;
1330 if (nextField > index)
1331 nextField--;
1333 int32 *value = fHeader->hash_table;
1334 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1335 if (*value > index)
1336 *value -= 1;
1337 else if (*value == index)
1338 *value = nextField;
1341 field_header *other = fFields;
1342 for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1343 if (other->next_field > index)
1344 other->next_field--;
1345 else if (other->next_field == index)
1346 other->next_field = nextField;
1349 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1350 memmove(fFields + index, fFields + index + 1, size);
1351 fHeader->field_count--;
1352 fFieldsAvailable++;
1354 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1355 ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1356 size = (fHeader->field_count + available) * sizeof(field_header);
1357 field_header *newFields = (field_header *)realloc(fFields, size);
1358 if (size > 0 && newFields == NULL) {
1359 // this is strange, but not really fatal
1360 return B_OK;
1363 fFields = newFields;
1364 fFieldsAvailable = available;
1367 return B_OK;
1371 status_t
1372 BMessage::AddData(const char *name, type_code type, const void *data,
1373 ssize_t numBytes, bool isFixedSize, int32 count)
1375 // Note that the "count" argument is only a hint at how many items
1376 // the caller expects to add to this field. Since we do no item pre-
1377 // allocation, we ignore this argument.
1378 DEBUG_FUNCTION_ENTER;
1379 if (numBytes <= 0 || data == NULL)
1380 return B_BAD_VALUE;
1382 field_header *field = NULL;
1383 status_t result = _FindField(name, type, &field);
1384 if (result == B_NAME_NOT_FOUND)
1385 result = _AddField(name, type, isFixedSize, &field);
1387 if (result < B_OK)
1388 return result;
1390 if (field == NULL)
1391 return B_ERROR;
1393 uint32 offset = field->offset + field->name_length + field->data_size;
1394 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1395 if (field->count) {
1396 ssize_t size = field->data_size / field->count;
1397 if (size != numBytes)
1398 return B_BAD_VALUE;
1401 result = _ResizeData(offset, numBytes);
1402 if (result < B_OK) {
1403 if (field->count == 0)
1404 _RemoveField(field);
1405 return result;
1408 memcpy(fData + offset, data, numBytes);
1409 field->data_size += numBytes;
1410 } else {
1411 int32 change = numBytes + sizeof(uint32);
1412 result = _ResizeData(offset, change);
1413 if (result < B_OK) {
1414 if (field->count == 0)
1415 _RemoveField(field);
1416 return result;
1419 uint32 size = (uint32)numBytes;
1420 memcpy(fData + offset, &size, sizeof(uint32));
1421 memcpy(fData + offset + sizeof(uint32), data, size);
1422 field->data_size += change;
1425 field->count++;
1426 return B_OK;
1430 status_t
1431 BMessage::RemoveData(const char *name, int32 index)
1433 DEBUG_FUNCTION_ENTER;
1434 if (index < 0)
1435 return B_BAD_INDEX;
1437 field_header *field = NULL;
1438 status_t result = _FindField(name, B_ANY_TYPE, &field);
1440 if (result < B_OK)
1441 return result;
1443 if (field == NULL)
1444 return B_ERROR;
1446 if ((uint32)index >= field->count)
1447 return B_BAD_INDEX;
1449 if (field->count == 1)
1450 return _RemoveField(field);
1452 uint32 offset = field->offset + field->name_length;
1453 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1454 ssize_t size = field->data_size / field->count;
1455 result = _ResizeData(offset + index * size, -size);
1456 if (result < B_OK)
1457 return result;
1459 field->data_size -= size;
1460 } else {
1461 uint8 *pointer = fData + offset;
1462 for (int32 i = 0; i < index; i++) {
1463 offset += *(uint32 *)pointer + sizeof(uint32);
1464 pointer = fData + offset;
1467 size_t currentSize = *(uint32 *)pointer + sizeof(uint32);
1468 result = _ResizeData(offset, -currentSize);
1469 if (result < B_OK)
1470 return result;
1472 field->data_size -= currentSize;
1475 field->count--;
1476 return B_OK;
1480 status_t
1481 BMessage::RemoveName(const char *name)
1483 DEBUG_FUNCTION_ENTER;
1484 field_header *field = NULL;
1485 status_t result = _FindField(name, B_ANY_TYPE, &field);
1487 if (result < B_OK)
1488 return result;
1490 if (field == NULL)
1491 return B_ERROR;
1493 return _RemoveField(field);
1497 status_t
1498 BMessage::MakeEmpty()
1500 DEBUG_FUNCTION_ENTER;
1501 _Clear();
1502 _InitHeader();
1503 return B_OK;
1507 status_t
1508 BMessage::FindData(const char *name, type_code type, int32 index,
1509 const void **data, ssize_t *numBytes) const
1511 DEBUG_FUNCTION_ENTER;
1512 if (data == NULL)
1513 return B_BAD_VALUE;
1515 *data = NULL;
1516 field_header *field = NULL;
1517 status_t result = _FindField(name, type, &field);
1519 if (result < B_OK)
1520 return result;
1522 if (field == NULL)
1523 return B_ERROR;
1525 if (index < 0 || (uint32)index >= field->count)
1526 return B_BAD_INDEX;
1528 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1529 size_t bytes = field->data_size / field->count;
1530 *data = fData + field->offset + field->name_length + index * bytes;
1531 if (numBytes != NULL)
1532 *numBytes = bytes;
1533 } else {
1534 uint8 *pointer = fData + field->offset + field->name_length;
1535 for (int32 i = 0; i < index; i++)
1536 pointer += *(uint32 *)pointer + sizeof(uint32);
1538 *data = pointer + sizeof(uint32);
1539 if (numBytes != NULL)
1540 *numBytes = *(uint32 *)pointer;
1543 return B_OK;
1547 status_t
1548 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1549 const void *data, ssize_t numBytes)
1551 DEBUG_FUNCTION_ENTER;
1552 if (numBytes <= 0 || data == NULL)
1553 return B_BAD_VALUE;
1555 field_header *field = NULL;
1556 status_t result = _FindField(name, type, &field);
1558 if (result < B_OK)
1559 return result;
1561 if (field == NULL)
1562 return B_ERROR;
1564 if (index < 0 || (uint32)index >= field->count)
1565 return B_BAD_INDEX;
1567 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1568 ssize_t size = field->data_size / field->count;
1569 if (size != numBytes)
1570 return B_BAD_VALUE;
1572 memcpy(fData + field->offset + field->name_length + index * size, data,
1573 size);
1574 } else {
1575 uint32 offset = field->offset + field->name_length;
1576 uint8 *pointer = fData + offset;
1578 for (int32 i = 0; i < index; i++) {
1579 offset += *(uint32 *)pointer + sizeof(uint32);
1580 pointer = fData + offset;
1583 size_t currentSize = *(uint32 *)pointer;
1584 int32 change = numBytes - currentSize;
1585 result = _ResizeData(offset, change);
1586 if (result < B_OK)
1587 return result;
1589 uint32 newSize = (uint32)numBytes;
1590 memcpy(fData + offset, &newSize, sizeof(uint32));
1591 memcpy(fData + offset + sizeof(uint32), data, newSize);
1592 field->data_size += change;
1595 return B_OK;
1599 bool
1600 BMessage::HasData(const char *name, type_code type, int32 index) const
1602 DEBUG_FUNCTION_ENTER;
1603 field_header *field = NULL;
1604 status_t result = _FindField(name, type, &field);
1606 if (result < B_OK)
1607 return false;
1609 if (field == NULL)
1610 return false;
1612 if (index < 0 || (uint32)index >= field->count)
1613 return false;
1615 return true;
1619 void BMessage::_ReservedMessage1(void) {};
1620 void BMessage::_ReservedMessage2(void) {};
1621 void BMessage::_ReservedMessage3(void) {};
1624 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
1626 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \
1627 status_t \
1628 BMessage::Add##typeName(const char *name, type val) \
1630 return AddData(name, typeCode, &val, sizeof(type), true); \
1633 status_t \
1634 BMessage::Find##typeName(const char *name, type *p) const \
1636 void *ptr = NULL; \
1637 ssize_t bytes = 0; \
1638 status_t error = B_OK; \
1640 *p = type(); \
1641 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \
1643 if (error == B_OK) \
1644 memcpy(p, ptr, sizeof(type)); \
1646 return error; \
1649 status_t \
1650 BMessage::Find##typeName(const char *name, int32 index, type *p) const \
1652 void *ptr = NULL; \
1653 ssize_t bytes = 0; \
1654 status_t error = B_OK; \
1656 *p = type(); \
1657 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \
1659 if (error == B_OK) \
1660 memcpy(p, ptr, sizeof(type)); \
1662 return error; \
1665 status_t \
1666 BMessage::Replace##typeName(const char *name, type val) \
1668 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \
1671 status_t \
1672 BMessage::Replace##typeName(const char *name, int32 index, type val) \
1674 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \
1677 bool \
1678 BMessage::Has##typeName(const char *name, int32 index) const \
1680 return HasData(name, typeCode, index); \
1683 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
1684 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
1685 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
1686 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
1687 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
1688 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
1689 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
1690 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
1691 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
1692 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
1693 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
1694 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
1695 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
1697 #undef DEFINE_FUNCTIONS
1699 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \
1700 bool \
1701 BMessage::Has##typeName(const char *name, int32 index) const \
1703 return HasData(name, typeCode, index); \
1706 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
1707 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
1708 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
1709 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
1710 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
1712 #undef DEFINE_HAS_FUNCTION
1714 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \
1715 type \
1716 BMessage::Find##typeName(const char *name, int32 index) const \
1718 type val = initialize; \
1719 Find##typeName(name, index, &val); \
1720 return val; \
1723 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
1724 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
1725 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
1726 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
1727 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
1728 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
1729 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
1730 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
1731 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
1732 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
1734 #undef DEFINE_LAZY_FIND_FUNCTION
1736 status_t
1737 BMessage::AddString(const char *name, const char *string)
1739 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
1743 status_t
1744 BMessage::AddString(const char *name, const BString &string)
1746 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
1750 status_t
1751 BMessage::AddStrings(const char *name, const BStringList &list)
1753 int32 count = list.CountStrings();
1754 for (int32 i = 0; i < count; i++) {
1755 status_t error = AddString(name, list.StringAt(i));
1756 if (error != B_OK)
1757 return error;
1760 return B_OK;
1764 status_t
1765 BMessage::AddPointer(const char *name, const void *pointer)
1767 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
1771 status_t
1772 BMessage::AddMessenger(const char *name, BMessenger messenger)
1774 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
1778 status_t
1779 BMessage::AddRef(const char *name, const entry_ref *ref)
1781 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
1782 char buffer[size];
1784 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
1786 if (error >= B_OK)
1787 error = AddData(name, B_REF_TYPE, buffer, size, false);
1789 return error;
1793 status_t
1794 BMessage::AddMessage(const char *name, const BMessage *message)
1796 if (message == NULL)
1797 return B_BAD_VALUE;
1799 // TODO: This and the following functions waste time by allocating and
1800 // copying an extra buffer. Functions can be added that return a direct
1801 // pointer into the message.
1803 char stackBuffer[16384];
1804 ssize_t size = message->FlattenedSize();
1806 char* buffer;
1807 if (size > (ssize_t)sizeof(stackBuffer)) {
1808 buffer = (char *)malloc(size);
1809 if (buffer == NULL)
1810 return B_NO_MEMORY;
1811 } else
1812 buffer = stackBuffer;
1814 status_t error = message->Flatten(buffer, size);
1816 if (error >= B_OK)
1817 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
1819 if (buffer != stackBuffer)
1820 free(buffer);
1822 return error;
1826 status_t
1827 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
1829 if (object == NULL)
1830 return B_BAD_VALUE;
1832 char stackBuffer[16384];
1833 ssize_t size = object->FlattenedSize();
1835 char* buffer;
1836 if (size > (ssize_t)sizeof(stackBuffer)) {
1837 buffer = (char *)malloc(size);
1838 if (buffer == NULL)
1839 return B_NO_MEMORY;
1840 } else
1841 buffer = stackBuffer;
1843 status_t error = object->Flatten(buffer, size);
1845 if (error >= B_OK)
1846 error = AddData(name, object->TypeCode(), buffer, size, false);
1848 if (buffer != stackBuffer)
1849 free(buffer);
1851 return error;
1855 status_t
1856 BMessage::FindString(const char *name, const char **string) const
1858 return FindString(name, 0, string);
1862 status_t
1863 BMessage::FindString(const char *name, int32 index, const char **string) const
1865 ssize_t bytes;
1866 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
1870 status_t
1871 BMessage::FindString(const char *name, BString *string) const
1873 return FindString(name, 0, string);
1877 status_t
1878 BMessage::FindString(const char *name, int32 index, BString *string) const
1880 if (string == NULL)
1881 return B_BAD_VALUE;
1883 const char *cstr;
1884 status_t error = FindString(name, index, &cstr);
1885 if (error < B_OK)
1886 return error;
1888 *string = cstr;
1889 return B_OK;
1893 status_t
1894 BMessage::FindStrings(const char *name, BStringList *list) const
1896 if (list == NULL)
1897 return B_BAD_VALUE;
1899 list->MakeEmpty();
1901 // get the number of items
1902 type_code type;
1903 int32 count;
1904 if (GetInfo(name, &type, &count) != B_OK)
1905 return B_NAME_NOT_FOUND;
1907 if (type != B_STRING_TYPE)
1908 return B_BAD_DATA;
1910 for (int32 i = 0; i < count; i++) {
1911 BString string;
1912 status_t error = FindString(name, i, &string);
1913 if (error != B_OK)
1914 return error;
1915 if (!list->Add(string))
1916 return B_NO_MEMORY;
1919 return B_OK;
1923 status_t
1924 BMessage::FindPointer(const char *name, void **pointer) const
1926 return FindPointer(name, 0, pointer);
1930 status_t
1931 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
1933 if (pointer == NULL)
1934 return B_BAD_VALUE;
1936 void **data = NULL;
1937 ssize_t size = 0;
1938 status_t error = FindData(name, B_POINTER_TYPE, index,
1939 (const void **)&data, &size);
1941 if (error == B_OK)
1942 *pointer = *data;
1943 else
1944 *pointer = NULL;
1946 return error;
1950 status_t
1951 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
1953 return FindMessenger(name, 0, messenger);
1957 status_t
1958 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
1959 const
1961 if (messenger == NULL)
1962 return B_BAD_VALUE;
1964 void *data = NULL;
1965 ssize_t size = 0;
1966 status_t error = FindData(name, B_MESSENGER_TYPE, index,
1967 (const void **)&data, &size);
1969 if (error == B_OK)
1970 memcpy(messenger, data, sizeof(BMessenger));
1971 else
1972 *messenger = BMessenger();
1974 return error;
1978 status_t
1979 BMessage::FindRef(const char *name, entry_ref *ref) const
1981 return FindRef(name, 0, ref);
1985 status_t
1986 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
1988 if (ref == NULL)
1989 return B_BAD_VALUE;
1991 void *data = NULL;
1992 ssize_t size = 0;
1993 status_t error = FindData(name, B_REF_TYPE, index,
1994 (const void **)&data, &size);
1996 if (error == B_OK)
1997 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
1998 else
1999 *ref = entry_ref();
2001 return error;
2005 status_t
2006 BMessage::FindMessage(const char *name, BMessage *message) const
2008 return FindMessage(name, 0, message);
2012 status_t
2013 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2015 if (message == NULL)
2016 return B_BAD_VALUE;
2018 void *data = NULL;
2019 ssize_t size = 0;
2020 status_t error = FindData(name, B_MESSAGE_TYPE, index,
2021 (const void **)&data, &size);
2023 if (error == B_OK)
2024 error = message->Unflatten((const char *)data);
2025 else
2026 *message = BMessage();
2028 return error;
2032 status_t
2033 BMessage::FindFlat(const char *name, BFlattenable *object) const
2035 return FindFlat(name, 0, object);
2039 status_t
2040 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2042 if (object == NULL)
2043 return B_BAD_VALUE;
2045 void *data = NULL;
2046 ssize_t numBytes = 0;
2047 status_t error = FindData(name, object->TypeCode(), index,
2048 (const void **)&data, &numBytes);
2050 if (error == B_OK)
2051 error = object->Unflatten(object->TypeCode(), data, numBytes);
2053 return error;
2057 status_t
2058 BMessage::FindData(const char *name, type_code type, const void **data,
2059 ssize_t *numBytes) const
2061 return FindData(name, type, 0, data, numBytes);
2065 status_t
2066 BMessage::ReplaceString(const char *name, const char *string)
2068 if (string == NULL)
2069 return B_BAD_VALUE;
2071 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2075 status_t
2076 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2078 if (string == NULL)
2079 return B_BAD_VALUE;
2081 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2085 status_t
2086 BMessage::ReplaceString(const char *name, const BString &string)
2088 return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2089 string.Length() + 1);
2093 status_t
2094 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2096 return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2097 string.Length() + 1);
2101 status_t
2102 BMessage::ReplacePointer(const char *name, const void *pointer)
2104 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2108 status_t
2109 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2111 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2115 status_t
2116 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2118 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2119 sizeof(BMessenger));
2123 status_t
2124 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2126 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2127 sizeof(BMessenger));
2131 status_t
2132 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2134 return ReplaceRef(name, 0, ref);
2138 status_t
2139 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2141 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2142 char buffer[size];
2144 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2146 if (error >= B_OK)
2147 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2149 return error;
2153 status_t
2154 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2156 return ReplaceMessage(name, 0, message);
2160 status_t
2161 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2163 if (message == NULL)
2164 return B_BAD_VALUE;
2166 ssize_t size = message->FlattenedSize();
2167 char buffer[size];
2169 status_t error = message->Flatten(buffer, size);
2171 if (error >= B_OK)
2172 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2174 return error;
2178 status_t
2179 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2181 return ReplaceFlat(name, 0, object);
2185 status_t
2186 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2188 if (object == NULL)
2189 return B_BAD_VALUE;
2191 ssize_t size = object->FlattenedSize();
2192 char buffer[size];
2194 status_t error = object->Flatten(buffer, size);
2196 if (error >= B_OK)
2197 error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2199 return error;
2203 status_t
2204 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2205 ssize_t numBytes)
2207 return ReplaceData(name, type, 0, data, numBytes);
2211 bool
2212 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2214 return HasFlat(name, 0, object);
2218 bool
2219 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2220 const
2222 return HasData(name, object->TypeCode(), index);