1 /*
2 * Copyright 2005-2017 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz, mmlr@mlotz.ch
7 */
8
9
10 #include <Message.h>
11 #include <MessageAdapter.h>
12 #include <MessagePrivate.h>
13 #include <MessageUtils.h>
14
15 #include <DirectMessageTarget.h>
16 #include <MessengerPrivate.h>
17 #include <TokenSpace.h>
18 #include <util/KMessage.h>
19
20 #include <Alignment.h>
21 #include <Application.h>
22 #include <AppMisc.h>
23 #include <BlockCache.h>
24 #include <GraphicsDefs.h>
25 #include <MessageQueue.h>
26 #include <Messenger.h>
27 #include <Path.h>
28 #include <Point.h>
29 #include <String.h>
30 #include <StringList.h>
31
32 #include <assert.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "tracing_config.h"
39 // kernel tracing configuration
40
41 //#define VERBOSE_DEBUG_OUTPUT
42 #ifdef VERBOSE_DEBUG_OUTPUT
43 #define DEBUG_FUNCTION_ENTER \
44 debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
45 " data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
46 find_thread(NULL), this, fHeader, fFields, fData, what, (char*)&what, \
47 __LINE__, __PRETTY_FUNCTION__);
48
49 #define DEBUG_FUNCTION_ENTER2 \
50 debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
51 __LINE__, __PRETTY_FUNCTION__);
52 #else
53 #define DEBUG_FUNCTION_ENTER /* nothing */
54 #define DEBUG_FUNCTION_ENTER2 /* nothing */
55 #endif
56
57 #if BMESSAGE_TRACING
58 # define KTRACE(format...) ktrace_printf(format)
59 #else
60 # define KTRACE(format...) ;
61 #endif
62
63
64 const char* B_SPECIFIER_ENTRY = "specifiers";
65 const char* B_PROPERTY_ENTRY = "property";
66 const char* B_PROPERTY_NAME_ENTRY = "name";
67
68
69 static status_t handle_reply(port_id replyPort, int32* pCode,
70 bigtime_t timeout, BMessage* reply);
71
72
73 extern "C" {
74 // private os function to set the owning team of an area
75 status_t _kern_transfer_area(area_id area, void** _address,
76 uint32 addressSpec, team_id target);
77 }
78
79
80 BBlockCache* BMessage::sMsgCache = NULL;
81 port_id BMessage::sReplyPorts[sNumReplyPorts];
82 int32 BMessage::sReplyPortInUse[sNumReplyPorts];
83
84
85 template<typename Type>
86 static void
print_to_stream_type(uint8 * pointer)87 print_to_stream_type(uint8* pointer)
88 {
89 Type* item = (Type*)pointer;
90 item->PrintToStream();
91 }
92
93
94 template<typename Type>
95 static void
print_type(const char * format,uint8 * pointer)96 print_type(const char* format, uint8* pointer)
97 {
98 Type* item = (Type*)pointer;
99 printf(format,* item,* item);
100 }
101
102
103 template<typename Type>
104 static void
print_type3(const char * format,uint8 * pointer)105 print_type3(const char* format, uint8* pointer)
106 {
107 Type* item = (Type*)pointer;
108 printf(format, *item, *item, *item);
109 }
110
111
112 static status_t
handle_reply(port_id replyPort,int32 * _code,bigtime_t timeout,BMessage * reply)113 handle_reply(port_id replyPort, int32* _code, bigtime_t timeout,
114 BMessage* reply)
115 {
116 DEBUG_FUNCTION_ENTER2;
117 ssize_t size;
118 do {
119 size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
120 } while (size == B_INTERRUPTED);
121
122 if (size < 0)
123 return size;
124
125 status_t result;
126 char* buffer = (char*)malloc(size);
127 if (buffer == NULL)
128 return B_NO_MEMORY;
129
130 do {
131 result = read_port(replyPort, _code, buffer, size);
132 } while (result == B_INTERRUPTED);
133
134 if (result < 0 || *_code != kPortMessageCode) {
135 free(buffer);
136 return result < 0 ? result : B_ERROR;
137 }
138
139 result = reply->Unflatten(buffer);
140 free(buffer);
141 return result;
142 }
143
144
145 // #pragma mark -
146
147
BMessage()148 BMessage::BMessage()
149 {
150 DEBUG_FUNCTION_ENTER;
151 _InitCommon(true);
152 }
153
154
BMessage(BMessage * other)155 BMessage::BMessage(BMessage* other)
156 {
157 DEBUG_FUNCTION_ENTER;
158 _InitCommon(false);
159 *this = *other;
160 }
161
162
BMessage(uint32 _what)163 BMessage::BMessage(uint32 _what)
164 {
165 DEBUG_FUNCTION_ENTER;
166 if (_InitCommon(true))
167 fHeader->what = _what;
168 what = _what;
169 }
170
171
BMessage(const BMessage & other)172 BMessage::BMessage(const BMessage& other)
173 {
174 DEBUG_FUNCTION_ENTER;
175 _InitCommon(false);
176 *this = other;
177 }
178
179
~BMessage()180 BMessage::~BMessage()
181 {
182 DEBUG_FUNCTION_ENTER;
183 _Clear();
184 }
185
186
187 BMessage&
operator =(const BMessage & other)188 BMessage::operator=(const BMessage& other)
189 {
190 DEBUG_FUNCTION_ENTER;
191
192 if (this == &other)
193 return *this;
194
195 _Clear();
196
197 fHeader = (message_header*)malloc(sizeof(message_header));
198 if (fHeader == NULL)
199 return *this;
200
201 if (other.fHeader == NULL)
202 return *this;
203
204 memcpy(fHeader, other.fHeader, sizeof(message_header));
205
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.
212
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);
217
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);
223 }
224
225 if (fHeader->data_size > 0) {
226 if (other.fData != NULL)
227 fData = (uint8*)malloc(fHeader->data_size);
228
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);
235 }
236
237 fHeader->what = what = other.what;
238 fHeader->message_area = -1;
239 fFieldsAvailable = 0;
240 fDataAvailable = 0;
241
242 return *this;
243 }
244
245
246 void*
operator new(size_t size)247 BMessage::operator new(size_t size)
248 {
249 DEBUG_FUNCTION_ENTER2;
250 return sMsgCache->Get(size);
251 }
252
253
254 void*
operator new(size_t size,const std::nothrow_t & noThrow)255 BMessage::operator new(size_t size, const std::nothrow_t& noThrow)
256 {
257 DEBUG_FUNCTION_ENTER2;
258 return sMsgCache->Get(size);
259 }
260
261
262 void*
operator new(size_t,void * pointer)263 BMessage::operator new(size_t, void* pointer)
264 {
265 DEBUG_FUNCTION_ENTER2;
266 return pointer;
267 }
268
269
270 void
operator delete(void * pointer,size_t size)271 BMessage::operator delete(void* pointer, size_t size)
272 {
273 DEBUG_FUNCTION_ENTER2;
274 if (pointer == NULL)
275 return;
276 sMsgCache->Save(pointer, size);
277 }
278
279
280 bool
HasSameData(const BMessage & other,bool ignoreFieldOrder,bool deep) const281 BMessage::HasSameData(const BMessage& other, bool ignoreFieldOrder,
282 bool deep) const
283 {
284 if (this == &other)
285 return true;
286
287 if (fHeader == NULL)
288 return other.fHeader == NULL;
289
290 if (fHeader->field_count != other.fHeader->field_count)
291 return false;
292
293 for (uint32 i = 0; i < fHeader->field_count; i++) {
294 field_header* field = &fFields[i];
295 field_header* otherField = NULL;
296
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;
305
306 const char* otherName = (const char*)other.fData
307 + otherField->offset;
308 if (strncmp(name, otherName, field->name_length) != 0)
309 return false;
310 }
311
312 if (otherField->type != field->type
313 || otherField->count != field->count) {
314 return false;
315 }
316
317 uint8* data = fData + field->offset + field->name_length;
318 uint8* otherData = other.fData + otherField->offset
319 + otherField->name_length;
320
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;
329 }
330 }
331
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;
337 }
338 }
339
340 return true;
341 }
342
343
344 status_t
_InitCommon(bool initHeader)345 BMessage::_InitCommon(bool initHeader)
346 {
347 DEBUG_FUNCTION_ENTER;
348 what = 0;
349
350 fHeader = NULL;
351 fFields = NULL;
352 fData = NULL;
353
354 fFieldsAvailable = 0;
355 fDataAvailable = 0;
356
357 fOriginal = NULL;
358 fQueueLink = NULL;
359
360 fArchivingPointer = NULL;
361
362 if (initHeader)
363 return _InitHeader();
364
365 return B_OK;
366 }
367
368
369 status_t
_InitHeader()370 BMessage::_InitHeader()
371 {
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;
377 }
378
379 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
380
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;
386
387 fHeader->target = B_NULL_TOKEN;
388 fHeader->reply_target = B_NULL_TOKEN;
389 fHeader->reply_port = -1;
390 fHeader->reply_team = -1;
391
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;
396 }
397
398
399 status_t
_Clear()400 BMessage::_Clear()
401 {
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);
409
410 if (fHeader->message_area >= 0)
411 _Dereference();
412
413 free(fHeader);
414 fHeader = NULL;
415 }
416
417 free(fFields);
418 fFields = NULL;
419 free(fData);
420 fData = NULL;
421
422 fArchivingPointer = NULL;
423
424 fFieldsAvailable = 0;
425 fDataAvailable = 0;
426
427 delete fOriginal;
428 fOriginal = NULL;
429
430 return B_OK;
431 }
432
433
434 status_t
GetInfo(type_code typeRequested,int32 index,char ** nameFound,type_code * typeFound,int32 * countFound) const435 BMessage::GetInfo(type_code typeRequested, int32 index, char** nameFound,
436 type_code* typeFound, int32* countFound) const
437 {
438 DEBUG_FUNCTION_ENTER;
439 if (fHeader == NULL)
440 return B_NO_INIT;
441
442 if (index < 0 || (uint32)index >= fHeader->field_count)
443 return B_BAD_INDEX;
444
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;
453 }
454
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++;
460
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;
469 }
470 }
471
472 if (counter == -1)
473 return B_BAD_TYPE;
474
475 return B_BAD_INDEX;
476 }
477
478
479 status_t
GetInfo(const char * name,type_code * typeFound,int32 * countFound) const480 BMessage::GetInfo(const char* name, type_code* typeFound,
481 int32* countFound) const
482 {
483 DEBUG_FUNCTION_ENTER;
484 if (countFound != NULL)
485 *countFound = 0;
486
487 field_header* field = NULL;
488 status_t result = _FindField(name, B_ANY_TYPE, &field);
489 if (result != B_OK)
490 return result;
491
492 if (typeFound != NULL)
493 *typeFound = field->type;
494 if (countFound != NULL)
495 *countFound = field->count;
496
497 return B_OK;
498 }
499
500
501 status_t
GetInfo(const char * name,type_code * typeFound,bool * fixedSize) const502 BMessage::GetInfo(const char* name, type_code* typeFound, bool* fixedSize)
503 const
504 {
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;
510
511 if (typeFound != NULL)
512 *typeFound = field->type;
513 if (fixedSize != NULL)
514 *fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
515
516 return B_OK;
517 }
518
519
520 status_t
GetInfo(const char * name,type_code * typeFound,int32 * countFound,bool * fixedSize) const521 BMessage::GetInfo(const char* name, type_code* typeFound, int32* countFound,
522 bool* fixedSize) const
523 {
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;
529
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;
536
537 return B_OK;
538 }
539
540
541 int32
CountNames(type_code type) const542 BMessage::CountNames(type_code type) const
543 {
544 DEBUG_FUNCTION_ENTER;
545 if (fHeader == NULL)
546 return 0;
547
548 if (type == B_ANY_TYPE)
549 return fHeader->field_count;
550
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++;
556 }
557
558 return count;
559 }
560
561
562 bool
IsEmpty() const563 BMessage::IsEmpty() const
564 {
565 DEBUG_FUNCTION_ENTER;
566 return fHeader == NULL || fHeader->field_count == 0;
567 }
568
569
570 bool
IsSystem() const571 BMessage::IsSystem() const
572 {
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);
578
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;
587
588 return false;
589 }
590
591
592 bool
IsReply() const593 BMessage::IsReply() const
594 {
595 DEBUG_FUNCTION_ENTER;
596 return fHeader != NULL && (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
597 }
598
599
600 void
PrintToStream() const601 BMessage::PrintToStream() const
602 {
603 _PrintToStream("");
604 printf("}\n");
605 }
606
607
608 void
_PrintToStream(const char * indent) const609 BMessage::_PrintToStream(const char* indent) const
610 {
611 DEBUG_FUNCTION_ENTER;
612
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");
620
621 if (fHeader == NULL || fFields == NULL || fData == NULL)
622 return;
623
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;
630
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);
639 }
640
641 if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) {
642 size = *(uint32*)pointer;
643 pointer += sizeof(uint32);
644 }
645
646 switch (field->type) {
647 case B_RECT_TYPE:
648 print_to_stream_type<BRect>(pointer);
649 break;
650
651 case B_POINT_TYPE:
652 print_to_stream_type<BPoint>(pointer);
653 break;
654
655 case B_STRING_TYPE:
656 printf("string(\"%.*s\", %ld bytes)\n", (int)size,
657 (char*)pointer, (long)size);
658 break;
659
660 case B_INT8_TYPE:
661 print_type3<int8>("int8(0x%hx or %d or '%c')\n",
662 pointer);
663 break;
664
665 case B_UINT8_TYPE:
666 print_type3<uint8>("uint8(0x%hx or %u or '%c')\n",
667 pointer);
668 break;
669
670 case B_INT16_TYPE:
671 print_type<int16>("int16(0x%x or %d)\n", pointer);
672 break;
673
674 case B_UINT16_TYPE:
675 print_type<uint16>("uint16(0x%x or %u)\n", pointer);
676 break;
677
678 case B_INT32_TYPE:
679 print_type<int32>("int32(0x%lx or %ld)\n", pointer);
680 break;
681
682 case B_UINT32_TYPE:
683 print_type<uint32>("uint32(0x%lx or %lu)\n", pointer);
684 break;
685
686 case B_INT64_TYPE:
687 print_type<int64>("int64(0x%Lx or %lld)\n", pointer);
688 break;
689
690 case B_UINT64_TYPE:
691 print_type<uint64>("uint64(0x%Lx or %lld)\n", pointer);
692 break;
693
694 case B_BOOL_TYPE:
695 printf("bool(%s)\n", *((bool*)pointer) != 0
696 ? "true" : "false");
697 break;
698
699 case B_FLOAT_TYPE:
700 print_type<float>("float(%.4f)\n", pointer);
701 break;
702
703 case B_DOUBLE_TYPE:
704 print_type<double>("double(%.8f)\n", pointer);
705 break;
706
707 case B_REF_TYPE:
708 {
709 entry_ref ref;
710 BPrivate::entry_ref_unflatten(&ref, (char*)pointer, size);
711
712 printf("entry_ref(device=%d, directory=%" B_PRIdINO
713 ", name=\"%s\", ", (int)ref.device, ref.directory,
714 ref.name);
715
716 BPath path(&ref);
717 printf("path=\"%s\")\n", path.Path());
718 break;
719 }
720
721 case B_NODE_REF_TYPE:
722 {
723 node_ref ref;
724 BPrivate::node_ref_unflatten(&ref, (char*)pointer, size);
725
726 printf("node_ref(device=%d, node=%" B_PRIdINO ", ",
727 (int)ref.device, ref.node);
728 break;
729 }
730
731 case B_MESSAGE_TYPE:
732 {
733 char buffer[1024];
734 snprintf(buffer, sizeof(buffer), "%s ", indent);
735
736 BMessage message;
737 status_t result = message.Unflatten((const char*)pointer);
738 if (result != B_OK) {
739 printf("failed unflatten: %s\n", strerror(result));
740 break;
741 }
742
743 message._PrintToStream(buffer);
744 printf("%s }\n", indent);
745 break;
746 }
747
748 case B_RGB_32_BIT_TYPE:
749 {
750 rgb_color* color = (rgb_color*)pointer;
751 printf("rgb_color(%u, %u, %u, %u)\n", color->red,
752 color->green, color->blue, color->alpha);
753 break;
754 }
755
756 default:
757 {
758 printf("(type = '%.4s')(size = %ld)\n", (char*)&value,
759 (long)size);
760 break;
761 }
762 }
763
764 pointer += size;
765 }
766 }
767 }
768
769
770 status_t
Rename(const char * oldEntry,const char * newEntry)771 BMessage::Rename(const char* oldEntry, const char* newEntry)
772 {
773 DEBUG_FUNCTION_ENTER;
774 if (oldEntry == NULL || newEntry == NULL)
775 return B_BAD_VALUE;
776
777 if (fHeader == NULL)
778 return B_NO_INIT;
779
780 status_t result;
781 if (fHeader->message_area >= 0) {
782 result = _CopyForWrite();
783 if (result != B_OK)
784 return result;
785 }
786
787 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
788 int32* nextField = &fHeader->hash_table[hash];
789
790 while (*nextField >= 0) {
791 field_header* field = &fFields[*nextField];
792
793 if (strncmp((const char*)(fData + field->offset), oldEntry,
794 field->name_length) == 0) {
795 // nextField points to the field for oldEntry, save it and unlink
796 int32 index = *nextField;
797 *nextField = field->next_field;
798 field->next_field = -1;
799
800 hash = _HashName(newEntry) % fHeader->hash_table_size;
801 nextField = &fHeader->hash_table[hash];
802 while (*nextField >= 0)
803 nextField = &fFields[*nextField].next_field;
804 *nextField = index;
805
806 int32 newLength = strlen(newEntry) + 1;
807 result = _ResizeData(field->offset + 1,
808 newLength - field->name_length);
809 if (result != B_OK)
810 return result;
811
812 memcpy(fData + field->offset, newEntry, newLength);
813 field->name_length = newLength;
814 return B_OK;
815 }
816
817 nextField = &field->next_field;
818 }
819
820 return B_NAME_NOT_FOUND;
821 }
822
823
824 bool
WasDelivered() const825 BMessage::WasDelivered() const
826 {
827 DEBUG_FUNCTION_ENTER;
828 return fHeader != NULL
829 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
830 }
831
832
833 bool
IsSourceWaiting() const834 BMessage::IsSourceWaiting() const
835 {
836 DEBUG_FUNCTION_ENTER;
837 return fHeader != NULL
838 && (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
839 && (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
840 }
841
842
843 bool
IsSourceRemote() const844 BMessage::IsSourceRemote() const
845 {
846 DEBUG_FUNCTION_ENTER;
847 return fHeader != NULL
848 && (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0
849 && fHeader->reply_team != BPrivate::current_team();
850 }
851
852
853 BMessenger
ReturnAddress() const854 BMessage::ReturnAddress() const
855 {
856 DEBUG_FUNCTION_ENTER;
857 if (fHeader == NULL || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
858 return BMessenger();
859
860 BMessenger messenger;
861 BMessenger::Private(messenger).SetTo(fHeader->reply_team,
862 fHeader->reply_port, fHeader->reply_target);
863 return messenger;
864 }
865
866
867 const BMessage*
Previous() const868 BMessage::Previous() const
869 {
870 DEBUG_FUNCTION_ENTER;
871 /* ToDo: test if the "_previous_" field is used in R5 */
872 if (fOriginal == NULL) {
873 fOriginal = new BMessage();
874
875 if (FindMessage("_previous_", fOriginal) != B_OK) {
876 delete fOriginal;
877 fOriginal = NULL;
878 }
879 }
880
881 return fOriginal;
882 }
883
884
885 bool
WasDropped() const886 BMessage::WasDropped() const
887 {
888 DEBUG_FUNCTION_ENTER;
889 return fHeader != NULL
890 && (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
891 }
892
893
894 BPoint
DropPoint(BPoint * offset) const895 BMessage::DropPoint(BPoint* offset) const
896 {
897 DEBUG_FUNCTION_ENTER;
898 if (offset != NULL)
899 *offset = FindPoint("_drop_offset_");
900
901 return FindPoint("_drop_point_");
902 }
903
904
905 status_t
SendReply(uint32 command,BHandler * replyTo)906 BMessage::SendReply(uint32 command, BHandler* replyTo)
907 {
908 DEBUG_FUNCTION_ENTER;
909 BMessage message(command);
910 return SendReply(&message, replyTo);
911 }
912
913
914 status_t
SendReply(BMessage * reply,BHandler * replyTo,bigtime_t timeout)915 BMessage::SendReply(BMessage* reply, BHandler* replyTo, bigtime_t timeout)
916 {
917 DEBUG_FUNCTION_ENTER;
918 BMessenger messenger(replyTo);
919 return SendReply(reply, messenger, timeout);
920 }
921
922
923 status_t
SendReply(BMessage * reply,BMessenger replyTo,bigtime_t timeout)924 BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
925 {
926 DEBUG_FUNCTION_ENTER;
927 if (fHeader == NULL)
928 return B_NO_INIT;
929
930 BMessenger messenger;
931 BMessenger::Private messengerPrivate(messenger);
932 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
933 fHeader->reply_target);
934 if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0)
935 reply->fHeader->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE;
936
937 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
938 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
939 return B_DUPLICATE_REPLY;
940
941 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
942 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
943 status_t result = messenger.SendMessage(reply, replyTo, timeout);
944 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
945
946 if (result != B_OK && set_port_owner(messengerPrivate.Port(),
947 messengerPrivate.Team()) == B_BAD_TEAM_ID) {
948 delete_port(messengerPrivate.Port());
949 }
950
951 return result;
952 }
953
954 // no reply required
955 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
956 return B_BAD_REPLY;
957
958 reply->AddMessage("_previous_", this);
959 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
960 status_t result = messenger.SendMessage(reply, replyTo, timeout);
961 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
962 reply->RemoveName("_previous_");
963 return result;
964 }
965
966
967 status_t
SendReply(uint32 command,BMessage * replyToReply)968 BMessage::SendReply(uint32 command, BMessage* replyToReply)
969 {
970 DEBUG_FUNCTION_ENTER;
971 BMessage message(command);
972 return SendReply(&message, replyToReply);
973 }
974
975
976 status_t
SendReply(BMessage * reply,BMessage * replyToReply,bigtime_t sendTimeout,bigtime_t replyTimeout)977 BMessage::SendReply(BMessage* reply, BMessage* replyToReply,
978 bigtime_t sendTimeout, bigtime_t replyTimeout)
979 {
980 DEBUG_FUNCTION_ENTER;
981 if (fHeader == NULL)
982 return B_NO_INIT;
983
984 BMessenger messenger;
985 BMessenger::Private messengerPrivate(messenger);
986 messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
987 fHeader->reply_target);
988
989 if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
990 if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
991 return B_DUPLICATE_REPLY;
992
993 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
994 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
995 status_t result = messenger.SendMessage(reply, replyToReply,
996 sendTimeout, replyTimeout);
997 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
998
999 if (result != B_OK) {
1000 if (set_port_owner(messengerPrivate.Port(),
1001 messengerPrivate.Team()) == B_BAD_TEAM_ID) {
1002 delete_port(messengerPrivate.Port());
1003 }
1004 }
1005
1006 return result;
1007 }
1008
1009 // no reply required
1010 if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1011 return B_BAD_REPLY;
1012
1013 reply->AddMessage("_previous_", this);
1014 reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY
1015 | (fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE);
1016 status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
1017 replyTimeout);
1018 reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
1019 reply->RemoveName("_previous_");
1020 return result;
1021 }
1022
1023
1024 ssize_t
FlattenedSize() const1025 BMessage::FlattenedSize() const
1026 {
1027 DEBUG_FUNCTION_ENTER;
1028 if (fHeader == NULL)
1029 return B_NO_INIT;
1030
1031 return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
1032 + fHeader->data_size;
1033 }
1034
1035
1036 status_t
Flatten(char * buffer,ssize_t size) const1037 BMessage::Flatten(char* buffer, ssize_t size) const
1038 {
1039 DEBUG_FUNCTION_ENTER;
1040 if (buffer == NULL || size < 0)
1041 return B_BAD_VALUE;
1042
1043 if (fHeader == NULL)
1044 return B_NO_INIT;
1045
1046 if (size < FlattenedSize())
1047 return B_BUFFER_OVERFLOW;
1048
1049 /* we have to sync the what code as it is a public member */
1050 fHeader->what = what;
1051
1052 memcpy(buffer, fHeader, sizeof(message_header));
1053 buffer += sizeof(message_header);
1054
1055 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1056 memcpy(buffer, fFields, fieldsSize);
1057 buffer += fieldsSize;
1058
1059 memcpy(buffer, fData, fHeader->data_size);
1060
1061 return B_OK;
1062 }
1063
1064
1065 status_t
Flatten(BDataIO * stream,ssize_t * size) const1066 BMessage::Flatten(BDataIO* stream, ssize_t* size) const
1067 {
1068 DEBUG_FUNCTION_ENTER;
1069 if (stream == NULL)
1070 return B_BAD_VALUE;
1071
1072 if (fHeader == NULL)
1073 return B_NO_INIT;
1074
1075 /* we have to sync the what code as it is a public member */
1076 fHeader->what = what;
1077
1078 ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
1079 if (result1 != sizeof(message_header))
1080 return result1 < 0 ? result1 : B_ERROR;
1081
1082 ssize_t result2 = 0;
1083 if (fHeader->field_count > 0) {
1084 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1085 result2 = stream->Write(fFields, fieldsSize);
1086 if (result2 != fieldsSize)
1087 return result2 < 0 ? result2 : B_ERROR;
1088 }
1089
1090 ssize_t result3 = 0;
1091 if (fHeader->data_size > 0) {
1092 result3 = stream->Write(fData, fHeader->data_size);
1093 if (result3 != (ssize_t)fHeader->data_size)
1094 return result3 < 0 ? result3 : B_ERROR;
1095 }
1096
1097 if (size)
1098 *size = result1 + result2 + result3;
1099
1100 return B_OK;
1101 }
1102
1103
1104 /* The concept of message sending by area:
1105
1106 The traditional way of sending a message is to send it by flattening it to
1107 a buffer, pushing it through a port, reading it into the outputbuffer and
1108 unflattening it from there (copying the data again). While this works ok
1109 for small messages it does not make any sense for larger ones and may even
1110 hit some port capacity limit.
1111 Often in the life of a BMessage, it will be sent to someone. Almost as
1112 often the one receiving the message will not need to change the message
1113 in any way, but uses it "read only" to get information from it. This means
1114 that all that copying is pretty pointless in the first place since we
1115 could simply pass the original buffers on.
1116 It's obviously not exactly as simple as this, since we cannot just use the
1117 memory of one application in another - but we can share areas with
1118 eachother.
1119 Therefore instead of flattening into a buffer, we copy the message data
1120 into an area, put this information into the message header and only push
1121 this through the port. The receiving looper then builds a BMessage from
1122 the header, that only references the data in the area (not copying it),
1123 allowing read only access to it.
1124 Only if write access is necessary the message will be copyed from the area
1125 to its own buffers (like in the unflatten step before).
1126 The double copying is reduced to a single copy in most cases and we safe
1127 the slower route of moving the data through a port.
1128 Additionally we save us the reference counting with the use of areas that
1129 are reference counted internally. So we don't have to worry about leaving
1130 an area behind or deleting one that is still in use.
1131 */
1132
1133 status_t
_FlattenToArea(message_header ** _header) const1134 BMessage::_FlattenToArea(message_header** _header) const
1135 {
1136 DEBUG_FUNCTION_ENTER;
1137 if (fHeader == NULL)
1138 return B_NO_INIT;
1139
1140 message_header* header = (message_header*)malloc(sizeof(message_header));
1141 if (header == NULL)
1142 return B_NO_MEMORY;
1143
1144 memcpy(header, fHeader, sizeof(message_header));
1145
1146 header->what = what;
1147 header->message_area = -1;
1148 *_header = header;
1149
1150 if (header->field_count == 0 && header->data_size == 0)
1151 return B_OK;
1152
1153 char* address = NULL;
1154 size_t fieldsSize = header->field_count * sizeof(field_header);
1155 size_t size = fieldsSize + header->data_size;
1156 size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
1157 area_id area = create_area("BMessage data", (void**)&address,
1158 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1159
1160 if (area < 0) {
1161 free(header);
1162 *_header = NULL;
1163 return area;
1164 }
1165
1166 memcpy(address, fFields, fieldsSize);
1167 memcpy(address + fieldsSize, fData, fHeader->data_size);
1168 header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
1169 header->message_area = area;
1170 return B_OK;
1171 }
1172
1173
1174 status_t
_Reference()1175 BMessage::_Reference()
1176 {
1177 DEBUG_FUNCTION_ENTER;
1178 if (fHeader == NULL)
1179 return B_NO_INIT;
1180
1181 fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
1182
1183 /* if there is no data at all we don't need the area */
1184 if (fHeader->field_count == 0 && fHeader->data_size == 0)
1185 return B_OK;
1186
1187 area_info areaInfo;
1188 status_t result = get_area_info(fHeader->message_area, &areaInfo);
1189 if (result != B_OK)
1190 return result;
1191
1192 if (areaInfo.team != BPrivate::current_team())
1193 return B_BAD_VALUE;
1194
1195 set_area_protection(fHeader->message_area, B_READ_AREA);
1196
1197 uint8* address = (uint8*)areaInfo.address;
1198
1199 fFields = (field_header*)address;
1200 fData = address + fHeader->field_count * sizeof(field_header);
1201 return B_OK;
1202 }
1203
1204
1205 status_t
_Dereference()1206 BMessage::_Dereference()
1207 {
1208 DEBUG_FUNCTION_ENTER;
1209 if (fHeader == NULL)
1210 return B_NO_INIT;
1211
1212 delete_area(fHeader->message_area);
1213 fHeader->message_area = -1;
1214 fFields = NULL;
1215 fData = NULL;
1216 return B_OK;
1217 }
1218
1219
1220 status_t
_CopyForWrite()1221 BMessage::_CopyForWrite()
1222 {
1223 DEBUG_FUNCTION_ENTER;
1224 if (fHeader == NULL)
1225 return B_NO_INIT;
1226
1227 field_header* newFields = NULL;
1228 uint8* newData = NULL;
1229
1230 if (fHeader->field_count > 0) {
1231 size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1232 newFields = (field_header*)malloc(fieldsSize);
1233 if (newFields == NULL)
1234 return B_NO_MEMORY;
1235
1236 memcpy(newFields, fFields, fieldsSize);
1237 }
1238
1239 if (fHeader->data_size > 0) {
1240 newData = (uint8*)malloc(fHeader->data_size);
1241 if (newData == NULL) {
1242 free(newFields);
1243 return B_NO_MEMORY;
1244 }
1245
1246 memcpy(newData, fData, fHeader->data_size);
1247 }
1248
1249 _Dereference();
1250
1251 fFieldsAvailable = 0;
1252 fDataAvailable = 0;
1253
1254 fFields = newFields;
1255 fData = newData;
1256 return B_OK;
1257 }
1258
1259
1260 status_t
_ValidateMessage()1261 BMessage::_ValidateMessage()
1262 {
1263 DEBUG_FUNCTION_ENTER;
1264 if (fHeader == NULL)
1265 return B_NO_INIT;
1266
1267 if (fHeader->field_count == 0)
1268 return B_OK;
1269
1270 if (fFields == NULL)
1271 return B_NO_INIT;
1272
1273 for (uint32 i = 0; i < fHeader->field_count; i++) {
1274 field_header* field = &fFields[i];
1275 if ((field->next_field >= 0
1276 && (uint32)field->next_field > fHeader->field_count)
1277 || (field->offset + field->name_length + field->data_size
1278 > fHeader->data_size)) {
1279 // the message is corrupt
1280 MakeEmpty();
1281 return B_BAD_VALUE;
1282 }
1283 }
1284
1285 return B_OK;
1286 }
1287
1288
1289 status_t
Unflatten(const char * flatBuffer)1290 BMessage::Unflatten(const char* flatBuffer)
1291 {
1292 DEBUG_FUNCTION_ENTER;
1293 if (flatBuffer == NULL)
1294 return B_BAD_VALUE;
1295
1296 uint32 format = *(uint32*)flatBuffer;
1297 if (format != MESSAGE_FORMAT_HAIKU)
1298 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
1299
1300 BMemoryIO io(flatBuffer, SSIZE_MAX);
1301 return Unflatten(&io);
1302 }
1303
1304
1305 status_t
Unflatten(BDataIO * stream)1306 BMessage::Unflatten(BDataIO* stream)
1307 {
1308 DEBUG_FUNCTION_ENTER;
1309 if (stream == NULL)
1310 return B_BAD_VALUE;
1311
1312 uint32 format = 0;
1313 stream->Read(&format, sizeof(uint32));
1314 if (format != MESSAGE_FORMAT_HAIKU)
1315 return BPrivate::MessageAdapter::Unflatten(format, this, stream);
1316
1317 // native message unflattening
1318
1319 _Clear();
1320
1321 fHeader = (message_header*)malloc(sizeof(message_header));
1322 if (fHeader == NULL)
1323 return B_NO_MEMORY;
1324
1325 fHeader->format = format;
1326 uint8* header = (uint8*)fHeader;
1327 ssize_t result = stream->Read(header + sizeof(uint32),
1328 sizeof(message_header) - sizeof(uint32));
1329 if (result != sizeof(message_header) - sizeof(uint32)
1330 || (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
1331 _InitHeader();
1332 return result < 0 ? result : B_BAD_VALUE;
1333 }
1334
1335 what = fHeader->what;
1336
1337 if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
1338 && fHeader->message_area >= 0) {
1339 status_t result = _Reference();
1340 if (result != B_OK) {
1341 _InitHeader();
1342 return result;
1343 }
1344 } else {
1345 fHeader->message_area = -1;
1346
1347 if (fHeader->field_count > 0) {
1348 ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1349 fFields = (field_header*)malloc(fieldsSize);
1350 if (fFields == NULL) {
1351 _InitHeader();
1352 return B_NO_MEMORY;
1353 }
1354
1355 result = stream->Read(fFields, fieldsSize);
1356 if (result != fieldsSize)
1357 return result < 0 ? result : B_BAD_VALUE;
1358 }
1359
1360 if (fHeader->data_size > 0) {
1361 fData = (uint8*)malloc(fHeader->data_size);
1362 if (fData == NULL) {
1363 free(fFields);
1364 fFields = NULL;
1365 _InitHeader();
1366 return B_NO_MEMORY;
1367 }
1368
1369 result = stream->Read(fData, fHeader->data_size);
1370 if (result != (ssize_t)fHeader->data_size) {
1371 free(fData);
1372 fData = NULL;
1373 free(fFields);
1374 fFields = NULL;
1375 _InitHeader();
1376 return result < 0 ? result : B_BAD_VALUE;
1377 }
1378 }
1379 }
1380
1381 return _ValidateMessage();
1382 }
1383
1384
1385 status_t
AddSpecifier(const char * property)1386 BMessage::AddSpecifier(const char* property)
1387 {
1388 DEBUG_FUNCTION_ENTER;
1389 BMessage message(B_DIRECT_SPECIFIER);
1390 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1391 if (result != B_OK)
1392 return result;
1393
1394 return AddSpecifier(&message);
1395 }
1396
1397
1398 status_t
AddSpecifier(const char * property,int32 index)1399 BMessage::AddSpecifier(const char* property, int32 index)
1400 {
1401 DEBUG_FUNCTION_ENTER;
1402 BMessage message(B_INDEX_SPECIFIER);
1403 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1404 if (result != B_OK)
1405 return result;
1406
1407 result = message.AddInt32("index", index);
1408 if (result != B_OK)
1409 return result;
1410
1411 return AddSpecifier(&message);
1412 }
1413
1414
1415 status_t
AddSpecifier(const char * property,int32 index,int32 range)1416 BMessage::AddSpecifier(const char* property, int32 index, int32 range)
1417 {
1418 DEBUG_FUNCTION_ENTER;
1419 if (range < 0)
1420 return B_BAD_VALUE;
1421
1422 BMessage message(B_RANGE_SPECIFIER);
1423 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1424 if (result != B_OK)
1425 return result;
1426
1427 result = message.AddInt32("index", index);
1428 if (result != B_OK)
1429 return result;
1430
1431 result = message.AddInt32("range", range);
1432 if (result != B_OK)
1433 return result;
1434
1435 return AddSpecifier(&message);
1436 }
1437
1438
1439 status_t
AddSpecifier(const char * property,const char * name)1440 BMessage::AddSpecifier(const char* property, const char* name)
1441 {
1442 DEBUG_FUNCTION_ENTER;
1443 BMessage message(B_NAME_SPECIFIER);
1444 status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1445 if (result != B_OK)
1446 return result;
1447
1448 result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1449 if (result != B_OK)
1450 return result;
1451
1452 return AddSpecifier(&message);
1453 }
1454
1455
1456 status_t
AddSpecifier(const BMessage * specifier)1457 BMessage::AddSpecifier(const BMessage* specifier)
1458 {
1459 DEBUG_FUNCTION_ENTER;
1460 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1461 if (result != B_OK)
1462 return result;
1463
1464 fHeader->current_specifier++;
1465 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1466 return B_OK;
1467 }
1468
1469
1470 status_t
SetCurrentSpecifier(int32 index)1471 BMessage::SetCurrentSpecifier(int32 index)
1472 {
1473 DEBUG_FUNCTION_ENTER;
1474 if (index < 0)
1475 return B_BAD_INDEX;
1476
1477 type_code type;
1478 int32 count;
1479 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1480 if (result != B_OK)
1481 return result;
1482
1483 if (index >= count)
1484 return B_BAD_INDEX;
1485
1486 fHeader->current_specifier = index;
1487 return B_OK;
1488 }
1489
1490
1491 status_t
GetCurrentSpecifier(int32 * index,BMessage * specifier,int32 * _what,const char ** property) const1492 BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what,
1493 const char** property) const
1494 {
1495 DEBUG_FUNCTION_ENTER;
1496 if (fHeader == NULL)
1497 return B_NO_INIT;
1498
1499 if (index != NULL)
1500 *index = fHeader->current_specifier;
1501
1502 if (fHeader->current_specifier < 0
1503 || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1504 return B_BAD_SCRIPT_SYNTAX;
1505
1506 if (specifier) {
1507 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1508 specifier) != B_OK)
1509 return B_BAD_SCRIPT_SYNTAX;
1510
1511 if (_what != NULL)
1512 *_what = specifier->what;
1513
1514 if (property) {
1515 if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK)
1516 return B_BAD_SCRIPT_SYNTAX;
1517 }
1518 }
1519
1520 return B_OK;
1521 }
1522
1523
1524 bool
HasSpecifiers() const1525 BMessage::HasSpecifiers() const
1526 {
1527 DEBUG_FUNCTION_ENTER;
1528 return fHeader != NULL
1529 && (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1530 }
1531
1532
1533 status_t
PopSpecifier()1534 BMessage::PopSpecifier()
1535 {
1536 DEBUG_FUNCTION_ENTER;
1537 if (fHeader == NULL)
1538 return B_NO_INIT;
1539
1540 if (fHeader->current_specifier < 0 ||
1541 (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1542 return B_BAD_VALUE;
1543
1544 if (fHeader->current_specifier >= 0)
1545 fHeader->current_specifier--;
1546
1547 return B_OK;
1548 }
1549
1550
1551 void
_UpdateOffsets(uint32 offset,int32 change)1552 BMessage::_UpdateOffsets(uint32 offset, int32 change)
1553 {
1554 // Update the header to match the new position of the fields
1555 if (offset < fHeader->data_size) {
1556 field_header* field = fFields;
1557 for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1558 if (field->offset >= offset)
1559 field->offset += change;
1560 }
1561 }
1562 }
1563
1564
1565 status_t
_ResizeData(uint32 offset,int32 change)1566 BMessage::_ResizeData(uint32 offset, int32 change)
1567 {
1568 if (change == 0)
1569 return B_OK;
1570
1571 /* optimize for the most usual case: appending data */
1572
1573 if (change > 0) {
1574 // We need to make the field bigger
1575 // check if there is enough free space allocated
1576 if (fDataAvailable >= (uint32)change) {
1577 // In this case, we just need to move the data after the growing
1578 // field to get the space at the right place
1579 if (offset < fHeader->data_size) {
1580 memmove(fData + offset + change, fData + offset,
1581 fHeader->data_size - offset);
1582 }
1583
1584 _UpdateOffsets(offset, change);
1585
1586 fDataAvailable -= change;
1587 fHeader->data_size += change;
1588 return B_OK;
1589 }
1590
1591 // We need to grow the buffer. We try to optimize reallocations by
1592 // preallocating space for more fields.
1593 size_t size = fHeader->data_size * 2;
1594 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1595 size = max_c(size, fHeader->data_size + change);
1596
1597 uint8* newData = (uint8*)realloc(fData, size);
1598 if (size > 0 && newData == NULL)
1599 return B_NO_MEMORY;
1600
1601 fData = newData;
1602 if (offset < fHeader->data_size) {
1603 memmove(fData + offset + change, fData + offset,
1604 fHeader->data_size - offset);
1605 }
1606
1607 fHeader->data_size += change;
1608 fDataAvailable = size - fHeader->data_size;
1609 } else {
1610 ssize_t length = fHeader->data_size - offset + change;
1611 if (length > 0)
1612 memmove(fData + offset, fData + offset - change, length);
1613
1614 // change is negative
1615 fHeader->data_size += change;
1616 fDataAvailable -= change;
1617
1618 if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1619 ssize_t available = MAX_DATA_PREALLOCATION / 2;
1620 ssize_t size = fHeader->data_size + available;
1621 uint8* newData = (uint8*)realloc(fData, size);
1622 if (size > 0 && newData == NULL) {
1623 // this is strange, but not really fatal
1624 _UpdateOffsets(offset, change);
1625 return B_OK;
1626 }
1627
1628 fData = newData;
1629 fDataAvailable = available;
1630 }
1631 }
1632
1633 _UpdateOffsets(offset, change);
1634 return B_OK;
1635 }
1636
1637
1638 uint32
_HashName(const char * name) const1639 BMessage::_HashName(const char* name) const
1640 {
1641 char ch;
1642 uint32 result = 0;
1643
1644 while ((ch = *name++) != 0) {
1645 result = (result << 7) ^ (result >> 24);
1646 result ^= ch;
1647 }
1648
1649 result ^= result << 12;
1650 return result;
1651 }
1652
1653
1654 status_t
_FindField(const char * name,type_code type,field_header ** result) const1655 BMessage::_FindField(const char* name, type_code type, field_header** result)
1656 const
1657 {
1658 if (name == NULL)
1659 return B_BAD_VALUE;
1660
1661 if (fHeader == NULL)
1662 return B_NO_INIT;
1663
1664 if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
1665 return B_NAME_NOT_FOUND;
1666
1667 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1668 int32 nextField = fHeader->hash_table[hash];
1669
1670 while (nextField >= 0) {
1671 field_header* field = &fFields[nextField];
1672 if ((field->flags & FIELD_FLAG_VALID) == 0)
1673 break;
1674
1675 if (strncmp((const char*)(fData + field->offset), name,
1676 field->name_length) == 0) {
1677 if (type != B_ANY_TYPE && field->type != type)
1678 return B_BAD_TYPE;
1679
1680 *result = field;
1681 return B_OK;
1682 }
1683
1684 nextField = field->next_field;
1685 }
1686
1687 return B_NAME_NOT_FOUND;
1688 }
1689
1690
1691 status_t
_AddField(const char * name,type_code type,bool isFixedSize,field_header ** result)1692 BMessage::_AddField(const char* name, type_code type, bool isFixedSize,
1693 field_header** result)
1694 {
1695 if (fHeader == NULL)
1696 return B_NO_INIT;
1697
1698 if (fFieldsAvailable <= 0) {
1699 uint32 count = fHeader->field_count * 2 + 1;
1700 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1701
1702 field_header* newFields = (field_header*)realloc(fFields,
1703 count * sizeof(field_header));
1704 if (count > 0 && newFields == NULL)
1705 return B_NO_MEMORY;
1706
1707 fFields = newFields;
1708 fFieldsAvailable = count - fHeader->field_count;
1709 }
1710
1711 uint32 hash = _HashName(name) % fHeader->hash_table_size;
1712 int32* nextField = &fHeader->hash_table[hash];
1713 while (*nextField >= 0)
1714 nextField = &fFields[*nextField].next_field;
1715 *nextField = fHeader->field_count;
1716
1717 field_header* field = &fFields[fHeader->field_count];
1718 field->type = type;
1719 field->count = 0;
1720 field->data_size = 0;
1721 field->next_field = -1;
1722 field->offset = fHeader->data_size;
1723 field->name_length = strlen(name) + 1;
1724 status_t status = _ResizeData(field->offset, field->name_length);
1725 if (status != B_OK)
1726 return status;
1727
1728 memcpy(fData + field->offset, name, field->name_length);
1729 field->flags = FIELD_FLAG_VALID;
1730 if (isFixedSize)
1731 field->flags |= FIELD_FLAG_FIXED_SIZE;
1732
1733 fFieldsAvailable--;
1734 fHeader->field_count++;
1735 *result = field;
1736 return B_OK;
1737 }
1738
1739
1740 status_t
_RemoveField(field_header * field)1741 BMessage::_RemoveField(field_header* field)
1742 {
1743 status_t result = _ResizeData(field->offset, -(field->data_size
1744 + field->name_length));
1745 if (result != B_OK)
1746 return result;
1747
1748 int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header);
1749 int32 nextField = field->next_field;
1750 if (nextField > index)
1751 nextField--;
1752
1753 int32* value = fHeader->hash_table;
1754 for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1755 if (*value > index)
1756 *value -= 1;
1757 else if (*value == index)
1758 *value = nextField;
1759 }
1760
1761 field_header* other = fFields;
1762 for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1763 if (other->next_field > index)
1764 other->next_field--;
1765 else if (other->next_field == index)
1766 other->next_field = nextField;
1767 }
1768
1769 size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1770 memmove(fFields + index, fFields + index + 1, size);
1771 fHeader->field_count--;
1772 fFieldsAvailable++;
1773
1774 if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1775 ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1776 size = (fHeader->field_count + available) * sizeof(field_header);
1777 field_header* newFields = (field_header*)realloc(fFields, size);
1778 if (size > 0 && newFields == NULL) {
1779 // this is strange, but not really fatal
1780 return B_OK;
1781 }
1782
1783 fFields = newFields;
1784 fFieldsAvailable = available;
1785 }
1786
1787 return B_OK;
1788 }
1789
1790
1791 status_t
AddData(const char * name,type_code type,const void * data,ssize_t numBytes,bool isFixedSize,int32 count)1792 BMessage::AddData(const char* name, type_code type, const void* data,
1793 ssize_t numBytes, bool isFixedSize, int32 count)
1794 {
1795 // Note that the "count" argument is only a hint at how many items
1796 // the caller expects to add to this field. Since we do no item pre-
1797 // allocation, we ignore this argument.
1798 DEBUG_FUNCTION_ENTER;
1799 if (numBytes <= 0 || data == NULL)
1800 return B_BAD_VALUE;
1801
1802 if (fHeader == NULL)
1803 return B_NO_INIT;
1804
1805 status_t result;
1806 if (fHeader->message_area >= 0) {
1807 result = _CopyForWrite();
1808 if (result != B_OK)
1809 return result;
1810 }
1811
1812 field_header* field = NULL;
1813 result = _FindField(name, type, &field);
1814 if (result == B_NAME_NOT_FOUND)
1815 result = _AddField(name, type, isFixedSize, &field);
1816
1817 if (result != B_OK)
1818 return result;
1819
1820 if (field == NULL)
1821 return B_ERROR;
1822
1823 uint32 offset = field->offset + field->name_length + field->data_size;
1824 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1825 if (field->count) {
1826 ssize_t size = field->data_size / field->count;
1827 if (size != numBytes)
1828 return B_BAD_VALUE;
1829 }
1830
1831 result = _ResizeData(offset, numBytes);
1832 if (result != B_OK) {
1833 if (field->count == 0)
1834 _RemoveField(field);
1835 return result;
1836 }
1837
1838 memcpy(fData + offset, data, numBytes);
1839 field->data_size += numBytes;
1840 } else {
1841 int32 change = numBytes + sizeof(uint32);
1842 result = _ResizeData(offset, change);
1843 if (result != B_OK) {
1844 if (field->count == 0)
1845 _RemoveField(field);
1846 return result;
1847 }
1848
1849 uint32 size = (uint32)numBytes;
1850 memcpy(fData + offset, &size, sizeof(uint32));
1851 memcpy(fData + offset + sizeof(uint32), data, size);
1852 field->data_size += change;
1853 }
1854
1855 field->count++;
1856 return B_OK;
1857 }
1858
1859
1860 status_t
RemoveData(const char * name,int32 index)1861 BMessage::RemoveData(const char* name, int32 index)
1862 {
1863 DEBUG_FUNCTION_ENTER;
1864 if (index < 0)
1865 return B_BAD_INDEX;
1866
1867 if (fHeader == NULL)
1868 return B_NO_INIT;
1869
1870 status_t result;
1871 if (fHeader->message_area >= 0) {
1872 result = _CopyForWrite();
1873 if (result != B_OK)
1874 return result;
1875 }
1876
1877 field_header* field = NULL;
1878 result = _FindField(name, B_ANY_TYPE, &field);
1879 if (result != B_OK)
1880 return result;
1881
1882 if ((uint32)index >= field->count)
1883 return B_BAD_INDEX;
1884
1885 if (field->count == 1)
1886 return _RemoveField(field);
1887
1888 uint32 offset = field->offset + field->name_length;
1889 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1890 ssize_t size = field->data_size / field->count;
1891 result = _ResizeData(offset + index * size, -size);
1892 if (result != B_OK)
1893 return result;
1894
1895 field->data_size -= size;
1896 } else {
1897 uint8* pointer = fData + offset;
1898 for (int32 i = 0; i < index; i++) {
1899 offset += *(uint32*)pointer + sizeof(uint32);
1900 pointer = fData + offset;
1901 }
1902
1903 size_t currentSize = *(uint32*)pointer + sizeof(uint32);
1904 result = _ResizeData(offset, -currentSize);
1905 if (result != B_OK)
1906 return result;
1907
1908 field->data_size -= currentSize;
1909 }
1910
1911 field->count--;
1912 return B_OK;
1913 }
1914
1915
1916 status_t
RemoveName(const char * name)1917 BMessage::RemoveName(const char* name)
1918 {
1919 DEBUG_FUNCTION_ENTER;
1920 if (fHeader == NULL)
1921 return B_NO_INIT;
1922
1923 status_t result;
1924 if (fHeader->message_area >= 0) {
1925 result = _CopyForWrite();
1926 if (result != B_OK)
1927 return result;
1928 }
1929
1930 field_header* field = NULL;
1931 result = _FindField(name, B_ANY_TYPE, &field);
1932 if (result != B_OK)
1933 return result;
1934
1935 return _RemoveField(field);
1936 }
1937
1938
1939 status_t
MakeEmpty()1940 BMessage::MakeEmpty()
1941 {
1942 DEBUG_FUNCTION_ENTER;
1943 _Clear();
1944 return _InitHeader();
1945 }
1946
1947
1948 status_t
FindData(const char * name,type_code type,int32 index,const void ** data,ssize_t * numBytes) const1949 BMessage::FindData(const char* name, type_code type, int32 index,
1950 const void** data, ssize_t* numBytes) const
1951 {
1952 DEBUG_FUNCTION_ENTER;
1953 if (data == NULL)
1954 return B_BAD_VALUE;
1955
1956 *data = NULL;
1957 field_header* field = NULL;
1958 status_t result = _FindField(name, type, &field);
1959 if (result != B_OK)
1960 return result;
1961
1962 if (index < 0 || (uint32)index >= field->count)
1963 return B_BAD_INDEX;
1964
1965 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1966 size_t bytes = field->data_size / field->count;
1967 *data = fData + field->offset + field->name_length + index * bytes;
1968 if (numBytes != NULL)
1969 *numBytes = bytes;
1970 } else {
1971 uint8* pointer = fData + field->offset + field->name_length;
1972 for (int32 i = 0; i < index; i++)
1973 pointer += *(uint32*)pointer + sizeof(uint32);
1974
1975 *data = pointer + sizeof(uint32);
1976 if (numBytes != NULL)
1977 *numBytes = *(uint32*)pointer;
1978 }
1979
1980 return B_OK;
1981 }
1982
1983
1984 status_t
ReplaceData(const char * name,type_code type,int32 index,const void * data,ssize_t numBytes)1985 BMessage::ReplaceData(const char* name, type_code type, int32 index,
1986 const void* data, ssize_t numBytes)
1987 {
1988 DEBUG_FUNCTION_ENTER;
1989 if (numBytes <= 0 || data == NULL)
1990 return B_BAD_VALUE;
1991
1992 status_t result;
1993 if (fHeader->message_area >= 0) {
1994 result = _CopyForWrite();
1995 if (result != B_OK)
1996 return result;
1997 }
1998
1999 field_header* field = NULL;
2000 result = _FindField(name, type, &field);
2001 if (result != B_OK)
2002 return result;
2003
2004 if (index < 0 || (uint32)index >= field->count)
2005 return B_BAD_INDEX;
2006
2007 if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
2008 ssize_t size = field->data_size / field->count;
2009 if (size != numBytes)
2010 return B_BAD_VALUE;
2011
2012 memcpy(fData + field->offset + field->name_length + index * size, data,
2013 size);
2014 } else {
2015 uint32 offset = field->offset + field->name_length;
2016 uint8* pointer = fData + offset;
2017
2018 for (int32 i = 0; i < index; i++) {
2019 offset += *(uint32*)pointer + sizeof(uint32);
2020 pointer = fData + offset;
2021 }
2022
2023 size_t currentSize = *(uint32*)pointer;
2024 int32 change = numBytes - currentSize;
2025 result = _ResizeData(offset, change);
2026 if (result != B_OK)
2027 return result;
2028
2029 uint32 newSize = (uint32)numBytes;
2030 memcpy(fData + offset, &newSize, sizeof(uint32));
2031 memcpy(fData + offset + sizeof(uint32), data, newSize);
2032 field->data_size += change;
2033 }
2034
2035 return B_OK;
2036 }
2037
2038
2039 bool
HasData(const char * name,type_code type,int32 index) const2040 BMessage::HasData(const char* name, type_code type, int32 index) const
2041 {
2042 DEBUG_FUNCTION_ENTER;
2043 field_header* field = NULL;
2044 status_t result = _FindField(name, type, &field);
2045 if (result != B_OK)
2046 return false;
2047
2048 if (index < 0 || (uint32)index >= field->count)
2049 return false;
2050
2051 return true;
2052 }
2053
2054
2055 /* Static functions for cache initialization and cleanup */
2056 void
_StaticInit()2057 BMessage::_StaticInit()
2058 {
2059 DEBUG_FUNCTION_ENTER2;
2060 sReplyPorts[0] = create_port(1, "tmp_rport0");
2061 sReplyPorts[1] = create_port(1, "tmp_rport1");
2062 sReplyPorts[2] = create_port(1, "tmp_rport2");
2063
2064 sReplyPortInUse[0] = 0;
2065 sReplyPortInUse[1] = 0;
2066 sReplyPortInUse[2] = 0;
2067
2068 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
2069 }
2070
2071
2072 void
_StaticReInitForkedChild()2073 BMessage::_StaticReInitForkedChild()
2074 {
2075 DEBUG_FUNCTION_ENTER2;
2076
2077 // overwrite the inherited ports with a set of our own
2078 sReplyPorts[0] = create_port(1, "tmp_rport0");
2079 sReplyPorts[1] = create_port(1, "tmp_rport1");
2080 sReplyPorts[2] = create_port(1, "tmp_rport2");
2081
2082 sReplyPortInUse[0] = 0;
2083 sReplyPortInUse[1] = 0;
2084 sReplyPortInUse[2] = 0;
2085 }
2086
2087
2088 void
_StaticCleanup()2089 BMessage::_StaticCleanup()
2090 {
2091 DEBUG_FUNCTION_ENTER2;
2092 delete_port(sReplyPorts[0]);
2093 sReplyPorts[0] = -1;
2094 delete_port(sReplyPorts[1]);
2095 sReplyPorts[1] = -1;
2096 delete_port(sReplyPorts[2]);
2097 sReplyPorts[2] = -1;
2098 }
2099
2100
2101 void
_StaticCacheCleanup()2102 BMessage::_StaticCacheCleanup()
2103 {
2104 DEBUG_FUNCTION_ENTER2;
2105 delete sMsgCache;
2106 sMsgCache = NULL;
2107 }
2108
2109
2110 int32
_StaticGetCachedReplyPort()2111 BMessage::_StaticGetCachedReplyPort()
2112 {
2113 DEBUG_FUNCTION_ENTER2;
2114 int index = -1;
2115 for (int32 i = 0; i < sNumReplyPorts; i++) {
2116 int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2117 if (old == 0) {
2118 // This entry is free
2119 index = i;
2120 break;
2121 } else {
2122 // This entry is being used.
2123 atomic_add(&(sReplyPortInUse[i]), -1);
2124 }
2125 }
2126
2127 return index;
2128 }
2129
2130
2131 status_t
_SendMessage(port_id port,team_id portOwner,int32 token,bigtime_t timeout,bool replyRequired,BMessenger & replyTo) const2132 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2133 bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const
2134 {
2135 DEBUG_FUNCTION_ENTER;
2136 ssize_t size = 0;
2137 char* buffer = NULL;
2138 message_header* header = NULL;
2139 status_t result = B_OK;
2140
2141 BPrivate::BDirectMessageTarget* direct = NULL;
2142 BMessage* copy = NULL;
2143 if (portOwner == BPrivate::current_team())
2144 BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
2145
2146 if (direct != NULL) {
2147 // We have a direct local message target - we can just enqueue the
2148 // message in its message queue. This will also prevent possible
2149 // deadlocks when the queue is full.
2150 copy = new BMessage(*this);
2151 if (copy != NULL) {
2152 header = copy->fHeader;
2153 header->flags = fHeader->flags;
2154 } else {
2155 direct->Release();
2156 return B_NO_MEMORY;
2157 }
2158 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2159 } else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) {
2160 KMessage toMessage;
2161 result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage);
2162 if (result != B_OK)
2163 return result;
2164
2165 return toMessage.SendTo(port, token);
2166 } else if (fHeader->data_size > B_PAGE_SIZE * 10) {
2167 // ToDo: bind the above size to the max port message size
2168 // use message passing by area for such a large message
2169 result = _FlattenToArea(&header);
2170 if (result != B_OK)
2171 return result;
2172
2173 buffer = (char*)header;
2174 size = sizeof(message_header);
2175
2176 if (header->message_area >= 0) {
2177 team_id target = portOwner;
2178 if (target < 0) {
2179 port_info info;
2180 result = get_port_info(port, &info);
2181 if (result != B_OK) {
2182 free(header);
2183 return result;
2184 }
2185 target = info.team;
2186 }
2187
2188 void* address = NULL;
2189 area_id transfered = _kern_transfer_area(header->message_area,
2190 &address, B_ANY_ADDRESS, target);
2191 if (transfered < 0) {
2192 delete_area(header->message_area);
2193 free(header);
2194 return transfered;
2195 }
2196
2197 header->message_area = transfered;
2198 }
2199 #endif
2200 } else {
2201 size = FlattenedSize();
2202 buffer = (char*)malloc(size);
2203 if (buffer == NULL)
2204 return B_NO_MEMORY;
2205
2206 result = Flatten(buffer, size);
2207 if (result != B_OK) {
2208 free(buffer);
2209 return result;
2210 }
2211
2212 header = (message_header*)buffer;
2213 }
2214
2215 if (!replyTo.IsValid()) {
2216 BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2217 fHeader->reply_port, fHeader->reply_target);
2218
2219 if (!replyTo.IsValid())
2220 replyTo = be_app_messenger;
2221 }
2222
2223 BMessenger::Private replyToPrivate(replyTo);
2224
2225 if (replyRequired) {
2226 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2227 header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2228 }
2229
2230 header->target = token;
2231 header->reply_team = replyToPrivate.Team();
2232 header->reply_port = replyToPrivate.Port();
2233 header->reply_target = replyToPrivate.Token();
2234 header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2235
2236 if (direct == NULL) {
2237 KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2238 "message: '%c%c%c%c'", portOwner, port, token,
2239 char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2240
2241 do {
2242 result = write_port_etc(port, kPortMessageCode, (void*)buffer,
2243 size, B_RELATIVE_TIMEOUT, timeout);
2244 } while (result == B_INTERRUPTED);
2245 }
2246
2247 if (result == B_OK && IsSourceWaiting()) {
2248 // the forwarded message will handle the reply - we must not do
2249 // this anymore
2250 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2251 }
2252
2253 // we need to do this last because it is possible our
2254 // message might be destroyed after it's enqueued in the
2255 // target looper. Thus we don't want to do any ops that depend on
2256 // members of this after the enqueue.
2257 if (direct != NULL) {
2258 KTRACE("BMessage send direct: port: %ld, token: %ld, "
2259 "message: '%c%c%c%c'", port, token,
2260 char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2261
2262 // this is a local message transmission
2263 direct->AddMessage(copy);
2264 if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2265 // there is currently no message waiting, and we need to wakeup the
2266 // looper
2267 write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2268 }
2269 direct->Release();
2270 }
2271
2272 free(buffer);
2273 return result;
2274 }
2275
2276
2277 // Sends a message and waits synchronously for a reply.
2278 status_t
_SendMessage(port_id port,team_id portOwner,int32 token,BMessage * reply,bigtime_t sendTimeout,bigtime_t replyTimeout) const2279 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2280 BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2281 {
2282 if (IsSourceWaiting()) {
2283 // we can't forward this message synchronously when it's already
2284 // waiting for a reply
2285 return B_ERROR;
2286 }
2287
2288 DEBUG_FUNCTION_ENTER;
2289 const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2290 port_id replyPort = B_BAD_PORT_ID;
2291 status_t result = B_OK;
2292
2293 if (cachedReplyPort < 0) {
2294 // All the cached reply ports are in use; create a new one
2295 replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2296 if (replyPort < 0)
2297 return replyPort;
2298 } else {
2299 assert(cachedReplyPort < sNumReplyPorts);
2300 replyPort = sReplyPorts[cachedReplyPort];
2301 }
2302
2303 bool recreateCachedPort = false;
2304
2305 team_id team = B_BAD_TEAM_ID;
2306 if (be_app != NULL)
2307 team = be_app->Team();
2308 else {
2309 port_info portInfo;
2310 result = get_port_info(replyPort, &portInfo);
2311 if (result != B_OK)
2312 goto error;
2313
2314 team = portInfo.team;
2315 }
2316
2317 result = set_port_owner(replyPort, portOwner);
2318 if (result != B_OK)
2319 goto error;
2320
2321 // tests if the queue of the reply port is really empty
2322 #if 0
2323 port_info portInfo;
2324 if (get_port_info(replyPort, &portInfo) == B_OK
2325 && portInfo.queue_count > 0) {
2326 debugger("reply port not empty!");
2327 printf(" reply port not empty! %ld message(s) in queue\n",
2328 portInfo.queue_count);
2329
2330 // fetch and print the messages
2331 for (int32 i = 0; i < portInfo.queue_count; i++) {
2332 char buffer[1024];
2333 int32 code;
2334 ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2335 if (size < 0) {
2336 printf("failed to read message from reply port\n");
2337 continue;
2338 }
2339 if (size >= (ssize_t)sizeof(buffer)) {
2340 printf("message from reply port too big\n");
2341 continue;
2342 }
2343
2344 BMemoryIO stream(buffer, size);
2345 BMessage reply;
2346 if (reply.Unflatten(&stream) != B_OK) {
2347 printf("failed to unflatten message from reply port\n");
2348 continue;
2349 }
2350
2351 printf("message %ld from reply port:\n", i);
2352 reply.PrintToStream();
2353 }
2354 }
2355 #endif
2356
2357 {
2358 BMessenger replyTarget;
2359 BMessenger::Private(replyTarget).SetTo(team, replyPort,
2360 B_PREFERRED_TOKEN);
2361 // TODO: replying could also use a BDirectMessageTarget like mechanism
2362 // for local targets
2363 result = _SendMessage(port, -1, token, sendTimeout, true,
2364 replyTarget);
2365 }
2366
2367 if (result != B_OK)
2368 goto error;
2369
2370 int32 code;
2371 result = handle_reply(replyPort, &code, replyTimeout, reply);
2372 if (result != B_OK && cachedReplyPort >= 0) {
2373 delete_port(replyPort);
2374 recreateCachedPort = true;
2375 }
2376
2377 error:
2378 if (cachedReplyPort >= 0) {
2379 // Reclaim ownership of cached port, if possible
2380 if (!recreateCachedPort && set_port_owner(replyPort, team) == B_OK) {
2381 // Flag as available
2382 atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2383 } else
2384 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2385
2386 return result;
2387 }
2388
2389 delete_port(replyPort);
2390 return result;
2391 }
2392
2393
2394 status_t
_SendFlattenedMessage(void * data,int32 size,port_id port,int32 token,bigtime_t timeout)2395 BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port,
2396 int32 token, bigtime_t timeout)
2397 {
2398 DEBUG_FUNCTION_ENTER2;
2399 if (data == NULL)
2400 return B_BAD_VALUE;
2401
2402 uint32 magic = *(uint32*)data;
2403
2404 if (magic == MESSAGE_FORMAT_HAIKU
2405 || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2406 message_header* header = (message_header*)data;
2407 header->target = token;
2408 header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2409 } else if (magic == MESSAGE_FORMAT_R5) {
2410 uint8* header = (uint8*)data;
2411 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2412 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2413 + sizeof(uint8) /* flags */;
2414 *(int32*)header = token;
2415 } else if (((KMessage::Header*)data)->magic
2416 == KMessage::kMessageHeaderMagic) {
2417 KMessage::Header* header = (KMessage::Header*)data;
2418 header->targetToken = token;
2419 } else {
2420 return B_NOT_A_MESSAGE;
2421 }
2422
2423 // send the message
2424 status_t result;
2425
2426 do {
2427 result = write_port_etc(port, kPortMessageCode, data, size,
2428 B_RELATIVE_TIMEOUT, timeout);
2429 } while (result == B_INTERRUPTED);
2430
2431 return result;
2432 }
2433
2434
_ReservedMessage1()2435 void BMessage::_ReservedMessage1() {}
_ReservedMessage2()2436 void BMessage::_ReservedMessage2() {}
_ReservedMessage3()2437 void BMessage::_ReservedMessage3() {}
2438
2439
2440 // #pragma mark - Macro definitions for data access methods
2441
2442
2443 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2444
2445 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \
2446 status_t \
2447 BMessage::Add##typeName(const char* name, type val) \
2448 { \
2449 return AddData(name, typeCode, &val, sizeof(type), true); \
2450 } \
2451 \
2452 \
2453 status_t \
2454 BMessage::Find##typeName(const char* name, type* p) const \
2455 { \
2456 return Find##typeName(name, 0, p); \
2457 } \
2458 \
2459 \
2460 status_t \
2461 BMessage::Find##typeName(const char* name, int32 index, type* p) const \
2462 { \
2463 type* ptr = NULL; \
2464 ssize_t bytes = 0; \
2465 status_t error = B_OK; \
2466 \
2467 *p = type(); \
2468 error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \
2469 \
2470 if (error == B_OK) \
2471 memcpy((void *)p, ptr, sizeof(type)); \
2472 \
2473 return error; \
2474 } \
2475 \
2476 \
2477 status_t \
2478 BMessage::Replace##typeName(const char* name, type value) \
2479 { \
2480 return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \
2481 } \
2482 \
2483 \
2484 status_t \
2485 BMessage::Replace##typeName(const char* name, int32 index, type value) \
2486 { \
2487 return ReplaceData(name, typeCode, index, &value, sizeof(type)); \
2488 } \
2489 \
2490 \
2491 bool \
2492 BMessage::Has##typeName(const char* name, int32 index) const \
2493 { \
2494 return HasData(name, typeCode, index); \
2495 }
2496
2497 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2498 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2499 DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2500 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2501 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2502 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2503 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2504 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2505 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2506 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2507 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2508 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2509 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2510 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2511 DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2512
2513 #undef DEFINE_FUNCTIONS
2514
2515 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \
2516 bool \
2517 BMessage::Has##typeName(const char* name, int32 index) const \
2518 { \
2519 return HasData(name, typeCode, index); \
2520 }
2521
2522
2523 DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE);
2524 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2525 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2526 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2527 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2528 DEFINE_HAS_FUNCTION(NodeRef, B_NODE_REF_TYPE);
2529 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2530
2531 #undef DEFINE_HAS_FUNCTION
2532
2533
2534 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \
2535 type \
2536 BMessage::Find##typeName(const char* name, int32 index) const \
2537 { \
2538 type val = initialize; \
2539 Find##typeName(name, index, &val); \
2540 return val; \
2541 }
2542
2543
2544 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2545 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2546 DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL);
2547 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2548 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2549 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2550 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2551 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2552 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2553 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2554
2555 #undef DEFINE_LAZY_FIND_FUNCTION
2556
2557
2558 #define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \
2559 type \
2560 BMessage::Get##typeName(const char* name, type defaultValue) const \
2561 { \
2562 return Get##typeName(name, 0, defaultValue); \
2563 } \
2564 \
2565 \
2566 type \
2567 BMessage::Get##typeName(const char* name, int32 index, \
2568 type defaultValue) const \
2569 { \
2570 type value; \
2571 if (Find##typeName(name, index, &value) == B_OK) \
2572 return value; \
2573 \
2574 return defaultValue; \
2575 } \
2576 \
2577 \
2578 status_t \
2579 BMessage::Set##typeName(const char* name, type value) \
2580 { \
2581 return SetData(name, typeCode, &value, sizeof(type)); \
2582 } \
2583
2584
2585 DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2586 DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2587 DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2588 DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2589 DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2590 DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2591 DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2592 DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2593 DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2594 DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2595 DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2596 DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
2597
2598 #undef DEFINE_SET_GET_FUNCTION
2599
2600
2601 const void*
GetPointer(const char * name,const void * defaultValue) const2602 BMessage::GetPointer(const char* name, const void* defaultValue) const
2603 {
2604 return GetPointer(name, 0, defaultValue);
2605 }
2606
2607
2608 const void*
GetPointer(const char * name,int32 index,const void * defaultValue) const2609 BMessage::GetPointer(const char* name, int32 index,
2610 const void* defaultValue) const
2611 {
2612 void* value;
2613 if (FindPointer(name, index, &value) == B_OK)
2614 return value;
2615
2616 return defaultValue;
2617 }
2618
2619
2620 status_t
SetPointer(const char * name,const void * value)2621 BMessage::SetPointer(const char* name, const void* value)
2622 {
2623 return SetData(name, B_POINTER_TYPE, &value, sizeof(void*));
2624 }
2625
2626
2627 #define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \
2628 type \
2629 BMessage::Get##typeName(const char* name, const type& defaultValue) const \
2630 { \
2631 return Get##typeName(name, 0, defaultValue); \
2632 } \
2633 \
2634 \
2635 type \
2636 BMessage::Get##typeName(const char* name, int32 index, \
2637 const type& defaultValue) const \
2638 { \
2639 type value; \
2640 if (Find##typeName(name, index, &value) == B_OK) \
2641 return value; \
2642 \
2643 return defaultValue; \
2644 } \
2645 \
2646 \
2647 status_t \
2648 BMessage::Set##typeName(const char* name, const type& value) \
2649 { \
2650 return SetData(name, typeCode, &value, sizeof(type)); \
2651 } \
2652
2653
2654 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2655 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2656 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
2657 DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BAlignment, Alignment, B_ALIGNMENT_TYPE);
2658
2659 #undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS
2660
2661
2662 status_t
AddAlignment(const char * name,const BAlignment & alignment)2663 BMessage::AddAlignment(const char* name, const BAlignment& alignment)
2664 {
2665 int32 data[2] = { alignment.horizontal, alignment.vertical };
2666 return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data));
2667 }
2668
2669
2670 status_t
AddString(const char * name,const char * string)2671 BMessage::AddString(const char* name, const char* string)
2672 {
2673 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0,
2674 false);
2675 }
2676
2677
2678 status_t
AddString(const char * name,const BString & string)2679 BMessage::AddString(const char* name, const BString& string)
2680 {
2681 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1,
2682 false);
2683 }
2684
2685
2686 status_t
AddStrings(const char * name,const BStringList & list)2687 BMessage::AddStrings(const char* name, const BStringList& list)
2688 {
2689 int32 count = list.CountStrings();
2690 for (int32 i = 0; i < count; i++) {
2691 status_t error = AddString(name, list.StringAt(i));
2692 if (error != B_OK)
2693 return error;
2694 }
2695
2696 return B_OK;
2697 }
2698
2699
2700 status_t
AddPointer(const char * name,const void * pointer)2701 BMessage::AddPointer(const char* name, const void* pointer)
2702 {
2703 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2704 }
2705
2706
2707 status_t
AddMessenger(const char * name,BMessenger messenger)2708 BMessage::AddMessenger(const char* name, BMessenger messenger)
2709 {
2710 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2711 }
2712
2713
2714 status_t
AddRef(const char * name,const entry_ref * ref)2715 BMessage::AddRef(const char* name, const entry_ref* ref)
2716 {
2717 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2718 char buffer[size];
2719
2720 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2721
2722 if (error >= B_OK)
2723 error = AddData(name, B_REF_TYPE, buffer, size, false);
2724
2725 return error;
2726 }
2727
2728
2729 status_t
AddNodeRef(const char * name,const node_ref * ref)2730 BMessage::AddNodeRef(const char* name, const node_ref* ref)
2731 {
2732 size_t size = sizeof(node_ref);
2733 char buffer[size];
2734
2735 status_t error = BPrivate::node_ref_flatten(buffer, &size, ref);
2736
2737 if (error >= B_OK)
2738 error = AddData(name, B_NODE_REF_TYPE, buffer, size, false);
2739
2740 return error;
2741 }
2742
2743
2744 status_t
AddMessage(const char * name,const BMessage * message)2745 BMessage::AddMessage(const char* name, const BMessage* message)
2746 {
2747 if (message == NULL)
2748 return B_BAD_VALUE;
2749
2750 // TODO: This and the following functions waste time by allocating and
2751 // copying an extra buffer. Functions can be added that return a direct
2752 // pointer into the message.
2753
2754 char stackBuffer[16384];
2755 ssize_t size = message->FlattenedSize();
2756
2757 char* buffer;
2758 if (size > (ssize_t)sizeof(stackBuffer)) {
2759 buffer = (char*)malloc(size);
2760 if (buffer == NULL)
2761 return B_NO_MEMORY;
2762 } else
2763 buffer = stackBuffer;
2764
2765 status_t error = message->Flatten(buffer, size);
2766
2767 if (error >= B_OK)
2768 error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2769
2770 if (buffer != stackBuffer)
2771 free(buffer);
2772
2773 return error;
2774 }
2775
2776
2777 status_t
AddFlat(const char * name,BFlattenable * object,int32 count)2778 BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
2779 {
2780 return AddFlat(name, (const BFlattenable*)object, count);
2781 }
2782
2783
2784 status_t
AddFlat(const char * name,const BFlattenable * object,int32 count)2785 BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count)
2786 {
2787 if (object == NULL)
2788 return B_BAD_VALUE;
2789
2790 char stackBuffer[16384];
2791 ssize_t size = object->FlattenedSize();
2792
2793 char* buffer;
2794 if (size > (ssize_t)sizeof(stackBuffer)) {
2795 buffer = (char*)malloc(size);
2796 if (buffer == NULL)
2797 return B_NO_MEMORY;
2798 } else
2799 buffer = stackBuffer;
2800
2801 status_t error = object->Flatten(buffer, size);
2802
2803 if (error >= B_OK)
2804 error = AddData(name, object->TypeCode(), buffer, size, false);
2805
2806 if (buffer != stackBuffer)
2807 free(buffer);
2808
2809 return error;
2810 }
2811
2812
2813 status_t
Append(const BMessage & other)2814 BMessage::Append(const BMessage& other)
2815 {
2816 field_header* field = other.fFields;
2817 for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) {
2818 const char* name = (const char*)(other.fData + field->offset);
2819 const void* data = (const void*)(other.fData + field->offset
2820 + field->name_length);
2821 bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
2822 size_t size = field->data_size / field->count;
2823
2824 for (uint32 j = 0; j < field->count; j++) {
2825 if (!isFixed) {
2826 size = *(uint32*)data;
2827 data = (const void*)((const char*)data + sizeof(uint32));
2828 }
2829
2830 status_t status = AddData(name, field->type, data, size,
2831 isFixed, 1);
2832 if (status != B_OK)
2833 return status;
2834
2835 data = (const void*)((const char*)data + size);
2836 }
2837 }
2838 return B_OK;
2839 }
2840
2841
2842 status_t
FindAlignment(const char * name,BAlignment * alignment) const2843 BMessage::FindAlignment(const char* name, BAlignment* alignment) const
2844 {
2845 return FindAlignment(name, 0, alignment);
2846 }
2847
2848
2849 status_t
FindAlignment(const char * name,int32 index,BAlignment * alignment) const2850 BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment)
2851 const
2852 {
2853 if (!alignment)
2854 return B_BAD_VALUE;
2855
2856 int32* data;
2857 ssize_t bytes;
2858
2859 status_t err = FindData(name, B_ALIGNMENT_TYPE, index,
2860 (const void**)&data, &bytes);
2861
2862 if (err == B_OK) {
2863 if (bytes != sizeof(int32[2]))
2864 return B_ERROR;
2865
2866 alignment->horizontal = (enum alignment)(*data);
2867 alignment->vertical = (vertical_alignment)*(data + 1);
2868 }
2869
2870 return err;
2871 }
2872
2873
2874 status_t
FindString(const char * name,const char ** string) const2875 BMessage::FindString(const char* name, const char** string) const
2876 {
2877 return FindString(name, 0, string);
2878 }
2879
2880
2881 status_t
FindString(const char * name,int32 index,const char ** string) const2882 BMessage::FindString(const char* name, int32 index, const char** string) const
2883 {
2884 ssize_t bytes;
2885 return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes);
2886 }
2887
2888
2889 status_t
FindString(const char * name,BString * string) const2890 BMessage::FindString(const char* name, BString* string) const
2891 {
2892 return FindString(name, 0, string);
2893 }
2894
2895
2896 status_t
FindString(const char * name,int32 index,BString * string) const2897 BMessage::FindString(const char* name, int32 index, BString* string) const
2898 {
2899 if (string == NULL)
2900 return B_BAD_VALUE;
2901
2902 const char* value;
2903 status_t error = FindString(name, index, &value);
2904
2905 // Find*() clobbers the object even on failure
2906 string->SetTo(value);
2907 return error;
2908 }
2909
2910
2911 status_t
FindStrings(const char * name,BStringList * list) const2912 BMessage::FindStrings(const char* name, BStringList* list) const
2913 {
2914 if (list == NULL)
2915 return B_BAD_VALUE;
2916
2917 list->MakeEmpty();
2918
2919 // get the number of items
2920 type_code type;
2921 int32 count;
2922 if (GetInfo(name, &type, &count) != B_OK)
2923 return B_NAME_NOT_FOUND;
2924
2925 if (type != B_STRING_TYPE)
2926 return B_BAD_DATA;
2927
2928 for (int32 i = 0; i < count; i++) {
2929 BString string;
2930 status_t error = FindString(name, i, &string);
2931 if (error != B_OK)
2932 return error;
2933 if (!list->Add(string))
2934 return B_NO_MEMORY;
2935 }
2936
2937 return B_OK;
2938 }
2939
2940
2941 status_t
FindPointer(const char * name,void ** pointer) const2942 BMessage::FindPointer(const char* name, void** pointer) const
2943 {
2944 return FindPointer(name, 0, pointer);
2945 }
2946
2947
2948 status_t
FindPointer(const char * name,int32 index,void ** pointer) const2949 BMessage::FindPointer(const char* name, int32 index, void** pointer) const
2950 {
2951 if (pointer == NULL)
2952 return B_BAD_VALUE;
2953
2954 void** data = NULL;
2955 ssize_t size = 0;
2956 status_t error = FindData(name, B_POINTER_TYPE, index,
2957 (const void**)&data, &size);
2958
2959 if (error == B_OK)
2960 *pointer = *data;
2961 else
2962 *pointer = NULL;
2963
2964 return error;
2965 }
2966
2967
2968 status_t
FindMessenger(const char * name,BMessenger * messenger) const2969 BMessage::FindMessenger(const char* name, BMessenger* messenger) const
2970 {
2971 return FindMessenger(name, 0, messenger);
2972 }
2973
2974
2975 status_t
FindMessenger(const char * name,int32 index,BMessenger * messenger) const2976 BMessage::FindMessenger(const char* name, int32 index,
2977 BMessenger* messenger) const
2978 {
2979 if (messenger == NULL)
2980 return B_BAD_VALUE;
2981
2982 BMessenger* data = NULL;
2983 ssize_t size = 0;
2984 status_t error = FindData(name, B_MESSENGER_TYPE, index,
2985 (const void**)&data, &size);
2986
2987 if (error == B_OK)
2988 *messenger = *data;
2989 else
2990 *messenger = BMessenger();
2991
2992 return error;
2993 }
2994
2995
2996 status_t
FindRef(const char * name,entry_ref * ref) const2997 BMessage::FindRef(const char* name, entry_ref* ref) const
2998 {
2999 return FindRef(name, 0, ref);
3000 }
3001
3002
3003 status_t
FindRef(const char * name,int32 index,entry_ref * ref) const3004 BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
3005 {
3006 if (ref == NULL)
3007 return B_BAD_VALUE;
3008
3009 void* data = NULL;
3010 ssize_t size = 0;
3011 status_t error = FindData(name, B_REF_TYPE, index,
3012 (const void**)&data, &size);
3013
3014 if (error == B_OK)
3015 error = BPrivate::entry_ref_unflatten(ref, (char*)data, size);
3016 else
3017 *ref = entry_ref();
3018
3019 return error;
3020 }
3021
3022
3023 status_t
FindNodeRef(const char * name,node_ref * ref) const3024 BMessage::FindNodeRef(const char* name, node_ref* ref) const
3025 {
3026 return FindNodeRef(name, 0, ref);
3027 }
3028
3029
3030 status_t
FindNodeRef(const char * name,int32 index,node_ref * ref) const3031 BMessage::FindNodeRef(const char* name, int32 index, node_ref* ref) const
3032 {
3033 if (ref == NULL)
3034 return B_BAD_VALUE;
3035
3036 void* data = NULL;
3037 ssize_t size = 0;
3038 status_t error = FindData(name, B_NODE_REF_TYPE, index,
3039 (const void**)&data, &size);
3040
3041 if (error == B_OK)
3042 error = BPrivate::node_ref_unflatten(ref, (char*)data, size);
3043 else
3044 *ref = node_ref();
3045
3046 return error;
3047 }
3048
3049
3050 status_t
FindMessage(const char * name,BMessage * message) const3051 BMessage::FindMessage(const char* name, BMessage* message) const
3052 {
3053 return FindMessage(name, 0, message);
3054 }
3055
3056
3057 status_t
FindMessage(const char * name,int32 index,BMessage * message) const3058 BMessage::FindMessage(const char* name, int32 index, BMessage* message) const
3059 {
3060 if (message == NULL)
3061 return B_BAD_VALUE;
3062
3063 void* data = NULL;
3064 ssize_t size = 0;
3065 status_t error = FindData(name, B_MESSAGE_TYPE, index,
3066 (const void**)&data, &size);
3067
3068 if (error == B_OK)
3069 error = message->Unflatten((const char*)data);
3070 else
3071 *message = BMessage();
3072
3073 return error;
3074 }
3075
3076
3077 status_t
FindFlat(const char * name,BFlattenable * object) const3078 BMessage::FindFlat(const char* name, BFlattenable* object) const
3079 {
3080 return FindFlat(name, 0, object);
3081 }
3082
3083
3084 status_t
FindFlat(const char * name,int32 index,BFlattenable * object) const3085 BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const
3086 {
3087 if (object == NULL)
3088 return B_BAD_VALUE;
3089
3090 void* data = NULL;
3091 ssize_t numBytes = 0;
3092 status_t error = FindData(name, object->TypeCode(), index,
3093 (const void**)&data, &numBytes);
3094
3095 if (error == B_OK)
3096 error = object->Unflatten(object->TypeCode(), data, numBytes);
3097
3098 return error;
3099 }
3100
3101
3102 status_t
FindData(const char * name,type_code type,const void ** data,ssize_t * numBytes) const3103 BMessage::FindData(const char* name, type_code type, const void** data,
3104 ssize_t* numBytes) const
3105 {
3106 return FindData(name, type, 0, data, numBytes);
3107 }
3108
3109
3110 status_t
ReplaceAlignment(const char * name,const BAlignment & alignment)3111 BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment)
3112 {
3113 int32 data[2] = {alignment.horizontal, alignment.vertical};
3114 return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data));
3115 }
3116
3117
3118 status_t
ReplaceAlignment(const char * name,int32 index,const BAlignment & alignment)3119 BMessage::ReplaceAlignment(const char* name, int32 index,
3120 const BAlignment& alignment)
3121 {
3122 int32 data[2] = {alignment.horizontal, alignment.vertical};
3123 return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data));
3124 }
3125
3126
3127 status_t
ReplaceString(const char * name,const char * string)3128 BMessage::ReplaceString(const char* name, const char* string)
3129 {
3130 if (string == NULL)
3131 return B_BAD_VALUE;
3132
3133 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
3134 }
3135
3136
3137 status_t
ReplaceString(const char * name,int32 index,const char * string)3138 BMessage::ReplaceString(const char* name, int32 index, const char* string)
3139 {
3140 if (string == NULL)
3141 return B_BAD_VALUE;
3142
3143 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
3144 }
3145
3146
3147 status_t
ReplaceString(const char * name,const BString & string)3148 BMessage::ReplaceString(const char* name, const BString& string)
3149 {
3150 return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
3151 string.Length() + 1);
3152 }
3153
3154
3155 status_t
ReplaceString(const char * name,int32 index,const BString & string)3156 BMessage::ReplaceString(const char* name, int32 index, const BString& string)
3157 {
3158 return ReplaceData(name, B_STRING_TYPE, index, string.String(),
3159 string.Length() + 1);
3160 }
3161
3162
3163 status_t
ReplacePointer(const char * name,const void * pointer)3164 BMessage::ReplacePointer(const char* name, const void* pointer)
3165 {
3166 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
3167 }
3168
3169
3170 status_t
ReplacePointer(const char * name,int32 index,const void * pointer)3171 BMessage::ReplacePointer(const char* name, int32 index, const void* pointer)
3172 {
3173 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
3174 }
3175
3176
3177 status_t
ReplaceMessenger(const char * name,BMessenger messenger)3178 BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
3179 {
3180 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
3181 sizeof(BMessenger));
3182 }
3183
3184
3185 status_t
ReplaceMessenger(const char * name,int32 index,BMessenger messenger)3186 BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
3187 {
3188 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
3189 sizeof(BMessenger));
3190 }
3191
3192
3193 status_t
ReplaceRef(const char * name,const entry_ref * ref)3194 BMessage::ReplaceRef(const char* name, const entry_ref* ref)
3195 {
3196 return ReplaceRef(name, 0, ref);
3197 }
3198
3199
3200 status_t
ReplaceRef(const char * name,int32 index,const entry_ref * ref)3201 BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
3202 {
3203 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
3204 char buffer[size];
3205
3206 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
3207
3208 if (error >= B_OK)
3209 error = ReplaceData(name, B_REF_TYPE, index, buffer, size);
3210
3211 return error;
3212 }
3213
3214
3215 status_t
ReplaceNodeRef(const char * name,const node_ref * ref)3216 BMessage::ReplaceNodeRef(const char* name, const node_ref* ref)
3217 {
3218 return ReplaceNodeRef(name, 0, ref);
3219 }
3220
3221
3222 status_t
ReplaceNodeRef(const char * name,int32 index,const node_ref * ref)3223 BMessage::ReplaceNodeRef(const char* name, int32 index, const node_ref* ref)
3224 {
3225 size_t size = sizeof(node_ref) + B_PATH_NAME_LENGTH;
3226 char buffer[size];
3227
3228 status_t error = BPrivate::node_ref_flatten(buffer, &size, ref);
3229
3230 if (error >= B_OK)
3231 error = ReplaceData(name, B_NODE_REF_TYPE, index, buffer, size);
3232
3233 return error;
3234 }
3235
3236
3237 status_t
ReplaceMessage(const char * name,const BMessage * message)3238 BMessage::ReplaceMessage(const char* name, const BMessage* message)
3239 {
3240 return ReplaceMessage(name, 0, message);
3241 }
3242
3243
3244 status_t
ReplaceMessage(const char * name,int32 index,const BMessage * message)3245 BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message)
3246 {
3247 if (message == NULL)
3248 return B_BAD_VALUE;
3249
3250 ssize_t size = message->FlattenedSize();
3251 if (size < 0)
3252 return B_BAD_VALUE;
3253
3254 char buffer[size];
3255
3256 status_t error = message->Flatten(buffer, size);
3257
3258 if (error >= B_OK)
3259 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
3260
3261 return error;
3262 }
3263
3264
3265 status_t
ReplaceFlat(const char * name,BFlattenable * object)3266 BMessage::ReplaceFlat(const char* name, BFlattenable* object)
3267 {
3268 return ReplaceFlat(name, 0, object);
3269 }
3270
3271
3272 status_t
ReplaceFlat(const char * name,int32 index,BFlattenable * object)3273 BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
3274 {
3275 if (object == NULL)
3276 return B_BAD_VALUE;
3277
3278 ssize_t size = object->FlattenedSize();
3279 if (size < 0)
3280 return B_BAD_VALUE;
3281
3282 char buffer[size];
3283
3284 status_t error = object->Flatten(buffer, size);
3285
3286 if (error >= B_OK)
3287 error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
3288
3289 return error;
3290 }
3291
3292
3293 status_t
ReplaceData(const char * name,type_code type,const void * data,ssize_t numBytes)3294 BMessage::ReplaceData(const char* name, type_code type, const void* data,
3295 ssize_t numBytes)
3296 {
3297 return ReplaceData(name, type, 0, data, numBytes);
3298 }
3299
3300
3301 bool
HasFlat(const char * name,const BFlattenable * object) const3302 BMessage::HasFlat(const char* name, const BFlattenable* object) const
3303 {
3304 return HasFlat(name, 0, object);
3305 }
3306
3307
3308 bool
HasFlat(const char * name,int32 index,const BFlattenable * object) const3309 BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object)
3310 const
3311 {
3312 return HasData(name, object->TypeCode(), index);
3313 }
3314
3315
3316 const char*
GetString(const char * name,const char * defaultValue) const3317 BMessage::GetString(const char* name, const char* defaultValue) const
3318 {
3319 return GetString(name, 0, defaultValue);
3320 }
3321
3322
3323 const char*
GetString(const char * name,int32 index,const char * defaultValue) const3324 BMessage::GetString(const char* name, int32 index,
3325 const char* defaultValue) const
3326 {
3327 const char* value;
3328 if (FindString(name, index, &value) == B_OK)
3329 return value;
3330
3331 return defaultValue;
3332 }
3333
3334
3335 status_t
SetString(const char * name,const BString & value)3336 BMessage::SetString(const char* name, const BString& value)
3337 {
3338 return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1,
3339 false);
3340 }
3341
3342
3343 status_t
SetString(const char * name,const char * value)3344 BMessage::SetString(const char* name, const char* value)
3345 {
3346 return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false);
3347 }
3348
3349
3350 status_t
SetData(const char * name,type_code type,const void * data,ssize_t numBytes,bool fixedSize,int count)3351 BMessage::SetData(const char* name, type_code type, const void* data,
3352 ssize_t numBytes, bool fixedSize, int count)
3353 {
3354 if (numBytes <= 0 || data == NULL)
3355 return B_BAD_VALUE;
3356
3357 if (ReplaceData(name, type, data, numBytes) == B_OK)
3358 return B_OK;
3359
3360 return AddData(name, type, data, numBytes, fixedSize, count);
3361 }
3362