2 * Copyright 2005-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz, mmlr@mlotz.ch
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>
23 #include <BlockCache.h>
25 #include <MessageQueue.h>
26 #include <Messenger.h>
31 #include <StringList.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__);
54 #define DEBUG_FUNCTION_ENTER /* nothing */
55 #define DEBUG_FUNCTION_ENTER2 /* nothing */
59 # define KTRACE(format...) ktrace_printf(format)
61 # define KTRACE(format...) ;
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
);
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
>
88 print_to_stream_type(uint8
* pointer
)
90 Type
* item
= (Type
*)pointer
;
91 item
->PrintToStream();
95 template<typename Type
>
97 print_type(const char* format
, uint8
* pointer
)
99 Type
* item
= (Type
*)pointer
;
100 printf(format
,* item
,* item
);
104 template<typename Type
>
106 print_type3(const char* format
, uint8
* pointer
)
108 Type
* item
= (Type
*)pointer
;
109 printf(format
, *item
, *item
, *item
);
114 handle_reply(port_id replyPort
, int32
* _code
, bigtime_t timeout
,
117 DEBUG_FUNCTION_ENTER2
;
120 size
= port_buffer_size_etc(replyPort
, B_RELATIVE_TIMEOUT
, timeout
);
121 } while (size
== B_INTERRUPTED
);
127 char* buffer
= (char*)malloc(size
);
132 result
= read_port(replyPort
, _code
, buffer
, size
);
133 } while (result
== B_INTERRUPTED
);
135 if (result
< 0 || *_code
!= kPortMessageCode
) {
137 return result
< 0 ? result
: B_ERROR
;
140 result
= reply
->Unflatten(buffer
);
151 DEBUG_FUNCTION_ENTER
;
156 BMessage::BMessage(BMessage
* other
)
158 DEBUG_FUNCTION_ENTER
;
164 BMessage::BMessage(uint32 _what
)
166 DEBUG_FUNCTION_ENTER
;
168 fHeader
->what
= what
= _what
;
172 BMessage::BMessage(const BMessage
& other
)
174 DEBUG_FUNCTION_ENTER
;
180 BMessage::~BMessage()
182 DEBUG_FUNCTION_ENTER
;
188 BMessage::operator=(const BMessage
& other
)
190 DEBUG_FUNCTION_ENTER
;
197 fHeader
= (message_header
*)malloc(sizeof(message_header
));
201 if (other
.fHeader
== NULL
)
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
);
230 fHeader
->field_count
= 0;
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;
247 BMessage::operator new(size_t size
)
249 DEBUG_FUNCTION_ENTER2
;
250 return sMsgCache
->Get(size
);
255 BMessage::operator new(size_t size
, const std::nothrow_t
& noThrow
)
257 DEBUG_FUNCTION_ENTER2
;
258 return sMsgCache
->Get(size
);
263 BMessage::operator new(size_t, void* pointer
)
265 DEBUG_FUNCTION_ENTER2
;
271 BMessage::operator delete(void* pointer
, size_t size
)
273 DEBUG_FUNCTION_ENTER2
;
276 sMsgCache
->Save(pointer
, size
);
281 BMessage::HasSameData(const BMessage
& other
, bool ignoreFieldOrder
,
288 return other
.fHeader
== NULL
;
290 if (fHeader
->field_count
!= other
.fHeader
->field_count
)
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
)
302 otherField
= &other
.fFields
[i
];
303 if (otherField
->name_length
!= field
->name_length
)
306 const char* otherName
= (const char*)other
.fData
307 + otherField
->offset
;
308 if (strncmp(name
, otherName
, field
->name_length
) != 0)
312 if (otherField
->type
!= field
->type
313 || otherField
->count
!= field
->count
) {
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
))
328 needsMemCompare
= false;
332 if (needsMemCompare
) {
333 if (otherField
->data_size
!= field
->data_size
)
335 if (memcmp(data
, otherData
, field
->data_size
) != 0)
345 BMessage::_InitCommon(bool initHeader
)
347 DEBUG_FUNCTION_ENTER
;
354 fFieldsAvailable
= 0;
360 fArchivingPointer
= NULL
;
363 return _InitHeader();
370 BMessage::_InitHeader()
372 DEBUG_FUNCTION_ENTER
;
373 if (fHeader
== NULL
) {
374 fHeader
= (message_header
*)malloc(sizeof(message_header
));
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
));
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
407 if (IsSourceWaiting())
408 SendReply(B_NO_REPLY
);
410 if (fHeader
->message_area
>= 0)
422 fArchivingPointer
= NULL
;
424 fFieldsAvailable
= 0;
435 BMessage::GetInfo(type_code typeRequested
, int32 index
, char** nameFound
,
436 type_code
* typeFound
, int32
* countFound
) const
438 DEBUG_FUNCTION_ENTER
;
442 if (index
< 0 || (uint32
)index
>= fHeader
->field_count
)
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
;
456 field_header
* field
= fFields
;
457 for (uint32 i
= 0; i
< fHeader
->field_count
; i
++, field
++) {
458 if (field
->type
== typeRequested
)
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
;
480 BMessage::GetInfo(const char* name
, type_code
* typeFound
,
481 int32
* countFound
) const
483 DEBUG_FUNCTION_ENTER
;
484 if (countFound
!= NULL
)
487 field_header
* field
= NULL
;
488 status_t result
= _FindField(name
, B_ANY_TYPE
, &field
);
492 if (typeFound
!= NULL
)
493 *typeFound
= field
->type
;
494 if (countFound
!= NULL
)
495 *countFound
= field
->count
;
502 BMessage::GetInfo(const char* name
, type_code
* typeFound
, bool* fixedSize
)
505 DEBUG_FUNCTION_ENTER
;
506 field_header
* field
= NULL
;
507 status_t result
= _FindField(name
, B_ANY_TYPE
, &field
);
511 if (typeFound
!= NULL
)
512 *typeFound
= field
->type
;
513 if (fixedSize
!= NULL
)
514 *fixedSize
= (field
->flags
& FIELD_FLAG_FIXED_SIZE
) != 0;
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
);
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;
542 BMessage::CountNames(type_code type
) const
544 DEBUG_FUNCTION_ENTER
;
548 if (type
== B_ANY_TYPE
)
549 return fHeader
->field_count
;
552 field_header
* field
= fFields
;
553 for (uint32 i
= 0; i
< fHeader
->field_count
; i
++, field
++) {
554 if (field
->type
== type
)
563 BMessage::IsEmpty() const
565 DEBUG_FUNCTION_ENTER
;
566 return fHeader
== NULL
|| fHeader
->field_count
== 0;
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);
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
))
593 BMessage::IsReply() const
595 DEBUG_FUNCTION_ENTER
;
596 return fHeader
!= NULL
&& (fHeader
->flags
& MESSAGE_FLAG_IS_REPLY
) != 0;
601 BMessage::PrintToStream() const
609 BMessage::_PrintToStream(const char* indent
) const
611 DEBUG_FUNCTION_ENTER
;
613 int32 value
= B_BENDIAN_TO_HOST_INT32(what
);
615 if (isprint(*(char*)&value
))
616 printf("'%.4s'", (char*)&value
);
618 printf("0x%" B_PRIx32
, what
);
621 if (fHeader
== NULL
|| fFields
== NULL
|| fData
== NULL
)
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
);
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
));
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
) {
648 print_to_stream_type
<BRect
>(pointer
);
652 print_to_stream_type
<BPoint
>(pointer
);
656 printf("string(\"%.*s\", %ld bytes)\n", (int)size
,
657 (char*)pointer
, (long)size
);
661 print_type3
<int8
>("int8(0x%hx or %d or '%c')\n",
666 print_type3
<uint8
>("uint8(0x%hx or %u or '%c')\n",
671 print_type
<int16
>("int16(0x%x or %d)\n", pointer
);
675 print_type
<uint16
>("uint16(0x%x or %u\n", pointer
);
679 print_type
<int32
>("int32(0x%lx or %ld)\n", pointer
);
683 print_type
<uint32
>("uint32(0x%lx or %lu\n", pointer
);
687 print_type
<int64
>("int64(0x%Lx or %Ld)\n", pointer
);
691 print_type
<uint64
>("uint64(0x%Lx or %Ld\n", pointer
);
695 printf("bool(%s)\n", *((bool*)pointer
) != 0
700 print_type
<float>("float(%.4f)\n", pointer
);
704 print_type
<double>("double(%.8f)\n", pointer
);
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
,
717 printf("path=\"%s\")\n", path
.Path());
724 snprintf(buffer
, sizeof(buffer
), "%s ", indent
);
727 status_t result
= message
.Unflatten((const char*)pointer
);
728 if (result
!= B_OK
) {
729 printf("failed unflatten: %s\n", strerror(result
));
733 message
._PrintToStream(buffer
);
734 printf("%s }\n", indent
);
740 printf("(type = '%.4s')(size = %ld)\n", (char*)&value
,
753 BMessage::Rename(const char* oldEntry
, const char* newEntry
)
755 DEBUG_FUNCTION_ENTER
;
756 if (oldEntry
== NULL
|| newEntry
== NULL
)
763 if (fHeader
->message_area
>= 0) {
764 result
= _CopyForWrite();
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
;
788 int32 newLength
= strlen(newEntry
) + 1;
789 result
= _ResizeData(field
->offset
+ 1,
790 newLength
- field
->name_length
);
794 memcpy(fData
+ field
->offset
, newEntry
, newLength
);
795 field
->name_length
= newLength
;
799 nextField
= &field
->next_field
;
802 return B_NAME_NOT_FOUND
;
807 BMessage::WasDelivered() const
809 DEBUG_FUNCTION_ENTER
;
810 return fHeader
!= NULL
811 && (fHeader
->flags
& MESSAGE_FLAG_WAS_DELIVERED
) != 0;
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;
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();
836 BMessage::ReturnAddress() const
838 DEBUG_FUNCTION_ENTER
;
839 if (fHeader
== NULL
|| (fHeader
->flags
& MESSAGE_FLAG_WAS_DELIVERED
) == 0)
842 BMessenger messenger
;
843 BMessenger::Private(messenger
).SetTo(fHeader
->reply_team
,
844 fHeader
->reply_port
, fHeader
->reply_target
);
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
) {
868 BMessage::WasDropped() const
870 DEBUG_FUNCTION_ENTER
;
871 return fHeader
!= NULL
872 && (fHeader
->flags
& MESSAGE_FLAG_WAS_DROPPED
) != 0;
877 BMessage::DropPoint(BPoint
* offset
) const
879 DEBUG_FUNCTION_ENTER
;
881 *offset
= FindPoint("_drop_offset_");
883 return FindPoint("_drop_point_");
888 BMessage::SendReply(uint32 command
, BHandler
* replyTo
)
890 DEBUG_FUNCTION_ENTER
;
891 BMessage
message(command
);
892 return SendReply(&message
, replyTo
);
897 BMessage::SendReply(BMessage
* reply
, BHandler
* replyTo
, bigtime_t timeout
)
899 DEBUG_FUNCTION_ENTER
;
900 BMessenger
messenger(replyTo
);
901 return SendReply(reply
, messenger
, timeout
);
906 BMessage::SendReply(BMessage
* reply
, BMessenger replyTo
, bigtime_t timeout
)
908 DEBUG_FUNCTION_ENTER
;
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());
937 if ((fHeader
->flags
& MESSAGE_FLAG_WAS_DELIVERED
) == 0)
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_");
950 BMessage::SendReply(uint32 command
, BMessage
* replyToReply
)
952 DEBUG_FUNCTION_ENTER
;
953 BMessage
message(command
);
954 return SendReply(&message
, replyToReply
);
959 BMessage::SendReply(BMessage
* reply
, BMessage
* replyToReply
,
960 bigtime_t sendTimeout
, bigtime_t replyTimeout
)
962 DEBUG_FUNCTION_ENTER
;
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());
992 if ((fHeader
->flags
& MESSAGE_FLAG_WAS_DELIVERED
) == 0)
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
,
1000 reply
->fHeader
->flags
&= ~MESSAGE_FLAG_IS_REPLY
;
1001 reply
->RemoveName("_previous_");
1007 BMessage::FlattenedSize() const
1009 DEBUG_FUNCTION_ENTER
;
1010 if (fHeader
== NULL
)
1013 return sizeof(message_header
) + fHeader
->field_count
* sizeof(field_header
)
1014 + fHeader
->data_size
;
1019 BMessage::Flatten(char* buffer
, ssize_t size
) const
1021 DEBUG_FUNCTION_ENTER
;
1022 if (buffer
== NULL
|| size
< 0)
1025 if (fHeader
== NULL
)
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
);
1048 BMessage::Flatten(BDataIO
* stream
, ssize_t
* size
) const
1050 DEBUG_FUNCTION_ENTER
;
1054 if (fHeader
== NULL
)
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
;
1080 *size
= result1
+ result2
+ result3
;
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
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.
1116 BMessage::_FlattenToArea(message_header
** _header
) const
1118 DEBUG_FUNCTION_ENTER
;
1119 if (fHeader
== NULL
)
1122 message_header
* header
= (message_header
*)malloc(sizeof(message_header
));
1126 memcpy(header
, fHeader
, sizeof(message_header
));
1128 header
->what
= what
;
1129 header
->message_area
= -1;
1132 if (header
->field_count
== 0 && header
->data_size
== 0)
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
);
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
;
1157 BMessage::_Reference()
1159 DEBUG_FUNCTION_ENTER
;
1160 if (fHeader
== NULL
)
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)
1170 status_t result
= get_area_info(fHeader
->message_area
, &areaInfo
);
1174 if (areaInfo
.team
!= BPrivate::current_team())
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
);
1188 BMessage::_Dereference()
1190 DEBUG_FUNCTION_ENTER
;
1191 if (fHeader
== NULL
)
1194 delete_area(fHeader
->message_area
);
1195 fHeader
->message_area
= -1;
1203 BMessage::_CopyForWrite()
1205 DEBUG_FUNCTION_ENTER
;
1206 if (fHeader
== NULL
)
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
)
1218 memcpy(newFields
, fFields
, fieldsSize
);
1221 if (fHeader
->data_size
> 0) {
1222 newData
= (uint8
*)malloc(fHeader
->data_size
);
1223 if (newData
== NULL
) {
1228 memcpy(newData
, fData
, fHeader
->data_size
);
1233 fFieldsAvailable
= 0;
1236 fFields
= newFields
;
1243 BMessage::_ValidateMessage()
1245 DEBUG_FUNCTION_ENTER
;
1246 if (fHeader
== NULL
)
1249 if (fHeader
->field_count
== 0)
1252 if (fFields
== NULL
)
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
1272 BMessage::Unflatten(const char* flatBuffer
)
1274 DEBUG_FUNCTION_ENTER
;
1275 if (flatBuffer
== NULL
)
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
);
1288 BMessage::Unflatten(BDataIO
* stream
)
1290 DEBUG_FUNCTION_ENTER
;
1295 stream
->Read(&format
, sizeof(uint32
));
1296 if (format
!= MESSAGE_FORMAT_HAIKU
)
1297 return BPrivate::MessageAdapter::Unflatten(format
, this, stream
);
1299 // native message unflattening
1303 fHeader
= (message_header
*)malloc(sizeof(message_header
));
1304 if (fHeader
== NULL
)
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) {
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
) {
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
) {
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
) {
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();
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
);
1370 return AddSpecifier(&message
);
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
);
1383 result
= message
.AddInt32("index", index
);
1387 return AddSpecifier(&message
);
1392 BMessage::AddSpecifier(const char* property
, int32 index
, int32 range
)
1394 DEBUG_FUNCTION_ENTER
;
1398 BMessage
message(B_RANGE_SPECIFIER
);
1399 status_t result
= message
.AddString(B_PROPERTY_ENTRY
, property
);
1403 result
= message
.AddInt32("index", index
);
1407 result
= message
.AddInt32("range", range
);
1411 return AddSpecifier(&message
);
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
);
1424 result
= message
.AddString(B_PROPERTY_NAME_ENTRY
, name
);
1428 return AddSpecifier(&message
);
1433 BMessage::AddSpecifier(const BMessage
* specifier
)
1435 DEBUG_FUNCTION_ENTER
;
1436 status_t result
= AddMessage(B_SPECIFIER_ENTRY
, specifier
);
1440 fHeader
->current_specifier
++;
1441 fHeader
->flags
|= MESSAGE_FLAG_HAS_SPECIFIERS
;
1447 BMessage::SetCurrentSpecifier(int32 index
)
1449 DEBUG_FUNCTION_ENTER
;
1455 status_t result
= GetInfo(B_SPECIFIER_ENTRY
, &type
, &count
);
1462 fHeader
->current_specifier
= index
;
1468 BMessage::GetCurrentSpecifier(int32
* index
, BMessage
* specifier
, int32
* _what
,
1469 const char** property
) const
1471 DEBUG_FUNCTION_ENTER
;
1472 if (fHeader
== 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
;
1483 if (FindMessage(B_SPECIFIER_ENTRY
, fHeader
->current_specifier
,
1485 return B_BAD_SCRIPT_SYNTAX
;
1488 *_what
= specifier
->what
;
1491 if (specifier
->FindString(B_PROPERTY_ENTRY
, property
) != B_OK
)
1492 return B_BAD_SCRIPT_SYNTAX
;
1501 BMessage::HasSpecifiers() const
1503 DEBUG_FUNCTION_ENTER
;
1504 return fHeader
!= NULL
1505 && (fHeader
->flags
& MESSAGE_FLAG_HAS_SPECIFIERS
) != 0;
1510 BMessage::PopSpecifier()
1512 DEBUG_FUNCTION_ENTER
;
1513 if (fHeader
== NULL
)
1516 if (fHeader
->current_specifier
< 0 ||
1517 (fHeader
->flags
& MESSAGE_FLAG_WAS_DELIVERED
) == 0)
1520 if (fHeader
->current_specifier
>= 0)
1521 fHeader
->current_specifier
--;
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
;
1542 BMessage::_ResizeData(uint32 offset
, int32 change
)
1547 /* optimize for the most usual case: appending data */
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
;
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
)
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
;
1586 ssize_t length
= fHeader
->data_size
- offset
+ change
;
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
);
1605 fDataAvailable
= available
;
1609 _UpdateOffsets(offset
, change
);
1615 BMessage::_HashName(const char* name
) const
1620 while ((ch
= *name
++) != 0) {
1621 result
= (result
<< 7) ^ (result
>> 24);
1625 result
^= result
<< 12;
1631 BMessage::_FindField(const char* name
, type_code type
, field_header
** result
)
1637 if (fHeader
== NULL
)
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)
1651 if (strncmp((const char*)(fData
+ field
->offset
), name
,
1652 field
->name_length
) == 0) {
1653 if (type
!= B_ANY_TYPE
&& field
->type
!= type
)
1660 nextField
= field
->next_field
;
1663 return B_NAME_NOT_FOUND
;
1668 BMessage::_AddField(const char* name
, type_code type
, bool isFixedSize
,
1669 field_header
** result
)
1671 if (fHeader
== NULL
)
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
)
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
];
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
);
1704 memcpy(fData
+ field
->offset
, name
, field
->name_length
);
1705 field
->flags
= FIELD_FLAG_VALID
;
1707 field
->flags
|= FIELD_FLAG_FIXED_SIZE
;
1710 fHeader
->field_count
++;
1717 BMessage::_RemoveField(field_header
* field
)
1719 status_t result
= _ResizeData(field
->offset
, -(field
->data_size
1720 + field
->name_length
));
1724 int32 index
= ((uint8
*)field
- (uint8
*)fFields
) / sizeof(field_header
);
1725 int32 nextField
= field
->next_field
;
1726 if (nextField
> index
)
1729 int32
* value
= fHeader
->hash_table
;
1730 for (uint32 i
= 0; i
< fHeader
->hash_table_size
; i
++, value
++) {
1733 else if (*value
== index
)
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
--;
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
1759 fFields
= newFields
;
1760 fFieldsAvailable
= available
;
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
)
1778 if (fHeader
== NULL
)
1782 if (fHeader
->message_area
>= 0) {
1783 result
= _CopyForWrite();
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
);
1799 uint32 offset
= field
->offset
+ field
->name_length
+ field
->data_size
;
1800 if ((field
->flags
& FIELD_FLAG_FIXED_SIZE
) != 0) {
1802 ssize_t size
= field
->data_size
/ field
->count
;
1803 if (size
!= numBytes
)
1807 result
= _ResizeData(offset
, numBytes
);
1808 if (result
!= B_OK
) {
1809 if (field
->count
== 0)
1810 _RemoveField(field
);
1814 memcpy(fData
+ offset
, data
, numBytes
);
1815 field
->data_size
+= numBytes
;
1817 int32 change
= numBytes
+ sizeof(uint32
);
1818 result
= _ResizeData(offset
, change
);
1819 if (result
!= B_OK
) {
1820 if (field
->count
== 0)
1821 _RemoveField(field
);
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
;
1837 BMessage::RemoveData(const char* name
, int32 index
)
1839 DEBUG_FUNCTION_ENTER
;
1843 if (fHeader
== NULL
)
1847 if (fHeader
->message_area
>= 0) {
1848 result
= _CopyForWrite();
1853 field_header
* field
= NULL
;
1854 result
= _FindField(name
, B_ANY_TYPE
, &field
);
1858 if ((uint32
)index
>= field
->count
)
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
);
1871 field
->data_size
-= size
;
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
);
1884 field
->data_size
-= currentSize
;
1893 BMessage::RemoveName(const char* name
)
1895 DEBUG_FUNCTION_ENTER
;
1896 if (fHeader
== NULL
)
1900 if (fHeader
->message_area
>= 0) {
1901 result
= _CopyForWrite();
1906 field_header
* field
= NULL
;
1907 result
= _FindField(name
, B_ANY_TYPE
, &field
);
1911 return _RemoveField(field
);
1916 BMessage::MakeEmpty()
1918 DEBUG_FUNCTION_ENTER
;
1920 return _InitHeader();
1925 BMessage::FindData(const char* name
, type_code type
, int32 index
,
1926 const void** data
, ssize_t
* numBytes
) const
1928 DEBUG_FUNCTION_ENTER
;
1933 field_header
* field
= NULL
;
1934 status_t result
= _FindField(name
, type
, &field
);
1938 if (index
< 0 || (uint32
)index
>= field
->count
)
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
)
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
;
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
)
1969 if (fHeader
->message_area
>= 0) {
1970 result
= _CopyForWrite();
1975 field_header
* field
= NULL
;
1976 result
= _FindField(name
, type
, &field
);
1980 if (index
< 0 || (uint32
)index
>= field
->count
)
1983 if ((field
->flags
& FIELD_FLAG_FIXED_SIZE
) != 0) {
1984 ssize_t size
= field
->data_size
/ field
->count
;
1985 if (size
!= numBytes
)
1988 memcpy(fData
+ field
->offset
+ field
->name_length
+ index
* size
, data
,
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
);
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
;
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
);
2024 if (index
< 0 || (uint32
)index
>= field
->count
)
2031 /* Static functions for cache initialization and cleanup */
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
);
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;
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;
2078 BMessage::_StaticCacheCleanup()
2080 DEBUG_FUNCTION_ENTER2
;
2087 BMessage::_StaticGetCachedReplyPort()
2089 DEBUG_FUNCTION_ENTER2
;
2091 for (int32 i
= 0; i
< sNumReplyPorts
; i
++) {
2092 int32 old
= atomic_add(&(sReplyPortInUse
[i
]), 1);
2094 // This entry is free
2098 // This entry is being used.
2099 atomic_add(&(sReplyPortInUse
[i
]), -1);
2108 BMessage::_SendMessage(port_id port
, team_id portOwner
, int32 token
,
2109 bigtime_t timeout
, bool replyRequired
, BMessenger
& replyTo
) const
2111 DEBUG_FUNCTION_ENTER
;
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);
2128 header
= copy
->fHeader
;
2129 header
->flags
= fHeader
->flags
;
2134 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2135 } else if ((fHeader
->flags
& MESSAGE_FLAG_REPLY_AS_KMESSAGE
) != 0) {
2137 result
= BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage
);
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
);
2149 buffer
= (char*)header
;
2150 size
= sizeof(message_header
);
2152 if (header
->message_area
>= 0) {
2153 team_id target
= portOwner
;
2156 result
= get_port_info(port
, &info
);
2157 if (result
!= B_OK
) {
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
);
2173 header
->message_area
= transfered
;
2177 size
= FlattenedSize();
2178 buffer
= (char*)malloc(size
);
2182 result
= Flatten(buffer
, size
);
2183 if (result
!= B_OK
) {
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
);
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
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
2243 write_port_etc(port
, 0, NULL
, 0, B_RELATIVE_TIMEOUT
, 0);
2253 // Sends a message and waits synchronously for a reply.
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
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");
2275 assert(cachedReplyPort
< sNumReplyPorts
);
2276 replyPort
= sReplyPorts
[cachedReplyPort
];
2279 bool recreateCachedPort
= false;
2281 team_id team
= B_BAD_TEAM_ID
;
2283 team
= be_app
->Team();
2286 result
= get_port_info(replyPort
, &portInfo
);
2290 team
= portInfo
.team
;
2293 result
= set_port_owner(replyPort
, portOwner
);
2297 // tests if the queue of the reply port is really empty
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
++) {
2310 ssize_t size
= read_port(replyPort
, &code
, buffer
, sizeof(buffer
));
2312 printf("failed to read message from reply port\n");
2315 if (size
>= (ssize_t
)sizeof(buffer
)) {
2316 printf("message from reply port too big\n");
2320 BMemoryIO
stream(buffer
, size
);
2322 if (reply
.Unflatten(&stream
) != B_OK
) {
2323 printf("failed to unflatten message from reply port\n");
2327 printf("message %ld from reply port:\n", i
);
2328 reply
.PrintToStream();
2334 BMessenger replyTarget
;
2335 BMessenger::Private(replyTarget
).SetTo(team
, replyPort
,
2337 // TODO: replying could also use a BDirectMessageTarget like mechanism
2338 // for local targets
2339 result
= _SendMessage(port
, -1, token
, sendTimeout
, true,
2347 result
= handle_reply(replyPort
, &code
, replyTimeout
, reply
);
2348 if (result
!= B_OK
&& cachedReplyPort
>= 0) {
2349 delete_port(replyPort
);
2350 recreateCachedPort
= true;
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);
2360 sReplyPorts
[cachedReplyPort
] = create_port(1, "tmp_rport");
2365 delete_port(replyPort
);
2371 BMessage::_SendFlattenedMessage(void* data
, int32 size
, port_id port
,
2372 int32 token
, bigtime_t timeout
)
2374 DEBUG_FUNCTION_ENTER2
;
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
;
2396 return B_NOT_A_MESSAGE
;
2403 result
= write_port_etc(port
, kPortMessageCode
, data
, size
,
2404 B_RELATIVE_TIMEOUT
, timeout
);
2405 } while (result
== B_INTERRUPTED
);
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) \
2423 BMessage::Add##typeName(const char* name, type val) \
2425 return AddData(name, typeCode, &val, sizeof(type), true); \
2430 BMessage::Find##typeName(const char* name, type* p) const \
2433 ssize_t bytes = 0; \
2434 status_t error = B_OK; \
2437 error = FindData(name, typeCode, 0, (const void**)&ptr, &bytes); \
2439 if (error == B_OK) \
2440 memcpy(p, ptr, sizeof(type)); \
2447 BMessage::Find##typeName(const char* name, int32 index, type* p) const \
2450 ssize_t bytes = 0; \
2451 status_t error = B_OK; \
2454 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \
2456 if (error == B_OK) \
2457 memcpy(p, ptr, sizeof(type)); \
2464 BMessage::Replace##typeName(const char* name, type value) \
2466 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \
2471 BMessage::Replace##typeName(const char* name, int32 index, type value) \
2473 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \
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) \
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) \
2520 BMessage::Find##typeName(const char* name, int32 index) const \
2522 type val = initialize; \
2523 Find##typeName(name, index, &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) \
2544 BMessage::Get##typeName(const char* name, type defaultValue) const \
2546 return Get##typeName(name, 0, defaultValue); \
2551 BMessage::Get##typeName(const char* name, int32 index, \
2552 type defaultValue) const \
2555 if (Find##typeName(name, index, &value) == B_OK) \
2558 return defaultValue; \
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) \
2586 BMessage::Get##typeName(const char* name, const type& defaultValue) const \
2588 return Get##typeName(name, 0, defaultValue); \
2593 BMessage::Get##typeName(const char* name, int32 index, \
2594 const type& defaultValue) const \
2597 if (Find##typeName(name, index, &value) == B_OK) \
2600 return defaultValue; \
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
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
));
2627 BMessage::AddString(const char* name
, const char* string
)
2629 return AddData(name
, B_STRING_TYPE
, string
, string
? strlen(string
) + 1 : 0,
2635 BMessage::AddString(const char* name
, const BString
& string
)
2637 return AddData(name
, B_STRING_TYPE
, string
.String(), string
.Length() + 1,
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
));
2657 BMessage::AddPointer(const char* name
, const void* pointer
)
2659 return AddData(name
, B_POINTER_TYPE
, &pointer
, sizeof(pointer
), true);
2664 BMessage::AddMessenger(const char* name
, BMessenger messenger
)
2666 return AddData(name
, B_MESSENGER_TYPE
, &messenger
, sizeof(messenger
), true);
2671 BMessage::AddRef(const char* name
, const entry_ref
* ref
)
2673 size_t size
= sizeof(entry_ref
) + B_PATH_NAME_LENGTH
;
2676 status_t error
= BPrivate::entry_ref_flatten(buffer
, &size
, ref
);
2679 error
= AddData(name
, B_REF_TYPE
, buffer
, size
, false);
2686 BMessage::AddMessage(const char* name
, const BMessage
* message
)
2688 if (message
== NULL
)
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();
2699 if (size
> (ssize_t
)sizeof(stackBuffer
)) {
2700 buffer
= (char*)malloc(size
);
2704 buffer
= stackBuffer
;
2706 status_t error
= message
->Flatten(buffer
, size
);
2709 error
= AddData(name
, B_MESSAGE_TYPE
, buffer
, size
, false);
2711 if (buffer
!= stackBuffer
)
2719 BMessage::AddFlat(const char* name
, BFlattenable
* object
, int32 count
)
2721 return AddFlat(name
, (const BFlattenable
*)object
, count
);
2726 BMessage::AddFlat(const char* name
, const BFlattenable
* object
, int32 count
)
2731 char stackBuffer
[16384];
2732 ssize_t size
= object
->FlattenedSize();
2735 if (size
> (ssize_t
)sizeof(stackBuffer
)) {
2736 buffer
= (char*)malloc(size
);
2740 buffer
= stackBuffer
;
2742 status_t error
= object
->Flatten(buffer
, size
);
2745 error
= AddData(name
, object
->TypeCode(), buffer
, size
, false);
2747 if (buffer
!= stackBuffer
)
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
++) {
2767 size
= *(uint32
*)data
;
2768 data
= (const void*)((const char*)data
+ sizeof(uint32
));
2771 status_t status
= AddData(name
, field
->type
, data
, size
,
2776 data
= (const void*)((const char*)data
+ size
);
2784 BMessage::FindAlignment(const char* name
, BAlignment
* alignment
) const
2786 return FindAlignment(name
, 0, alignment
);
2791 BMessage::FindAlignment(const char* name
, int32 index
, BAlignment
* alignment
)
2800 status_t err
= FindData(name
, B_ALIGNMENT_TYPE
, index
,
2801 (const void**)&data
, &bytes
);
2804 if (bytes
!= sizeof(int32
[2]))
2807 alignment
->horizontal
= (enum alignment
)(*data
);
2808 alignment
->vertical
= (vertical_alignment
)*(data
+ 1);
2816 BMessage::FindString(const char* name
, const char** string
) const
2818 return FindString(name
, 0, string
);
2823 BMessage::FindString(const char* name
, int32 index
, const char** string
) const
2826 return FindData(name
, B_STRING_TYPE
, index
, (const void**)string
, &bytes
);
2831 BMessage::FindString(const char* name
, BString
* string
) const
2833 return FindString(name
, 0, string
);
2838 BMessage::FindString(const char* name
, int32 index
, BString
* string
) const
2844 status_t error
= FindString(name
, index
, &value
);
2846 // Find*() clobbers the object even on failure
2847 string
->SetTo(value
);
2853 BMessage::FindStrings(const char* name
, BStringList
* list
) const
2860 // get the number of items
2863 if (GetInfo(name
, &type
, &count
) != B_OK
)
2864 return B_NAME_NOT_FOUND
;
2866 if (type
!= B_STRING_TYPE
)
2869 for (int32 i
= 0; i
< count
; i
++) {
2871 status_t error
= FindString(name
, i
, &string
);
2874 if (!list
->Add(string
))
2883 BMessage::FindPointer(const char* name
, void** pointer
) const
2885 return FindPointer(name
, 0, pointer
);
2890 BMessage::FindPointer(const char* name
, int32 index
, void** pointer
) const
2892 if (pointer
== NULL
)
2897 status_t error
= FindData(name
, B_POINTER_TYPE
, index
,
2898 (const void**)&data
, &size
);
2910 BMessage::FindMessenger(const char* name
, BMessenger
* messenger
) const
2912 return FindMessenger(name
, 0, messenger
);
2917 BMessage::FindMessenger(const char* name
, int32 index
,
2918 BMessenger
* messenger
) const
2920 if (messenger
== NULL
)
2925 status_t error
= FindData(name
, B_MESSENGER_TYPE
, index
,
2926 (const void**)&data
, &size
);
2929 memcpy(messenger
, data
, sizeof(BMessenger
));
2931 *messenger
= BMessenger();
2938 BMessage::FindRef(const char* name
, entry_ref
* ref
) const
2940 return FindRef(name
, 0, ref
);
2945 BMessage::FindRef(const char* name
, int32 index
, entry_ref
* ref
) const
2952 status_t error
= FindData(name
, B_REF_TYPE
, index
,
2953 (const void**)&data
, &size
);
2956 error
= BPrivate::entry_ref_unflatten(ref
, (char*)data
, size
);
2965 BMessage::FindMessage(const char* name
, BMessage
* message
) const
2967 return FindMessage(name
, 0, message
);
2972 BMessage::FindMessage(const char* name
, int32 index
, BMessage
* message
) const
2974 if (message
== NULL
)
2979 status_t error
= FindData(name
, B_MESSAGE_TYPE
, index
,
2980 (const void**)&data
, &size
);
2983 error
= message
->Unflatten((const char*)data
);
2985 *message
= BMessage();
2992 BMessage::FindFlat(const char* name
, BFlattenable
* object
) const
2994 return FindFlat(name
, 0, object
);
2999 BMessage::FindFlat(const char* name
, int32 index
, BFlattenable
* object
) const
3005 ssize_t numBytes
= 0;
3006 status_t error
= FindData(name
, object
->TypeCode(), index
,
3007 (const void**)&data
, &numBytes
);
3010 error
= object
->Unflatten(object
->TypeCode(), data
, numBytes
);
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
);
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
));
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
));
3042 BMessage::ReplaceString(const char* name
, const char* string
)
3047 return ReplaceData(name
, B_STRING_TYPE
, 0, string
, strlen(string
) + 1);
3052 BMessage::ReplaceString(const char* name
, int32 index
, const char* string
)
3057 return ReplaceData(name
, B_STRING_TYPE
, index
, string
, strlen(string
) + 1);
3062 BMessage::ReplaceString(const char* name
, const BString
& string
)
3064 return ReplaceData(name
, B_STRING_TYPE
, 0, string
.String(),
3065 string
.Length() + 1);
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);
3078 BMessage::ReplacePointer(const char* name
, const void* pointer
)
3080 return ReplaceData(name
, B_POINTER_TYPE
, 0, &pointer
, sizeof(pointer
));
3085 BMessage::ReplacePointer(const char* name
, int32 index
, const void* pointer
)
3087 return ReplaceData(name
, B_POINTER_TYPE
, index
, &pointer
, sizeof(pointer
));
3092 BMessage::ReplaceMessenger(const char* name
, BMessenger messenger
)
3094 return ReplaceData(name
, B_MESSENGER_TYPE
, 0, &messenger
,
3095 sizeof(BMessenger
));
3100 BMessage::ReplaceMessenger(const char* name
, int32 index
, BMessenger messenger
)
3102 return ReplaceData(name
, B_MESSENGER_TYPE
, index
, &messenger
,
3103 sizeof(BMessenger
));
3108 BMessage::ReplaceRef(const char* name
, const entry_ref
* ref
)
3110 return ReplaceRef(name
, 0, ref
);
3115 BMessage::ReplaceRef(const char* name
, int32 index
, const entry_ref
* ref
)
3117 size_t size
= sizeof(entry_ref
) + B_PATH_NAME_LENGTH
;
3120 status_t error
= BPrivate::entry_ref_flatten(buffer
, &size
, ref
);
3123 error
= ReplaceData(name
, B_REF_TYPE
, index
, buffer
, size
);
3130 BMessage::ReplaceMessage(const char* name
, const BMessage
* message
)
3132 return ReplaceMessage(name
, 0, message
);
3137 BMessage::ReplaceMessage(const char* name
, int32 index
, const BMessage
* message
)
3139 if (message
== NULL
)
3142 ssize_t size
= message
->FlattenedSize();
3145 status_t error
= message
->Flatten(buffer
, size
);
3148 error
= ReplaceData(name
, B_MESSAGE_TYPE
, index
, &buffer
, size
);
3155 BMessage::ReplaceFlat(const char* name
, BFlattenable
* object
)
3157 return ReplaceFlat(name
, 0, object
);
3162 BMessage::ReplaceFlat(const char* name
, int32 index
, BFlattenable
* object
)
3167 ssize_t size
= object
->FlattenedSize();
3170 status_t error
= object
->Flatten(buffer
, size
);
3173 error
= ReplaceData(name
, object
->TypeCode(), index
, &buffer
, size
);
3180 BMessage::ReplaceData(const char* name
, type_code type
, const void* data
,
3183 return ReplaceData(name
, type
, 0, data
, numBytes
);
3188 BMessage::HasFlat(const char* name
, const BFlattenable
* object
) const
3190 return HasFlat(name
, 0, object
);
3195 BMessage::HasFlat(const char* name
, int32 index
, const BFlattenable
* object
)
3198 return HasData(name
, object
->TypeCode(), index
);
3203 BMessage::GetString(const char* name
, const char* defaultValue
) const
3205 return GetString(name
, 0, defaultValue
);
3210 BMessage::GetString(const char* name
, int32 index
,
3211 const char* defaultValue
) const
3214 if (FindString(name
, index
, &value
) == B_OK
)
3217 return defaultValue
;
3222 BMessage::SetString(const char* name
, const BString
& value
)
3224 return SetData(name
, B_STRING_TYPE
, value
.String(), value
.Length() + 1,
3230 BMessage::SetString(const char* name
, const char* value
)
3232 return SetData(name
, B_STRING_TYPE
, value
, strlen(value
) + 1, false);
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
)
3243 if (ReplaceData(name
, type
, data
, numBytes
) == B_OK
)
3246 return AddData(name
, type
, data
, numBytes
, fixedSize
, count
);