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