* Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <util/KMessage.h>
#include <stdlib.h>
#include <string.h>
#include <ByteOrder.h>
#include <Debug.h>
#include <KernelExport.h>
#include <TypeConstants.h>
#if defined(_BOOT_MODE) || defined(_LOADER_MODE)
# include <util/kernel_cpp.h>
#else
# include <new>
#endif
#ifndef PANIC
# if defined(_KERNEL_MODE) || defined(_BOOT_MODE)
# define PANIC(str) panic(str)
# else
# define PANIC(str) debugger(str)
# endif
#endif
#if !defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(_BOOT_MODE) \
|| defined(_LOADER_MODE)
# define MEMALIGN(alignment, size) malloc(size)
#else
# include <malloc.h>
# define MEMALIGN(alignment, size) memalign(alignment, size)
#endif
static const int32 kMessageReallocChunkSize = 64;
static const size_t kMessageBufferAlignment = 4;
const uint32 KMessage::kMessageHeaderMagic = 'kMsG';
static inline int32
_Align(int32 offset)
{
return (offset + kMessageBufferAlignment - 1)
& ~(kMessageBufferAlignment - 1);
}
static inline void*
_Align(void* address, int32 offset = 0)
{
return (void*)(((addr_t)address + offset + kMessageBufferAlignment - 1)
& ~(kMessageBufferAlignment - 1));
}
struct KMessage::FieldValueHeader {
int32 size;
void* Data()
{
return _Align(this, sizeof(FieldValueHeader));
}
FieldValueHeader* NextFieldValueHeader()
{
return (FieldValueHeader*)_Align(Data(), size);
}
};
struct KMessage::FieldHeader {
type_code type;
int32 elementSize;
int32 elementCount;
int32 fieldSize;
int16 headerSize;
char name[1];
void* Data()
{
return (uint8*)this + headerSize;
}
bool HasFixedElementSize()
{
return elementSize >= 0;
}
void* ElementAt(int32 index, int32* size)
{
if (index < 0 || index >= elementCount)
return NULL;
uint8* data = (uint8*)this + headerSize;
if (HasFixedElementSize()) {
*size = elementSize;
return data + elementSize * index;
}
FieldValueHeader* valueHeader = (FieldValueHeader*)data;
for (int i = 0; i < index; i++)
valueHeader = valueHeader->NextFieldValueHeader();
*size = valueHeader->size;
return valueHeader->Data();
}
FieldHeader* NextFieldHeader()
{
return (FieldHeader*)_Align(this, fieldSize);
}
};
KMessage::KMessage()
:
fBuffer(NULL),
fBufferCapacity(0),
fFlags(0),
fLastFieldOffset(0)
{
Unset();
}
KMessage::KMessage(uint32 what)
:
fBuffer(NULL),
fBufferCapacity(0),
fFlags(0),
fLastFieldOffset(0)
{
Unset();
SetWhat(what);
}
KMessage::~KMessage()
{
Unset();
}
status_t
KMessage::SetTo(uint32 what, uint32 flags)
{
Unset();
SetWhat(what);
return B_OK;
}
status_t
KMessage::SetTo(void* buffer, int32 bufferSize, uint32 what, uint32 flags)
{
Unset();
if (!buffer)
return B_BAD_VALUE;
if (bufferSize < 0) {
if (!(flags & KMESSAGE_INIT_FROM_BUFFER))
return B_BAD_VALUE;
} else if (bufferSize < (int)sizeof(Header))
return B_BAD_VALUE;
if ((flags & KMESSAGE_READ_ONLY) != 0
&& (flags & KMESSAGE_INIT_FROM_BUFFER) == 0) {
return B_BAD_VALUE;
}
if ((flags & KMESSAGE_INIT_FROM_BUFFER) == 0
&& (flags & KMESSAGE_CLONE_BUFFER) != 0) {
return B_BAD_VALUE;
}
fBuffer = buffer;
fBufferCapacity = bufferSize;
fFlags = flags;
status_t error = B_OK;
if (flags & KMESSAGE_INIT_FROM_BUFFER)
error = _InitFromBuffer(bufferSize < 0);
else
_InitBuffer(what);
if (error != B_OK)
Unset();
return error;
}
status_t
KMessage::SetTo(const void* buffer, int32 bufferSize, uint32 flags)
{
return SetTo(const_cast<void*>(buffer), bufferSize, 0,
KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY | flags);
}
void
KMessage::Unset()
{
if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER))
free(fBuffer);
fBuffer = &fHeader;
fBufferCapacity = sizeof(Header);
_InitBuffer(0);
}
void
KMessage::SetWhat(uint32 what)
{
_Header()->what = what;
}
uint32
KMessage::What() const
{
return _Header()->what;
}
const void*
KMessage::Buffer() const
{
return fBuffer;
}
int32
KMessage::BufferCapacity() const
{
return fBufferCapacity;
}
int32
KMessage::ContentSize() const
{
return _Header()->size;
}
status_t
KMessage::AddField(const char* name, type_code type, int32 elementSize,
KMessageField* field)
{
if (!name || type == B_ANY_TYPE)
return B_BAD_VALUE;
KMessageField existingField;
if (FindField(name, &existingField) == B_OK)
return B_NAME_IN_USE;
return _AddField(name, type, elementSize, field);
}
status_t
KMessage::FindField(const char* name, KMessageField* field) const
{
return FindField(name, B_ANY_TYPE, field);
}
status_t
KMessage::FindField(const char* name, type_code type,
KMessageField* field) const
{
if (!name)
return B_BAD_VALUE;
KMessageField stackField;
if (field)
field->Unset();
else
field = &stackField;
while (GetNextField(field) == B_OK) {
if ((type == B_ANY_TYPE || field->TypeCode() == type)
&& strcmp(name, field->Name()) == 0) {
return B_OK;
}
}
return B_NAME_NOT_FOUND;
}
status_t
KMessage::GetNextField(KMessageField* field) const
{
if (!field || (field->Message() != NULL && field->Message() != this))
return B_BAD_VALUE;
FieldHeader* fieldHeader = field->_Header();
FieldHeader* lastField = _LastFieldHeader();
if (!lastField)
return B_NAME_NOT_FOUND;
if (fieldHeader == NULL) {
fieldHeader = _FirstFieldHeader();
} else {
if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader()
|| (uint8*)fieldHeader > (uint8*)lastField) {
return B_BAD_VALUE;
}
if (fieldHeader == lastField)
return B_NAME_NOT_FOUND;
fieldHeader = fieldHeader->NextFieldHeader();
}
field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader));
return B_OK;
}
bool
KMessage::IsEmpty() const
{
return _LastFieldHeader() == NULL;
}
status_t
KMessage::AddData(const char* name, type_code type, const void* data,
int32 numBytes, bool isFixedSize)
{
if (!name || type == B_ANY_TYPE || !data || numBytes < 0)
return B_BAD_VALUE;
KMessageField field;
if (FindField(name, &field) == B_OK) {
if (field.TypeCode() != type)
return B_BAD_TYPE;
} else {
status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1),
&field);
if (error != B_OK)
return error;
}
return _AddFieldData(&field, data, numBytes, 1);
}
status_t
KMessage::AddArray(const char* name, type_code type, const void* data,
int32 elementSize, int32 elementCount)
{
if (!name || type == B_ANY_TYPE || !data || elementSize < 0
|| elementCount < 0) {
return B_BAD_VALUE;
}
KMessageField field;
if (FindField(name, &field) == B_OK) {
if (field.TypeCode() != type)
return B_BAD_TYPE;
} else {
status_t error = _AddField(name, type, elementSize, &field);
if (error != B_OK)
return error;
}
return _AddFieldData(&field, data, elementSize, elementCount);
}
status_t
KMessage::SetData(const char* name, type_code type, const void* data,
int32 numBytes)
{
if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
return B_NOT_ALLOWED;
KMessageField field;
if (FindField(name, &field) == B_OK) {
if (field.TypeCode() != type || !field.HasFixedElementSize()
|| field.ElementSize() != numBytes) {
return B_BAD_VALUE;
}
if (field.CountElements() > 0) {
const void* element = field.ElementAt(0);
memcpy(const_cast<void*>(element), data, numBytes);
return B_OK;
}
} else {
status_t error = _AddField(name, type, numBytes, &field);
if (error != B_OK)
return error;
}
return _AddFieldData(&field, data, numBytes, 1);
}
status_t
KMessage::FindData(const char* name, type_code type, const void** data,
int32* numBytes) const
{
return FindData(name, type, 0, data, numBytes);
}
status_t
KMessage::FindData(const char* name, type_code type, int32 index,
const void** data, int32* numBytes) const
{
if (!name || !data || !numBytes)
return B_BAD_VALUE;
KMessageField field;
status_t error = FindField(name, type, &field);
if (error != B_OK)
return error;
const void* foundData = field.ElementAt(index, numBytes);
if (!foundData)
return B_BAD_INDEX;
if (data)
*data = foundData;
return B_OK;
}
team_id
KMessage::Sender() const
{
return _Header()->sender;
}
int32
KMessage::TargetToken() const
{
return _Header()->targetToken;
}
port_id
KMessage::ReplyPort() const
{
return _Header()->replyPort;
}
int32
KMessage::ReplyToken() const
{
return _Header()->replyToken;
}
void
KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
int32 replyToken, team_id senderTeam)
{
Header* header = _Header();
header->sender = senderTeam;
header->targetToken = targetToken;
header->replyPort = replyPort;
header->replyToken = replyToken;
header->sender = senderTeam;
}
#ifndef KMESSAGE_CONTAINER_ONLY
status_t
KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
int32 replyToken, bigtime_t timeout, team_id senderTeam)
{
if (senderTeam < 0) {
thread_info info;
status_t error = get_thread_info(find_thread(NULL), &info);
if (error != B_OK)
return error;
senderTeam = info.team;
}
SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
if (timeout < 0)
return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
B_RELATIVE_TIMEOUT, timeout);
}
status_t
KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
{
port_info portInfo;
status_t error = get_port_info(targetPort, &portInfo);
if (error != B_OK)
return error;
team_id targetTeam = portInfo.team;
port_id replyPort = -1;
if (reply) {
team_id ourTeam = B_SYSTEM_TEAM;
#ifndef _KERNEL_MODE
if (targetTeam != B_SYSTEM_TEAM) {
thread_info threadInfo;
error = get_thread_info(find_thread(NULL), &threadInfo);
if (error != B_OK)
return error;
ourTeam = threadInfo.team;
}
#endif
replyPort = create_port(1, "KMessage reply port");
if (replyPort < 0)
return replyPort;
if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM)
set_port_owner(replyPort, targetTeam);
}
struct PortDeleter {
PortDeleter(port_id port) : port(port) {}
~PortDeleter()
{
if (port >= 0)
delete_port(port);
}
port_id port;
} replyPortDeleter(replyPort);
error = SendTo(targetPort, targetToken, replyPort, 0,
deliveryTimeout, senderTeam);
if (error != B_OK)
return error;
if (reply)
return reply->ReceiveFrom(replyPort, replyTimeout);
return B_OK;
}
status_t
KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
bigtime_t timeout, team_id senderTeam)
{
if (!message)
return B_BAD_VALUE;
return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
timeout, senderTeam);
}
status_t
KMessage::SendReply(KMessage* message, KMessage* reply,
bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
{
if (!message)
return B_BAD_VALUE;
return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
replyTimeout, senderTeam);
}
status_t
KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
port_message_info* messageInfo)
{
port_message_info _messageInfo;
if (messageInfo == NULL)
messageInfo = &_messageInfo;
status_t error;
if (timeout < 0) {
error = get_port_message_info_etc(fromPort, messageInfo, 0, 0);
} else {
error = get_port_message_info_etc(fromPort, messageInfo,
B_RELATIVE_TIMEOUT, timeout);
}
if (error != B_OK)
return error;
uint8* buffer = (uint8*)MEMALIGN(kMessageBufferAlignment,
messageInfo->size);
if (!buffer)
return B_NO_MEMORY;
int32 what;
ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size,
B_RELATIVE_TIMEOUT, 0);
if (realSize < 0) {
free(buffer);
return realSize;
}
if (messageInfo->size != (size_t)realSize) {
free(buffer);
return B_ERROR;
}
return SetTo(buffer, messageInfo->size, 0,
KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
}
#endif
void
KMessage::Dump(void (*printFunc)(const char*, ...)) const
{
Header* header = _Header();
printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: %#"
B_PRIx32 "\n", fBuffer, header->size, fBufferCapacity, fFlags);
KMessageField field;
while (GetNextField(&field) == B_OK) {
type_code type = field.TypeCode();
uint32 bigEndianType = B_HOST_TO_BENDIAN_INT32(type);
int nameSpacing = 17 - strlen(field.Name());
if (nameSpacing < 0)
nameSpacing = 0;
printFunc(" field: \"%s\"%*s (%.4s): ", field.Name(), nameSpacing, "",
(char*)&bigEndianType);
if (field.CountElements() != 1)
printFunc("\n");
int32 size;
for (int i = 0; const void* data = field.ElementAt(i, &size); i++) {
if (field.CountElements() != 1)
printFunc(" [%2d] ", i);
bool isIntType = false;
int64 intData = 0;
switch (type) {
case B_BOOL_TYPE:
printFunc("%s\n", (*(bool*)data ? "true" : "false"));
break;
case B_INT8_TYPE:
isIntType = true;
intData = *(int8*)data;
break;
case B_INT16_TYPE:
isIntType = true;
intData = *(int16*)data;
break;
case B_INT32_TYPE:
isIntType = true;
intData = *(int32*)data;
break;
case B_INT64_TYPE:
isIntType = true;
intData = *(int64*)data;
break;
case B_STRING_TYPE:
printFunc("\"%s\"\n", (char*)data);
break;
default:
printFunc("data at %p, %ld bytes\n", (char*)data, size);
break;
}
if (isIntType)
printFunc("%lld (0x%llx)\n", intData, intData);
}
}
}
KMessage::Header*
KMessage::_Header() const
{
return (Header*)fBuffer;
}
int32
KMessage::_BufferOffsetFor(const void* data) const
{
if (!data)
return -1;
return (uint8*)data - (uint8*)fBuffer;
}
KMessage::FieldHeader*
KMessage::_FirstFieldHeader() const
{
return (FieldHeader*)_Align(fBuffer, sizeof(Header));
}
KMessage::FieldHeader*
KMessage::_LastFieldHeader() const
{
return _FieldHeaderForOffset(fLastFieldOffset);
}
KMessage::FieldHeader*
KMessage::_FieldHeaderForOffset(int32 offset) const
{
if (offset <= 0 || offset >= _Header()->size)
return NULL;
return (FieldHeader*)((uint8*)fBuffer + offset);
}
status_t
KMessage::_AddField(const char* name, type_code type, int32 elementSize,
KMessageField* field)
{
FieldHeader* fieldHeader;
int32 alignedSize;
status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
true, (void**)&fieldHeader, &alignedSize);
if (error != B_OK)
return error;
fieldHeader->type = type;
fieldHeader->elementSize = elementSize;
fieldHeader->elementCount = 0;
fieldHeader->fieldSize = alignedSize;
fieldHeader->headerSize = alignedSize;
strcpy(fieldHeader->name, name);
fLastFieldOffset = _BufferOffsetFor(fieldHeader);
if (field)
field->SetTo(this, _BufferOffsetFor(fieldHeader));
return B_OK;
}
status_t
KMessage::_AddFieldData(KMessageField* field, const void* data,
int32 elementSize, int32 elementCount)
{
if (!field)
return B_BAD_VALUE;
FieldHeader* fieldHeader = field->_Header();
FieldHeader* lastField = _LastFieldHeader();
if (!fieldHeader || fieldHeader != lastField || !data
|| elementSize < 0 || elementCount < 0) {
return B_BAD_VALUE;
}
if (elementCount == 0)
return B_OK;
if (fieldHeader->HasFixedElementSize()) {
if (elementSize != fieldHeader->elementSize)
return B_BAD_VALUE;
void* address;
int32 alignedSize;
status_t error = _AllocateSpace(elementSize * elementCount,
(fieldHeader->elementCount == 0), false, &address, &alignedSize);
if (error != B_OK)
return error;
fieldHeader = field->_Header();
memcpy(address, data, elementSize * elementCount);
fieldHeader->elementCount += elementCount;
fieldHeader->fieldSize = (uint8*)address + alignedSize
- (uint8*)fieldHeader;
return B_OK;
}
int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
int32 entrySize = valueHeaderSize + elementSize;
for (int32 i = 0; i < elementCount; i++) {
void* address;
int32 alignedSize;
status_t error = _AllocateSpace(entrySize, true, false, &address,
&alignedSize);
if (error != B_OK)
return error;
fieldHeader = field->_Header();
FieldValueHeader* valueHeader = (FieldValueHeader*)address;
valueHeader->size = elementSize;
memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
elementSize);
fieldHeader->elementCount++;
fieldHeader->fieldSize = (uint8*)address + alignedSize
- (uint8*)fieldHeader;
}
return B_OK;
}
status_t
KMessage::_InitFromBuffer(bool sizeFromBuffer)
{
if (fBuffer == NULL)
return B_BAD_DATA;
if ((fFlags & KMESSAGE_CLONE_BUFFER) != 0 || _Align(fBuffer) != fBuffer) {
if (sizeFromBuffer) {
int32 size = fBufferCapacity;
memcpy(&size, &_Header()->size, 4);
fBufferCapacity = size;
}
void* buffer = MEMALIGN(kMessageBufferAlignment, fBufferCapacity);
if (buffer == NULL)
return B_NO_MEMORY;
memcpy(buffer, fBuffer, fBufferCapacity);
if ((fFlags & KMESSAGE_OWNS_BUFFER) != 0)
free(fBuffer);
fBuffer = buffer;
fFlags &= ~(uint32)(KMESSAGE_READ_ONLY | KMESSAGE_CLONE_BUFFER);
fFlags |= KMESSAGE_OWNS_BUFFER;
}
if (_Align(fBuffer) != fBuffer)
return B_BAD_DATA;
Header* header = _Header();
if (sizeFromBuffer)
fBufferCapacity = header->size;
if (fBufferCapacity < (int)sizeof(Header))
return B_BAD_DATA;
if (header->magic != kMessageHeaderMagic)
return B_BAD_DATA;
if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
return B_BAD_DATA;
FieldHeader* fieldHeader = NULL;
uint8* data = (uint8*)_FirstFieldHeader();
int32 remainingBytes = (uint8*)fBuffer + header->size - data;
while (remainingBytes > 0) {
if (remainingBytes < (int)sizeof(FieldHeader))
return B_BAD_DATA;
fieldHeader = (FieldHeader*)data;
if (fieldHeader->type == B_ANY_TYPE)
return B_BAD_DATA;
if (fieldHeader->elementCount < 0)
return B_BAD_DATA;
if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
|| fieldHeader->fieldSize > remainingBytes) {
return B_BAD_DATA;
}
if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
|| fieldHeader->headerSize > fieldHeader->fieldSize) {
return B_BAD_DATA;
}
int32 maxNameLen = data + fieldHeader->headerSize
- (uint8*)fieldHeader->name;
int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
if (nameLen == maxNameLen || nameLen == 0)
return B_BAD_DATA;
int32 fieldSize = fieldHeader->headerSize;
if (fieldHeader->HasFixedElementSize()) {
int32 dataSize = fieldHeader->elementSize
* fieldHeader->elementCount;
fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
} else {
FieldValueHeader* valueHeader
= (FieldValueHeader*)fieldHeader->Data();
for (int32 i = 0; i < fieldHeader->elementCount; i++) {
remainingBytes = (uint8*)fBuffer + header->size
- (uint8*)valueHeader;
if (remainingBytes < (int)sizeof(FieldValueHeader))
return B_BAD_DATA;
uint8* value = (uint8*)valueHeader->Data();
remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
if (remainingBytes < valueHeader->size)
return B_BAD_DATA;
fieldSize = value + valueHeader->size - data;
valueHeader = valueHeader->NextFieldValueHeader();
}
if (fieldSize > fieldHeader->fieldSize)
return B_BAD_DATA;
}
data = (uint8*)fieldHeader->NextFieldHeader();
remainingBytes = (uint8*)fBuffer + header->size - data;
}
fLastFieldOffset = _BufferOffsetFor(fieldHeader);
return B_OK;
}
void
KMessage::_InitBuffer(uint32 what)
{
Header* header = _Header();
header->magic = kMessageHeaderMagic;
header->size = sizeof(Header);
header->what = what;
header->sender = -1;
header->targetToken = -1;
header->replyPort = -1;
header->replyToken = -1;
fLastFieldOffset = 0;
}
void
KMessage::_CheckBuffer()
{
int32 lastFieldOffset = fLastFieldOffset;
if (_InitFromBuffer(false) != B_OK) {
PANIC("internal data mangled");
}
if (fLastFieldOffset != lastFieldOffset) {
PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
}
}
status_t
KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
void** address, int32* alignedSize)
{
if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
return B_NOT_ALLOWED;
int32 offset = ContentSize();
if (alignAddress)
offset = _Align(offset);
int32 newSize = offset + size;
if (alignSize)
newSize = _Align(newSize);
if (fBuffer == &fHeader) {
int32 newCapacity = _CapacityFor(newSize);
void* newBuffer = MEMALIGN(kMessageBufferAlignment, newCapacity);
if (!newBuffer)
return B_NO_MEMORY;
fBuffer = newBuffer;
fBufferCapacity = newCapacity;
fFlags |= KMESSAGE_OWNS_BUFFER;
memcpy(fBuffer, &fHeader, sizeof(fHeader));
} else {
if (newSize > fBufferCapacity) {
if (!(fFlags & KMESSAGE_OWNS_BUFFER)) {
#if defined(_KERNEL_MODE) && 0
panic("KMessage: out of space: available: %" B_PRId32
", needed: %" B_PRId32 "\n", fBufferCapacity, newSize);
#endif
return B_BUFFER_OVERFLOW;
}
int32 newCapacity = _CapacityFor(newSize);
void* newBuffer = realloc(fBuffer, newCapacity);
if (!newBuffer)
return B_NO_MEMORY;
fBuffer = newBuffer;
fBufferCapacity = newCapacity;
}
}
_Header()->size = newSize;
*address = (char*)fBuffer + offset;
*alignedSize = newSize - offset;
return B_OK;
}
int32
KMessage::_CapacityFor(int32 size)
{
return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
* kMessageReallocChunkSize;
}
KMessageField::KMessageField()
:
fMessage(NULL),
fHeaderOffset(0)
{
}
void
KMessageField::Unset()
{
fMessage = NULL;
fHeaderOffset = 0;
}
KMessage*
KMessageField::Message() const
{
return fMessage;
}
const char*
KMessageField::Name() const
{
KMessage::FieldHeader* header = _Header();
return header ? header->name : NULL;
}
type_code
KMessageField::TypeCode() const
{
KMessage::FieldHeader* header = _Header();
return header ? header->type : 0;
}
bool
KMessageField::HasFixedElementSize() const
{
KMessage::FieldHeader* header = _Header();
return header ? header->HasFixedElementSize() : false;
}
int32
KMessageField::ElementSize() const
{
KMessage::FieldHeader* header = _Header();
return header ? header->elementSize : -1;
}
status_t
KMessageField::AddElement(const void* data, int32 size)
{
KMessage::FieldHeader* header = _Header();
if (!header || !data)
return B_BAD_VALUE;
if (size < 0) {
size = ElementSize();
if (size < 0)
return B_BAD_VALUE;
}
return fMessage->_AddFieldData(this, data, size, 1);
}
status_t
KMessageField::AddElements(const void* data, int32 count, int32 elementSize)
{
KMessage::FieldHeader* header = _Header();
if (!header || !data || count < 0)
return B_BAD_VALUE;
if (elementSize < 0) {
elementSize = ElementSize();
if (elementSize < 0)
return B_BAD_VALUE;
}
return fMessage->_AddFieldData(this, data, elementSize, count);
}
const void*
KMessageField::ElementAt(int32 index, int32* size) const
{
KMessage::FieldHeader* header = _Header();
return header ? header->ElementAt(index, size) : NULL;
}
int32
KMessageField::CountElements() const
{
KMessage::FieldHeader* header = _Header();
return header ? header->elementCount : 0;
}
void
KMessageField::SetTo(KMessage* message, int32 headerOffset)
{
fMessage = message;
fHeaderOffset = headerOffset;
}
KMessage::FieldHeader*
KMessageField::_Header() const
{
return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL;
}