1// KMessage.cpp 2 3#include <stdlib.h> 4#include <string.h> 5 6#include <Debug.h> 7#include <KernelExport.h> 8#include <TypeConstants.h> 9 10#include "KMessage.h" 11 12// define the PANIC macro 13#ifndef PANIC 14# if USER 15# define PANIC(str) debugger(str) 16# else 17# define PANIC(str) panic(str) 18# endif 19#endif 20 21static const uint32 kMessageHeaderMagic = 'kMsG'; 22static const int32 kMessageReallocChunkSize = 64; 23 24#ifndef B_BUFFER_OVERFLOW 25# define B_BUFFER_OVERFLOW EOVERFLOW 26#endif 27 28/*// strnlen 29static inline 30size_t 31strnlen(const char *str, size_t maxLen) 32{ 33 if (str) { 34 size_t origMaxLen = maxLen; 35 while (maxLen > 0 && *str != '\0') { 36 maxLen--; 37 str++; 38 } 39 return origMaxLen - maxLen; 40 } 41 return 0; 42}*/ 43 44// _Align 45static inline 46int32 47_Align(int32 offset) 48{ 49 return (offset + 3) & ~0x3; 50} 51 52// _Align 53static inline 54void* 55_Align(void *address, int32 offset = 0) 56{ 57 return (void*)(((uint32)address + offset + 3) & ~0x3); 58} 59 60// FieldValueHeader 61struct KMessage::FieldValueHeader { 62 int32 size; 63 64 void *Data() 65 { 66 return _Align(this, sizeof(FieldValueHeader)); 67 } 68 69 FieldValueHeader *NextFieldValueHeader() 70 { 71 return (FieldValueHeader*)_Align(Data(), size); 72 } 73}; 74 75// FieldHeader 76struct KMessage::FieldHeader { 77 type_code type; 78 int32 elementSize; // if < 0: non-fixed size 79 int32 elementCount; 80 int32 fieldSize; 81 int16 headerSize; 82 char name[1]; 83 84 void *Data() 85 { 86 return (uint8*)this + headerSize; 87 } 88 89 bool HasFixedElementSize() { return (elementSize >= 0); } 90 91 void *ElementAt(int32 index, int32 *size) 92 { 93 if (index < 0 || index >= elementCount) 94 return NULL; 95 uint8 *data = (uint8*)this + headerSize; 96 if (HasFixedElementSize()) { 97 *size = elementSize; 98 return data + elementSize * index; 99 } 100 // non-fixed element size: we need to iterate 101 FieldValueHeader *valueHeader = (FieldValueHeader *)data; 102 for (int i = 0; i < index; i++) 103 valueHeader = valueHeader->NextFieldValueHeader(); 104 *size = valueHeader->size; 105 return valueHeader->Data(); 106 } 107 108 FieldHeader *NextFieldHeader() 109 { 110 return (FieldHeader*)_Align(this, fieldSize); 111 } 112}; 113 114// constructor 115KMessage::KMessage() 116 : fBuffer(NULL), 117 fBufferCapacity(0), 118 fFlags(0), 119 fLastFieldOffset(0) 120{ 121 Unset(); 122} 123 124// constructor 125KMessage::KMessage(uint32 what) 126 : fBuffer(NULL), 127 fBufferCapacity(0), 128 fFlags(0), 129 fLastFieldOffset(0) 130{ 131 Unset(); 132 SetWhat(what); 133} 134 135// destructor 136KMessage::~KMessage() 137{ 138 Unset(); 139} 140 141// SetTo 142status_t 143KMessage::SetTo(uint32 what, uint32 flags) 144{ 145 // There are no flags interesting in this case at the moment. 146 Unset(); 147 SetWhat(what); 148 return B_OK; 149} 150 151// SetTo 152status_t 153KMessage::SetTo(void *buffer, int32 bufferSize, uint32 what, uint32 flags) 154{ 155 Unset(); 156 if (!buffer || bufferSize < (int)sizeof(Header)) 157 return B_BAD_VALUE; 158 // if read-only, we need to init from the buffer, too 159 if (flags & KMESSAGE_READ_ONLY && !(flags & KMESSAGE_INIT_FROM_BUFFER)) 160 return B_BAD_VALUE; 161 fBuffer = buffer; 162 fBufferCapacity = bufferSize; 163 fFlags = flags; 164 status_t error = B_OK; 165 if (flags & KMESSAGE_INIT_FROM_BUFFER) 166 error = _InitFromBuffer(); 167 else 168 _InitBuffer(what); 169 if (error != B_OK) 170 Unset(); 171 return error; 172} 173 174// SetTo 175status_t 176KMessage::SetTo(const void *buffer, int32 bufferSize) 177{ 178 return SetTo(const_cast<void*>(buffer), bufferSize, 0, 179 KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY); 180} 181 182// Unset 183void 184KMessage::Unset() 185{ 186 // free buffer 187 if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER)) 188 free(fBuffer); 189 fBuffer = &fHeader; 190 fBufferCapacity = sizeof(Header); 191 _InitBuffer(0); 192} 193 194// SetWhat 195void 196KMessage::SetWhat(uint32 what) 197{ 198 _Header()->what = what; 199} 200 201// What 202uint32 203KMessage::What() const 204{ 205 return _Header()->what; 206} 207 208// Buffer 209const void * 210KMessage::Buffer() const 211{ 212 return fBuffer; 213} 214 215// BufferCapacity 216int32 217KMessage::BufferCapacity() const 218{ 219 return fBufferCapacity; 220} 221 222// ContentSize 223int32 224KMessage::ContentSize() const 225{ 226 return _Header()->size; 227} 228 229// AddField 230status_t 231KMessage::AddField(const char *name, type_code type, int32 elementSize, 232 KMessageField* field) 233{ 234 if (!name || type == B_ANY_TYPE) 235 return B_BAD_VALUE; 236 KMessageField existingField; 237 if (FindField(name, &existingField) == B_OK) 238 return B_NAME_IN_USE; 239 return _AddField(name, type, elementSize, field); 240} 241 242// FindField 243status_t 244KMessage::FindField(const char *name, KMessageField *field) const 245{ 246 return FindField(name, B_ANY_TYPE, field); 247} 248 249// FindField 250status_t 251KMessage::FindField(const char *name, type_code type, 252 KMessageField *field) const 253{ 254 if (!name) 255 return B_BAD_VALUE; 256 KMessageField stackField; 257 if (field) 258 field->Unset(); 259 else 260 field = &stackField; 261 while (GetNextField(field) == B_OK) { 262 if ((type == B_ANY_TYPE || field->TypeCode() == type) 263 && strcmp(name, field->Name()) == 0) { 264 return B_OK; 265 } 266 } 267 return B_NAME_NOT_FOUND; 268} 269 270// GetNextField 271status_t 272KMessage::GetNextField(KMessageField *field) const 273{ 274 if (!field || (field->Message() != NULL && field->Message() != this)) 275 return B_BAD_VALUE; 276 FieldHeader *fieldHeader = field->_Header(); 277 FieldHeader* lastField = _LastFieldHeader(); 278 if (!lastField) 279 return B_NAME_NOT_FOUND; 280 if (fieldHeader == NULL) { 281 fieldHeader = _FirstFieldHeader(); 282 } else { 283 if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader() 284 || (uint8*)fieldHeader > (uint8*)lastField) { 285 return B_BAD_VALUE; 286 } 287 if (fieldHeader == lastField) 288 return B_NAME_NOT_FOUND; 289 fieldHeader = fieldHeader->NextFieldHeader(); 290 } 291 field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader)); 292 return B_OK; 293} 294 295// AddData 296status_t 297KMessage::AddData(const char *name, type_code type, const void *data, 298 int32 numBytes, bool isFixedSize) 299{ 300 if (!name || type == B_ANY_TYPE || !data || numBytes < 0) 301 return B_BAD_VALUE; 302 KMessageField field; 303 if (FindField(name, &field) == B_OK) { 304 // field with that name already exists: check its type 305 if (field.TypeCode() != type) 306 return B_BAD_TYPE; 307 } else { 308 // no such field yet: add it 309 status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1), 310 &field); 311 if (error != B_OK) 312 return error; 313 } 314 return _AddFieldData(&field, data, numBytes, 1); 315} 316 317// AddArray 318status_t 319KMessage::AddArray(const char *name, type_code type, const void *data, 320 int32 elementSize, int32 elementCount) 321{ 322 if (!name || type == B_ANY_TYPE || !data || elementSize < 0 323 || elementCount < 0) { 324 return B_BAD_VALUE; 325 } 326 KMessageField field; 327 if (FindField(name, &field) == B_OK) { 328 // field with that name already exists: check its type 329 if (field.TypeCode() != type) 330 return B_BAD_TYPE; 331 } else { 332 // no such field yet: add it 333 status_t error = _AddField(name, type, elementSize, &field); 334 if (error != B_OK) 335 return error; 336 } 337 return _AddFieldData(&field, data, elementSize, elementCount); 338} 339 340// FindData 341status_t 342KMessage::FindData(const char *name, type_code type, const void **data, 343 int32 *numBytes) const 344{ 345 return FindData(name, type, 0, data, numBytes); 346} 347 348// FindData 349status_t 350KMessage::FindData(const char *name, type_code type, int32 index, 351 const void **data, int32 *numBytes) const 352{ 353 if (!name || !data || !numBytes) 354 return B_BAD_VALUE; 355 KMessageField field; 356 status_t error = FindField(name, type, &field); 357 if (error != B_OK) 358 return error; 359 const void *foundData = field.ElementAt(index, numBytes); 360 if (!foundData) 361 return B_BAD_INDEX; 362 if (data) 363 *data = foundData; 364 return B_OK; 365} 366 367// Sender 368team_id 369KMessage::Sender() const 370{ 371 return _Header()->sender; 372} 373 374// TargetToken 375int32 376KMessage::TargetToken() const 377{ 378 return _Header()->targetToken; 379} 380 381// ReplyPort 382port_id 383KMessage::ReplyPort() const 384{ 385 return _Header()->replyPort; 386} 387 388// ReplyToken 389int32 390KMessage::ReplyToken() const 391{ 392 return _Header()->replyToken; 393} 394 395// SendTo 396status_t 397KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort, 398 int32 replyToken, bigtime_t timeout, team_id senderTeam) 399{ 400 // set the deliver info 401 Header* header = _Header(); 402 header->sender = senderTeam; 403 header->targetToken = targetToken; 404 header->replyPort = replyPort; 405 header->replyToken = replyToken; 406 // get the sender team 407 if (senderTeam >= 0) { 408 thread_info info; 409 status_t error = get_thread_info(find_thread(NULL), &info); 410 if (error != B_OK) 411 return error; 412 header->sender = info.team; 413 } 414 // send the message 415 if (timeout < 0) 416 return write_port(targetPort, 'KMSG', fBuffer, ContentSize()); 417 return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(), 418 B_RELATIVE_TIMEOUT, timeout); 419} 420 421// SendTo 422status_t 423KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply, 424 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 425{ 426 // get the team the target port belongs to 427 port_info portInfo; 428 status_t error = get_port_info(targetPort, &portInfo); 429 if (error != B_OK) 430 return error; 431 team_id targetTeam = portInfo.team; 432 // allocate a reply port, if a reply is desired 433 port_id replyPort = -1; 434 if (reply) { 435 // get our team 436 team_id ourTeam = B_SYSTEM_TEAM; 437 #if USER 438 if (targetTeam != B_SYSTEM_TEAM) { 439 thread_info threadInfo; 440 error = get_thread_info(find_thread(NULL), &threadInfo); 441 if (error != B_OK) 442 return error; 443 ourTeam = threadInfo.team; 444 } 445 #endif 446 // create the port 447 replyPort = create_port(1, "KMessage reply port"); 448 if (replyPort < 0) 449 return replyPort; 450 // If the target team is not our team and not the kernel team either, 451 // we transfer the ownership of the port to it, so we will not block 452 if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM) 453 set_port_owner(replyPort, targetTeam); 454 } 455 struct PortDeleter { 456 PortDeleter(port_id port) : port(port) {} 457 ~PortDeleter() 458 { 459 if (port >= 0) 460 delete_port(port); 461 } 462 463 port_id port; 464 } replyPortDeleter(replyPort); 465 // send the message 466 error = SendTo(targetPort, targetToken, replyPort, 0, 467 deliveryTimeout, senderTeam); 468 if (error != B_OK) 469 return error; 470 // get the reply 471 if (reply) 472 return reply->ReceiveFrom(replyPort, replyTimeout); 473 return B_OK; 474} 475 476// SendReply 477status_t 478KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken, 479 bigtime_t timeout, team_id senderTeam) 480{ 481 if (!message) 482 return B_BAD_VALUE; 483 return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken, 484 timeout, senderTeam); 485} 486 487// SendReply 488status_t 489KMessage::SendReply(KMessage* message, KMessage* reply, 490 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 491{ 492 if (!message) 493 return B_BAD_VALUE; 494 return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout, 495 replyTimeout, senderTeam); 496} 497 498// ReceiveFrom 499status_t 500KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout) 501{ 502 // get the port buffer size 503 ssize_t size; 504 if (timeout < 0) 505 size = port_buffer_size(fromPort); 506 else 507 size = port_buffer_size_etc(fromPort, B_RELATIVE_TIMEOUT, timeout); 508 if (size < 0) 509 return size; 510 // allocate a buffer 511 uint8* buffer = (uint8*)malloc(size); 512 if (!buffer) 513 return B_NO_MEMORY; 514 // read the message 515 int32 what; 516 ssize_t realSize = read_port_etc(fromPort, &what, buffer, size, 517 B_RELATIVE_TIMEOUT, 0); 518 if (realSize < 0) 519 return realSize; 520 if (size != realSize) 521 return B_ERROR; 522 // init the message 523 return SetTo(buffer, size, 0, 524 KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER); 525} 526 527// _Header 528KMessage::Header * 529KMessage::_Header() const 530{ 531 return (Header*)fBuffer; 532} 533 534// _BufferOffsetFor 535int32 536KMessage::_BufferOffsetFor(const void* data) const 537{ 538 if (!data) 539 return -1; 540 return ((uint8*)data - (uint8*)fBuffer); 541} 542 543// _FirstFieldHeader 544KMessage::FieldHeader * 545KMessage::_FirstFieldHeader() const 546{ 547 return (FieldHeader*)_Align(fBuffer, sizeof(Header)); 548} 549 550// _LastFieldHeader 551KMessage::FieldHeader * 552KMessage::_LastFieldHeader() const 553{ 554 return _FieldHeaderForOffset(fLastFieldOffset); 555} 556 557// _FieldHeaderForOffset 558KMessage::FieldHeader * 559KMessage::_FieldHeaderForOffset(int32 offset) const 560{ 561 if (offset <= 0 || offset >= _Header()->size) 562 return NULL; 563 return (FieldHeader*)((uint8*)fBuffer + offset); 564} 565 566// _AddField 567status_t 568KMessage::_AddField(const char *name, type_code type, int32 elementSize, 569 KMessageField *field) 570{ 571 FieldHeader *fieldHeader; 572 int32 alignedSize; 573 status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true, 574 true, (void**)&fieldHeader, &alignedSize); 575 if (error != B_OK) 576 return error; 577 fieldHeader->type = type; 578 fieldHeader->elementSize = elementSize; 579 fieldHeader->elementCount = 0; 580 fieldHeader->fieldSize = alignedSize; 581 fieldHeader->headerSize = alignedSize; 582 strcpy(fieldHeader->name, name); 583 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 584 if (field) 585 field->SetTo(this, _BufferOffsetFor(fieldHeader)); 586 return B_OK; 587} 588 589// _AddFieldData 590status_t 591KMessage::_AddFieldData(KMessageField *field, const void *data, 592 int32 elementSize, int32 elementCount) 593{ 594 if (!field) 595 return B_BAD_VALUE; 596 FieldHeader *fieldHeader = field->_Header(); 597 FieldHeader* lastField = _LastFieldHeader(); 598 if (!fieldHeader || fieldHeader != lastField || !data 599 || elementSize < 0 || elementCount < 0) { 600 return B_BAD_VALUE; 601 } 602 if (elementCount == 0) 603 return B_OK; 604 // fixed size values 605 if (fieldHeader->HasFixedElementSize()) { 606 if (elementSize != fieldHeader->elementSize) 607 return B_BAD_VALUE; 608 void *address; 609 int32 alignedSize; 610 status_t error = _AllocateSpace(elementSize * elementCount, 611 (fieldHeader->elementCount == 0), false, &address, &alignedSize); 612 if (error != B_OK) 613 return error; 614 fieldHeader = field->_Header(); // might have been relocated 615 memcpy(address, data, elementSize * elementCount); 616 fieldHeader->elementCount += elementCount; 617 fieldHeader->fieldSize = (uint8*)address + alignedSize 618 - (uint8*)fieldHeader; 619 return B_OK; 620 } 621 // non-fixed size values 622 // add the elements individually (TODO: Optimize!) 623 int32 valueHeaderSize = _Align(sizeof(FieldValueHeader)); 624 int32 entrySize = valueHeaderSize + elementSize; 625 for (int32 i = 0; i < elementCount; i++) { 626 void *address; 627 int32 alignedSize; 628 status_t error = _AllocateSpace(entrySize, true, false, &address, 629 &alignedSize); 630 if (error != B_OK) 631 return error; 632 fieldHeader = field->_Header(); // might have been relocated 633 FieldValueHeader *valueHeader = (FieldValueHeader*)address; 634 valueHeader->size = elementSize; 635 memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize, 636 elementSize); 637 fieldHeader->elementCount++; 638 fieldHeader->fieldSize = (uint8*)address + alignedSize 639 - (uint8*)fieldHeader; 640 } 641 return B_OK; 642} 643 644// _InitFromBuffer 645status_t 646KMessage::_InitFromBuffer() 647{ 648 if (!fBuffer || fBufferCapacity < (int)sizeof(Header) 649 || _Align(fBuffer) != fBuffer) { 650 return B_BAD_DATA; 651 } 652 // check header 653 Header *header = _Header(); 654 if (header->magic != kMessageHeaderMagic) 655 return B_BAD_DATA; 656 if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity) 657 return B_BAD_DATA; 658 // check the fields 659 FieldHeader *fieldHeader = NULL; 660 uint8 *data = (uint8*)_FirstFieldHeader(); 661 int32 remainingBytes = (uint8*)fBuffer + header->size - data; 662 while (remainingBytes > 0) { 663 if (remainingBytes < (int)sizeof(FieldHeader)) 664 return B_BAD_DATA; 665 fieldHeader = (FieldHeader*)data; 666 // check field header 667 if (fieldHeader->type == B_ANY_TYPE) 668 return B_BAD_DATA; 669 if (fieldHeader->elementCount < 0) 670 return B_BAD_DATA; 671 if (fieldHeader->fieldSize < (int)sizeof(FieldHeader) 672 || fieldHeader->fieldSize > remainingBytes) { 673 return B_BAD_DATA; 674 } 675 if (fieldHeader->headerSize < (int)sizeof(FieldHeader) 676 || fieldHeader->headerSize > fieldHeader->fieldSize) { 677 return B_BAD_DATA; 678 } 679 int32 maxNameLen = data + fieldHeader->headerSize 680 - (uint8*)fieldHeader->name; 681 int32 nameLen = strnlen(fieldHeader->name, maxNameLen); 682 if (nameLen == maxNameLen || nameLen == 0) 683 return B_BAD_DATA; 684 int32 fieldSize = fieldHeader->headerSize; 685 if (fieldHeader->HasFixedElementSize()) { 686 // fixed element size 687 int32 dataSize = fieldHeader->elementSize 688 * fieldHeader->elementCount; 689 fieldSize = (uint8*)fieldHeader->Data() + dataSize - data; 690 } else { 691 // non-fixed element size 692 FieldValueHeader *valueHeader 693 = (FieldValueHeader *)fieldHeader->Data(); 694 for (int32 i = 0; i < fieldHeader->elementCount; i++) { 695 remainingBytes = (uint8*)fBuffer + header->size 696 - (uint8*)valueHeader; 697 if (remainingBytes < (int)sizeof(FieldValueHeader)) 698 return B_BAD_DATA; 699 uint8 *value = (uint8*)valueHeader->Data(); 700 remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value; 701 if (remainingBytes < valueHeader->size) 702 return B_BAD_DATA; 703 fieldSize = value + valueHeader->size - data; 704 valueHeader = valueHeader->NextFieldValueHeader(); 705 } 706 if (fieldSize > fieldHeader->fieldSize) 707 return B_BAD_DATA; 708 } 709 data = (uint8*)fieldHeader->NextFieldHeader(); 710 remainingBytes = (uint8*)fBuffer + header->size - data; 711 } 712 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 713 return B_OK; 714} 715 716// _InitBuffer 717void 718KMessage::_InitBuffer(uint32 what) 719{ 720 Header *header = _Header(); 721 header->magic = kMessageHeaderMagic; 722 header->size = sizeof(Header); 723 header->what = what; 724 header->sender = -1; 725 header->targetToken = -1; 726 header->replyPort = -1; 727 header->replyToken = -1; 728 fLastFieldOffset = 0; 729} 730 731// _CheckBuffer 732void 733KMessage::_CheckBuffer() 734{ 735 int32 lastFieldOffset = fLastFieldOffset; 736 if (_InitFromBuffer() != B_OK) { 737 PANIC("internal data mangled"); 738 } 739 if (fLastFieldOffset != lastFieldOffset) { 740 PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()"); 741 } 742} 743 744// _AllocateSpace 745status_t 746KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize, 747 void **address, int32 *alignedSize) 748{ 749 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) 750 return B_NOT_ALLOWED; 751 int32 offset = ContentSize(); 752 if (alignAddress) 753 offset = _Align(offset); 754 int32 newSize = offset + size; 755 if (alignSize) 756 newSize = _Align(newSize); 757 // reallocate if necessary 758 if (fBuffer == &fHeader) { 759 int32 newCapacity = _CapacityFor(newSize); 760 void *newBuffer = malloc(newCapacity); 761 if (!newBuffer) 762 return B_NO_MEMORY; 763 fBuffer = newBuffer; 764 fBufferCapacity = newCapacity; 765 fFlags |= KMESSAGE_OWNS_BUFFER; 766 memcpy(fBuffer, &fHeader, sizeof(fHeader)); 767 } else { 768 if (newSize > fBufferCapacity) { 769 // if we don't own the buffer, we can't resize it 770 if (!(fFlags & KMESSAGE_OWNS_BUFFER)) 771 return B_BUFFER_OVERFLOW; 772 int32 newCapacity = _CapacityFor(newSize); 773 void *newBuffer = realloc(fBuffer, newCapacity); 774 if (!newBuffer) 775 return B_NO_MEMORY; 776 fBuffer = newBuffer; 777 fBufferCapacity = newCapacity; 778 } 779 } 780 _Header()->size = newSize; 781 *address = (char*)fBuffer + offset; 782 *alignedSize = newSize - offset; 783 return B_OK; 784} 785 786// _CapacityFor 787int32 788KMessage::_CapacityFor(int32 size) 789{ 790 return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize 791 * kMessageReallocChunkSize; 792} 793 794// _FindType 795template<typename T> 796status_t 797KMessage::_FindType(const char* name, type_code type, int32 index, 798 T *value) const 799{ 800 const void *data; 801 int32 size; 802 status_t error = FindData(name, type, index, &data, &size); 803 if (error != B_OK) 804 return error; 805 if (size != sizeof(T)) 806 return B_BAD_DATA; 807 *value = *(T*)data; 808 return B_OK; 809} 810 811 812// #pragma mark - 813 814// constructor 815KMessageField::KMessageField() 816 : fMessage(NULL), 817 fHeaderOffset(0) 818{ 819} 820 821// Unset 822void 823KMessageField::Unset() 824{ 825 fMessage = NULL; 826 fHeaderOffset = 0; 827} 828 829// Message 830KMessage * 831KMessageField::Message() const 832{ 833 return fMessage; 834} 835 836// Name 837const char * 838KMessageField::Name() const 839{ 840 KMessage::FieldHeader* header = _Header(); 841 return (header ? header->name : NULL); 842} 843 844// TypeCode 845type_code 846KMessageField::TypeCode() const 847{ 848 KMessage::FieldHeader* header = _Header(); 849 return (header ? header->type : 0); 850} 851 852// HasFixedElementSize 853bool 854KMessageField::HasFixedElementSize() const 855{ 856 KMessage::FieldHeader* header = _Header(); 857 return (header ? header->HasFixedElementSize() : false); 858} 859 860// ElementSize 861int32 862KMessageField::ElementSize() const 863{ 864 KMessage::FieldHeader* header = _Header(); 865 return (header ? header->elementSize : -1); 866} 867 868// AddElement 869status_t 870KMessageField::AddElement(const void *data, int32 size) 871{ 872 KMessage::FieldHeader* header = _Header(); 873 if (!header || !data) 874 return B_BAD_VALUE; 875 if (size < 0) { 876 size = ElementSize(); 877 if (size < 0) 878 return B_BAD_VALUE; 879 } 880 return fMessage->_AddFieldData(this, data, size, 1); 881} 882 883// AddElements 884status_t 885KMessageField::AddElements(const void *data, int32 count, int32 elementSize) 886{ 887 KMessage::FieldHeader* header = _Header(); 888 if (!header || !data || count < 0) 889 return B_BAD_VALUE; 890 if (elementSize < 0) { 891 elementSize = ElementSize(); 892 if (elementSize < 0) 893 return B_BAD_VALUE; 894 } 895 return fMessage->_AddFieldData(this, data, elementSize, count); 896} 897 898// ElementAt 899const void * 900KMessageField::ElementAt(int32 index, int32 *size) const 901{ 902 KMessage::FieldHeader* header = _Header(); 903 return (header ? header->ElementAt(index, size) : NULL); 904} 905 906// CountElements 907int32 908KMessageField::CountElements() const 909{ 910 KMessage::FieldHeader* header = _Header(); 911 return (header ? header->elementCount : 0); 912} 913 914// SetTo 915void 916KMessageField::SetTo(KMessage *message, int32 headerOffset) 917{ 918 fMessage = message; 919 fHeaderOffset = headerOffset; 920} 921 922// _GetHeader 923KMessage::FieldHeader* 924KMessageField::_Header() const 925{ 926 return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL); 927} 928 929