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