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