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 try { 1044 if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped) 1045 return BPrivate::unflatten_r5_message(format, this, flatBuffer); 1046 1047 if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped) { 1048 BMemoryIO stream(flatBuffer + sizeof(uint32), 1049 BPrivate::dano_message_flattened_size(flatBuffer)); 1050 return BPrivate::unflatten_dano_message(format, stream, *this); 1051 } 1052 } catch (status_t error) { 1053 MakeEmpty(); 1054 return error; 1055 } 1056 1057 return B_NOT_A_MESSAGE; 1058 } 1059 1060 // native message unflattening 1061 1062 _Clear(); 1063 1064 fHeader = (message_header *)malloc(sizeof(message_header)); 1065 if (!fHeader) 1066 return B_NO_MEMORY; 1067 1068 memcpy(fHeader, flatBuffer, sizeof(message_header)); 1069 flatBuffer += sizeof(message_header); 1070 1071 if (fHeader->format != kMessageMagicHaiku 1072 || !(fHeader->flags & MESSAGE_FLAG_VALID)) { 1073 free(fHeader); 1074 fHeader = NULL; 1075 _InitHeader(); 1076 return B_BAD_VALUE; 1077 } 1078 1079 fHeader->fields_available = 0; 1080 fHeader->data_available = 0; 1081 what = fHeader->what; 1082 1083 if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) { 1084 status_t result = _Reference(fHeader); 1085 if (result < B_OK) 1086 return result; 1087 } else { 1088 fHeader->shared_area = -1; 1089 1090 if (fHeader->fields_size > 0) { 1091 fFields = (field_header *)malloc(fHeader->fields_size); 1092 if (!fFields) 1093 return B_NO_MEMORY; 1094 1095 memcpy(fFields, flatBuffer, fHeader->fields_size); 1096 flatBuffer += fHeader->fields_size; 1097 } 1098 1099 if (fHeader->data_size > 0) { 1100 fData = (uint8 *)malloc(fHeader->data_size); 1101 if (!fData) 1102 return B_NO_MEMORY; 1103 1104 memcpy(fData, flatBuffer, fHeader->data_size); 1105 } 1106 } 1107 1108 /*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size) 1109 || fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) { 1110 debug_printf("checksum mismatch 1\n"); 1111 _Clear(); 1112 _InitHeader(); 1113 return B_BAD_VALUE; 1114 }*/ 1115 1116 return B_OK; 1117 } 1118 1119 1120 status_t 1121 BMessage::Unflatten(BDataIO *stream) 1122 { 1123 DEBUG_FUNCTION_ENTER; 1124 if (!stream) 1125 return B_BAD_VALUE; 1126 1127 uint32 format = 0; 1128 stream->Read(&format, sizeof(uint32)); 1129 if (format != kMessageMagicHaiku) { 1130 try { 1131 if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped) 1132 return BPrivate::unflatten_r5_message(format, this, stream); 1133 1134 if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped) 1135 return BPrivate::unflatten_dano_message(format, *stream, *this); 1136 } catch (status_t error) { 1137 MakeEmpty(); 1138 return error; 1139 } 1140 1141 return B_NOT_A_MESSAGE; 1142 } 1143 1144 // native message unflattening 1145 1146 _Clear(); 1147 1148 fHeader = (message_header *)malloc(sizeof(message_header)); 1149 if (!fHeader) 1150 return B_NO_MEMORY; 1151 1152 fHeader->format = format; 1153 uint8 *header = (uint8 *)fHeader; 1154 ssize_t result = stream->Read(header + sizeof(uint32), 1155 sizeof(message_header) - sizeof(uint32)); 1156 result -= sizeof(message_header) - sizeof(uint32); 1157 1158 if (result != B_OK || fHeader->format != kMessageMagicHaiku 1159 || !(fHeader->flags & MESSAGE_FLAG_VALID)) { 1160 free(fHeader); 1161 fHeader = NULL; 1162 _InitHeader(); 1163 return B_BAD_VALUE; 1164 } 1165 1166 fHeader->fields_available = 0; 1167 fHeader->data_available = 0; 1168 what = fHeader->what; 1169 1170 if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) { 1171 result = _Reference(fHeader); 1172 if (result < B_OK) 1173 return result; 1174 } else { 1175 fHeader->shared_area = -1; 1176 1177 if (result == B_OK && fHeader->fields_size > 0) { 1178 fFields = (field_header *)malloc(fHeader->fields_size); 1179 if (!fFields) 1180 return B_NO_MEMORY; 1181 1182 result = stream->Read(fFields, fHeader->fields_size); 1183 result -= fHeader->fields_size; 1184 } 1185 1186 if (result == B_OK && fHeader->data_size > 0) { 1187 fData = (uint8 *)malloc(fHeader->data_size); 1188 if (!fData) 1189 return B_NO_MEMORY; 1190 1191 result = stream->Read(fData, fHeader->data_size); 1192 result -= fHeader->data_size; 1193 } 1194 1195 if (result < B_OK) 1196 return B_BAD_VALUE; 1197 } 1198 1199 /*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size) 1200 || fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) { 1201 debug_printf("checksum mismatch 2\n"); 1202 _Clear(); 1203 _InitHeader(); 1204 return B_BAD_VALUE; 1205 }*/ 1206 1207 return B_OK; 1208 } 1209 1210 1211 status_t 1212 BMessage::AddSpecifier(const char *property) 1213 { 1214 DEBUG_FUNCTION_ENTER; 1215 BMessage message(B_DIRECT_SPECIFIER); 1216 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1217 if (result < B_OK) 1218 return result; 1219 1220 return AddSpecifier(&message); 1221 } 1222 1223 1224 status_t 1225 BMessage::AddSpecifier(const char *property, int32 index) 1226 { 1227 DEBUG_FUNCTION_ENTER; 1228 BMessage message(B_INDEX_SPECIFIER); 1229 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1230 if (result < B_OK) 1231 return result; 1232 1233 result = message.AddInt32("index", index); 1234 if (result < B_OK) 1235 return result; 1236 1237 return AddSpecifier(&message); 1238 } 1239 1240 1241 status_t 1242 BMessage::AddSpecifier(const char *property, int32 index, int32 range) 1243 { 1244 DEBUG_FUNCTION_ENTER; 1245 if (range < 0) 1246 return B_BAD_VALUE; 1247 1248 BMessage message(B_RANGE_SPECIFIER); 1249 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1250 if (result < B_OK) 1251 return result; 1252 1253 result = message.AddInt32("index", index); 1254 if (result < B_OK) 1255 return result; 1256 1257 result = message.AddInt32("range", range); 1258 if (result < B_OK) 1259 return result; 1260 1261 return AddSpecifier(&message); 1262 } 1263 1264 1265 status_t 1266 BMessage::AddSpecifier(const char *property, const char *name) 1267 { 1268 DEBUG_FUNCTION_ENTER; 1269 BMessage message(B_NAME_SPECIFIER); 1270 status_t result = message.AddString(B_PROPERTY_ENTRY, property); 1271 if (result < B_OK) 1272 return result; 1273 1274 result = message.AddString(B_PROPERTY_NAME_ENTRY, name); 1275 if (result < B_OK) 1276 return result; 1277 1278 return AddSpecifier(&message); 1279 } 1280 1281 1282 status_t 1283 BMessage::AddSpecifier(const BMessage *specifier) 1284 { 1285 DEBUG_FUNCTION_ENTER; 1286 status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier); 1287 if (result < B_OK) 1288 return result; 1289 1290 fHeader->current_specifier++; 1291 fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS; 1292 return B_OK; 1293 } 1294 1295 1296 status_t 1297 BMessage::SetCurrentSpecifier(int32 index) 1298 { 1299 DEBUG_FUNCTION_ENTER; 1300 if (index < 0) 1301 return B_BAD_INDEX; 1302 1303 type_code type; 1304 int32 count; 1305 status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count); 1306 if (result < B_OK) 1307 return result; 1308 1309 if (index > count) 1310 return B_BAD_INDEX; 1311 1312 fHeader->current_specifier = index; 1313 return B_OK; 1314 } 1315 1316 1317 status_t 1318 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *what, 1319 const char **property) const 1320 { 1321 DEBUG_FUNCTION_ENTER; 1322 if (fHeader->current_specifier < 0 1323 || !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED)) 1324 return B_BAD_SCRIPT_SYNTAX; 1325 1326 if (index) 1327 *index = fHeader->current_specifier; 1328 1329 if (specifier) { 1330 if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier, 1331 specifier) < B_OK) 1332 return B_BAD_SCRIPT_SYNTAX; 1333 1334 if (what) 1335 *what = specifier->what; 1336 1337 if (property) { 1338 if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK) 1339 return B_BAD_SCRIPT_SYNTAX; 1340 } 1341 } 1342 1343 return B_OK; 1344 } 1345 1346 1347 bool 1348 BMessage::HasSpecifiers() const 1349 { 1350 DEBUG_FUNCTION_ENTER; 1351 return fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS; 1352 } 1353 1354 1355 status_t 1356 BMessage::PopSpecifier() 1357 { 1358 DEBUG_FUNCTION_ENTER; 1359 if (fHeader->current_specifier < 0 || 1360 !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED)) 1361 return B_BAD_VALUE; 1362 1363 if (fHeader->current_specifier >= 0) 1364 fHeader->current_specifier--; 1365 1366 return B_OK; 1367 } 1368 1369 1370 status_t 1371 BMessage::_ResizeData(int32 offset, int32 change) 1372 { 1373 if (change == 0) 1374 return B_OK; 1375 1376 /* optimize for the most usual case: appending data */ 1377 if (offset < fHeader->data_size) { 1378 field_header *field = fFields; 1379 for (int32 i = 0; i < fHeader->field_count; i++, field++) { 1380 if (field->offset >= offset) 1381 field->offset += change; 1382 } 1383 } 1384 1385 if (change > 0) { 1386 if (fHeader->data_available >= change) { 1387 if (offset < fHeader->data_size) { 1388 memmove(fData + offset + change, fData + offset, 1389 fHeader->data_size - offset); 1390 } 1391 1392 fHeader->data_available -= change; 1393 fHeader->data_size += change; 1394 return B_OK; 1395 } 1396 1397 ssize_t size = fHeader->data_size * 2; 1398 size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION); 1399 size = max_c(size, fHeader->data_size + change); 1400 1401 fData = (uint8 *)realloc(fData, size); 1402 if (!fData) 1403 return B_NO_MEMORY; 1404 1405 if (offset < fHeader->data_size) { 1406 memmove(fData + offset + change, fData + offset, 1407 fHeader->data_size - offset); 1408 } 1409 1410 fHeader->data_size += change; 1411 fHeader->data_available = size - fHeader->data_size; 1412 } else { 1413 ssize_t length = fHeader->data_size - offset + change; 1414 if (length > 0) 1415 memmove(fData + offset, fData + offset - change, length); 1416 1417 fHeader->data_size += change; 1418 fHeader->data_available -= change; 1419 1420 if (fHeader->data_available > MAX_DATA_PREALLOCATION) { 1421 ssize_t available = MAX_DATA_PREALLOCATION / 2; 1422 fData = (uint8 *)realloc(fData, fHeader->data_size + available); 1423 if (!fData) 1424 return B_NO_MEMORY; 1425 1426 fHeader->data_available = available; 1427 } 1428 } 1429 1430 return B_OK; 1431 } 1432 1433 1434 uint32 1435 BMessage::_HashName(const char *name) const 1436 { 1437 char ch; 1438 uint32 result = 0; 1439 1440 while ((ch = *name++) != 0) { 1441 result = (result << 7) ^ (result >> 24); 1442 result ^= ch; 1443 } 1444 1445 result ^= result << 12; 1446 return result; 1447 } 1448 1449 1450 status_t 1451 BMessage::_FindField(const char *name, type_code type, field_header **result) const 1452 { 1453 if (!name) 1454 return B_BAD_VALUE; 1455 1456 if (!fHeader || !fFields || !fData) 1457 return B_NAME_NOT_FOUND; 1458 1459 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1460 int32 nextField = fHeader->hash_table[hash]; 1461 1462 while (nextField >= 0) { 1463 field_header *field = &fFields[nextField]; 1464 1465 if (strncmp((const char *)(fData + field->offset), name, 1466 field->name_length) == 0) { 1467 if (type != B_ANY_TYPE && field->type != type) 1468 return B_BAD_TYPE; 1469 1470 *result = field; 1471 return B_OK; 1472 } 1473 1474 nextField = field->next_field; 1475 } 1476 1477 return B_NAME_NOT_FOUND; 1478 } 1479 1480 1481 status_t 1482 BMessage::_AddField(const char *name, type_code type, bool isFixedSize, 1483 field_header **result) 1484 { 1485 if (!fHeader) 1486 return B_ERROR; 1487 1488 if (fHeader->fields_available <= 0) { 1489 int32 count = fHeader->field_count * 2 + 1; 1490 count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION); 1491 1492 fFields = (field_header *)realloc(fFields, count * sizeof(field_header)); 1493 if (!fFields) 1494 return B_NO_MEMORY; 1495 1496 fHeader->fields_available = count - fHeader->field_count; 1497 } 1498 1499 uint32 hash = _HashName(name) % fHeader->hash_table_size; 1500 1501 int32 *nextField = &fHeader->hash_table[hash]; 1502 while (*nextField >= 0) 1503 nextField = &fFields[*nextField].next_field; 1504 *nextField = fHeader->field_count; 1505 1506 field_header *field = &fFields[fHeader->field_count]; 1507 field->type = type; 1508 field->flags = FIELD_FLAG_VALID; 1509 if (isFixedSize) 1510 field->flags |= FIELD_FLAG_FIXED_SIZE; 1511 1512 field->count = 0; 1513 field->data_size = 0; 1514 field->allocated = 0; 1515 field->next_field = -1; 1516 field->offset = fHeader->data_size; 1517 field->name_length = strlen(name) + 1; 1518 _ResizeData(field->offset, field->name_length); 1519 memcpy(fData + field->offset, name, field->name_length); 1520 1521 fHeader->fields_available--; 1522 fHeader->fields_size += sizeof(field_header); 1523 fHeader->field_count++; 1524 *result = field; 1525 return B_OK; 1526 } 1527 1528 1529 status_t 1530 BMessage::_RemoveField(field_header *field) 1531 { 1532 int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header); 1533 int32 nextField = field->next_field; 1534 if (nextField > index) 1535 nextField--; 1536 1537 int32 *value = fHeader->hash_table; 1538 for (int32 i = 0; i < fHeader->hash_table_size; i++, value++) { 1539 if (*value > index) 1540 *value -= 1; 1541 else if (*value == index) 1542 *value = nextField; 1543 } 1544 1545 field_header *other = fFields; 1546 for (int32 i = 0; i < fHeader->field_count; i++, other++) { 1547 if (other->next_field > index) 1548 other->next_field--; 1549 else if (other->next_field == index) 1550 other->next_field = nextField; 1551 } 1552 1553 _ResizeData(field->offset, -(field->data_size + field->name_length)); 1554 1555 ssize_t size = fHeader->fields_size - (index + 1) * sizeof(field_header); 1556 memmove(fFields + index, fFields + index + 1, size); 1557 fHeader->fields_size -= sizeof(field_header); 1558 fHeader->field_count--; 1559 fHeader->fields_available++; 1560 1561 if (fHeader->fields_available > MAX_FIELD_PREALLOCATION) { 1562 ssize_t available = MAX_FIELD_PREALLOCATION / 2; 1563 fFields = (field_header *)realloc(fFields, fHeader->fields_size 1564 + available * sizeof(field_header)); 1565 if (!fFields) 1566 return B_NO_MEMORY; 1567 1568 fHeader->fields_available = available; 1569 } 1570 1571 return B_OK; 1572 } 1573 1574 1575 status_t 1576 BMessage::AddData(const char *name, type_code type, const void *data, 1577 ssize_t numBytes, bool isFixedSize, int32 count) 1578 { 1579 DEBUG_FUNCTION_ENTER; 1580 if (numBytes <= 0 || !data) 1581 return B_BAD_VALUE; 1582 1583 if (fClonedArea >= B_OK) 1584 _CopyForWrite(); 1585 1586 field_header *field = NULL; 1587 status_t result = _FindField(name, type, &field); 1588 if (result == B_NAME_NOT_FOUND) 1589 result = _AddField(name, type, isFixedSize, &field); 1590 1591 if (result < B_OK || !field) 1592 return result; 1593 1594 uint32 offset = field->offset + field->name_length + field->data_size; 1595 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1596 if (field->count) { 1597 ssize_t size = field->data_size / field->count; 1598 if (size != numBytes) 1599 return B_BAD_VALUE; 1600 } 1601 1602 _ResizeData(offset, numBytes); 1603 memcpy(fData + offset, data, numBytes); 1604 field->data_size += numBytes; 1605 } else { 1606 int32 change = numBytes + sizeof(numBytes); 1607 _ResizeData(offset, change); 1608 memcpy(fData + offset, &numBytes, sizeof(numBytes)); 1609 memcpy(fData + offset + sizeof(numBytes), data, numBytes); 1610 field->data_size += change; 1611 } 1612 1613 field->count++; 1614 return B_OK; 1615 } 1616 1617 1618 status_t 1619 BMessage::RemoveData(const char *name, int32 index) 1620 { 1621 DEBUG_FUNCTION_ENTER; 1622 if (index < 0) 1623 return B_BAD_VALUE; 1624 1625 if (fClonedArea >= B_OK) 1626 _CopyForWrite(); 1627 1628 field_header *field = NULL; 1629 status_t result = _FindField(name, B_ANY_TYPE, &field); 1630 1631 if (result < B_OK) 1632 return result; 1633 1634 if (!field) 1635 return B_ERROR; 1636 1637 if (index >= field->count) 1638 return B_BAD_INDEX; 1639 1640 if (field->count == 1) 1641 return _RemoveField(field); 1642 1643 uint32 offset = field->offset + field->name_length; 1644 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1645 ssize_t size = field->data_size / field->count; 1646 _ResizeData(offset + index * size, -size); 1647 field->data_size -= size; 1648 } else { 1649 uint8 *pointer = fData + offset; 1650 1651 for (int32 i = 0; i < index; i++) { 1652 offset += *(ssize_t *)pointer + sizeof(ssize_t); 1653 pointer = fData + offset; 1654 } 1655 1656 ssize_t currentSize = *(ssize_t *)pointer + sizeof(ssize_t); 1657 _ResizeData(offset, -currentSize); 1658 field->data_size -= currentSize; 1659 } 1660 1661 field->count--; 1662 return B_OK; 1663 } 1664 1665 1666 status_t 1667 BMessage::RemoveName(const char *name) 1668 { 1669 DEBUG_FUNCTION_ENTER; 1670 if (fClonedArea >= B_OK) 1671 _CopyForWrite(); 1672 1673 field_header *field = NULL; 1674 status_t result = _FindField(name, B_ANY_TYPE, &field); 1675 1676 if (result < B_OK) 1677 return result; 1678 1679 if (!field) 1680 return B_ERROR; 1681 1682 return _RemoveField(field); 1683 } 1684 1685 1686 status_t 1687 BMessage::MakeEmpty() 1688 { 1689 DEBUG_FUNCTION_ENTER; 1690 _Clear(); 1691 _InitHeader(); 1692 return B_OK; 1693 } 1694 1695 1696 status_t 1697 BMessage::FindData(const char *name, type_code type, int32 index, 1698 const void **data, ssize_t *numBytes) const 1699 { 1700 DEBUG_FUNCTION_ENTER; 1701 if (!data || !numBytes) 1702 return B_BAD_VALUE; 1703 1704 *data = NULL; 1705 field_header *field = NULL; 1706 status_t result = _FindField(name, type, &field); 1707 1708 if (result < B_OK) 1709 return result; 1710 1711 if (!field) 1712 return B_ERROR; 1713 1714 if (index >= field->count) 1715 return B_BAD_INDEX; 1716 1717 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1718 *numBytes = field->data_size / field->count; 1719 *data = fData + field->offset + field->name_length + index * *numBytes; 1720 } else { 1721 uint8 *pointer = fData + field->offset + field->name_length; 1722 1723 for (int32 i = 0; i < index; i++) 1724 pointer += *(ssize_t *)pointer + sizeof(ssize_t); 1725 1726 *numBytes = *(ssize_t *)pointer; 1727 *data = pointer + sizeof(ssize_t); 1728 } 1729 1730 return B_OK; 1731 } 1732 1733 1734 status_t 1735 BMessage::ReplaceData(const char *name, type_code type, int32 index, 1736 const void *data, ssize_t numBytes) 1737 { 1738 DEBUG_FUNCTION_ENTER; 1739 if (numBytes <= 0 || !data) 1740 return B_BAD_VALUE; 1741 1742 if (fClonedArea >= B_OK) 1743 _CopyForWrite(); 1744 1745 field_header *field = NULL; 1746 status_t result = _FindField(name, type, &field); 1747 1748 if (result < B_OK) 1749 return result; 1750 1751 if (!field) 1752 return B_ERROR; 1753 1754 if (index >= field->count) 1755 return B_BAD_INDEX; 1756 1757 if (field->flags & FIELD_FLAG_FIXED_SIZE) { 1758 ssize_t size = field->data_size / field->count; 1759 if (size != numBytes) 1760 return B_BAD_VALUE; 1761 1762 memcpy(fData + field->offset + field->name_length + index * size, data, 1763 size); 1764 } else { 1765 uint32 offset = field->offset + field->name_length; 1766 uint8 *pointer = fData + offset; 1767 1768 for (int32 i = 0; i < index; i++) { 1769 offset += *(ssize_t *)pointer + sizeof(ssize_t); 1770 pointer = fData + offset; 1771 } 1772 1773 ssize_t currentSize = *(ssize_t *)pointer; 1774 int32 change = numBytes - currentSize; 1775 _ResizeData(offset, change); 1776 memcpy(fData + offset, &numBytes, sizeof(numBytes)); 1777 memcpy(fData + offset + sizeof(numBytes), data, numBytes); 1778 field->data_size += change; 1779 } 1780 1781 return B_OK; 1782 } 1783 1784 1785 bool 1786 BMessage::HasData(const char *name, type_code type, int32 index) const 1787 { 1788 DEBUG_FUNCTION_ENTER; 1789 field_header *field = NULL; 1790 status_t result = _FindField(name, type, &field); 1791 1792 if (result < B_OK) 1793 return false; 1794 1795 if (!field) 1796 return false; 1797 1798 if (index >= field->count) 1799 return false; 1800 1801 return true; 1802 } 1803 1804 1805 /* Static functions for cache initialization and cleanup */ 1806 void 1807 BMessage::_StaticInit() 1808 { 1809 DEBUG_FUNCTION_ENTER2; 1810 sReplyPorts[0] = create_port(1, "tmp_rport0"); 1811 sReplyPorts[1] = create_port(1, "tmp_rport1"); 1812 sReplyPorts[2] = create_port(1, "tmp_rport2"); 1813 1814 sReplyPortInUse[0] = 0; 1815 sReplyPortInUse[1] = 0; 1816 sReplyPortInUse[2] = 0; 1817 1818 sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE); 1819 } 1820 1821 1822 void 1823 BMessage::_StaticCleanup() 1824 { 1825 DEBUG_FUNCTION_ENTER2; 1826 delete_port(sReplyPorts[0]); 1827 sReplyPorts[0] = -1; 1828 delete_port(sReplyPorts[1]); 1829 sReplyPorts[1] = -1; 1830 delete_port(sReplyPorts[2]); 1831 sReplyPorts[2] = -1; 1832 } 1833 1834 1835 void 1836 BMessage::_StaticCacheCleanup() 1837 { 1838 DEBUG_FUNCTION_ENTER2; 1839 delete sMsgCache; 1840 sMsgCache = NULL; 1841 } 1842 1843 1844 int32 1845 BMessage::_StaticGetCachedReplyPort() 1846 { 1847 DEBUG_FUNCTION_ENTER2; 1848 int index = -1; 1849 for (int32 i = 0; i < sNumReplyPorts; i++) { 1850 int32 old = atomic_add(&(sReplyPortInUse[i]), 1); 1851 if (old == 0) { 1852 // This entry is free 1853 index = i; 1854 break; 1855 } else { 1856 // This entry is being used. 1857 atomic_add(&(sReplyPortInUse[i]), -1); 1858 } 1859 } 1860 1861 return index; 1862 } 1863 1864 1865 status_t 1866 BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout, 1867 bool replyRequired, BMessenger &replyTo) const 1868 { 1869 DEBUG_FUNCTION_ENTER; 1870 ssize_t size = 0; 1871 char *buffer = NULL; 1872 message_header *header = NULL; 1873 status_t result; 1874 1875 if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) { 1876 result = _FlattenToArea(&header); 1877 buffer = (char *)header; 1878 size = sizeof(message_header); 1879 1880 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 1881 port_info info; 1882 get_port_info(port, &info); 1883 void *address = NULL; 1884 _kern_transfer_area(header->shared_area, &address, B_ANY_ADDRESS, 1885 info.team); 1886 #endif 1887 } else { 1888 size = _NativeFlattenedSize(); 1889 buffer = (char *)malloc(size); 1890 result = _NativeFlatten(buffer, size); 1891 header = (message_header *)buffer; 1892 } 1893 1894 if (result < B_OK) 1895 return result; 1896 1897 if (!replyTo.IsValid()) { 1898 BMessenger::Private(replyTo).SetTo(header->reply_team, 1899 header->reply_port, header->reply_target); 1900 1901 if (!replyTo.IsValid()) 1902 replyTo = be_app_messenger; 1903 } 1904 1905 BMessenger::Private replyToPrivate(replyTo); 1906 1907 if (replyRequired) 1908 header->flags |= MESSAGE_FLAG_REPLY_REQUIRED; 1909 else 1910 header->flags &= ~MESSAGE_FLAG_REPLY_REQUIRED; 1911 1912 header->target = token; 1913 header->reply_team = replyToPrivate.Team(); 1914 header->reply_port = replyToPrivate.Port(); 1915 header->reply_target = replyToPrivate.Token(); 1916 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 1917 1918 do { 1919 result = write_port_etc(port, kPortMessageCode, (void *)buffer, size, 1920 B_RELATIVE_TIMEOUT, timeout); 1921 } while (result == B_INTERRUPTED); 1922 1923 if (result == B_OK && IsSourceWaiting()) { 1924 // the forwarded message will handle the reply - we must not do 1925 // this anymore 1926 fHeader->flags |= MESSAGE_FLAG_REPLY_DONE; 1927 } 1928 1929 free(buffer); 1930 return result; 1931 } 1932 1933 1934 status_t 1935 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token, 1936 BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const 1937 { 1938 if (IsSourceWaiting()) { 1939 // we can't forward this message synchronously when it's already 1940 // waiting for a reply 1941 return B_ERROR; 1942 } 1943 1944 DEBUG_FUNCTION_ENTER; 1945 const int32 cachedReplyPort = _StaticGetCachedReplyPort(); 1946 port_id replyPort = B_BAD_PORT_ID; 1947 status_t result = B_OK; 1948 1949 if (cachedReplyPort < B_OK) { 1950 // All the cached reply ports are in use; create a new one 1951 replyPort = create_port(1 /* for one message */, "tmp_reply_port"); 1952 if (replyPort < B_OK) 1953 return replyPort; 1954 } else { 1955 assert(cachedReplyPort < sNumReplyPorts); 1956 replyPort = sReplyPorts[cachedReplyPort]; 1957 } 1958 1959 team_id team = B_BAD_TEAM_ID; 1960 if (be_app != NULL) 1961 team = be_app->Team(); 1962 else { 1963 port_info portInfo; 1964 result = get_port_info(replyPort, &portInfo); 1965 if (result < B_OK) 1966 goto error; 1967 1968 team = portInfo.team; 1969 } 1970 1971 result = set_port_owner(replyPort, portOwner); 1972 if (result < B_OK) 1973 goto error; 1974 1975 // tests if the queue of the reply port is really empty 1976 #if 0 1977 port_info portInfo; 1978 if (get_port_info(replyPort, &portInfo) == B_OK 1979 && portInfo.queue_count > 0) 1980 debugger("reply port not empty!"); 1981 #endif 1982 1983 { 1984 BMessenger replyTarget; 1985 BMessenger::Private(replyTarget).SetTo(team, replyPort, 1986 B_PREFERRED_TOKEN); 1987 result = _SendMessage(port, token, sendTimeout, true, replyTarget); 1988 } 1989 1990 if (result < B_OK) 1991 goto error; 1992 1993 int32 code; 1994 result = handle_reply(replyPort, &code, replyTimeout, reply); 1995 if (result < B_OK && cachedReplyPort >= 0) { 1996 delete_port(replyPort); 1997 sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport"); 1998 } 1999 2000 error: 2001 if (cachedReplyPort >= 0) { 2002 // Reclaim ownership of cached port 2003 set_port_owner(replyPort, team); 2004 // Flag as available 2005 atomic_add(&sReplyPortInUse[cachedReplyPort], -1); 2006 return result; 2007 } 2008 2009 delete_port(replyPort); 2010 return result; 2011 } 2012 2013 2014 status_t 2015 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, 2016 int32 token, bigtime_t timeout) 2017 { 2018 DEBUG_FUNCTION_ENTER2; 2019 if (!data) 2020 return B_BAD_VALUE; 2021 2022 uint32 magic = *(uint32 *)data; 2023 2024 if (magic == kMessageMagicHaiku || magic == kMessageMagicHaikuSwapped) { 2025 message_header *header = (message_header *)data; 2026 header->target = token; 2027 header->flags |= MESSAGE_FLAG_WAS_DELIVERED; 2028 } else if (magic == kMessageMagicR5) { 2029 uint8 *header = (uint8 *)data; 2030 header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */ 2031 + sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */ 2032 + sizeof(uint8) /* flags */; 2033 *(int32 *)header = token; 2034 } else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) { 2035 KMessage::Header *header = (KMessage::Header *)data; 2036 header->targetToken = token; 2037 } else { 2038 return B_NOT_A_MESSAGE; 2039 } 2040 2041 // send the message 2042 status_t result; 2043 2044 do { 2045 result = write_port_etc(port, kPortMessageCode, data, size, 2046 B_RELATIVE_TIMEOUT, timeout); 2047 } while (result == B_INTERRUPTED); 2048 2049 return result; 2050 } 2051 2052 2053 static status_t 2054 handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout, 2055 BMessage *reply) 2056 { 2057 DEBUG_FUNCTION_ENTER2; 2058 ssize_t size; 2059 do { 2060 size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout); 2061 } while (size == B_INTERRUPTED); 2062 2063 if (size < B_OK) 2064 return size; 2065 2066 status_t result; 2067 char *buffer = (char *)malloc(size); 2068 do { 2069 result = read_port(replyPort, _code, buffer, size); 2070 } while (result == B_INTERRUPTED); 2071 2072 if (result < B_OK || *_code != kPortMessageCode) { 2073 free(buffer); 2074 return result < B_OK ? result : B_ERROR; 2075 } 2076 2077 result = reply->Unflatten(buffer); 2078 free(buffer); 2079 return result; 2080 } 2081 2082 2083 static status_t 2084 convert_message(const KMessage *fromMessage, BMessage *toMessage) 2085 { 2086 DEBUG_FUNCTION_ENTER2; 2087 if (!fromMessage || !toMessage) 2088 return B_BAD_VALUE; 2089 2090 // make empty and init what of the target message 2091 toMessage->MakeEmpty(); 2092 toMessage->what = fromMessage->What(); 2093 2094 BMessage::Private toPrivate(toMessage); 2095 toPrivate.SetTarget(fromMessage->TargetToken()); 2096 toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(), 2097 fromMessage->ReplyToken()); 2098 2099 // iterate through the fields and import them in the target message 2100 KMessageField field; 2101 while (fromMessage->GetNextField(&field) == B_OK) { 2102 int32 elementCount = field.CountElements(); 2103 if (elementCount > 0) { 2104 for (int32 i = 0; i < elementCount; i++) { 2105 int32 size; 2106 const void *data = field.ElementAt(i, &size); 2107 status_t result; 2108 2109 if (field.TypeCode() == B_MESSAGE_TYPE) { 2110 // message type: if it's a KMessage, convert it 2111 KMessage message; 2112 if (message.SetTo(data, size) == B_OK) { 2113 BMessage bMessage; 2114 result = convert_message(&message, &bMessage); 2115 if (result < B_OK) 2116 return result; 2117 2118 result = toMessage->AddMessage(field.Name(), &bMessage); 2119 } else { 2120 // just add it 2121 result = toMessage->AddData(field.Name(), 2122 field.TypeCode(), data, size, 2123 field.HasFixedElementSize(), 1); 2124 } 2125 } else { 2126 result = toMessage->AddData(field.Name(), field.TypeCode(), 2127 data, size, field.HasFixedElementSize(), 1); 2128 } 2129 2130 if (result < B_OK) 2131 return result; 2132 } 2133 } 2134 } 2135 2136 return B_OK; 2137 } 2138 2139 2140 void BMessage::_ReservedMessage1(void) {}; 2141 void BMessage::_ReservedMessage2(void) {}; 2142 void BMessage::_ReservedMessage3(void) {}; 2143 2144 2145 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */ 2146 2147 #define DEFINE_FUNCTIONS(type, typeName, typeCode) \ 2148 status_t \ 2149 BMessage::Add##typeName(const char *name, type val) \ 2150 { \ 2151 return AddData(name, typeCode, &val, sizeof(type), true); \ 2152 } \ 2153 \ 2154 status_t \ 2155 BMessage::Find##typeName(const char *name, type *p) const \ 2156 { \ 2157 void *ptr = NULL; \ 2158 ssize_t bytes = 0; \ 2159 status_t error = B_OK; \ 2160 \ 2161 *p = type(); \ 2162 error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes); \ 2163 \ 2164 if (error == B_OK) \ 2165 memcpy(p, ptr, sizeof(type)); \ 2166 \ 2167 return error; \ 2168 } \ 2169 \ 2170 status_t \ 2171 BMessage::Find##typeName(const char *name, int32 index, type *p) const \ 2172 { \ 2173 void *ptr = NULL; \ 2174 ssize_t bytes = 0; \ 2175 status_t error = B_OK; \ 2176 \ 2177 *p = type(); \ 2178 error = FindData(name, typeCode, index, (const void **)&ptr, &bytes); \ 2179 \ 2180 if (error == B_OK) \ 2181 memcpy(p, ptr, sizeof(type)); \ 2182 \ 2183 return error; \ 2184 } \ 2185 \ 2186 status_t \ 2187 BMessage::Replace##typeName(const char *name, type val) \ 2188 { \ 2189 return ReplaceData(name, typeCode, 0, &val, sizeof(type)); \ 2190 } \ 2191 \ 2192 status_t \ 2193 BMessage::Replace##typeName(const char *name, int32 index, type val) \ 2194 { \ 2195 return ReplaceData(name, typeCode, index, &val, sizeof(type)); \ 2196 } \ 2197 \ 2198 bool \ 2199 BMessage::Has##typeName(const char *name, int32 index) const \ 2200 { \ 2201 return HasData(name, typeCode, index); \ 2202 } 2203 2204 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE); 2205 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE); 2206 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE); 2207 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE); 2208 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE); 2209 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE); 2210 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE); 2211 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE); 2212 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE); 2213 2214 #undef DEFINE_FUNCTIONS 2215 2216 #define DEFINE_HAS_FUNCTION(typeName, typeCode) \ 2217 bool \ 2218 BMessage::Has##typeName(const char *name, int32 index) const \ 2219 { \ 2220 return HasData(name, typeCode, index); \ 2221 } 2222 2223 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE); 2224 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE); 2225 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE); 2226 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE); 2227 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE); 2228 2229 #undef DEFINE_HAS_FUNCTION 2230 2231 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \ 2232 type \ 2233 BMessage::Find##typeName(const char *name, int32 index) const \ 2234 { \ 2235 type val = initialize; \ 2236 Find##typeName(name, index, &val); \ 2237 return val; \ 2238 } 2239 2240 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect()); 2241 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint()); 2242 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL); 2243 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0); 2244 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0); 2245 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0); 2246 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0); 2247 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false); 2248 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0); 2249 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0); 2250 2251 #undef DEFINE_LAZY_FIND_FUNCTION 2252 2253 status_t 2254 BMessage::AddString(const char *name, const char *string) 2255 { 2256 return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false); 2257 } 2258 2259 2260 status_t 2261 BMessage::AddString(const char *name, const BString &string) 2262 { 2263 return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false); 2264 } 2265 2266 2267 status_t 2268 BMessage::AddPointer(const char *name, const void *pointer) 2269 { 2270 return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true); 2271 } 2272 2273 2274 status_t 2275 BMessage::AddMessenger(const char *name, BMessenger messenger) 2276 { 2277 return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true); 2278 } 2279 2280 2281 status_t 2282 BMessage::AddRef(const char *name, const entry_ref *ref) 2283 { 2284 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2285 char buffer[size]; 2286 2287 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2288 2289 if (error >= B_OK) 2290 error = AddData(name, B_REF_TYPE, buffer, size, false); 2291 2292 return error; 2293 } 2294 2295 2296 status_t 2297 BMessage::AddMessage(const char *name, const BMessage *message) 2298 { 2299 /* ToDo: This and the following functions waste time by allocating and 2300 copying an extra buffer. Functions can be added that return a direct 2301 pointer into the message. */ 2302 2303 ssize_t size = message->FlattenedSize(); 2304 char buffer[size]; 2305 2306 status_t error = message->Flatten(buffer, size); 2307 2308 if (error >= B_OK) 2309 error = AddData(name, B_MESSAGE_TYPE, &buffer, size, false); 2310 2311 return error; 2312 } 2313 2314 2315 status_t 2316 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count) 2317 { 2318 ssize_t size = object->FlattenedSize(); 2319 char buffer[size]; 2320 2321 status_t error = object->Flatten(buffer, size); 2322 2323 if (error >= B_OK) 2324 error = AddData(name, object->TypeCode(), &buffer, size, false); 2325 2326 return error; 2327 } 2328 2329 2330 status_t 2331 BMessage::FindString(const char *name, const char **string) const 2332 { 2333 return FindString(name, 0, string); 2334 } 2335 2336 2337 status_t 2338 BMessage::FindString(const char *name, int32 index, const char **string) const 2339 { 2340 ssize_t bytes; 2341 return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes); 2342 } 2343 2344 2345 status_t 2346 BMessage::FindString(const char *name, BString *string) const 2347 { 2348 return FindString(name, 0, string); 2349 } 2350 2351 2352 status_t 2353 BMessage::FindString(const char *name, int32 index, BString *string) const 2354 { 2355 const char *cstr; 2356 status_t error = FindString(name, index, &cstr); 2357 if (error < B_OK) 2358 return error; 2359 2360 *string = cstr; 2361 return B_OK; 2362 } 2363 2364 2365 status_t 2366 BMessage::FindPointer(const char *name, void **pointer) const 2367 { 2368 return FindPointer(name, 0, pointer); 2369 } 2370 2371 2372 status_t 2373 BMessage::FindPointer(const char *name, int32 index, void **pointer) const 2374 { 2375 void **data = NULL; 2376 ssize_t size = 0; 2377 status_t error = FindData(name, B_POINTER_TYPE, index, 2378 (const void **)&data, &size); 2379 2380 if (error == B_OK) 2381 *pointer = *data; 2382 else 2383 *pointer = NULL; 2384 2385 return error; 2386 } 2387 2388 2389 status_t 2390 BMessage::FindMessenger(const char *name, BMessenger *messenger) const 2391 { 2392 return FindMessenger(name, 0, messenger); 2393 } 2394 2395 2396 status_t 2397 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger) 2398 const 2399 { 2400 void *data = NULL; 2401 ssize_t size = 0; 2402 status_t error = FindData(name, B_MESSENGER_TYPE, index, 2403 (const void **)&data, &size); 2404 2405 if (error == B_OK) 2406 memcpy(messenger, data, sizeof(BMessenger)); 2407 else 2408 *messenger = BMessenger(); 2409 2410 return error; 2411 } 2412 2413 2414 status_t 2415 BMessage::FindRef(const char *name, entry_ref *ref) const 2416 { 2417 return FindRef(name, 0, ref); 2418 } 2419 2420 2421 status_t 2422 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const 2423 { 2424 void *data = NULL; 2425 ssize_t size = 0; 2426 status_t error = FindData(name, B_REF_TYPE, index, 2427 (const void **)&data, &size); 2428 2429 if (error == B_OK) 2430 error = BPrivate::entry_ref_unflatten(ref, (char *)data, size); 2431 else 2432 *ref = entry_ref(); 2433 2434 return error; 2435 } 2436 2437 2438 status_t 2439 BMessage::FindMessage(const char *name, BMessage *message) const 2440 { 2441 return FindMessage(name, 0, message); 2442 } 2443 2444 2445 status_t 2446 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const 2447 { 2448 void *data = NULL; 2449 ssize_t size = 0; 2450 status_t error = FindData(name, B_MESSAGE_TYPE, index, 2451 (const void **)&data, &size); 2452 2453 if (error == B_OK) 2454 error = message->Unflatten((const char *)data); 2455 else 2456 *message = BMessage(); 2457 2458 return error; 2459 } 2460 2461 2462 status_t 2463 BMessage::FindFlat(const char *name, BFlattenable *object) const 2464 { 2465 return FindFlat(name, 0, object); 2466 } 2467 2468 2469 status_t 2470 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const 2471 { 2472 void *data = NULL; 2473 ssize_t numBytes = 0; 2474 status_t error = FindData(name, object->TypeCode(), index, 2475 (const void **)&data, &numBytes); 2476 2477 if (error == B_OK) 2478 error = object->Unflatten(object->TypeCode(), data, numBytes); 2479 2480 return error; 2481 } 2482 2483 2484 status_t 2485 BMessage::FindData(const char *name, type_code type, const void **data, 2486 ssize_t *numBytes) const 2487 { 2488 return FindData(name, type, 0, data, numBytes); 2489 } 2490 2491 2492 status_t 2493 BMessage::ReplaceString(const char *name, const char *string) 2494 { 2495 return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1); 2496 } 2497 2498 2499 status_t 2500 BMessage::ReplaceString(const char *name, int32 index, const char *string) 2501 { 2502 return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1); 2503 } 2504 2505 2506 status_t 2507 BMessage::ReplaceString(const char *name, const BString &string) 2508 { 2509 return ReplaceData(name, B_STRING_TYPE, 0, string.String(), 2510 string.Length() + 1); 2511 } 2512 2513 2514 status_t 2515 BMessage::ReplaceString(const char *name, int32 index, const BString &string) 2516 { 2517 return ReplaceData(name, B_STRING_TYPE, index, string.String(), 2518 string.Length() + 1); 2519 } 2520 2521 2522 status_t 2523 BMessage::ReplacePointer(const char *name, const void *pointer) 2524 { 2525 return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer)); 2526 } 2527 2528 2529 status_t 2530 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer) 2531 { 2532 return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer)); 2533 } 2534 2535 2536 status_t 2537 BMessage::ReplaceMessenger(const char *name, BMessenger messenger) 2538 { 2539 return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger, 2540 sizeof(BMessenger)); 2541 } 2542 2543 2544 status_t 2545 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger) 2546 { 2547 return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger, 2548 sizeof(BMessenger)); 2549 } 2550 2551 2552 status_t 2553 BMessage::ReplaceRef(const char *name, const entry_ref *ref) 2554 { 2555 return ReplaceRef(name, 0, ref); 2556 } 2557 2558 2559 status_t 2560 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref) 2561 { 2562 size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; 2563 char buffer[size]; 2564 2565 status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref); 2566 2567 if (error >= B_OK) 2568 error = ReplaceData(name, B_REF_TYPE, index, &buffer, size); 2569 2570 return error; 2571 } 2572 2573 2574 status_t 2575 BMessage::ReplaceMessage(const char *name, const BMessage *message) 2576 { 2577 return ReplaceMessage(name, 0, message); 2578 } 2579 2580 2581 status_t 2582 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message) 2583 { 2584 ssize_t size = message->FlattenedSize(); 2585 char buffer[size]; 2586 2587 status_t error = message->Flatten(buffer, size); 2588 2589 if (error >= B_OK) 2590 error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size); 2591 2592 return error; 2593 } 2594 2595 2596 status_t 2597 BMessage::ReplaceFlat(const char *name, BFlattenable *object) 2598 { 2599 return ReplaceFlat(name, 0, object); 2600 } 2601 2602 2603 status_t 2604 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object) 2605 { 2606 ssize_t size = object->FlattenedSize(); 2607 char buffer[size]; 2608 2609 status_t error = object->Flatten(buffer, size); 2610 2611 if (error >= B_OK) 2612 error = ReplaceData(name, object->TypeCode(), index, &buffer, size); 2613 2614 return error; 2615 } 2616 2617 2618 status_t 2619 BMessage::ReplaceData(const char *name, type_code type, const void *data, 2620 ssize_t numBytes) 2621 { 2622 return ReplaceData(name, type, 0, data, numBytes); 2623 } 2624 2625 2626 bool 2627 BMessage::HasFlat(const char *name, const BFlattenable *object) const 2628 { 2629 return HasFlat(name, 0, object); 2630 } 2631 2632 2633 bool 2634 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object) 2635 const 2636 { 2637 return HasData(name, object->TypeCode(), index); 2638 } 2639