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