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