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