1 /* 2 * Copyright 2005-2008, 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 #include <Message.h> 10 11 #include <assert.h> 12 #include <ctype.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <Application.h> 18 #include <BlockCache.h> 19 #include <Entry.h> 20 #include <MessageQueue.h> 21 #include <Messenger.h> 22 #include <Path.h> 23 #include <Point.h> 24 #include <Rect.h> 25 #include <String.h> 26 27 #include <AppMisc.h> 28 #include <MessageAdapter.h> 29 #include <MessagePrivate.h> 30 #include <MessageUtils.h> 31 #include <TokenSpace.h> 32 33 34 const char *B_SPECIFIER_ENTRY = "specifiers"; 35 const char *B_PROPERTY_ENTRY = "property"; 36 const char *B_PROPERTY_NAME_ENTRY = "name"; 37 38 39 BBlockCache *BMessage::sMsgCache = NULL; 40 41 42 BMessage::BMessage() 43 { 44 _InitCommon(); 45 } 46 47 48 BMessage::BMessage(BMessage *other) 49 { 50 _InitCommon(); 51 *this = *other; 52 } 53 54 55 BMessage::BMessage(uint32 _what) 56 { 57 _InitCommon(); 58 fHeader->what = what = _what; 59 } 60 61 62 BMessage::BMessage(const BMessage &other) 63 { 64 _InitCommon(); 65 *this = other; 66 } 67 68 69 BMessage::~BMessage() 70 { 71 _Clear(); 72 } 73 74 75 BMessage & 76 BMessage::operator=(const BMessage &other) 77 { 78 _Clear(); 79 80 fHeader = (message_header *)malloc(sizeof(message_header)); 81 memcpy(fHeader, other.fHeader, sizeof(message_header)); 82 83 // Clear some header flags inherited from the original message that don't 84 // apply to the clone. 85 fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE 86 | MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED 87 | MESSAGE_FLAG_WAS_DROPPED | MESSAGE_FLAG_PASS_BY_AREA); 88 // Note, that BeOS R5 seems to keep the reply info. 89 90 if (fHeader->fields_size > 0) { 91 fFields = (field_header *)malloc(fHeader->fields_size); 92 memcpy(fFields, other.fFields, fHeader->fields_size); 93 } 94 95 if (fHeader->data_size > 0) { 96 fData = (uint8 *)malloc(fHeader->data_size); 97 memcpy(fData, other.fData, fHeader->data_size); 98 } 99 100 fHeader->shared_area = -1; 101 fHeader->fields_available = 0; 102 fHeader->data_available = 0; 103 fHeader->what = what = other.what; 104 105 return *this; 106 } 107 108 109 void * 110 BMessage::operator new(size_t size) 111 { 112 if (!sMsgCache) 113 sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE); 114 115 return sMsgCache->Get(size); 116 } 117 118 119 void * 120 BMessage::operator new(size_t, void *pointer) 121 { 122 return pointer; 123 } 124 125 126 void 127 BMessage::operator delete(void *pointer, size_t size) 128 { 129 sMsgCache->Save(pointer, size); 130 } 131 132 133 status_t 134 BMessage::_InitCommon() 135 { 136 what = 0; 137 138 fHeader = NULL; 139 fFields = NULL; 140 fData = NULL; 141 142 fOriginal = NULL; 143 fQueueLink = NULL; 144 145 return _InitHeader(); 146 } 147 148 149 status_t 150 BMessage::_InitHeader() 151 { 152 fHeader = (message_header *)malloc(sizeof(message_header)); 153 memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table)); 154 155 fHeader->format = MESSAGE_FORMAT_HAIKU; 156 fHeader->flags = MESSAGE_FLAG_VALID; 157 fHeader->what = what; 158 fHeader->current_specifier = -1; 159 fHeader->shared_area = -1; 160 161 fHeader->target = B_NULL_TOKEN; 162 fHeader->reply_target = B_NULL_TOKEN; 163 fHeader->reply_port = -1; 164 fHeader->reply_team = -1; 165 166 // initializing the hash table to -1 because 0 is a valid index 167 fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE; 168 memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table)); 169 return B_OK; 170 } 171 172 173 status_t 174 BMessage::_Clear() 175 { 176 free(fHeader); 177 fHeader = NULL; 178 free(fFields); 179 fFields = NULL; 180 free(fData); 181 fData = NULL; 182 183 delete fOriginal; 184 fOriginal = NULL; 185 186 return B_OK; 187 } 188 189 190 status_t 191 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound, 192 type_code *typeFound, int32 *countFound) const 193 { 194 if (typeRequested == B_ANY_TYPE) { 195 if (index >= fHeader->field_count) 196 return B_BAD_INDEX; 197 198 if (nameFound) 199 *nameFound = (char *)fData + fFields[index].offset; 200 if (typeFound) 201 *typeFound = fFields[index].type; 202 if (countFound) 203 *countFound = fFields[index].count; 204 return B_OK; 205 } 206 207 int32 counter = -1; 208 field_header *field = fFields; 209 for (int32 i = 0; i < fHeader->field_count; i++, field++) { 210 if (field->type == typeRequested) 211 counter++; 212 213 if (counter == index) { 214 if (nameFound) 215 *nameFound = (char *)fData + field->offset; 216 if (typeFound) 217 *typeFound = field->type; 218 if (countFound) 219 *countFound = field->count; 220 return B_OK; 221 } 222 } 223 224 if (counter == -1) 225 return B_BAD_TYPE; 226 227 return B_BAD_INDEX; 228 } 229 230 231 status_t 232 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound) 233 const 234 { 235 if (countFound) 236 *countFound = 0; 237 238 field_header *field = NULL; 239 status_t result = _FindField(name, B_ANY_TYPE, &field); 240 if (result < B_OK || !field) 241 return result; 242 243 if (typeFound) 244 *typeFound = field->type; 245 if (countFound) 246 *countFound = field->count; 247 248 return B_OK; 249 } 250 251 252 status_t 253 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize) 254 const 255 { 256 field_header *field = NULL; 257 status_t result = _FindField(name, B_ANY_TYPE, &field); 258 if (result < B_OK || !field) 259 return result; 260 261 if (typeFound) 262 *typeFound = field->type; 263 if (fixedSize) 264 *fixedSize = field->flags & FIELD_FLAG_FIXED_SIZE; 265 266 return B_OK; 267 } 268 269 270 int32 271 BMessage::CountNames(type_code type) const 272 { 273 if (type == B_ANY_TYPE) 274 return fHeader->field_count; 275 276 int32 count = 0; 277 field_header *field = fFields; 278 for (int32 i = 0; i < fHeader->field_count; i++, field++) { 279 if (field->type == type) 280 count++; 281 } 282 283 return count; 284 } 285 286 287 bool 288 BMessage::IsEmpty() const 289 { 290 return fHeader->field_count == 0; 291 } 292 293 294 bool 295 BMessage::IsSystem() const 296 { 297 char a = char(what >> 24); 298 char b = char(what >> 16); 299 char c = char(what >> 8); 300 char d = char(what); 301 302 // The BeBook says: 303 // ... we've adopted a strict convention for assigning values to all 304 // Be-defined constants. The value assigned will always be formed by 305 // combining four characters into a multicharacter constant, with the 306 // characters limited to uppercase letters and the underbar 307 // Between that and what's in AppDefs.h, this algo seems like a safe bet: 308 if (a == '_' && isupper(b) && isupper(c) && isupper(d)) 309 return true; 310 311 return false; 312 } 313 314 315 bool 316 BMessage::IsReply() const 317 { 318 return fHeader->flags & MESSAGE_FLAG_IS_REPLY; 319 } 320 321 322 template<typename Type> static uint8 * 323 print_to_stream_type(uint8* pointer) 324 { 325 Type *item = (Type *)pointer; 326 item->PrintToStream(); 327 return (uint8 *)(item+1); 328 } 329 330 331 template<typename Type> static uint8 * 332 print_type(const char* format, uint8* pointer) 333 { 334 Type *item = (Type *)pointer; 335 printf(format, *item, *item); 336 return (uint8 *)(item+1); 337 } 338 339 340 void 341 BMessage::PrintToStream() const 342 { 343 _PrintToStream(""); 344 printf("}\n"); 345 } 346 347 348 void 349 BMessage::_PrintToStream(const char* indent) const 350 { 351 int32 value = B_BENDIAN_TO_HOST_INT32(what); 352 printf("BMessage("); 353 if (isprint(*(char *)&value)) { 354 printf("'%.4s'", (char *)&value); 355 } else 356 printf("0x%lx", what); 357 printf(") {\n"); 358 359 field_header *field = fFields; 360 for (int32 i = 0; i < fHeader->field_count; i++, field++) { 361 value = B_BENDIAN_TO_HOST_INT32(field->type); 362 ssize_t size = 0; 363 if ((field->flags & FIELD_FLAG_FIXED_SIZE) && field->count > 0) 364 size = field->data_size / field->count; 365 366 uint8 *pointer = fData + field->offset + field->name_length; 367 for (int32 j = 0; j < field->count; j++) { 368 if (field->count == 1) { 369 printf("%s %s = ", indent, 370 (char *)(fData + field->offset)); 371 } else { 372 printf("%s %s[%ld] = ", indent, 373 (char *)(fData + field->offset), j); 374 } 375 376 switch (field->type) { 377 case B_RECT_TYPE: 378 pointer = print_to_stream_type<BRect>(pointer); 379 break; 380 381 case B_POINT_TYPE: 382 pointer = print_to_stream_type<BPoint>(pointer); 383 break; 384 385 case B_STRING_TYPE: { 386 ssize_t size = *(ssize_t *)pointer; 387 pointer += sizeof(ssize_t); 388 printf("string(\"%s\", %ld bytes)\n", (char *)pointer, 389 (long)size); 390 pointer += size; 391 break; 392 } 393 394 case B_INT8_TYPE: 395 pointer = print_type<int8>("int8(0x%hx or %d or \'%.1s\')\n", pointer); 396 break; 397 398 case B_INT16_TYPE: 399 pointer = print_type<int16>("int16 (0x%x or %d)\n", pointer); 400 break; 401 402 case B_INT32_TYPE: 403 pointer = print_type<int32>("int32(0x%lx or %ld)\n", pointer); 404 break; 405 406 case B_INT64_TYPE: 407 pointer = print_type<int64>("int64(0x%Lx or %Ld)\n", pointer); 408 break; 409 410 case B_BOOL_TYPE: 411 printf("bool(%s)\n", *((bool *)pointer)!= 0 ? "true" : "false"); 412 pointer += sizeof(bool); 413 break; 414 415 case B_FLOAT_TYPE: 416 pointer = print_type<float>("float(%.4f)\n", pointer); 417 break; 418 419 case B_DOUBLE_TYPE: 420 pointer = print_type<double>("double(%.8f)\n", pointer); 421 break; 422 423 case B_REF_TYPE: { 424 ssize_t size = *(ssize_t *)pointer; 425 pointer += sizeof(ssize_t); 426 entry_ref ref; 427 BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size); 428 429 printf("entry_ref(device=%ld, directory=%lld, name=\"%s\", ", 430 (long)ref.device, ref.directory, ref.name); 431 432 BPath path(&ref); 433 printf("path=\"%s\")\n", path.Path()); 434 pointer += size; 435 break; 436 } 437 438 case B_MESSAGE_TYPE: 439 { 440 char buffer[1024]; 441 sprintf(buffer, "%s ", indent); 442 443 BMessage message; 444 const ssize_t size = *(const ssize_t *)pointer; 445 pointer += sizeof(ssize_t); 446 if (message.Unflatten((const char *)pointer) != B_OK) { 447 fprintf(stderr, "couldn't unflatten item %ld\n", i); 448 break; 449 } 450 message._PrintToStream(buffer); 451 printf("%s }\n", indent); 452 pointer += size; 453 break; 454 } 455 456 default: 457 printf("(type = '%.4s')(size = %ld)\n", (char *)&value, 458 (long)size); 459 break; 460 } 461 } 462 } 463 } 464 465 466 status_t 467 BMessage::Rename(const char *oldEntry, const char *newEntry) 468 { 469 if (!oldEntry || !newEntry) 470 return B_BAD_VALUE; 471 472 uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size; 473 int32 *nextField = &fHeader->hash_table[hash]; 474 475 while (*nextField >= 0) { 476 field_header *field = &fFields[*nextField]; 477 478 if (strncmp((const char *)(fData + field->offset), oldEntry, 479 field->name_length) == 0) { 480 // nextField points to the field for oldEntry, save it and unlink 481 int32 index = *nextField; 482 *nextField = field->next_field; 483 field->next_field = -1; 484 485 hash = _HashName(newEntry) % fHeader->hash_table_size; 486 nextField = &fHeader->hash_table[hash]; 487 while (*nextField >= 0) 488 nextField = &fFields[*nextField].next_field; 489 *nextField = index; 490 491 int32 newLength = strlen(newEntry) + 1; 492 status_t result = _ResizeData(field->offset + 1, 493 newLength - field->name_length); 494 if (result < B_OK) 495 return result; 496 497 memcpy(fData + field->offset, newEntry, newLength); 498 field->name_length = newLength; 499 return B_OK; 500 } 501 502 nextField = &field->next_field; 503 } 504 505 return B_NAME_NOT_FOUND; 506 } 507 508 509 bool 510 BMessage::WasDelivered() const 511 { 512 return fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED; 513 } 514 515 516 bool 517 BMessage::IsSourceWaiting() const 518 { 519 return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) 520 && !(fHeader->flags & MESSAGE_FLAG_REPLY_DONE); 521 } 522 523 524 BMessenger 525 BMessage::ReturnAddress() const 526 { 527 return BMessenger(); 528 } 529 530 531 const BMessage * 532 BMessage::Previous() const 533 { 534 /* ToDo: test if the "_previous_" field is used in R5 */ 535 if (!fOriginal) { 536 fOriginal = new BMessage(); 537 538 if (FindMessage("_previous_", fOriginal) != B_OK) { 539 delete fOriginal; 540 fOriginal = NULL; 541 } 542 } 543 544 return fOriginal; 545 } 546 547 548 bool 549 BMessage::WasDropped() const 550 { 551 return fHeader->flags & MESSAGE_FLAG_WAS_DROPPED; 552 } 553 554 555 BPoint 556 BMessage::DropPoint(BPoint *offset) const 557 { 558 if (offset) 559 *offset = FindPoint("_drop_offset_"); 560 561 return FindPoint("_drop_point_"); 562 } 563 564 565 ssize_t 566 BMessage::FlattenedSize() const 567 { 568 return BPrivate::MessageAdapter::FlattenedSize(MESSAGE_FORMAT_R5, this); 569 } 570 571 572 status_t 573 BMessage::Flatten(char *buffer, ssize_t size) const 574 { 575 return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, buffer, 576 &size); 577 } 578 579 580 status_t 581 BMessage::Flatten(BDataIO *stream, ssize_t *size) const 582 { 583 return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, stream, 584 size); 585 } 586 587 588 ssize_t 589 BMessage::_NativeFlattenedSize() const 590 { 591 return sizeof(message_header) + fHeader->fields_size + fHeader->data_size; 592 } 593 594 595 status_t 596 BMessage::_NativeFlatten(char *buffer, ssize_t size) const 597 { 598 if (!buffer) 599 return B_BAD_VALUE; 600 601 if (!fHeader) 602 return B_NO_INIT; 603 604 /* we have to sync the what code as it is a public member */ 605 fHeader->what = what; 606 607 memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size)); 608 buffer += sizeof(message_header); 609 size -= sizeof(message_header); 610 611 memcpy(buffer, fFields, min_c(fHeader->fields_size, size)); 612 buffer += fHeader->fields_size; 613 size -= fHeader->fields_size; 614 615 memcpy(buffer, fData, min_c(fHeader->data_size, size)); 616 if (size >= fHeader->data_size) 617 return B_OK; 618 619 return B_NO_MEMORY; 620 } 621 622 623 status_t 624 BMessage::_NativeFlatten(BDataIO *stream, ssize_t *size) const 625 { 626 if (!stream) 627 return B_BAD_VALUE; 628 629 if (!fHeader) 630 return B_NO_INIT; 631 632 /* we have to sync the what code as it is a public member */ 633 fHeader->what = what; 634 635 ssize_t result1 = stream->Write(fHeader, sizeof(message_header)); 636 if (result1 != sizeof(message_header)) 637 return (result1 >= 0 ? B_ERROR : result1); 638 639 ssize_t result2 = 0; 640 if (fHeader->fields_size > 0) { 641 result2 = stream->Write(fFields, fHeader->fields_size); 642 if (result2 != fHeader->fields_size) 643 return (result2 >= 0 ? B_ERROR : result2); 644 } 645 646 ssize_t result3 = 0; 647 if (fHeader->data_size > 0) { 648 result3 = stream->Write(fData, fHeader->data_size); 649 if (result3 != fHeader->data_size) 650 return (result3 >= 0 ? B_ERROR : result3); 651 } 652 653 if (size) 654 *size = result1 + result2 + result3; 655 656 return B_OK; 657 } 658 659 660 status_t 661 BMessage::Unflatten(const char *flatBuffer) 662 { 663 if (!flatBuffer) 664 return B_BAD_VALUE; 665 666 uint32 format = *(uint32 *)flatBuffer; 667 if (format != MESSAGE_FORMAT_HAIKU) 668 return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer); 669 670 // native message unflattening 671 672 _Clear(); 673 674 fHeader = (message_header *)malloc(sizeof(message_header)); 675 if (!fHeader) 676 return B_NO_MEMORY; 677 678 memcpy(fHeader, flatBuffer, sizeof(message_header)); 679 flatBuffer += sizeof(message_header); 680 681 if (fHeader->format != MESSAGE_FORMAT_HAIKU 682 || !(fHeader->flags & MESSAGE_FLAG_VALID)) { 683 free(fHeader); 684 fHeader = NULL; 685 _InitHeader(); 686 return B_BAD_VALUE; 687 } 688 689 fHeader->fields_available = 0; 690 fHeader->data_available = 0; 691 what = fHeader->what; 692 693 fHeader->shared_area = -1; 694 695 if (fHeader->fields_size > 0) { 696 fFields = (field_header *)malloc(fHeader->fields_size); 697 if (!fFields) 698 return B_NO_MEMORY; 699 700 memcpy(fFields, flatBuffer, fHeader->fields_size); 701 flatBuffer += fHeader->fields_size; 702 } 703 704 if (fHeader->data_size > 0) { 705 fData = (uint8 *)malloc(fHeader->data_size); 706 if (!fData) 707 return B_NO_MEMORY; 708 709 memcpy(fData, flatBuffer, fHeader->data_size); 710 } 711 712 return B_OK; 713 } 714 715 716 status_t 717 BMessage::Unflatten(BDataIO *stream) 718 { 719 if (!stream) 720 return B_BAD_VALUE; 721 722 uint32 format = 0; 723 stream->Read(&format, sizeof(uint32)); 724 if (format != MESSAGE_FORMAT_HAIKU) 725 return BPrivate::MessageAdapter::Unflatten(format, this, stream); 726 727 // native message unflattening 728 729 _Clear(); 730 731 fHeader = (message_header *)malloc(sizeof(message_header)); 732 if (!fHeader) 733 return B_NO_MEMORY; 734 735 fHeader->format = format; 736 uint8 *header = (uint8 *)fHeader; 737 ssize_t result = stream->Read(header + sizeof(uint32), 738 sizeof(message_header) - sizeof(uint32)); 739 result -= sizeof(message_header) - sizeof(uint32); 740 741 if (result != B_OK || fHeader->format != MESSAGE_FORMAT_HAIKU 742 || !(fHeader->flags & MESSAGE_FLAG_VALID)) { 743 free(fHeader); 744 fHeader = NULL; 745 _InitHeader(); 746 return B_BAD_VALUE; 747 } 748 749 fHeader->fields_available = 0; 750 fHeader->data_available = 0; 751 what = fHeader->what; 752 753 fHeader->shared_area = -1; 754 755 if (result == B_OK && fHeader->fields_size > 0) { 756 fFields = (field_header *)malloc(fHeader->fields_size); 757 if (!fFields) 758 return B_NO_MEMORY; 759 760 result = stream->Read(fFields, fHeader->fields_size); 761 result -= fHeader->fields_size; 762 } 763 764 if (result == B_OK && fHeader->data_size > 0) { 765 fData = (uint8 *)malloc(fHeader->data_size); 766 if (!fData) 767 return B_NO_MEMORY; 768 769 result = stream->Read(fData, fHeader->data_size); 770 result -= fHeader->data_size; 771 } 772 773 if (result < B_OK) 774 return B_BAD_VALUE; 775 776 return B_OK; 777 } 778 779 780 status_t 781 BMessage::AddSpecifier(const char *property) 782 { 783 BMessage message(B_DIRECT_SPECIFIER); 784 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 785 if (result < B_OK) 786 return result; 787 788 return AddSpecifier(&message); 789 } 790 791 792 status_t 793 BMessage::AddSpecifier(const char *property, int32 index) 794 { 795 BMessage message(B_INDEX_SPECIFIER); 796 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 797 if (result < B_OK) 798 return result; 799 800 result = message.AddInt32("index", index); 801 if (result < B_OK) 802 return result; 803 804 return AddSpecifier(&message); 805 } 806 807 808 status_t 809 BMessage::AddSpecifier(const char *property, int32 index, int32 range) 810 { 811 if (range < 0) 812 return B_BAD_VALUE; 813 814 BMessage message(B_RANGE_SPECIFIER); 815 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 816 if (result < B_OK) 817 return result; 818 819 result = message.AddInt32("index", index); 820 if (result < B_OK) 821 return result; 822 823 result = message.AddInt32("range", range); 824 if (result < B_OK) 825 return result; 826 827 return AddSpecifier(&message); 828 } 829 830 831 status_t 832 BMessage::AddSpecifier(const char *property, const char *name) 833 { 834 BMessage message(B_NAME_SPECIFIER); 835 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 836 if (result < B_OK) 837 return result; 838 839 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 840 if (result < B_OK) 841 return result; 842 843 return AddSpecifier(&message); 844 } 845 846 847 status_t 848 BMessage::AddSpecifier(const BMessage *specifier) 849 { 850 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 851 if (result < B_OK) 852 return result; 853 854 fHeader->current_specifier++; 855 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 856 return B_OK; 857 } 858 859 860 status_t 861 BMessage::SetCurrentSpecifier(int32 index) 862 { 863 if (index < 0) 864 return B_BAD_INDEX; 865 866 type_code type; 867 int32 count; 868 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 869 if (result < B_OK) 870 return result; 871 872 if (index > count) 873 return B_BAD_INDEX; 874 875 fHeader->current_specifier = index; 876 return B_OK; 877 } 878 879 880 status_t 881 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *what, 882 const char **property) const 883 { 884 if (index) 885 *index = fHeader->current_specifier; 886 887 if (fHeader->current_specifier < 0 888 || !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED)) 889 return B_BAD_SCRIPT_SYNTAX; 890 891 if (specifier) { 892 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 893 specifier) < B_OK) 894 return B_BAD_SCRIPT_SYNTAX; 895 896 if (what) 897 *what = specifier->what; 898 899 if (property) { 900 if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK) 901 return B_BAD_SCRIPT_SYNTAX; 902 } 903 } 904 905 return B_OK; 906 } 907 908 909 bool 910 BMessage::HasSpecifiers() const 911 { 912 return fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS; 913 } 914 915 916 status_t 917 BMessage::PopSpecifier() 918 { 919 if (fHeader->current_specifier < 0 || 920 !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED)) 921 return B_BAD_VALUE; 922 923 if (fHeader->current_specifier >= 0) 924 fHeader->current_specifier--; 925 926 return B_OK; 927 } 928 929 930 status_t 931 BMessage::_ResizeData(int32 offset, int32 change) 932 { 933 if (change == 0) 934 return B_OK; 935 936 /* optimize for the most usual case: appending data */ 937 if (offset < fHeader->data_size) { 938 field_header *field = fFields; 939 for (int32 i = 0; i < fHeader->field_count; i++, field++) { 940 if (field->offset >= offset) 941 field->offset += change; 942 } 943 } 944 945 if (change > 0) { 946 if (fHeader->data_available >= change) { 947 if (offset < fHeader->data_size) { 948 memmove(fData + offset + change, fData + offset, 949 fHeader->data_size - offset); 950 } 951 952 fHeader->data_available -= change; 953 fHeader->data_size += change; 954 return B_OK; 955 } 956 957 ssize_t size = fHeader->data_size * 2; 958 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 959 size = max_c(size, fHeader->data_size + change); 960 961 uint8 *newData = (uint8 *)realloc(fData, size); 962 if (size > 0 && !newData) 963 return B_NO_MEMORY; 964 965 fData = newData; 966 if (offset < fHeader->data_size) { 967 memmove(fData + offset + change, fData + offset, 968 fHeader->data_size - offset); 969 } 970 971 fHeader->data_size += change; 972 fHeader->data_available = size - fHeader->data_size; 973 } else { 974 ssize_t length = fHeader->data_size - offset + change; 975 if (length > 0) 976 memmove(fData + offset, fData + offset - change, length); 977 978 fHeader->data_size += change; 979 fHeader->data_available -= change; 980 981 if (fHeader->data_available > MAX_DATA_PREALLOCATION) { 982 ssize_t available = MAX_DATA_PREALLOCATION / 2; 983 ssize_t size = fHeader->data_size + available; 984 uint8 *newData = (uint8 *)realloc(fData, size); 985 if (size > 0 && !newData) { 986 // this is strange, but not really fatal 987 return B_OK; 988 } 989 990 fData = newData; 991 fHeader->data_available = available; 992 } 993 } 994 995 return B_OK; 996 } 997 998 999 uint32 1000 BMessage::_HashName(const char *name) const 1001 { 1002 char ch; 1003 uint32 result = 0; 1004 1005 while ((ch = *name++) != 0) { 1006 result = (result << 7) ^ (result >> 24); 1007 result ^= ch; 1008 } 1009 1010 result ^= result << 12; 1011 return result; 1012 } 1013 1014 1015 status_t 1016 BMessage::_FindField(const char *name, type_code type, field_header **result) const 1017 { 1018 if (!name) 1019 return B_BAD_VALUE; 1020 1021 if (!fHeader || !fFields || !fData) 1022 return B_NAME_NOT_FOUND; 1023 1024 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1025 int32 nextField = fHeader->hash_table[hash]; 1026 1027 while (nextField >= 0) { 1028 field_header *field = &fFields[nextField]; 1029 1030 if (strncmp((const char *)(fData + field->offset), name, 1031 field->name_length) == 0) { 1032 if (type != B_ANY_TYPE && field->type != type) 1033 return B_BAD_TYPE; 1034 1035 *result = field; 1036 return B_OK; 1037 } 1038 1039 nextField = field->next_field; 1040 } 1041 1042 return B_NAME_NOT_FOUND; 1043 } 1044 1045 1046 status_t 1047 BMessage::_AddField(const char *name, type_code type, bool isFixedSize, 1048 field_header **result) 1049 { 1050 if (!fHeader) 1051 return B_ERROR; 1052 1053 if (fHeader->fields_available <= 0) { 1054 int32 count = fHeader->field_count * 2 + 1; 1055 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1056 1057 field_header *newFields = (field_header *)realloc(fFields, 1058 count * sizeof(field_header)); 1059 if (count > 0 && !newFields) 1060 return B_NO_MEMORY; 1061 1062 fFields = newFields; 1063 fHeader->fields_available = count - fHeader->field_count; 1064 } 1065 1066 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1067 int32 *nextField = &fHeader->hash_table[hash]; 1068 while (*nextField >= 0) 1069 nextField = &fFields[*nextField].next_field; 1070 *nextField = fHeader->field_count; 1071 1072 field_header *field = &fFields[fHeader->field_count]; 1073 field->type = type; 1074 field->count = 0; 1075 field->data_size = 0; 1076 field->allocated = 0; 1077 field->next_field = -1; 1078 field->offset = fHeader->data_size; 1079 field->name_length = strlen(name) + 1; 1080 status_t status = _ResizeData(field->offset, field->name_length); 1081 if (status < B_OK) 1082 return status; 1083 1084 memcpy(fData + field->offset, name, field->name_length); 1085 field->flags = FIELD_FLAG_VALID; 1086 if (isFixedSize) 1087 field->flags |= FIELD_FLAG_FIXED_SIZE; 1088 1089 fHeader->fields_available--; 1090 fHeader->fields_size += sizeof(field_header); 1091 fHeader->field_count++; 1092 *result = field; 1093 return B_OK; 1094 } 1095 1096 1097 status_t 1098 BMessage::_RemoveField(field_header *field) 1099 { 1100 status_t result = _ResizeData(field->offset, -(field->data_size 1101 + field->name_length)); 1102 if (result < B_OK) 1103 return result; 1104 1105 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header); 1106 int32 nextField = field->next_field; 1107 if (nextField > index) 1108 nextField--; 1109 1110 int32 *value = fHeader->hash_table; 1111 for (int32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1112 if (*value > index) 1113 *value -= 1; 1114 else if (*value == index) 1115 *value = nextField; 1116 } 1117 1118 field_header *other = fFields; 1119 for (int32 i = 0; i < fHeader->field_count; i++, other++) { 1120 if (other->next_field > index) 1121 other->next_field--; 1122 else if (other->next_field == index) 1123 other->next_field = nextField; 1124 } 1125 1126 ssize_t size = fHeader->fields_size - (index + 1) * sizeof(field_header); 1127 memmove(fFields + index, fFields + index + 1, size); 1128 fHeader->fields_size -= sizeof(field_header); 1129 fHeader->field_count--; 1130 fHeader->fields_available++; 1131 1132 if (fHeader->fields_available > MAX_FIELD_PREALLOCATION) { 1133 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1134 size = fHeader->fields_size + available * sizeof(field_header); 1135 field_header *newFields = (field_header *)realloc(fFields, size); 1136 if (size > 0 && !newFields) { 1137 // this is strange, but not really fatal 1138 return B_OK; 1139 } 1140 1141 fFields = newFields; 1142 fHeader->fields_available = available; 1143 } 1144 1145 return B_OK; 1146 } 1147 1148 1149 status_t 1150 BMessage::AddData(const char *name, type_code type, const void *data, 1151 ssize_t numBytes, bool isFixedSize, int32 count) 1152 { 1153 if (numBytes <= 0 || !data) 1154 return B_BAD_VALUE; 1155 1156 field_header *field = NULL; 1157 status_t result = _FindField(name, type, &field); 1158 if (result == B_NAME_NOT_FOUND) 1159 result = _AddField(name, type, isFixedSize, &field); 1160 1161 if (result < B_OK) 1162 return result; 1163 1164 if (!field) 1165 return B_ERROR; 1166 1167 uint32 offset = field->offset + field->name_length + field->data_size; 1168 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1169 if (field->count) { 1170 ssize_t size = field->data_size / field->count; 1171 if (size != numBytes) 1172 return B_BAD_VALUE; 1173 } 1174 1175 result = _ResizeData(offset, numBytes); 1176 if (result < B_OK) { 1177 if (field->count == 0) 1178 _RemoveField(field); 1179 return result; 1180 } 1181 1182 memcpy(fData + offset, data, numBytes); 1183 field->data_size += numBytes; 1184 } else { 1185 int32 change = numBytes + sizeof(numBytes); 1186 result = _ResizeData(offset, change); 1187 if (result < B_OK) { 1188 if (field->count == 0) 1189 _RemoveField(field); 1190 return result; 1191 } 1192 1193 memcpy(fData + offset, &numBytes, sizeof(numBytes)); 1194 memcpy(fData + offset + sizeof(numBytes), data, numBytes); 1195 field->data_size += change; 1196 } 1197 1198 field->count++; 1199 return B_OK; 1200 } 1201 1202 1203 status_t 1204 BMessage::RemoveData(const char *name, int32 index) 1205 { 1206 if (index < 0) 1207 return B_BAD_VALUE; 1208 1209 field_header *field = NULL; 1210 status_t result = _FindField(name, B_ANY_TYPE, &field); 1211 1212 if (result < B_OK) 1213 return result; 1214 1215 if (!field) 1216 return B_ERROR; 1217 1218 if (index >= field->count) 1219 return B_BAD_INDEX; 1220 1221 if (field->count == 1) 1222 return _RemoveField(field); 1223 1224 uint32 offset = field->offset + field->name_length; 1225 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1226 ssize_t size = field->data_size / field->count; 1227 result = _ResizeData(offset + index * size, -size); 1228 if (result < B_OK) 1229 return result; 1230 1231 field->data_size -= size; 1232 } else { 1233 uint8 *pointer = fData + offset; 1234 1235 for (int32 i = 0; i < index; i++) { 1236 offset += *(ssize_t *)pointer + sizeof(ssize_t); 1237 pointer = fData + offset; 1238 } 1239 1240 ssize_t currentSize = *(ssize_t *)pointer + sizeof(ssize_t); 1241 result = _ResizeData(offset, -currentSize); 1242 if (result < B_OK) 1243 return result; 1244 1245 field->data_size -= currentSize; 1246 } 1247 1248 field->count--; 1249 return B_OK; 1250 } 1251 1252 1253 status_t 1254 BMessage::RemoveName(const char *name) 1255 { 1256 field_header *field = NULL; 1257 status_t result = _FindField(name, B_ANY_TYPE, &field); 1258 1259 if (result < B_OK) 1260 return result; 1261 1262 if (!field) 1263 return B_ERROR; 1264 1265 return _RemoveField(field); 1266 } 1267 1268 1269 status_t 1270 BMessage::MakeEmpty() 1271 { 1272 _Clear(); 1273 _InitHeader(); 1274 return B_OK; 1275 } 1276 1277 1278 status_t 1279 BMessage::FindData(const char *name, type_code type, int32 index, 1280 const void **data, ssize_t *numBytes) const 1281 { 1282 if (!data || !numBytes) 1283 return B_BAD_VALUE; 1284 1285 *data = NULL; 1286 field_header *field = NULL; 1287 status_t result = _FindField(name, type, &field); 1288 1289 if (result < B_OK) 1290 return result; 1291 1292 if (!field) 1293 return B_ERROR; 1294 1295 if (index >= field->count) 1296 return B_BAD_INDEX; 1297 1298 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1299 *numBytes = field->data_size / field->count; 1300 *data = fData + field->offset + field->name_length + index * *numBytes; 1301 } else { 1302 uint8 *pointer = fData + field->offset + field->name_length; 1303 1304 for (int32 i = 0; i < index; i++) 1305 pointer += *(ssize_t *)pointer + sizeof(ssize_t); 1306 1307 *numBytes = *(ssize_t *)pointer; 1308 *data = pointer + sizeof(ssize_t); 1309 } 1310 1311 return B_OK; 1312 } 1313 1314 1315 status_t 1316 BMessage::ReplaceData(const char *name, type_code type, int32 index, 1317 const void *data, ssize_t numBytes) 1318 { 1319 if (numBytes <= 0 || !data) 1320 return B_BAD_VALUE; 1321 1322 field_header *field = NULL; 1323 status_t result = _FindField(name, type, &field); 1324 1325 if (result < B_OK) 1326 return result; 1327 1328 if (!field) 1329 return B_ERROR; 1330 1331 if (index >= field->count) 1332 return B_BAD_INDEX; 1333 1334 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1335 ssize_t size = field->data_size / field->count; 1336 if (size != numBytes) 1337 return B_BAD_VALUE; 1338 1339 memcpy(fData + field->offset + field->name_length + index * size, data, 1340 size); 1341 } else { 1342 uint32 offset = field->offset + field->name_length; 1343 uint8 *pointer = fData + offset; 1344 1345 for (int32 i = 0; i < index; i++) { 1346 offset += *(ssize_t *)pointer + sizeof(ssize_t); 1347 pointer = fData + offset; 1348 } 1349 1350 ssize_t currentSize = *(ssize_t *)pointer; 1351 int32 change = numBytes - currentSize; 1352 result = _ResizeData(offset, change); 1353 if (result < B_OK) 1354 return result; 1355 1356 memcpy(fData + offset, &numBytes, sizeof(numBytes)); 1357 memcpy(fData + offset + sizeof(numBytes), data, numBytes); 1358 field->data_size += change; 1359 } 1360 1361 return B_OK; 1362 } 1363 1364 1365 bool 1366 BMessage::HasData(const char *name, type_code type, int32 index) const 1367 { 1368 field_header *field = NULL; 1369 status_t result = _FindField(name, type, &field); 1370 1371 if (result < B_OK) 1372 return false; 1373 1374 if (!field) 1375 return false; 1376 1377 if (index >= field->count) 1378 return false; 1379 1380 return true; 1381 } 1382 1383 1384 void 1385 BMessage::_StaticCacheCleanup() 1386 { 1387 delete sMsgCache; 1388 sMsgCache = NULL; 1389 } 1390 1391 1392 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 1393 1394 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 1395 status_t \ 1396 BMessage::Add##typeName(const char *name, type val) \ 1397 { \ 1398 return AddData(name, typeCode, &val, sizeof(type), true); \ 1399 } \ 1400 \ 1401 status_t \ 1402 BMessage::Find##typeName(const char *name, type *p) const \ 1403 { \ 1404 void *ptr = NULL; \ 1405 ssize_t bytes = 0; \ 1406 status_t error = B_OK; \ 1407 \ 1408 *p = type(); \ 1409 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 1410 \ 1411 if (error == B_OK) \ 1412 memcpy(p, ptr, sizeof(type)); \ 1413 \ 1414 return error; \ 1415 } \ 1416 \ 1417 status_t \ 1418 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 1419 { \ 1420 void *ptr = NULL; \ 1421 ssize_t bytes = 0; \ 1422 status_t error = B_OK; \ 1423 \ 1424 *p = type(); \ 1425 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 1426 \ 1427 if (error == B_OK) \ 1428 memcpy(p, ptr, sizeof(type)); \ 1429 \ 1430 return error; \ 1431 } \ 1432 \ 1433 status_t \ 1434 BMessage::Replace##typeName(const char *name, type val) \ 1435 { \ 1436 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \ 1437 } \ 1438 \ 1439 status_t \ 1440 BMessage::Replace##typeName(const char *name, int32 index, type val) \ 1441 { \ 1442 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \ 1443 } \ 1444 \ 1445 bool \ 1446 BMessage::Has##typeName(const char *name, int32 index) const \ 1447 { \ 1448 return HasData(name, typeCode, index); \ 1449 } 1450 1451 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 1452 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 1453 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 1454 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 1455 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 1456 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 1457 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 1458 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 1459 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 1460 1461 #undef DEFINE_FUNCTIONS 1462 1463 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 1464 bool \ 1465 BMessage::Has##typeName(const char *name, int32 index) const \ 1466 { \ 1467 return HasData(name, typeCode, index); \ 1468 } 1469 1470 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 1471 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 1472 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 1473 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 1474 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 1475 1476 #undef DEFINE_HAS_FUNCTION 1477 1478 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 1479 type \ 1480 BMessage::Find##typeName(const char *name, int32 index) const \ 1481 { \ 1482 type val = initialize; \ 1483 Find##typeName(name, index, &val); \ 1484 return val; \ 1485 } 1486 1487 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 1488 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 1489 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 1490 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 1491 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 1492 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 1493 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 1494 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 1495 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 1496 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 1497 1498 #undef DEFINE_LAZY_FIND_FUNCTION 1499 1500 status_t 1501 BMessage::AddString(const char *name, const char *string) 1502 { 1503 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false); 1504 } 1505 1506 1507 status_t 1508 BMessage::AddString(const char *name, const BString &string) 1509 { 1510 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false); 1511 } 1512 1513 1514 status_t 1515 BMessage::AddPointer(const char *name, const void *pointer) 1516 { 1517 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 1518 } 1519 1520 1521 status_t 1522 BMessage::AddMessenger(const char *name, BMessenger messenger) 1523 { 1524 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 1525 } 1526 1527 1528 status_t 1529 BMessage::AddRef(const char *name, const entry_ref *ref) 1530 { 1531 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 1532 char buffer[size]; 1533 1534 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 1535 1536 if (error >= B_OK) 1537 error = AddData(name, B_REF_TYPE, buffer, size, false); 1538 1539 return error; 1540 } 1541 1542 1543 status_t 1544 BMessage::AddMessage(const char *name, const BMessage *message) 1545 { 1546 /* ToDo: This and the following functions waste time by allocating and 1547 copying an extra buffer. Functions can be added that return a direct 1548 pointer into the message. */ 1549 1550 ssize_t size = message->FlattenedSize(); 1551 char buffer[size]; 1552 1553 status_t error = message->Flatten(buffer, size); 1554 1555 if (error >= B_OK) 1556 error = AddData(name, B_MESSAGE_TYPE, &buffer, size, false); 1557 1558 return error; 1559 } 1560 1561 1562 status_t 1563 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 1564 { 1565 ssize_t size = object->FlattenedSize(); 1566 char buffer[size]; 1567 1568 status_t error = object->Flatten(buffer, size); 1569 1570 if (error >= B_OK) 1571 error = AddData(name, object->TypeCode(), &buffer, size, false); 1572 1573 return error; 1574 } 1575 1576 1577 status_t 1578 BMessage::FindString(const char *name, const char **string) const 1579 { 1580 return FindString(name, 0, string); 1581 } 1582 1583 1584 status_t 1585 BMessage::FindString(const char *name, int32 index, const char **string) const 1586 { 1587 ssize_t bytes; 1588 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 1589 } 1590 1591 1592 status_t 1593 BMessage::FindString(const char *name, BString *string) const 1594 { 1595 return FindString(name, 0, string); 1596 } 1597 1598 1599 status_t 1600 BMessage::FindString(const char *name, int32 index, BString *string) const 1601 { 1602 const char *cstr; 1603 status_t error = FindString(name, index, &cstr); 1604 if (error < B_OK) 1605 return error; 1606 1607 *string = cstr; 1608 return B_OK; 1609 } 1610 1611 1612 status_t 1613 BMessage::FindPointer(const char *name, void **pointer) const 1614 { 1615 return FindPointer(name, 0, pointer); 1616 } 1617 1618 1619 status_t 1620 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 1621 { 1622 void **data = NULL; 1623 ssize_t size = 0; 1624 status_t error = FindData(name, B_POINTER_TYPE, index, 1625 (const void **)&data, &size); 1626 1627 if (error == B_OK) 1628 *pointer = *data; 1629 else 1630 *pointer = NULL; 1631 1632 return error; 1633 } 1634 1635 1636 status_t 1637 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 1638 { 1639 return FindMessenger(name, 0, messenger); 1640 } 1641 1642 1643 status_t 1644 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 1645 const 1646 { 1647 void *data = NULL; 1648 ssize_t size = 0; 1649 status_t error = FindData(name, B_MESSENGER_TYPE, index, 1650 (const void **)&data, &size); 1651 1652 if (error == B_OK) 1653 memcpy(messenger, data, sizeof(BMessenger)); 1654 else 1655 *messenger = BMessenger(); 1656 1657 return error; 1658 } 1659 1660 1661 status_t 1662 BMessage::FindRef(const char *name, entry_ref *ref) const 1663 { 1664 return FindRef(name, 0, ref); 1665 } 1666 1667 1668 status_t 1669 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 1670 { 1671 void *data = NULL; 1672 ssize_t size = 0; 1673 status_t error = FindData(name, B_REF_TYPE, index, 1674 (const void **)&data, &size); 1675 1676 if (error == B_OK) 1677 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 1678 else 1679 *ref = entry_ref(); 1680 1681 return error; 1682 } 1683 1684 1685 status_t 1686 BMessage::FindMessage(const char *name, BMessage *message) const 1687 { 1688 return FindMessage(name, 0, message); 1689 } 1690 1691 1692 status_t 1693 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 1694 { 1695 void *data = NULL; 1696 ssize_t size = 0; 1697 status_t error = FindData(name, B_MESSAGE_TYPE, index, 1698 (const void **)&data, &size); 1699 1700 if (error == B_OK) 1701 error = message->Unflatten((const char *)data); 1702 else 1703 *message = BMessage(); 1704 1705 return error; 1706 } 1707 1708 1709 status_t 1710 BMessage::FindFlat(const char *name, BFlattenable *object) const 1711 { 1712 return FindFlat(name, 0, object); 1713 } 1714 1715 1716 status_t 1717 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 1718 { 1719 void *data = NULL; 1720 ssize_t numBytes = 0; 1721 status_t error = FindData(name, object->TypeCode(), index, 1722 (const void **)&data, &numBytes); 1723 1724 if (error == B_OK) 1725 error = object->Unflatten(object->TypeCode(), data, numBytes); 1726 1727 return error; 1728 } 1729 1730 1731 status_t 1732 BMessage::FindData(const char *name, type_code type, const void **data, 1733 ssize_t *numBytes) const 1734 { 1735 return FindData(name, type, 0, data, numBytes); 1736 } 1737 1738 1739 status_t 1740 BMessage::ReplaceString(const char *name, const char *string) 1741 { 1742 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 1743 } 1744 1745 1746 status_t 1747 BMessage::ReplaceString(const char *name, int32 index, const char *string) 1748 { 1749 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 1750 } 1751 1752 1753 status_t 1754 BMessage::ReplaceString(const char *name, const BString &string) 1755 { 1756 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 1757 string.Length() + 1); 1758 } 1759 1760 1761 status_t 1762 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 1763 { 1764 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 1765 string.Length() + 1); 1766 } 1767 1768 1769 status_t 1770 BMessage::ReplacePointer(const char *name, const void *pointer) 1771 { 1772 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 1773 } 1774 1775 1776 status_t 1777 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 1778 { 1779 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 1780 } 1781 1782 1783 status_t 1784 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 1785 { 1786 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 1787 sizeof(BMessenger)); 1788 } 1789 1790 1791 status_t 1792 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 1793 { 1794 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 1795 sizeof(BMessenger)); 1796 } 1797 1798 1799 status_t 1800 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 1801 { 1802 return ReplaceRef(name, 0, ref); 1803 } 1804 1805 1806 status_t 1807 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 1808 { 1809 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 1810 char buffer[size]; 1811 1812 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 1813 1814 if (error >= B_OK) 1815 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 1816 1817 return error; 1818 } 1819 1820 1821 status_t 1822 BMessage::ReplaceMessage(const char *name, const BMessage *message) 1823 { 1824 return ReplaceMessage(name, 0, message); 1825 } 1826 1827 1828 status_t 1829 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 1830 { 1831 ssize_t size = message->FlattenedSize(); 1832 char buffer[size]; 1833 1834 status_t error = message->Flatten(buffer, size); 1835 1836 if (error >= B_OK) 1837 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 1838 1839 return error; 1840 } 1841 1842 1843 status_t 1844 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 1845 { 1846 return ReplaceFlat(name, 0, object); 1847 } 1848 1849 1850 status_t 1851 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 1852 { 1853 ssize_t size = object->FlattenedSize(); 1854 char buffer[size]; 1855 1856 status_t error = object->Flatten(buffer, size); 1857 1858 if (error >= B_OK) 1859 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 1860 1861 return error; 1862 } 1863 1864 1865 status_t 1866 BMessage::ReplaceData(const char *name, type_code type, const void *data, 1867 ssize_t numBytes) 1868 { 1869 return ReplaceData(name, type, 0, data, numBytes); 1870 } 1871 1872 1873 bool 1874 BMessage::HasFlat(const char *name, const BFlattenable *object) const 1875 { 1876 return HasFlat(name, 0, object); 1877 } 1878 1879 1880 bool 1881 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 1882 const 1883 { 1884 return HasData(name, object->TypeCode(), index); 1885 } 1886