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