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