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 <util/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) || defined(_LOADER_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 // SetDeliveryInfo 440 void 441 KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort, 442 int32 replyToken, team_id senderTeam) 443 { 444 Header* header = _Header(); 445 header->sender = senderTeam; 446 header->targetToken = targetToken; 447 header->replyPort = replyPort; 448 header->replyToken = replyToken; 449 header->sender = senderTeam; 450 } 451 452 #ifndef KMESSAGE_CONTAINER_ONLY 453 454 // SendTo 455 status_t 456 KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort, 457 int32 replyToken, bigtime_t timeout, team_id senderTeam) 458 { 459 // get the sender team 460 if (senderTeam < 0) { 461 thread_info info; 462 status_t error = get_thread_info(find_thread(NULL), &info); 463 if (error != B_OK) 464 return error; 465 466 senderTeam = info.team; 467 } 468 469 SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam); 470 471 // send the message 472 if (timeout < 0) 473 return write_port(targetPort, 'KMSG', fBuffer, ContentSize()); 474 475 return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(), 476 B_RELATIVE_TIMEOUT, timeout); 477 } 478 479 // SendTo 480 status_t 481 KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply, 482 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 483 { 484 // get the team the target port belongs to 485 port_info portInfo; 486 status_t error = get_port_info(targetPort, &portInfo); 487 if (error != B_OK) 488 return error; 489 team_id targetTeam = portInfo.team; 490 // allocate a reply port, if a reply is desired 491 port_id replyPort = -1; 492 if (reply) { 493 // get our team 494 team_id ourTeam = B_SYSTEM_TEAM; 495 #ifndef _KERNEL_MODE 496 if (targetTeam != B_SYSTEM_TEAM) { 497 thread_info threadInfo; 498 error = get_thread_info(find_thread(NULL), &threadInfo); 499 if (error != B_OK) 500 return error; 501 ourTeam = threadInfo.team; 502 } 503 #endif 504 // create the port 505 replyPort = create_port(1, "KMessage reply port"); 506 if (replyPort < 0) 507 return replyPort; 508 // If the target team is not our team and not the kernel team either, 509 // we transfer the ownership of the port to it, so we will not block 510 if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM) 511 set_port_owner(replyPort, targetTeam); 512 } 513 struct PortDeleter { 514 PortDeleter(port_id port) : port(port) {} 515 ~PortDeleter() 516 { 517 if (port >= 0) 518 delete_port(port); 519 } 520 521 port_id port; 522 } replyPortDeleter(replyPort); 523 // send the message 524 error = SendTo(targetPort, targetToken, replyPort, 0, 525 deliveryTimeout, senderTeam); 526 if (error != B_OK) 527 return error; 528 // get the reply 529 if (reply) 530 return reply->ReceiveFrom(replyPort, replyTimeout); 531 return B_OK; 532 } 533 534 // SendReply 535 status_t 536 KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken, 537 bigtime_t timeout, team_id senderTeam) 538 { 539 if (!message) 540 return B_BAD_VALUE; 541 return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken, 542 timeout, senderTeam); 543 } 544 545 // SendReply 546 status_t 547 KMessage::SendReply(KMessage* message, KMessage* reply, 548 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam) 549 { 550 if (!message) 551 return B_BAD_VALUE; 552 return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout, 553 replyTimeout, senderTeam); 554 } 555 556 557 // ReceiveFrom 558 status_t 559 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout, 560 port_message_info* messageInfo) 561 { 562 port_message_info _messageInfo; 563 if (messageInfo == NULL) 564 messageInfo = &_messageInfo; 565 566 // get the port buffer size 567 status_t error; 568 if (timeout < 0) { 569 error = get_port_message_info_etc(fromPort, messageInfo, 0, 0); 570 } else { 571 error = get_port_message_info_etc(fromPort, messageInfo, 572 B_RELATIVE_TIMEOUT, timeout); 573 } 574 if (error != B_OK) 575 return error; 576 577 // allocate a buffer 578 uint8* buffer = (uint8*)malloc(messageInfo->size); 579 if (!buffer) 580 return B_NO_MEMORY; 581 582 // read the message 583 int32 what; 584 ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size, 585 B_RELATIVE_TIMEOUT, 0); 586 if (realSize < 0) 587 return realSize; 588 if (messageInfo->size != (size_t)realSize) 589 return B_ERROR; 590 591 // init the message 592 return SetTo(buffer, messageInfo->size, 0, 593 KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER); 594 } 595 596 #endif // !KMESSAGE_CONTAINER_ONLY 597 598 599 void 600 KMessage::Dump(void (*printFunc)(const char*,...)) 601 { 602 Header* header = _Header(); 603 printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: 0x0lx\n", 604 fBuffer, header->size, fBufferCapacity, fFlags); 605 606 KMessageField field; 607 while (GetNextField(&field) == B_OK) { 608 type_code type = field.TypeCode(); 609 int32 count = field.CountElements(); 610 printFunc(" field: %-20s: type: 0x%lx ('%c%c%c%c'), %ld element%s\n", 611 field.Name(), type, (char)(type >> 24), (char)(type >> 16), 612 (char)(type >> 8), (char)type, count, count == 1 ? "" : "s"); 613 } 614 } 615 616 617 // _Header 618 KMessage::Header * 619 KMessage::_Header() const 620 { 621 return (Header*)fBuffer; 622 } 623 624 // _BufferOffsetFor 625 int32 626 KMessage::_BufferOffsetFor(const void* data) const 627 { 628 if (!data) 629 return -1; 630 return ((uint8*)data - (uint8*)fBuffer); 631 } 632 633 // _FirstFieldHeader 634 KMessage::FieldHeader * 635 KMessage::_FirstFieldHeader() const 636 { 637 return (FieldHeader*)_Align(fBuffer, sizeof(Header)); 638 } 639 640 // _LastFieldHeader 641 KMessage::FieldHeader * 642 KMessage::_LastFieldHeader() const 643 { 644 return _FieldHeaderForOffset(fLastFieldOffset); 645 } 646 647 // _FieldHeaderForOffset 648 KMessage::FieldHeader * 649 KMessage::_FieldHeaderForOffset(int32 offset) const 650 { 651 if (offset <= 0 || offset >= _Header()->size) 652 return NULL; 653 return (FieldHeader*)((uint8*)fBuffer + offset); 654 } 655 656 // _AddField 657 status_t 658 KMessage::_AddField(const char *name, type_code type, int32 elementSize, 659 KMessageField *field) 660 { 661 FieldHeader *fieldHeader; 662 int32 alignedSize; 663 status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true, 664 true, (void**)&fieldHeader, &alignedSize); 665 if (error != B_OK) 666 return error; 667 fieldHeader->type = type; 668 fieldHeader->elementSize = elementSize; 669 fieldHeader->elementCount = 0; 670 fieldHeader->fieldSize = alignedSize; 671 fieldHeader->headerSize = alignedSize; 672 strcpy(fieldHeader->name, name); 673 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 674 if (field) 675 field->SetTo(this, _BufferOffsetFor(fieldHeader)); 676 return B_OK; 677 } 678 679 // _AddFieldData 680 status_t 681 KMessage::_AddFieldData(KMessageField *field, const void *data, 682 int32 elementSize, int32 elementCount) 683 { 684 if (!field) 685 return B_BAD_VALUE; 686 FieldHeader *fieldHeader = field->_Header(); 687 FieldHeader* lastField = _LastFieldHeader(); 688 if (!fieldHeader || fieldHeader != lastField || !data 689 || elementSize < 0 || elementCount < 0) { 690 return B_BAD_VALUE; 691 } 692 if (elementCount == 0) 693 return B_OK; 694 // fixed size values 695 if (fieldHeader->HasFixedElementSize()) { 696 if (elementSize != fieldHeader->elementSize) 697 return B_BAD_VALUE; 698 void *address; 699 int32 alignedSize; 700 status_t error = _AllocateSpace(elementSize * elementCount, 701 (fieldHeader->elementCount == 0), false, &address, &alignedSize); 702 if (error != B_OK) 703 return error; 704 fieldHeader = field->_Header(); // might have been relocated 705 memcpy(address, data, elementSize * elementCount); 706 fieldHeader->elementCount += elementCount; 707 fieldHeader->fieldSize = (uint8*)address + alignedSize 708 - (uint8*)fieldHeader; 709 return B_OK; 710 } 711 // non-fixed size values 712 // add the elements individually (TODO: Optimize!) 713 int32 valueHeaderSize = _Align(sizeof(FieldValueHeader)); 714 int32 entrySize = valueHeaderSize + elementSize; 715 for (int32 i = 0; i < elementCount; i++) { 716 void *address; 717 int32 alignedSize; 718 status_t error = _AllocateSpace(entrySize, true, false, &address, 719 &alignedSize); 720 if (error != B_OK) 721 return error; 722 fieldHeader = field->_Header(); // might have been relocated 723 FieldValueHeader *valueHeader = (FieldValueHeader*)address; 724 valueHeader->size = elementSize; 725 memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize, 726 elementSize); 727 fieldHeader->elementCount++; 728 fieldHeader->fieldSize = (uint8*)address + alignedSize 729 - (uint8*)fieldHeader; 730 } 731 return B_OK; 732 } 733 734 // _InitFromBuffer 735 status_t 736 KMessage::_InitFromBuffer(bool sizeFromBuffer) 737 { 738 if (!fBuffer || _Align(fBuffer) != fBuffer) 739 return B_BAD_DATA; 740 Header *header = _Header(); 741 742 if (sizeFromBuffer) 743 fBufferCapacity = header->size; 744 745 if (fBufferCapacity < (int)sizeof(Header)) 746 return B_BAD_DATA; 747 748 // check header 749 if (header->magic != kMessageHeaderMagic) 750 return B_BAD_DATA; 751 if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity) 752 return B_BAD_DATA; 753 754 // check the fields 755 FieldHeader *fieldHeader = NULL; 756 uint8 *data = (uint8*)_FirstFieldHeader(); 757 int32 remainingBytes = (uint8*)fBuffer + header->size - data; 758 while (remainingBytes > 0) { 759 if (remainingBytes < (int)sizeof(FieldHeader)) 760 return B_BAD_DATA; 761 fieldHeader = (FieldHeader*)data; 762 // check field header 763 if (fieldHeader->type == B_ANY_TYPE) 764 return B_BAD_DATA; 765 if (fieldHeader->elementCount < 0) 766 return B_BAD_DATA; 767 if (fieldHeader->fieldSize < (int)sizeof(FieldHeader) 768 || fieldHeader->fieldSize > remainingBytes) { 769 return B_BAD_DATA; 770 } 771 if (fieldHeader->headerSize < (int)sizeof(FieldHeader) 772 || fieldHeader->headerSize > fieldHeader->fieldSize) { 773 return B_BAD_DATA; 774 } 775 int32 maxNameLen = data + fieldHeader->headerSize 776 - (uint8*)fieldHeader->name; 777 int32 nameLen = strnlen(fieldHeader->name, maxNameLen); 778 if (nameLen == maxNameLen || nameLen == 0) 779 return B_BAD_DATA; 780 int32 fieldSize = fieldHeader->headerSize; 781 if (fieldHeader->HasFixedElementSize()) { 782 // fixed element size 783 int32 dataSize = fieldHeader->elementSize 784 * fieldHeader->elementCount; 785 fieldSize = (uint8*)fieldHeader->Data() + dataSize - data; 786 } else { 787 // non-fixed element size 788 FieldValueHeader *valueHeader 789 = (FieldValueHeader *)fieldHeader->Data(); 790 for (int32 i = 0; i < fieldHeader->elementCount; i++) { 791 remainingBytes = (uint8*)fBuffer + header->size 792 - (uint8*)valueHeader; 793 if (remainingBytes < (int)sizeof(FieldValueHeader)) 794 return B_BAD_DATA; 795 uint8 *value = (uint8*)valueHeader->Data(); 796 remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value; 797 if (remainingBytes < valueHeader->size) 798 return B_BAD_DATA; 799 fieldSize = value + valueHeader->size - data; 800 valueHeader = valueHeader->NextFieldValueHeader(); 801 } 802 if (fieldSize > fieldHeader->fieldSize) 803 return B_BAD_DATA; 804 } 805 data = (uint8*)fieldHeader->NextFieldHeader(); 806 remainingBytes = (uint8*)fBuffer + header->size - data; 807 } 808 fLastFieldOffset = _BufferOffsetFor(fieldHeader); 809 return B_OK; 810 } 811 812 // _InitBuffer 813 void 814 KMessage::_InitBuffer(uint32 what) 815 { 816 Header *header = _Header(); 817 header->magic = kMessageHeaderMagic; 818 header->size = sizeof(Header); 819 header->what = what; 820 header->sender = -1; 821 header->targetToken = -1; 822 header->replyPort = -1; 823 header->replyToken = -1; 824 fLastFieldOffset = 0; 825 } 826 827 // _CheckBuffer 828 void 829 KMessage::_CheckBuffer() 830 { 831 int32 lastFieldOffset = fLastFieldOffset; 832 if (_InitFromBuffer(false) != B_OK) { 833 PANIC("internal data mangled"); 834 } 835 if (fLastFieldOffset != lastFieldOffset) { 836 PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()"); 837 } 838 } 839 840 // _AllocateSpace 841 status_t 842 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize, 843 void **address, int32 *alignedSize) 844 { 845 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY)) 846 return B_NOT_ALLOWED; 847 848 int32 offset = ContentSize(); 849 if (alignAddress) 850 offset = _Align(offset); 851 int32 newSize = offset + size; 852 if (alignSize) 853 newSize = _Align(newSize); 854 // reallocate if necessary 855 if (fBuffer == &fHeader) { 856 int32 newCapacity = _CapacityFor(newSize); 857 void *newBuffer = malloc(newCapacity); 858 if (!newBuffer) 859 return B_NO_MEMORY; 860 fBuffer = newBuffer; 861 fBufferCapacity = newCapacity; 862 fFlags |= KMESSAGE_OWNS_BUFFER; 863 memcpy(fBuffer, &fHeader, sizeof(fHeader)); 864 } else { 865 if (newSize > fBufferCapacity) { 866 // if we don't own the buffer, we can't resize it 867 if (!(fFlags & KMESSAGE_OWNS_BUFFER)) 868 return B_BUFFER_OVERFLOW; 869 int32 newCapacity = _CapacityFor(newSize); 870 void *newBuffer = realloc(fBuffer, newCapacity); 871 if (!newBuffer) 872 return B_NO_MEMORY; 873 fBuffer = newBuffer; 874 fBufferCapacity = newCapacity; 875 } 876 } 877 _Header()->size = newSize; 878 *address = (char*)fBuffer + offset; 879 *alignedSize = newSize - offset; 880 return B_OK; 881 } 882 883 // _CapacityFor 884 int32 885 KMessage::_CapacityFor(int32 size) 886 { 887 return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize 888 * kMessageReallocChunkSize; 889 } 890 891 892 // #pragma mark - 893 894 // constructor 895 KMessageField::KMessageField() 896 : fMessage(NULL), 897 fHeaderOffset(0) 898 { 899 } 900 901 // Unset 902 void 903 KMessageField::Unset() 904 { 905 fMessage = NULL; 906 fHeaderOffset = 0; 907 } 908 909 // Message 910 KMessage * 911 KMessageField::Message() const 912 { 913 return fMessage; 914 } 915 916 // Name 917 const char * 918 KMessageField::Name() const 919 { 920 KMessage::FieldHeader* header = _Header(); 921 return (header ? header->name : NULL); 922 } 923 924 // TypeCode 925 type_code 926 KMessageField::TypeCode() const 927 { 928 KMessage::FieldHeader* header = _Header(); 929 return (header ? header->type : 0); 930 } 931 932 // HasFixedElementSize 933 bool 934 KMessageField::HasFixedElementSize() const 935 { 936 KMessage::FieldHeader* header = _Header(); 937 return (header ? header->HasFixedElementSize() : false); 938 } 939 940 // ElementSize 941 int32 942 KMessageField::ElementSize() const 943 { 944 KMessage::FieldHeader* header = _Header(); 945 return (header ? header->elementSize : -1); 946 } 947 948 // AddElement 949 status_t 950 KMessageField::AddElement(const void *data, int32 size) 951 { 952 KMessage::FieldHeader* header = _Header(); 953 if (!header || !data) 954 return B_BAD_VALUE; 955 if (size < 0) { 956 size = ElementSize(); 957 if (size < 0) 958 return B_BAD_VALUE; 959 } 960 return fMessage->_AddFieldData(this, data, size, 1); 961 } 962 963 // AddElements 964 status_t 965 KMessageField::AddElements(const void *data, int32 count, int32 elementSize) 966 { 967 KMessage::FieldHeader* header = _Header(); 968 if (!header || !data || count < 0) 969 return B_BAD_VALUE; 970 if (elementSize < 0) { 971 elementSize = ElementSize(); 972 if (elementSize < 0) 973 return B_BAD_VALUE; 974 } 975 return fMessage->_AddFieldData(this, data, elementSize, count); 976 } 977 978 // ElementAt 979 const void * 980 KMessageField::ElementAt(int32 index, int32 *size) const 981 { 982 KMessage::FieldHeader* header = _Header(); 983 return (header ? header->ElementAt(index, size) : NULL); 984 } 985 986 // CountElements 987 int32 988 KMessageField::CountElements() const 989 { 990 KMessage::FieldHeader* header = _Header(); 991 return (header ? header->elementCount : 0); 992 } 993 994 // SetTo 995 void 996 KMessageField::SetTo(KMessage *message, int32 headerOffset) 997 { 998 fMessage = message; 999 fHeaderOffset = headerOffset; 1000 } 1001 1002 // _GetHeader 1003 KMessage::FieldHeader* 1004 KMessageField::_Header() const 1005 { 1006 return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL); 1007 } 1008 1009