BPicture: Fix archive constructor.
[haiku.git] / src / kits / app / Message.cpp
blobd1824937e74b22761b94a156d67adfb16fed27ac
1 /*
2 * Copyright 2005-2015 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 <DirectMessageTarget.h>
16 #include <MessengerPrivate.h>
17 #include <TokenSpace.h>
18 #include <util/KMessage.h>
20 #include <Alignment.h>
21 #include <Application.h>
22 #include <AppMisc.h>
23 #include <BlockCache.h>
24 #include <Entry.h>
25 #include <MessageQueue.h>
26 #include <Messenger.h>
27 #include <Path.h>
28 #include <Point.h>
29 #include <Rect.h>
30 #include <String.h>
31 #include <StringList.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
39 #include "tracing_config.h"
40 // kernel tracing configuration
42 //#define VERBOSE_DEBUG_OUTPUT
43 #ifdef VERBOSE_DEBUG_OUTPUT
44 #define DEBUG_FUNCTION_ENTER \
45 debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
46 " data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
47 find_thread(NULL), this, fHeader, fFields, fData, what, (char*)&what, \
48 __LINE__, __PRETTY_FUNCTION__);
50 #define DEBUG_FUNCTION_ENTER2 \
51 debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
52 __LINE__, __PRETTY_FUNCTION__);
53 #else
54 #define DEBUG_FUNCTION_ENTER /* nothing */
55 #define DEBUG_FUNCTION_ENTER2 /* nothing */
56 #endif
58 #if BMESSAGE_TRACING
59 # define KTRACE(format...) ktrace_printf(format)
60 #else
61 # define KTRACE(format...) ;
62 #endif
65 const char* B_SPECIFIER_ENTRY = "specifiers";
66 const char* B_PROPERTY_ENTRY = "property";
67 const char* B_PROPERTY_NAME_ENTRY = "name";
70 static status_t handle_reply(port_id replyPort, int32* pCode,
71 bigtime_t timeout, BMessage* reply);
74 extern "C" {
75 // private os function to set the owning team of an area
76 status_t _kern_transfer_area(area_id area, void** _address,
77 uint32 addressSpec, team_id target);
81 BBlockCache* BMessage::sMsgCache = NULL;
82 port_id BMessage::sReplyPorts[sNumReplyPorts];
83 int32 BMessage::sReplyPortInUse[sNumReplyPorts];
86 template<typename Type>
87 static void
88 print_to_stream_type(uint8* pointer)
90 Type* item = (Type*)pointer;
91 item->PrintToStream();
95 template<typename Type>
96 static void
97 print_type(const char* format, uint8* pointer)
99 Type* item = (Type*)pointer;
100 printf(format,* item,* item);
104 template<typename Type>
105 static void
106 print_type3(const char* format, uint8* pointer)
108 Type* item = (Type*)pointer;
109 printf(format, *item, *item, *item);
113 static status_t
114 handle_reply(port_id replyPort, int32* _code, bigtime_t timeout,
115 BMessage* reply)
117 DEBUG_FUNCTION_ENTER2;
118 ssize_t size;
119 do {
120 size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
121 } while (size == B_INTERRUPTED);
123 if (size < 0)
124 return size;
126 status_t result;
127 char* buffer = (char*)malloc(size);
128 if (buffer == NULL)
129 return B_NO_MEMORY;
131 do {
132 result = read_port(replyPort, _code, buffer, size);
133 } while (result == B_INTERRUPTED);
135 if (result < 0 || *_code != kPortMessageCode) {
136 free(buffer);
137 return result < 0 ? result : B_ERROR;
140 result = reply->Unflatten(buffer);
141 free(buffer);
142 return result;
146 // #pragma mark -
149 BMessage::BMessage()
151 DEBUG_FUNCTION_ENTER;
152 _InitCommon(true);
156 BMessage::BMessage(BMessage* other)
158 DEBUG_FUNCTION_ENTER;
159 _InitCommon(false);
160 *this = *other;
164 BMessage::BMessage(uint32 _what)
166 DEBUG_FUNCTION_ENTER;
167 _InitCommon(true);
168 fHeader->what = what = _what;
172 BMessage::BMessage(const BMessage& other)
174 DEBUG_FUNCTION_ENTER;
175 _InitCommon(false);
176 *this = other;
180 BMessage::~BMessage()
182 DEBUG_FUNCTION_ENTER;
183 _Clear();
187 BMessage&
188 BMessage::operator=(const BMessage& other)
190 DEBUG_FUNCTION_ENTER;
192 if (this == &other)
193 return *this;
195 _Clear();
197 fHeader = (message_header*)malloc(sizeof(message_header));
198 if (fHeader == NULL)
199 return *this;
201 if (other.fHeader == NULL)
202 return *this;
204 memcpy(fHeader, other.fHeader, sizeof(message_header));
206 // Clear some header flags inherited from the original message that don't
207 // apply to the clone.
208 fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
209 | MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
210 | MESSAGE_FLAG_PASS_BY_AREA);
211 // Note, that BeOS R5 seems to keep the reply info.
213 if (fHeader->field_count > 0) {
214 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
215 if (other.fFields != NULL)
216 fFields = (field_header*)malloc(fieldsSize);
218 if (fFields == NULL) {
219 fHeader->field_count = 0;
220 fHeader->data_size = 0;
221 } else if (other.fFields != NULL)
222 memcpy(fFields, other.fFields, fieldsSize);
225 if (fHeader->data_size > 0) {
226 if (other.fData != NULL)
227 fData = (uint8*)malloc(fHeader->data_size);
229 if (fData == NULL) {
230 fHeader->field_count = 0;
231 free(fFields);
232 fFields = NULL;
233 } else if (other.fData != NULL)
234 memcpy(fData, other.fData, fHeader->data_size);
237 fHeader->what = what = other.what;
238 fHeader->message_area = -1;
239 fFieldsAvailable = 0;
240 fDataAvailable = 0;
242 return *this;
246 void*
247 BMessage::operator new(size_t size)
249 DEBUG_FUNCTION_ENTER2;
250 return sMsgCache->Get(size);
254 void*
255 BMessage::operator new(size_t size, const std::nothrow_t& noThrow)
257 DEBUG_FUNCTION_ENTER2;
258 return sMsgCache->Get(size);
262 void*
263 BMessage::operator new(size_t, void* pointer)
265 DEBUG_FUNCTION_ENTER2;
266 return pointer;
270 void
271 BMessage::operator delete(void* pointer, size_t size)
273 DEBUG_FUNCTION_ENTER2;
274 if (pointer == NULL)
275 return;
276 sMsgCache->Save(pointer, size);
280 bool
281 BMessage::HasSameData(const BMessage& other, bool ignoreFieldOrder,
282 bool deep) const
284 if (this == &other)
285 return true;
287 if (fHeader == NULL)
288 return other.fHeader == NULL;
290 if (fHeader->field_count != other.fHeader->field_count)
291 return false;
293 for (uint32 i = 0; i < fHeader->field_count; i++) {
294 field_header* field = &fFields[i];
295 field_header* otherField = NULL;
297 const char* name = (const char*)fData + field->offset;
298 if (ignoreFieldOrder) {
299 if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
300 return false;
301 } else {
302 otherField = &other.fFields[i];
303 if (otherField->name_length != field->name_length)
304 return false;
306 const char* otherName = (const char*)other.fData
307 + otherField->offset;
308 if (strncmp(name, otherName, field->name_length) != 0)
309 return false;
312 if (otherField->type != field->type
313 || otherField->count != field->count) {
314 return false;
317 uint8* data = fData + field->offset + field->name_length;
318 uint8* otherData = other.fData + otherField->offset
319 + otherField->name_length;
321 bool needsMemCompare = true;
322 if (deep && field->type == B_MESSAGE_TYPE) {
323 BMessage message, otherMessage;
324 if (message.Unflatten((const char*)data) == B_OK
325 && otherMessage.Unflatten((const char*)otherData) == B_OK) {
326 if (!message.HasSameData(ignoreFieldOrder, deep))
327 return false;
328 needsMemCompare = false;
332 if (needsMemCompare) {
333 if (otherField->data_size != field->data_size)
334 return false;
335 if (memcmp(data, otherData, field->data_size) != 0)
336 return false;
340 return true;
344 status_t
345 BMessage::_InitCommon(bool initHeader)
347 DEBUG_FUNCTION_ENTER;
348 what = 0;
350 fHeader = NULL;
351 fFields = NULL;
352 fData = NULL;
354 fFieldsAvailable = 0;
355 fDataAvailable = 0;
357 fOriginal = NULL;
358 fQueueLink = NULL;
360 fArchivingPointer = NULL;
362 if (initHeader)
363 return _InitHeader();
365 return B_OK;
369 status_t
370 BMessage::_InitHeader()
372 DEBUG_FUNCTION_ENTER;
373 if (fHeader == NULL) {
374 fHeader = (message_header*)malloc(sizeof(message_header));
375 if (fHeader == NULL)
376 return B_NO_MEMORY;
379 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
381 fHeader->format = MESSAGE_FORMAT_HAIKU;
382 fHeader->flags = MESSAGE_FLAG_VALID;
383 fHeader->what = what;
384 fHeader->current_specifier = -1;
385 fHeader->message_area = -1;
387 fHeader->target = B_NULL_TOKEN;
388 fHeader->reply_target = B_NULL_TOKEN;
389 fHeader->reply_port = -1;
390 fHeader->reply_team = -1;
392 // initializing the hash table to -1 because 0 is a valid index
393 fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
394 memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
395 return B_OK;
399 status_t
400 BMessage::_Clear()
402 DEBUG_FUNCTION_ENTER;
403 if (fHeader != NULL) {
404 // We're going to destroy all information of this message. If there's
405 // still someone waiting for a reply to this message, we have to send
406 // one now.
407 if (IsSourceWaiting())
408 SendReply(B_NO_REPLY);
410 if (fHeader->message_area >= 0)
411 _Dereference();
413 free(fHeader);
414 fHeader = NULL;
417 free(fFields);
418 fFields = NULL;
419 free(fData);
420 fData = NULL;
422 fArchivingPointer = NULL;
424 fFieldsAvailable = 0;
425 fDataAvailable = 0;
427 delete fOriginal;
428 fOriginal = NULL;
430 return B_OK;
434 status_t
435 BMessage::GetInfo(type_code typeRequested, int32 index, char** nameFound,
436 type_code* typeFound, int32* countFound) const
438 DEBUG_FUNCTION_ENTER;
439 if (fHeader == NULL)
440 return B_NO_INIT;
442 if (index < 0 || (uint32)index >= fHeader->field_count)
443 return B_BAD_INDEX;
445 if (typeRequested == B_ANY_TYPE) {
446 if (nameFound != NULL)
447 *nameFound = (char*)fData + fFields[index].offset;
448 if (typeFound != NULL)
449 *typeFound = fFields[index].type;
450 if (countFound != NULL)
451 *countFound = fFields[index].count;
452 return B_OK;
455 int32 counter = -1;
456 field_header* field = fFields;
457 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
458 if (field->type == typeRequested)
459 counter++;
461 if (counter == index) {
462 if (nameFound != NULL)
463 *nameFound = (char*)fData + field->offset;
464 if (typeFound != NULL)
465 *typeFound = field->type;
466 if (countFound != NULL)
467 *countFound = field->count;
468 return B_OK;
472 if (counter == -1)
473 return B_BAD_TYPE;
475 return B_BAD_INDEX;
479 status_t
480 BMessage::GetInfo(const char* name, type_code* typeFound,
481 int32* countFound) const
483 DEBUG_FUNCTION_ENTER;
484 if (countFound != NULL)
485 *countFound = 0;
487 field_header* field = NULL;
488 status_t result = _FindField(name, B_ANY_TYPE, &field);
489 if (result != B_OK)
490 return result;
492 if (typeFound != NULL)
493 *typeFound = field->type;
494 if (countFound != NULL)
495 *countFound = field->count;
497 return B_OK;
501 status_t
502 BMessage::GetInfo(const char* name, type_code* typeFound, bool* fixedSize)
503 const
505 DEBUG_FUNCTION_ENTER;
506 field_header* field = NULL;
507 status_t result = _FindField(name, B_ANY_TYPE, &field);
508 if (result != B_OK)
509 return result;
511 if (typeFound != NULL)
512 *typeFound = field->type;
513 if (fixedSize != NULL)
514 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
516 return B_OK;
520 status_t
521 BMessage::GetInfo(const char* name, type_code* typeFound, int32* countFound,
522 bool* fixedSize) const
524 DEBUG_FUNCTION_ENTER;
525 field_header* field = NULL;
526 status_t result = _FindField(name, B_ANY_TYPE, &field);
527 if (result != B_OK)
528 return result;
530 if (typeFound != NULL)
531 *typeFound = field->type;
532 if (countFound != NULL)
533 *countFound = field->count;
534 if (fixedSize != NULL)
535 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
537 return B_OK;
541 int32
542 BMessage::CountNames(type_code type) const
544 DEBUG_FUNCTION_ENTER;
545 if (fHeader == NULL)
546 return 0;
548 if (type == B_ANY_TYPE)
549 return fHeader->field_count;
551 int32 count = 0;
552 field_header* field = fFields;
553 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
554 if (field->type == type)
555 count++;
558 return count;
562 bool
563 BMessage::IsEmpty() const
565 DEBUG_FUNCTION_ENTER;
566 return fHeader == NULL || fHeader->field_count == 0;
570 bool
571 BMessage::IsSystem() const
573 DEBUG_FUNCTION_ENTER;
574 char a = char(what >> 24);
575 char b = char(what >> 16);
576 char c = char(what >> 8);
577 char d = char(what);
579 // The BeBook says:
580 // ... we've adopted a strict convention for assigning values to all
581 // Be-defined constants. The value assigned will always be formed by
582 // combining four characters into a multicharacter constant, with the
583 // characters limited to uppercase letters and the underbar
584 // Between that and what's in AppDefs.h, this algo seems like a safe bet:
585 if (a == '_' && isupper(b) && isupper(c) && isupper(d))
586 return true;
588 return false;
592 bool
593 BMessage::IsReply() const
595 DEBUG_FUNCTION_ENTER;
596 return fHeader != NULL && (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
600 void
601 BMessage::PrintToStream() const
603 _PrintToStream("");
604 printf("}\n");
608 void
609 BMessage::_PrintToStream(const char* indent) const
611 DEBUG_FUNCTION_ENTER;
613 int32 value = B_BENDIAN_TO_HOST_INT32(what);
614 printf("BMessage(");
615 if (isprint(*(char*)&value))
616 printf("'%.4s'", (char*)&value);
617 else
618 printf("0x%" B_PRIx32, what);
619 printf(") {\n");
621 if (fHeader == NULL || fFields == NULL || fData == NULL)
622 return;
624 field_header* field = fFields;
625 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
626 value = B_BENDIAN_TO_HOST_INT32(field->type);
627 ssize_t size = 0;
628 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
629 size = field->data_size / field->count;
631 uint8* pointer = fData + field->offset + field->name_length;
632 for (uint32 j = 0; j < field->count; j++) {
633 if (field->count == 1) {
634 printf("%s %s = ", indent,
635 (char*)(fData + field->offset));
636 } else {
637 printf("%s %s[%" B_PRIu32 "] = ", indent,
638 (char*)(fData + field->offset), j);
641 if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) {
642 size = *(uint32*)pointer;
643 pointer += sizeof(uint32);
646 switch (field->type) {
647 case B_RECT_TYPE:
648 print_to_stream_type<BRect>(pointer);
649 break;
651 case B_POINT_TYPE:
652 print_to_stream_type<BPoint>(pointer);
653 break;
655 case B_STRING_TYPE:
656 printf("string(\"%.*s\", %ld bytes)\n", (int)size,
657 (char*)pointer, (long)size);
658 break;
660 case B_INT8_TYPE:
661 print_type3<int8>("int8(0x%hx or %d or '%c')\n",
662 pointer);
663 break;
665 case B_UINT8_TYPE:
666 print_type3<uint8>("uint8(0x%hx or %u or '%c')\n",
667 pointer);
668 break;
670 case B_INT16_TYPE:
671 print_type<int16>("int16(0x%x or %d)\n", pointer);
672 break;
674 case B_UINT16_TYPE:
675 print_type<uint16>("uint16(0x%x or %u\n", pointer);
676 break;
678 case B_INT32_TYPE:
679 print_type<int32>("int32(0x%lx or %ld)\n", pointer);
680 break;
682 case B_UINT32_TYPE:
683 print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
684 break;
686 case B_INT64_TYPE:
687 print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
688 break;
690 case B_UINT64_TYPE:
691 print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
692 break;
694 case B_BOOL_TYPE:
695 printf("bool(%s)\n", *((bool*)pointer) != 0
696 ? "true" : "false");
697 break;
699 case B_FLOAT_TYPE:
700 print_type<float>("float(%.4f)\n", pointer);
701 break;
703 case B_DOUBLE_TYPE:
704 print_type<double>("double(%.8f)\n", pointer);
705 break;
707 case B_REF_TYPE:
709 entry_ref ref;
710 BPrivate::entry_ref_unflatten(&ref, (char*)pointer, size);
712 printf("entry_ref(device=%d, directory=%" B_PRIdINO
713 ", name=\"%s\", ", (int)ref.device, ref.directory,
714 ref.name);
716 BPath path(&ref);
717 printf("path=\"%s\")\n", path.Path());
718 break;
721 case B_MESSAGE_TYPE:
723 char buffer[1024];
724 snprintf(buffer, sizeof(buffer), "%s ", indent);
726 BMessage message;
727 status_t result = message.Unflatten((const char*)pointer);
728 if (result != B_OK) {
729 printf("failed unflatten: %s\n", strerror(result));
730 break;
733 message._PrintToStream(buffer);
734 printf("%s }\n", indent);
735 break;
738 default:
740 printf("(type = '%.4s')(size = %ld)\n", (char*)&value,
741 (long)size);
742 break;
746 pointer += size;
752 status_t
753 BMessage::Rename(const char* oldEntry, const char* newEntry)
755 DEBUG_FUNCTION_ENTER;
756 if (oldEntry == NULL || newEntry == NULL)
757 return B_BAD_VALUE;
759 if (fHeader == NULL)
760 return B_NO_INIT;
762 status_t result;
763 if (fHeader->message_area >= 0) {
764 result = _CopyForWrite();
765 if (result != B_OK)
766 return result;
769 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
770 int32* nextField = &fHeader->hash_table[hash];
772 while (*nextField >= 0) {
773 field_header* field = &fFields[*nextField];
775 if (strncmp((const char*)(fData + field->offset), oldEntry,
776 field->name_length) == 0) {
777 // nextField points to the field for oldEntry, save it and unlink
778 int32 index = *nextField;
779 *nextField = field->next_field;
780 field->next_field = -1;
782 hash = _HashName(newEntry) % fHeader->hash_table_size;
783 nextField = &fHeader->hash_table[hash];
784 while (*nextField >= 0)
785 nextField = &fFields[*nextField].next_field;
786 *nextField = index;
788 int32 newLength = strlen(newEntry) + 1;
789 result = _ResizeData(field->offset + 1,
790 newLength - field->name_length);
791 if (result != B_OK)
792 return result;
794 memcpy(fData + field->offset, newEntry, newLength);
795 field->name_length = newLength;
796 return B_OK;
799 nextField = &field->next_field;
802 return B_NAME_NOT_FOUND;
806 bool
807 BMessage::WasDelivered() const
809 DEBUG_FUNCTION_ENTER;
810 return fHeader != NULL
811 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
815 bool
816 BMessage::IsSourceWaiting() const
818 DEBUG_FUNCTION_ENTER;
819 return fHeader != NULL
820 && (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
821 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
825 bool
826 BMessage::IsSourceRemote() const
828 DEBUG_FUNCTION_ENTER;
829 return fHeader != NULL
830 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0
831 && fHeader->reply_team != BPrivate::current_team();
835 BMessenger
836 BMessage::ReturnAddress() const
838 DEBUG_FUNCTION_ENTER;
839 if (fHeader == NULL || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
840 return BMessenger();
842 BMessenger messenger;
843 BMessenger::Private(messenger).SetTo(fHeader->reply_team,
844 fHeader->reply_port, fHeader->reply_target);
845 return messenger;
849 const BMessage*
850 BMessage::Previous() const
852 DEBUG_FUNCTION_ENTER;
853 /* ToDo: test if the "_previous_" field is used in R5 */
854 if (fOriginal == NULL) {
855 fOriginal = new BMessage();
857 if (FindMessage("_previous_", fOriginal) != B_OK) {
858 delete fOriginal;
859 fOriginal = NULL;
863 return fOriginal;
867 bool
868 BMessage::WasDropped() const
870 DEBUG_FUNCTION_ENTER;
871 return fHeader != NULL
872 && (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
876 BPoint
877 BMessage::DropPoint(BPoint* offset) const
879 DEBUG_FUNCTION_ENTER;
880 if (offset != NULL)
881 *offset = FindPoint("_drop_offset_");
883 return FindPoint("_drop_point_");
887 status_t
888 BMessage::SendReply(uint32 command, BHandler* replyTo)
890 DEBUG_FUNCTION_ENTER;
891 BMessage message(command);
892 return SendReply(&message, replyTo);
896 status_t
897 BMessage::SendReply(BMessage* reply, BHandler* replyTo, bigtime_t timeout)
899 DEBUG_FUNCTION_ENTER;
900 BMessenger messenger(replyTo);
901 return SendReply(reply, messenger, timeout);
905 status_t
906 BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
908 DEBUG_FUNCTION_ENTER;
909 if (fHeader == NULL)
910 return B_NO_INIT;
912 BMessenger messenger;
913 BMessenger::Private messengerPrivate(messenger);
914 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
915 fHeader->reply_target);
916 if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0)
917 reply->fHeader->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE;
919 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
920 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
921 return B_DUPLICATE_REPLY;
923 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
924 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
925 status_t result = messenger.SendMessage(reply, replyTo, timeout);
926 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
928 if (result != B_OK && set_port_owner(messengerPrivate.Port(),
929 messengerPrivate.Team()) == B_BAD_TEAM_ID) {
930 delete_port(messengerPrivate.Port());
933 return result;
936 // no reply required
937 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
938 return B_BAD_REPLY;
940 reply->AddMessage("_previous_", this);
941 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
942 status_t result = messenger.SendMessage(reply, replyTo, timeout);
943 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
944 reply->RemoveName("_previous_");
945 return result;
949 status_t
950 BMessage::SendReply(uint32 command, BMessage* replyToReply)
952 DEBUG_FUNCTION_ENTER;
953 BMessage message(command);
954 return SendReply(&message, replyToReply);
958 status_t
959 BMessage::SendReply(BMessage* reply, BMessage* replyToReply,
960 bigtime_t sendTimeout, bigtime_t replyTimeout)
962 DEBUG_FUNCTION_ENTER;
963 if (fHeader == NULL)
964 return B_NO_INIT;
966 BMessenger messenger;
967 BMessenger::Private messengerPrivate(messenger);
968 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
969 fHeader->reply_target);
971 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
972 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
973 return B_DUPLICATE_REPLY;
975 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
976 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
977 status_t result = messenger.SendMessage(reply, replyToReply,
978 sendTimeout, replyTimeout);
979 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
981 if (result != B_OK) {
982 if (set_port_owner(messengerPrivate.Port(),
983 messengerPrivate.Team()) == B_BAD_TEAM_ID) {
984 delete_port(messengerPrivate.Port());
988 return result;
991 // no reply required
992 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
993 return B_BAD_REPLY;
995 reply->AddMessage("_previous_", this);
996 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY
997 | (fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE);
998 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
999 replyTimeout);
1000 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
1001 reply->RemoveName("_previous_");
1002 return result;
1006 ssize_t
1007 BMessage::FlattenedSize() const
1009 DEBUG_FUNCTION_ENTER;
1010 if (fHeader == NULL)
1011 return B_NO_INIT;
1013 return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
1014 + fHeader->data_size;
1018 status_t
1019 BMessage::Flatten(char* buffer, ssize_t size) const
1021 DEBUG_FUNCTION_ENTER;
1022 if (buffer == NULL || size < 0)
1023 return B_BAD_VALUE;
1025 if (fHeader == NULL)
1026 return B_NO_INIT;
1028 if (size < FlattenedSize())
1029 return B_BUFFER_OVERFLOW;
1031 /* we have to sync the what code as it is a public member */
1032 fHeader->what = what;
1034 memcpy(buffer, fHeader, sizeof(message_header));
1035 buffer += sizeof(message_header);
1037 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1038 memcpy(buffer, fFields, fieldsSize);
1039 buffer += fieldsSize;
1041 memcpy(buffer, fData, fHeader->data_size);
1043 return B_OK;
1047 status_t
1048 BMessage::Flatten(BDataIO* stream, ssize_t* size) const
1050 DEBUG_FUNCTION_ENTER;
1051 if (stream == NULL)
1052 return B_BAD_VALUE;
1054 if (fHeader == NULL)
1055 return B_NO_INIT;
1057 /* we have to sync the what code as it is a public member */
1058 fHeader->what = what;
1060 ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
1061 if (result1 != sizeof(message_header))
1062 return result1 < 0 ? result1 : B_ERROR;
1064 ssize_t result2 = 0;
1065 if (fHeader->field_count > 0) {
1066 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1067 result2 = stream->Write(fFields, fieldsSize);
1068 if (result2 != fieldsSize)
1069 return result2 < 0 ? result2 : B_ERROR;
1072 ssize_t result3 = 0;
1073 if (fHeader->data_size > 0) {
1074 result3 = stream->Write(fData, fHeader->data_size);
1075 if (result3 != (ssize_t)fHeader->data_size)
1076 return result3 < 0 ? result3 : B_ERROR;
1079 if (size)
1080 *size = result1 + result2 + result3;
1082 return B_OK;
1086 /* The concept of message sending by area:
1088 The traditional way of sending a message is to send it by flattening it to
1089 a buffer, pushing it through a port, reading it into the outputbuffer and
1090 unflattening it from there (copying the data again). While this works ok
1091 for small messages it does not make any sense for larger ones and may even
1092 hit some port capacity limit.
1093 Often in the life of a BMessage, it will be sent to someone. Almost as
1094 often the one receiving the message will not need to change the message
1095 in any way, but uses it "read only" to get information from it. This means
1096 that all that copying is pretty pointless in the first place since we
1097 could simply pass the original buffers on.
1098 It's obviously not exactly as simple as this, since we cannot just use the
1099 memory of one application in another - but we can share areas with
1100 eachother.
1101 Therefore instead of flattening into a buffer, we copy the message data
1102 into an area, put this information into the message header and only push
1103 this through the port. The receiving looper then builds a BMessage from
1104 the header, that only references the data in the area (not copying it),
1105 allowing read only access to it.
1106 Only if write access is necessary the message will be copyed from the area
1107 to its own buffers (like in the unflatten step before).
1108 The double copying is reduced to a single copy in most cases and we safe
1109 the slower route of moving the data through a port.
1110 Additionally we save us the reference counting with the use of areas that
1111 are reference counted internally. So we don't have to worry about leaving
1112 an area behind or deleting one that is still in use.
1115 status_t
1116 BMessage::_FlattenToArea(message_header** _header) const
1118 DEBUG_FUNCTION_ENTER;
1119 if (fHeader == NULL)
1120 return B_NO_INIT;
1122 message_header* header = (message_header*)malloc(sizeof(message_header));
1123 if (header == NULL)
1124 return B_NO_MEMORY;
1126 memcpy(header, fHeader, sizeof(message_header));
1128 header->what = what;
1129 header->message_area = -1;
1130 *_header = header;
1132 if (header->field_count == 0 && header->data_size == 0)
1133 return B_OK;
1135 char* address = NULL;
1136 size_t fieldsSize = header->field_count * sizeof(field_header);
1137 size_t size = fieldsSize + header->data_size;
1138 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
1139 area_id area = create_area("BMessage data", (void**)&address,
1140 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1142 if (area < 0) {
1143 free(header);
1144 *_header = NULL;
1145 return area;
1148 memcpy(address, fFields, fieldsSize);
1149 memcpy(address + fieldsSize, fData, fHeader->data_size);
1150 header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
1151 header->message_area = area;
1152 return B_OK;
1156 status_t
1157 BMessage::_Reference()
1159 DEBUG_FUNCTION_ENTER;
1160 if (fHeader == NULL)
1161 return B_NO_INIT;
1163 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
1165 /* if there is no data at all we don't need the area */
1166 if (fHeader->field_count == 0 && fHeader->data_size == 0)
1167 return B_OK;
1169 area_info areaInfo;
1170 status_t result = get_area_info(fHeader->message_area, &areaInfo);
1171 if (result != B_OK)
1172 return result;
1174 if (areaInfo.team != BPrivate::current_team())
1175 return B_BAD_VALUE;
1177 set_area_protection(fHeader->message_area, B_READ_AREA);
1179 uint8* address = (uint8*)areaInfo.address;
1181 fFields = (field_header*)address;
1182 fData = address + fHeader->field_count * sizeof(field_header);
1183 return B_OK;
1187 status_t
1188 BMessage::_Dereference()
1190 DEBUG_FUNCTION_ENTER;
1191 if (fHeader == NULL)
1192 return B_NO_INIT;
1194 delete_area(fHeader->message_area);
1195 fHeader->message_area = -1;
1196 fFields = NULL;
1197 fData = NULL;
1198 return B_OK;
1202 status_t
1203 BMessage::_CopyForWrite()
1205 DEBUG_FUNCTION_ENTER;
1206 if (fHeader == NULL)
1207 return B_NO_INIT;
1209 field_header* newFields = NULL;
1210 uint8* newData = NULL;
1212 if (fHeader->field_count > 0) {
1213 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1214 newFields = (field_header*)malloc(fieldsSize);
1215 if (newFields == NULL)
1216 return B_NO_MEMORY;
1218 memcpy(newFields, fFields, fieldsSize);
1221 if (fHeader->data_size > 0) {
1222 newData = (uint8*)malloc(fHeader->data_size);
1223 if (newData == NULL) {
1224 free(newFields);
1225 return B_NO_MEMORY;
1228 memcpy(newData, fData, fHeader->data_size);
1231 _Dereference();
1233 fFieldsAvailable = 0;
1234 fDataAvailable = 0;
1236 fFields = newFields;
1237 fData = newData;
1238 return B_OK;
1242 status_t
1243 BMessage::_ValidateMessage()
1245 DEBUG_FUNCTION_ENTER;
1246 if (fHeader == NULL)
1247 return B_NO_INIT;
1249 if (fHeader->field_count == 0)
1250 return B_OK;
1252 if (fFields == NULL)
1253 return B_NO_INIT;
1255 for (uint32 i = 0; i < fHeader->field_count; i++) {
1256 field_header* field = &fFields[i];
1257 if ((field->next_field >= 0
1258 && (uint32)field->next_field > fHeader->field_count)
1259 || (field->offset + field->name_length + field->data_size
1260 > fHeader->data_size)) {
1261 // the message is corrupt
1262 MakeEmpty();
1263 return B_BAD_VALUE;
1267 return B_OK;
1271 status_t
1272 BMessage::Unflatten(const char* flatBuffer)
1274 DEBUG_FUNCTION_ENTER;
1275 if (flatBuffer == NULL)
1276 return B_BAD_VALUE;
1278 uint32 format = *(uint32*)flatBuffer;
1279 if (format != MESSAGE_FORMAT_HAIKU)
1280 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
1282 BMemoryIO io(flatBuffer, SSIZE_MAX);
1283 return Unflatten(&io);
1287 status_t
1288 BMessage::Unflatten(BDataIO* stream)
1290 DEBUG_FUNCTION_ENTER;
1291 if (stream == NULL)
1292 return B_BAD_VALUE;
1294 uint32 format = 0;
1295 stream->Read(&format, sizeof(uint32));
1296 if (format != MESSAGE_FORMAT_HAIKU)
1297 return BPrivate::MessageAdapter::Unflatten(format, this, stream);
1299 // native message unflattening
1301 _Clear();
1303 fHeader = (message_header*)malloc(sizeof(message_header));
1304 if (fHeader == NULL)
1305 return B_NO_MEMORY;
1307 fHeader->format = format;
1308 uint8* header = (uint8*)fHeader;
1309 ssize_t result = stream->Read(header + sizeof(uint32),
1310 sizeof(message_header) - sizeof(uint32));
1311 if (result != sizeof(message_header) - sizeof(uint32)
1312 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
1313 _InitHeader();
1314 return result < 0 ? result : B_BAD_VALUE;
1317 what = fHeader->what;
1319 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
1320 && fHeader->message_area >= 0) {
1321 status_t result = _Reference();
1322 if (result != B_OK) {
1323 _InitHeader();
1324 return result;
1326 } else {
1327 fHeader->message_area = -1;
1329 if (fHeader->field_count > 0) {
1330 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1331 fFields = (field_header*)malloc(fieldsSize);
1332 if (fFields == NULL) {
1333 _InitHeader();
1334 return B_NO_MEMORY;
1337 result = stream->Read(fFields, fieldsSize);
1338 if (result != fieldsSize)
1339 return result < 0 ? result : B_BAD_VALUE;
1342 if (fHeader->data_size > 0) {
1343 fData = (uint8*)malloc(fHeader->data_size);
1344 if (fData == NULL) {
1345 free(fFields);
1346 fFields = NULL;
1347 _InitHeader();
1348 return B_NO_MEMORY;
1351 result = stream->Read(fData, fHeader->data_size);
1352 if (result != (ssize_t)fHeader->data_size)
1353 return result < 0 ? result : B_BAD_VALUE;
1357 return _ValidateMessage();
1361 status_t
1362 BMessage::AddSpecifier(const char* property)
1364 DEBUG_FUNCTION_ENTER;
1365 BMessage message(B_DIRECT_SPECIFIER);
1366 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1367 if (result != B_OK)
1368 return result;
1370 return AddSpecifier(&message);
1374 status_t
1375 BMessage::AddSpecifier(const char* property, int32 index)
1377 DEBUG_FUNCTION_ENTER;
1378 BMessage message(B_INDEX_SPECIFIER);
1379 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1380 if (result != B_OK)
1381 return result;
1383 result = message.AddInt32("index", index);
1384 if (result != B_OK)
1385 return result;
1387 return AddSpecifier(&message);
1391 status_t
1392 BMessage::AddSpecifier(const char* property, int32 index, int32 range)
1394 DEBUG_FUNCTION_ENTER;
1395 if (range < 0)
1396 return B_BAD_VALUE;
1398 BMessage message(B_RANGE_SPECIFIER);
1399 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1400 if (result != B_OK)
1401 return result;
1403 result = message.AddInt32("index", index);
1404 if (result != B_OK)
1405 return result;
1407 result = message.AddInt32("range", range);
1408 if (result != B_OK)
1409 return result;
1411 return AddSpecifier(&message);
1415 status_t
1416 BMessage::AddSpecifier(const char* property, const char* name)
1418 DEBUG_FUNCTION_ENTER;
1419 BMessage message(B_NAME_SPECIFIER);
1420 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1421 if (result != B_OK)
1422 return result;
1424 result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1425 if (result != B_OK)
1426 return result;
1428 return AddSpecifier(&message);
1432 status_t
1433 BMessage::AddSpecifier(const BMessage* specifier)
1435 DEBUG_FUNCTION_ENTER;
1436 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1437 if (result != B_OK)
1438 return result;
1440 fHeader->current_specifier++;
1441 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1442 return B_OK;
1446 status_t
1447 BMessage::SetCurrentSpecifier(int32 index)
1449 DEBUG_FUNCTION_ENTER;
1450 if (index < 0)
1451 return B_BAD_INDEX;
1453 type_code type;
1454 int32 count;
1455 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1456 if (result != B_OK)
1457 return result;
1459 if (index >= count)
1460 return B_BAD_INDEX;
1462 fHeader->current_specifier = index;
1463 return B_OK;
1467 status_t
1468 BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what,
1469 const char** property) const
1471 DEBUG_FUNCTION_ENTER;
1472 if (fHeader == NULL)
1473 return B_NO_INIT;
1475 if (index != NULL)
1476 *index = fHeader->current_specifier;
1478 if (fHeader->current_specifier < 0
1479 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1480 return B_BAD_SCRIPT_SYNTAX;
1482 if (specifier) {
1483 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1484 specifier) != B_OK)
1485 return B_BAD_SCRIPT_SYNTAX;
1487 if (_what != NULL)
1488 *_what = specifier->what;
1490 if (property) {
1491 if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK)
1492 return B_BAD_SCRIPT_SYNTAX;
1496 return B_OK;
1500 bool
1501 BMessage::HasSpecifiers() const
1503 DEBUG_FUNCTION_ENTER;
1504 return fHeader != NULL
1505 && (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1509 status_t
1510 BMessage::PopSpecifier()
1512 DEBUG_FUNCTION_ENTER;
1513 if (fHeader == NULL)
1514 return B_NO_INIT;
1516 if (fHeader->current_specifier < 0 ||
1517 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1518 return B_BAD_VALUE;
1520 if (fHeader->current_specifier >= 0)
1521 fHeader->current_specifier--;
1523 return B_OK;
1527 void
1528 BMessage::_UpdateOffsets(uint32 offset, int32 change)
1530 // Update the header to match the new position of the fields
1531 if (offset < fHeader->data_size) {
1532 field_header* field = fFields;
1533 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1534 if (field->offset >= offset)
1535 field->offset += change;
1541 status_t
1542 BMessage::_ResizeData(uint32 offset, int32 change)
1544 if (change == 0)
1545 return B_OK;
1547 /* optimize for the most usual case: appending data */
1549 if (change > 0) {
1550 // We need to make the field bigger
1551 // check if there is enough free space allocated
1552 if (fDataAvailable >= (uint32)change) {
1553 // In this case, we just need to move the data after the growing
1554 // field to get the space at the right place
1555 if (offset < fHeader->data_size) {
1556 memmove(fData + offset + change, fData + offset,
1557 fHeader->data_size - offset);
1560 _UpdateOffsets(offset, change);
1562 fDataAvailable -= change;
1563 fHeader->data_size += change;
1564 return B_OK;
1567 // We need to grow the buffer. We try to optimize reallocations by
1568 // preallocating space for more fields.
1569 size_t size = fHeader->data_size * 2;
1570 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1571 size = max_c(size, fHeader->data_size + change);
1573 uint8* newData = (uint8*)realloc(fData, size);
1574 if (size > 0 && newData == NULL)
1575 return B_NO_MEMORY;
1577 fData = newData;
1578 if (offset < fHeader->data_size) {
1579 memmove(fData + offset + change, fData + offset,
1580 fHeader->data_size - offset);
1583 fHeader->data_size += change;
1584 fDataAvailable = size - fHeader->data_size;
1585 } else {
1586 ssize_t length = fHeader->data_size - offset + change;
1587 if (length > 0)
1588 memmove(fData + offset, fData + offset - change, length);
1590 // change is negative
1591 fHeader->data_size += change;
1592 fDataAvailable -= change;
1594 if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1595 ssize_t available = MAX_DATA_PREALLOCATION / 2;
1596 ssize_t size = fHeader->data_size + available;
1597 uint8* newData = (uint8*)realloc(fData, size);
1598 if (size > 0 && newData == NULL) {
1599 // this is strange, but not really fatal
1600 _UpdateOffsets(offset, change);
1601 return B_OK;
1604 fData = newData;
1605 fDataAvailable = available;
1609 _UpdateOffsets(offset, change);
1610 return B_OK;
1614 uint32
1615 BMessage::_HashName(const char* name) const
1617 char ch;
1618 uint32 result = 0;
1620 while ((ch = *name++) != 0) {
1621 result = (result << 7) ^ (result >> 24);
1622 result ^= ch;
1625 result ^= result << 12;
1626 return result;
1630 status_t
1631 BMessage::_FindField(const char* name, type_code type, field_header** result)
1632 const
1634 if (name == NULL)
1635 return B_BAD_VALUE;
1637 if (fHeader == NULL)
1638 return B_NO_INIT;
1640 if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
1641 return B_NAME_NOT_FOUND;
1643 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1644 int32 nextField = fHeader->hash_table[hash];
1646 while (nextField >= 0) {
1647 field_header* field = &fFields[nextField];
1648 if ((field->flags & FIELD_FLAG_VALID) == 0)
1649 break;
1651 if (strncmp((const char*)(fData + field->offset), name,
1652 field->name_length) == 0) {
1653 if (type != B_ANY_TYPE && field->type != type)
1654 return B_BAD_TYPE;
1656 *result = field;
1657 return B_OK;
1660 nextField = field->next_field;
1663 return B_NAME_NOT_FOUND;
1667 status_t
1668 BMessage::_AddField(const char* name, type_code type, bool isFixedSize,
1669 field_header** result)
1671 if (fHeader == NULL)
1672 return B_NO_INIT;
1674 if (fFieldsAvailable <= 0) {
1675 uint32 count = fHeader->field_count * 2 + 1;
1676 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1678 field_header* newFields = (field_header*)realloc(fFields,
1679 count * sizeof(field_header));
1680 if (count > 0 && newFields == NULL)
1681 return B_NO_MEMORY;
1683 fFields = newFields;
1684 fFieldsAvailable = count - fHeader->field_count;
1687 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1688 int32* nextField = &fHeader->hash_table[hash];
1689 while (*nextField >= 0)
1690 nextField = &fFields[*nextField].next_field;
1691 *nextField = fHeader->field_count;
1693 field_header* field = &fFields[fHeader->field_count];
1694 field->type = type;
1695 field->count = 0;
1696 field->data_size = 0;
1697 field->next_field = -1;
1698 field->offset = fHeader->data_size;
1699 field->name_length = strlen(name) + 1;
1700 status_t status = _ResizeData(field->offset, field->name_length);
1701 if (status != B_OK)
1702 return status;
1704 memcpy(fData + field->offset, name, field->name_length);
1705 field->flags = FIELD_FLAG_VALID;
1706 if (isFixedSize)
1707 field->flags |= FIELD_FLAG_FIXED_SIZE;
1709 fFieldsAvailable--;
1710 fHeader->field_count++;
1711 *result = field;
1712 return B_OK;
1716 status_t
1717 BMessage::_RemoveField(field_header* field)
1719 status_t result = _ResizeData(field->offset, -(field->data_size
1720 + field->name_length));
1721 if (result != B_OK)
1722 return result;
1724 int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header);
1725 int32 nextField = field->next_field;
1726 if (nextField > index)
1727 nextField--;
1729 int32* value = fHeader->hash_table;
1730 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1731 if (*value > index)
1732 *value -= 1;
1733 else if (*value == index)
1734 *value = nextField;
1737 field_header* other = fFields;
1738 for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1739 if (other->next_field > index)
1740 other->next_field--;
1741 else if (other->next_field == index)
1742 other->next_field = nextField;
1745 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1746 memmove(fFields + index, fFields + index + 1, size);
1747 fHeader->field_count--;
1748 fFieldsAvailable++;
1750 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1751 ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1752 size = (fHeader->field_count + available) * sizeof(field_header);
1753 field_header* newFields = (field_header*)realloc(fFields, size);
1754 if (size > 0 && newFields == NULL) {
1755 // this is strange, but not really fatal
1756 return B_OK;
1759 fFields = newFields;
1760 fFieldsAvailable = available;
1763 return B_OK;
1767 status_t
1768 BMessage::AddData(const char* name, type_code type, const void* data,
1769 ssize_t numBytes, bool isFixedSize, int32 count)
1771 // Note that the "count" argument is only a hint at how many items
1772 // the caller expects to add to this field. Since we do no item pre-
1773 // allocation, we ignore this argument.
1774 DEBUG_FUNCTION_ENTER;
1775 if (numBytes <= 0 || data == NULL)
1776 return B_BAD_VALUE;
1778 if (fHeader == NULL)
1779 return B_NO_INIT;
1781 status_t result;
1782 if (fHeader->message_area >= 0) {
1783 result = _CopyForWrite();
1784 if (result != B_OK)
1785 return result;
1788 field_header* field = NULL;
1789 result = _FindField(name, type, &field);
1790 if (result == B_NAME_NOT_FOUND)
1791 result = _AddField(name, type, isFixedSize, &field);
1793 if (result != B_OK)
1794 return result;
1796 if (field == NULL)
1797 return B_ERROR;
1799 uint32 offset = field->offset + field->name_length + field->data_size;
1800 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1801 if (field->count) {
1802 ssize_t size = field->data_size / field->count;
1803 if (size != numBytes)
1804 return B_BAD_VALUE;
1807 result = _ResizeData(offset, numBytes);
1808 if (result != B_OK) {
1809 if (field->count == 0)
1810 _RemoveField(field);
1811 return result;
1814 memcpy(fData + offset, data, numBytes);
1815 field->data_size += numBytes;
1816 } else {
1817 int32 change = numBytes + sizeof(uint32);
1818 result = _ResizeData(offset, change);
1819 if (result != B_OK) {
1820 if (field->count == 0)
1821 _RemoveField(field);
1822 return result;
1825 uint32 size = (uint32)numBytes;
1826 memcpy(fData + offset, &size, sizeof(uint32));
1827 memcpy(fData + offset + sizeof(uint32), data, size);
1828 field->data_size += change;
1831 field->count++;
1832 return B_OK;
1836 status_t
1837 BMessage::RemoveData(const char* name, int32 index)
1839 DEBUG_FUNCTION_ENTER;
1840 if (index < 0)
1841 return B_BAD_INDEX;
1843 if (fHeader == NULL)
1844 return B_NO_INIT;
1846 status_t result;
1847 if (fHeader->message_area >= 0) {
1848 result = _CopyForWrite();
1849 if (result != B_OK)
1850 return result;
1853 field_header* field = NULL;
1854 result = _FindField(name, B_ANY_TYPE, &field);
1855 if (result != B_OK)
1856 return result;
1858 if ((uint32)index >= field->count)
1859 return B_BAD_INDEX;
1861 if (field->count == 1)
1862 return _RemoveField(field);
1864 uint32 offset = field->offset + field->name_length;
1865 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1866 ssize_t size = field->data_size / field->count;
1867 result = _ResizeData(offset + index * size, -size);
1868 if (result != B_OK)
1869 return result;
1871 field->data_size -= size;
1872 } else {
1873 uint8* pointer = fData + offset;
1874 for (int32 i = 0; i < index; i++) {
1875 offset += *(uint32*)pointer + sizeof(uint32);
1876 pointer = fData + offset;
1879 size_t currentSize = *(uint32*)pointer + sizeof(uint32);
1880 result = _ResizeData(offset, -currentSize);
1881 if (result != B_OK)
1882 return result;
1884 field->data_size -= currentSize;
1887 field->count--;
1888 return B_OK;
1892 status_t
1893 BMessage::RemoveName(const char* name)
1895 DEBUG_FUNCTION_ENTER;
1896 if (fHeader == NULL)
1897 return B_NO_INIT;
1899 status_t result;
1900 if (fHeader->message_area >= 0) {
1901 result = _CopyForWrite();
1902 if (result != B_OK)
1903 return result;
1906 field_header* field = NULL;
1907 result = _FindField(name, B_ANY_TYPE, &field);
1908 if (result != B_OK)
1909 return result;
1911 return _RemoveField(field);
1915 status_t
1916 BMessage::MakeEmpty()
1918 DEBUG_FUNCTION_ENTER;
1919 _Clear();
1920 return _InitHeader();
1924 status_t
1925 BMessage::FindData(const char* name, type_code type, int32 index,
1926 const void** data, ssize_t* numBytes) const
1928 DEBUG_FUNCTION_ENTER;
1929 if (data == NULL)
1930 return B_BAD_VALUE;
1932 *data = NULL;
1933 field_header* field = NULL;
1934 status_t result = _FindField(name, type, &field);
1935 if (result != B_OK)
1936 return result;
1938 if (index < 0 || (uint32)index >= field->count)
1939 return B_BAD_INDEX;
1941 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1942 size_t bytes = field->data_size / field->count;
1943 *data = fData + field->offset + field->name_length + index * bytes;
1944 if (numBytes != NULL)
1945 *numBytes = bytes;
1946 } else {
1947 uint8* pointer = fData + field->offset + field->name_length;
1948 for (int32 i = 0; i < index; i++)
1949 pointer += *(uint32*)pointer + sizeof(uint32);
1951 *data = pointer + sizeof(uint32);
1952 if (numBytes != NULL)
1953 *numBytes = *(uint32*)pointer;
1956 return B_OK;
1960 status_t
1961 BMessage::ReplaceData(const char* name, type_code type, int32 index,
1962 const void* data, ssize_t numBytes)
1964 DEBUG_FUNCTION_ENTER;
1965 if (numBytes <= 0 || data == NULL)
1966 return B_BAD_VALUE;
1968 status_t result;
1969 if (fHeader->message_area >= 0) {
1970 result = _CopyForWrite();
1971 if (result != B_OK)
1972 return result;
1975 field_header* field = NULL;
1976 result = _FindField(name, type, &field);
1977 if (result != B_OK)
1978 return result;
1980 if (index < 0 || (uint32)index >= field->count)
1981 return B_BAD_INDEX;
1983 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1984 ssize_t size = field->data_size / field->count;
1985 if (size != numBytes)
1986 return B_BAD_VALUE;
1988 memcpy(fData + field->offset + field->name_length + index * size, data,
1989 size);
1990 } else {
1991 uint32 offset = field->offset + field->name_length;
1992 uint8* pointer = fData + offset;
1994 for (int32 i = 0; i < index; i++) {
1995 offset += *(uint32*)pointer + sizeof(uint32);
1996 pointer = fData + offset;
1999 size_t currentSize = *(uint32*)pointer;
2000 int32 change = numBytes - currentSize;
2001 result = _ResizeData(offset, change);
2002 if (result != B_OK)
2003 return result;
2005 uint32 newSize = (uint32)numBytes;
2006 memcpy(fData + offset, &newSize, sizeof(uint32));
2007 memcpy(fData + offset + sizeof(uint32), data, newSize);
2008 field->data_size += change;
2011 return B_OK;
2015 bool
2016 BMessage::HasData(const char* name, type_code type, int32 index) const
2018 DEBUG_FUNCTION_ENTER;
2019 field_header* field = NULL;
2020 status_t result = _FindField(name, type, &field);
2021 if (result != B_OK)
2022 return false;
2024 if (index < 0 || (uint32)index >= field->count)
2025 return false;
2027 return true;
2031 /* Static functions for cache initialization and cleanup */
2032 void
2033 BMessage::_StaticInit()
2035 DEBUG_FUNCTION_ENTER2;
2036 sReplyPorts[0] = create_port(1, "tmp_rport0");
2037 sReplyPorts[1] = create_port(1, "tmp_rport1");
2038 sReplyPorts[2] = create_port(1, "tmp_rport2");
2040 sReplyPortInUse[0] = 0;
2041 sReplyPortInUse[1] = 0;
2042 sReplyPortInUse[2] = 0;
2044 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
2048 void
2049 BMessage::_StaticReInitForkedChild()
2051 DEBUG_FUNCTION_ENTER2;
2053 // overwrite the inherited ports with a set of our own
2054 sReplyPorts[0] = create_port(1, "tmp_rport0");
2055 sReplyPorts[1] = create_port(1, "tmp_rport1");
2056 sReplyPorts[2] = create_port(1, "tmp_rport2");
2058 sReplyPortInUse[0] = 0;
2059 sReplyPortInUse[1] = 0;
2060 sReplyPortInUse[2] = 0;
2064 void
2065 BMessage::_StaticCleanup()
2067 DEBUG_FUNCTION_ENTER2;
2068 delete_port(sReplyPorts[0]);
2069 sReplyPorts[0] = -1;
2070 delete_port(sReplyPorts[1]);
2071 sReplyPorts[1] = -1;
2072 delete_port(sReplyPorts[2]);
2073 sReplyPorts[2] = -1;
2077 void
2078 BMessage::_StaticCacheCleanup()
2080 DEBUG_FUNCTION_ENTER2;
2081 delete sMsgCache;
2082 sMsgCache = NULL;
2086 int32
2087 BMessage::_StaticGetCachedReplyPort()
2089 DEBUG_FUNCTION_ENTER2;
2090 int index = -1;
2091 for (int32 i = 0; i < sNumReplyPorts; i++) {
2092 int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2093 if (old == 0) {
2094 // This entry is free
2095 index = i;
2096 break;
2097 } else {
2098 // This entry is being used.
2099 atomic_add(&(sReplyPortInUse[i]), -1);
2103 return index;
2107 status_t
2108 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2109 bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const
2111 DEBUG_FUNCTION_ENTER;
2112 ssize_t size = 0;
2113 char* buffer = NULL;
2114 message_header* header = NULL;
2115 status_t result = B_OK;
2117 BPrivate::BDirectMessageTarget* direct = NULL;
2118 BMessage* copy = NULL;
2119 if (portOwner == BPrivate::current_team())
2120 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
2122 if (direct != NULL) {
2123 // We have a direct local message target - we can just enqueue the
2124 // message in its message queue. This will also prevent possible
2125 // deadlocks when the queue is full.
2126 copy = new BMessage(*this);
2127 if (copy != NULL) {
2128 header = copy->fHeader;
2129 header->flags = fHeader->flags;
2130 } else {
2131 direct->Release();
2132 return B_NO_MEMORY;
2134 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2135 } else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) {
2136 KMessage toMessage;
2137 result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage);
2138 if (result != B_OK)
2139 return result;
2141 return toMessage.SendTo(port, token);
2142 } else if (fHeader->data_size > B_PAGE_SIZE * 10) {
2143 // ToDo: bind the above size to the max port message size
2144 // use message passing by area for such a large message
2145 result = _FlattenToArea(&header);
2146 if (result != B_OK)
2147 return result;
2149 buffer = (char*)header;
2150 size = sizeof(message_header);
2152 if (header->message_area >= 0) {
2153 team_id target = portOwner;
2154 if (target < 0) {
2155 port_info info;
2156 result = get_port_info(port, &info);
2157 if (result != B_OK) {
2158 free(header);
2159 return result;
2161 target = info.team;
2164 void* address = NULL;
2165 area_id transfered = _kern_transfer_area(header->message_area,
2166 &address, B_ANY_ADDRESS, target);
2167 if (transfered < 0) {
2168 delete_area(header->message_area);
2169 free(header);
2170 return transfered;
2173 header->message_area = transfered;
2175 #endif
2176 } else {
2177 size = FlattenedSize();
2178 buffer = (char*)malloc(size);
2179 if (buffer == NULL)
2180 return B_NO_MEMORY;
2182 result = Flatten(buffer, size);
2183 if (result != B_OK) {
2184 free(buffer);
2185 return result;
2188 header = (message_header*)buffer;
2191 if (!replyTo.IsValid()) {
2192 BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2193 fHeader->reply_port, fHeader->reply_target);
2195 if (!replyTo.IsValid())
2196 replyTo = be_app_messenger;
2199 BMessenger::Private replyToPrivate(replyTo);
2201 if (replyRequired) {
2202 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2203 header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2206 header->target = token;
2207 header->reply_team = replyToPrivate.Team();
2208 header->reply_port = replyToPrivate.Port();
2209 header->reply_target = replyToPrivate.Token();
2210 header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2212 if (direct == NULL) {
2213 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2214 "message: '%c%c%c%c'", portOwner, port, token,
2215 char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2217 do {
2218 result = write_port_etc(port, kPortMessageCode, (void*)buffer,
2219 size, B_RELATIVE_TIMEOUT, timeout);
2220 } while (result == B_INTERRUPTED);
2223 if (result == B_OK && IsSourceWaiting()) {
2224 // the forwarded message will handle the reply - we must not do
2225 // this anymore
2226 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2229 // we need to do this last because it is possible our
2230 // message might be destroyed after it's enqueued in the
2231 // target looper. Thus we don't want to do any ops that depend on
2232 // members of this after the enqueue.
2233 if (direct != NULL) {
2234 KTRACE("BMessage send direct: port: %ld, token: %ld, "
2235 "message: '%c%c%c%c'", port, token,
2236 char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2238 // this is a local message transmission
2239 direct->AddMessage(copy);
2240 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2241 // there is currently no message waiting, and we need to wakeup the
2242 // looper
2243 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2245 direct->Release();
2248 free(buffer);
2249 return result;
2253 // Sends a message and waits synchronously for a reply.
2254 status_t
2255 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2256 BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2258 if (IsSourceWaiting()) {
2259 // we can't forward this message synchronously when it's already
2260 // waiting for a reply
2261 return B_ERROR;
2264 DEBUG_FUNCTION_ENTER;
2265 const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2266 port_id replyPort = B_BAD_PORT_ID;
2267 status_t result = B_OK;
2269 if (cachedReplyPort < 0) {
2270 // All the cached reply ports are in use; create a new one
2271 replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2272 if (replyPort < 0)
2273 return replyPort;
2274 } else {
2275 assert(cachedReplyPort < sNumReplyPorts);
2276 replyPort = sReplyPorts[cachedReplyPort];
2279 bool recreateCachedPort = false;
2281 team_id team = B_BAD_TEAM_ID;
2282 if (be_app != NULL)
2283 team = be_app->Team();
2284 else {
2285 port_info portInfo;
2286 result = get_port_info(replyPort, &portInfo);
2287 if (result != B_OK)
2288 goto error;
2290 team = portInfo.team;
2293 result = set_port_owner(replyPort, portOwner);
2294 if (result != B_OK)
2295 goto error;
2297 // tests if the queue of the reply port is really empty
2298 #if 0
2299 port_info portInfo;
2300 if (get_port_info(replyPort, &portInfo) == B_OK
2301 && portInfo.queue_count > 0) {
2302 debugger("reply port not empty!");
2303 printf(" reply port not empty! %ld message(s) in queue\n",
2304 portInfo.queue_count);
2306 // fetch and print the messages
2307 for (int32 i = 0; i < portInfo.queue_count; i++) {
2308 char buffer[1024];
2309 int32 code;
2310 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2311 if (size < 0) {
2312 printf("failed to read message from reply port\n");
2313 continue;
2315 if (size >= (ssize_t)sizeof(buffer)) {
2316 printf("message from reply port too big\n");
2317 continue;
2320 BMemoryIO stream(buffer, size);
2321 BMessage reply;
2322 if (reply.Unflatten(&stream) != B_OK) {
2323 printf("failed to unflatten message from reply port\n");
2324 continue;
2327 printf("message %ld from reply port:\n", i);
2328 reply.PrintToStream();
2331 #endif
2334 BMessenger replyTarget;
2335 BMessenger::Private(replyTarget).SetTo(team, replyPort,
2336 B_PREFERRED_TOKEN);
2337 // TODO: replying could also use a BDirectMessageTarget like mechanism
2338 // for local targets
2339 result = _SendMessage(port, -1, token, sendTimeout, true,
2340 replyTarget);
2343 if (result != B_OK)
2344 goto error;
2346 int32 code;
2347 result = handle_reply(replyPort, &code, replyTimeout, reply);
2348 if (result != B_OK && cachedReplyPort >= 0) {
2349 delete_port(replyPort);
2350 recreateCachedPort = true;
2353 error:
2354 if (cachedReplyPort >= 0) {
2355 // Reclaim ownership of cached port, if possible
2356 if (!recreateCachedPort && set_port_owner(replyPort, team) == B_OK) {
2357 // Flag as available
2358 atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2359 } else
2360 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2362 return result;
2365 delete_port(replyPort);
2366 return result;
2370 status_t
2371 BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port,
2372 int32 token, bigtime_t timeout)
2374 DEBUG_FUNCTION_ENTER2;
2375 if (data == NULL)
2376 return B_BAD_VALUE;
2378 uint32 magic = *(uint32*)data;
2380 if (magic == MESSAGE_FORMAT_HAIKU
2381 || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2382 message_header* header = (message_header*)data;
2383 header->target = token;
2384 header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2385 } else if (magic == MESSAGE_FORMAT_R5) {
2386 uint8* header = (uint8*)data;
2387 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2388 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2389 + sizeof(uint8) /* flags */;
2390 *(int32*)header = token;
2391 } else if (((KMessage::Header*)data)->magic
2392 == KMessage::kMessageHeaderMagic) {
2393 KMessage::Header* header = (KMessage::Header*)data;
2394 header->targetToken = token;
2395 } else {
2396 return B_NOT_A_MESSAGE;
2399 // send the message
2400 status_t result;
2402 do {
2403 result = write_port_etc(port, kPortMessageCode, data, size,
2404 B_RELATIVE_TIMEOUT, timeout);
2405 } while (result == B_INTERRUPTED);
2407 return result;
2411 void BMessage::_ReservedMessage1() {}
2412 void BMessage::_ReservedMessage2() {}
2413 void BMessage::_ReservedMessage3() {}
2416 // #pragma mark - Macro definitions for data access methods
2419 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2421 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \
2422 status_t \
2423 BMessage::Add##typeName(const char* name, type val) \
2425 return AddData(name, typeCode, &val, sizeof(type), true); \
2429 status_t \
2430 BMessage::Find##typeName(const char* name, type* p) const \
2432 void* ptr = NULL; \
2433 ssize_t bytes = 0; \
2434 status_t error = B_OK; \
2436 *p = type(); \
2437 error = FindData(name, typeCode, 0, (const void**)&ptr, &bytes); \
2439 if (error == B_OK) \
2440 memcpy(p, ptr, sizeof(type)); \
2442 return error; \
2446 status_t \
2447 BMessage::Find##typeName(const char* name, int32 index, type* p) const \
2449 void* ptr = NULL; \
2450 ssize_t bytes = 0; \
2451 status_t error = B_OK; \
2453 *p = type(); \
2454 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \
2456 if (error == B_OK) \
2457 memcpy(p, ptr, sizeof(type)); \
2459 return error; \
2463 status_t \
2464 BMessage::Replace##typeName(const char* name, type value) \
2466 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \
2470 status_t \
2471 BMessage::Replace##typeName(const char* name, int32 index, type value) \
2473 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \
2477 bool \
2478 BMessage::Has##typeName(const char* name, int32 index) const \
2480 return HasData(name, typeCode, index); \
2483 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2484 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2485 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2486 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2487 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2488 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2489 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2490 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2491 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2492 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2493 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2494 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2495 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2496 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2498 #undef DEFINE_FUNCTIONS
2500 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \
2501 bool \
2502 BMessage::Has##typeName(const char* name, int32 index) const \
2504 return HasData(name, typeCode, index); \
2508 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE);
2509 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2510 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2511 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2512 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2513 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2515 #undef DEFINE_HAS_FUNCTION
2518 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \
2519 type \
2520 BMessage::Find##typeName(const char* name, int32 index) const \
2522 type val = initialize; \
2523 Find##typeName(name, index, &val); \
2524 return val; \
2528 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2529 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2530 DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL);
2531 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2532 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2533 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2534 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2535 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2536 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2537 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2539 #undef DEFINE_LAZY_FIND_FUNCTION
2542 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \
2543 type \
2544 BMessage::Get##typeName(const char* name, type defaultValue) const \
2546 return Get##typeName(name, 0, defaultValue); \
2550 type \
2551 BMessage::Get##typeName(const char* name, int32 index, \
2552 type defaultValue) const \
2554 type value; \
2555 if (Find##typeName(name, index, &value) == B_OK) \
2556 return value; \
2558 return defaultValue; \
2562 status_t \
2563 BMessage::Set##typeName(const char* name, type value) \
2565 return SetData(name, typeCode, &value, sizeof(type)); \
2569 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2570 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2571 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2572 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2573 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2574 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2575 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2576 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2577 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2578 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2579 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2581 #undef DEFINE_SET_GET_FUNCTION
2584 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \
2585 type \
2586 BMessage::Get##typeName(const char* name, const type& defaultValue) const \
2588 return Get##typeName(name, 0, defaultValue); \
2592 type \
2593 BMessage::Get##typeName(const char* name, int32 index, \
2594 const type& defaultValue) const \
2596 type value; \
2597 if (Find##typeName(name, index, &value) == B_OK) \
2598 return value; \
2600 return defaultValue; \
2604 status_t \
2605 BMessage::Set##typeName(const char* name, const type& value) \
2607 return SetData(name, typeCode, &value, sizeof(type)); \
2611 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2612 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2613 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2615 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS
2618 status_t
2619 BMessage::AddAlignment(const char* name, const BAlignment& alignment)
2621 int32 data[2] = { alignment.horizontal, alignment.vertical };
2622 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data));
2626 status_t
2627 BMessage::AddString(const char* name, const char* string)
2629 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0,
2630 false);
2634 status_t
2635 BMessage::AddString(const char* name, const BString& string)
2637 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1,
2638 false);
2642 status_t
2643 BMessage::AddStrings(const char* name, const BStringList& list)
2645 int32 count = list.CountStrings();
2646 for (int32 i = 0; i < count; i++) {
2647 status_t error = AddString(name, list.StringAt(i));
2648 if (error != B_OK)
2649 return error;
2652 return B_OK;
2656 status_t
2657 BMessage::AddPointer(const char* name, const void* pointer)
2659 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2663 status_t
2664 BMessage::AddMessenger(const char* name, BMessenger messenger)
2666 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2670 status_t
2671 BMessage::AddRef(const char* name, const entry_ref* ref)
2673 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2674 char buffer[size];
2676 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2678 if (error >= B_OK)
2679 error = AddData(name, B_REF_TYPE, buffer, size, false);
2681 return error;
2685 status_t
2686 BMessage::AddMessage(const char* name, const BMessage* message)
2688 if (message == NULL)
2689 return B_BAD_VALUE;
2691 // TODO: This and the following functions waste time by allocating and
2692 // copying an extra buffer. Functions can be added that return a direct
2693 // pointer into the message.
2695 char stackBuffer[16384];
2696 ssize_t size = message->FlattenedSize();
2698 char* buffer;
2699 if (size > (ssize_t)sizeof(stackBuffer)) {
2700 buffer = (char*)malloc(size);
2701 if (buffer == NULL)
2702 return B_NO_MEMORY;
2703 } else
2704 buffer = stackBuffer;
2706 status_t error = message->Flatten(buffer, size);
2708 if (error >= B_OK)
2709 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2711 if (buffer != stackBuffer)
2712 free(buffer);
2714 return error;
2718 status_t
2719 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
2721 return AddFlat(name, (const BFlattenable*)object, count);
2725 status_t
2726 BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count)
2728 if (object == NULL)
2729 return B_BAD_VALUE;
2731 char stackBuffer[16384];
2732 ssize_t size = object->FlattenedSize();
2734 char* buffer;
2735 if (size > (ssize_t)sizeof(stackBuffer)) {
2736 buffer = (char*)malloc(size);
2737 if (buffer == NULL)
2738 return B_NO_MEMORY;
2739 } else
2740 buffer = stackBuffer;
2742 status_t error = object->Flatten(buffer, size);
2744 if (error >= B_OK)
2745 error = AddData(name, object->TypeCode(), buffer, size, false);
2747 if (buffer != stackBuffer)
2748 free(buffer);
2750 return error;
2754 status_t
2755 BMessage::Append(const BMessage& other)
2757 field_header* field = other.fFields;
2758 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) {
2759 const char* name = (const char*)(other.fData + field->offset);
2760 const void* data = (const void*)(other.fData + field->offset
2761 + field->name_length);
2762 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
2763 size_t size = field->data_size / field->count;
2765 for (uint32 j = 0; j < field->count; j++) {
2766 if (!isFixed) {
2767 size = *(uint32*)data;
2768 data = (const void*)((const char*)data + sizeof(uint32));
2771 status_t status = AddData(name, field->type, data, size,
2772 isFixed, 1);
2773 if (status != B_OK)
2774 return status;
2776 data = (const void*)((const char*)data + size);
2779 return B_OK;
2783 status_t
2784 BMessage::FindAlignment(const char* name, BAlignment* alignment) const
2786 return FindAlignment(name, 0, alignment);
2790 status_t
2791 BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment)
2792 const
2794 if (!alignment)
2795 return B_BAD_VALUE;
2797 int32* data;
2798 ssize_t bytes;
2800 status_t err = FindData(name, B_ALIGNMENT_TYPE, index,
2801 (const void**)&data, &bytes);
2803 if (err == B_OK) {
2804 if (bytes != sizeof(int32[2]))
2805 return B_ERROR;
2807 alignment->horizontal = (enum alignment)(*data);
2808 alignment->vertical = (vertical_alignment)*(data + 1);
2811 return err;
2815 status_t
2816 BMessage::FindString(const char* name, const char** string) const
2818 return FindString(name, 0, string);
2822 status_t
2823 BMessage::FindString(const char* name, int32 index, const char** string) const
2825 ssize_t bytes;
2826 return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes);
2830 status_t
2831 BMessage::FindString(const char* name, BString* string) const
2833 return FindString(name, 0, string);
2837 status_t
2838 BMessage::FindString(const char* name, int32 index, BString* string) const
2840 if (string == NULL)
2841 return B_BAD_VALUE;
2843 const char* value;
2844 status_t error = FindString(name, index, &value);
2846 // Find*() clobbers the object even on failure
2847 string->SetTo(value);
2848 return error;
2852 status_t
2853 BMessage::FindStrings(const char* name, BStringList* list) const
2855 if (list == NULL)
2856 return B_BAD_VALUE;
2858 list->MakeEmpty();
2860 // get the number of items
2861 type_code type;
2862 int32 count;
2863 if (GetInfo(name, &type, &count) != B_OK)
2864 return B_NAME_NOT_FOUND;
2866 if (type != B_STRING_TYPE)
2867 return B_BAD_DATA;
2869 for (int32 i = 0; i < count; i++) {
2870 BString string;
2871 status_t error = FindString(name, i, &string);
2872 if (error != B_OK)
2873 return error;
2874 if (!list->Add(string))
2875 return B_NO_MEMORY;
2878 return B_OK;
2882 status_t
2883 BMessage::FindPointer(const char* name, void** pointer) const
2885 return FindPointer(name, 0, pointer);
2889 status_t
2890 BMessage::FindPointer(const char* name, int32 index, void** pointer) const
2892 if (pointer == NULL)
2893 return B_BAD_VALUE;
2895 void** data = NULL;
2896 ssize_t size = 0;
2897 status_t error = FindData(name, B_POINTER_TYPE, index,
2898 (const void**)&data, &size);
2900 if (error == B_OK)
2901 *pointer = *data;
2902 else
2903 *pointer = NULL;
2905 return error;
2909 status_t
2910 BMessage::FindMessenger(const char* name, BMessenger* messenger) const
2912 return FindMessenger(name, 0, messenger);
2916 status_t
2917 BMessage::FindMessenger(const char* name, int32 index,
2918 BMessenger* messenger) const
2920 if (messenger == NULL)
2921 return B_BAD_VALUE;
2923 void* data = NULL;
2924 ssize_t size = 0;
2925 status_t error = FindData(name, B_MESSENGER_TYPE, index,
2926 (const void**)&data, &size);
2928 if (error == B_OK)
2929 memcpy(messenger, data, sizeof(BMessenger));
2930 else
2931 *messenger = BMessenger();
2933 return error;
2937 status_t
2938 BMessage::FindRef(const char* name, entry_ref* ref) const
2940 return FindRef(name, 0, ref);
2944 status_t
2945 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
2947 if (ref == NULL)
2948 return B_BAD_VALUE;
2950 void* data = NULL;
2951 ssize_t size = 0;
2952 status_t error = FindData(name, B_REF_TYPE, index,
2953 (const void**)&data, &size);
2955 if (error == B_OK)
2956 error = BPrivate::entry_ref_unflatten(ref, (char*)data, size);
2957 else
2958 *ref = entry_ref();
2960 return error;
2964 status_t
2965 BMessage::FindMessage(const char* name, BMessage* message) const
2967 return FindMessage(name, 0, message);
2971 status_t
2972 BMessage::FindMessage(const char* name, int32 index, BMessage* message) const
2974 if (message == NULL)
2975 return B_BAD_VALUE;
2977 void* data = NULL;
2978 ssize_t size = 0;
2979 status_t error = FindData(name, B_MESSAGE_TYPE, index,
2980 (const void**)&data, &size);
2982 if (error == B_OK)
2983 error = message->Unflatten((const char*)data);
2984 else
2985 *message = BMessage();
2987 return error;
2991 status_t
2992 BMessage::FindFlat(const char* name, BFlattenable* object) const
2994 return FindFlat(name, 0, object);
2998 status_t
2999 BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const
3001 if (object == NULL)
3002 return B_BAD_VALUE;
3004 void* data = NULL;
3005 ssize_t numBytes = 0;
3006 status_t error = FindData(name, object->TypeCode(), index,
3007 (const void**)&data, &numBytes);
3009 if (error == B_OK)
3010 error = object->Unflatten(object->TypeCode(), data, numBytes);
3012 return error;
3016 status_t
3017 BMessage::FindData(const char* name, type_code type, const void** data,
3018 ssize_t* numBytes) const
3020 return FindData(name, type, 0, data, numBytes);
3024 status_t
3025 BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment)
3027 int32 data[2] = {alignment.horizontal, alignment.vertical};
3028 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data));
3032 status_t
3033 BMessage::ReplaceAlignment(const char* name, int32 index,
3034 const BAlignment& alignment)
3036 int32 data[2] = {alignment.horizontal, alignment.vertical};
3037 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data));
3041 status_t
3042 BMessage::ReplaceString(const char* name, const char* string)
3044 if (string == NULL)
3045 return B_BAD_VALUE;
3047 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
3051 status_t
3052 BMessage::ReplaceString(const char* name, int32 index, const char* string)
3054 if (string == NULL)
3055 return B_BAD_VALUE;
3057 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
3061 status_t
3062 BMessage::ReplaceString(const char* name, const BString& string)
3064 return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
3065 string.Length() + 1);
3069 status_t
3070 BMessage::ReplaceString(const char* name, int32 index, const BString& string)
3072 return ReplaceData(name, B_STRING_TYPE, index, string.String(),
3073 string.Length() + 1);
3077 status_t
3078 BMessage::ReplacePointer(const char* name, const void* pointer)
3080 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
3084 status_t
3085 BMessage::ReplacePointer(const char* name, int32 index, const void* pointer)
3087 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
3091 status_t
3092 BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
3094 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
3095 sizeof(BMessenger));
3099 status_t
3100 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
3102 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
3103 sizeof(BMessenger));
3107 status_t
3108 BMessage::ReplaceRef(const char* name, const entry_ref* ref)
3110 return ReplaceRef(name, 0, ref);
3114 status_t
3115 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
3117 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
3118 char buffer[size];
3120 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
3122 if (error >= B_OK)
3123 error = ReplaceData(name, B_REF_TYPE, index, buffer, size);
3125 return error;
3129 status_t
3130 BMessage::ReplaceMessage(const char* name, const BMessage* message)
3132 return ReplaceMessage(name, 0, message);
3136 status_t
3137 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message)
3139 if (message == NULL)
3140 return B_BAD_VALUE;
3142 ssize_t size = message->FlattenedSize();
3143 char buffer[size];
3145 status_t error = message->Flatten(buffer, size);
3147 if (error >= B_OK)
3148 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
3150 return error;
3154 status_t
3155 BMessage::ReplaceFlat(const char* name, BFlattenable* object)
3157 return ReplaceFlat(name, 0, object);
3161 status_t
3162 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
3164 if (object == NULL)
3165 return B_BAD_VALUE;
3167 ssize_t size = object->FlattenedSize();
3168 char buffer[size];
3170 status_t error = object->Flatten(buffer, size);
3172 if (error >= B_OK)
3173 error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
3175 return error;
3179 status_t
3180 BMessage::ReplaceData(const char* name, type_code type, const void* data,
3181 ssize_t numBytes)
3183 return ReplaceData(name, type, 0, data, numBytes);
3187 bool
3188 BMessage::HasFlat(const char* name, const BFlattenable* object) const
3190 return HasFlat(name, 0, object);
3194 bool
3195 BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object)
3196 const
3198 return HasData(name, object->TypeCode(), index);
3202 const char*
3203 BMessage::GetString(const char* name, const char* defaultValue) const
3205 return GetString(name, 0, defaultValue);
3209 const char*
3210 BMessage::GetString(const char* name, int32 index,
3211 const char* defaultValue) const
3213 const char* value;
3214 if (FindString(name, index, &value) == B_OK)
3215 return value;
3217 return defaultValue;
3221 status_t
3222 BMessage::SetString(const char* name, const BString& value)
3224 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1,
3225 false);
3229 status_t
3230 BMessage::SetString(const char* name, const char* value)
3232 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false);
3236 status_t
3237 BMessage::SetData(const char* name, type_code type, const void* data,
3238 ssize_t numBytes, bool fixedSize, int count)
3240 if (numBytes <= 0 || data == NULL)
3241 return B_BAD_VALUE;
3243 if (ReplaceData(name, type, data, numBytes) == B_OK)
3244 return B_OK;
3246 return AddData(name, type, data, numBytes, fixedSize, count);