Moving towards more flat buffering. Speed is still lower than the original Be implementation, but it's not because of the backend, it's probably the slow BMessage::Header implementation.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13909 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2005-08-06 15:03:18 +00:00
parent 0401007080
commit 54ca2a11db
5 changed files with 367 additions and 362 deletions

View File

@ -43,16 +43,17 @@ public:
status_t Flatten(BDataIO *stream) const;
status_t Unflatten(BDataIO *stream);
status_t AddData(const char *name, BSimpleMallocIO *buffer,
type_code type);
status_t AddData(const char *name, type_code type,
size_t length, void **buffer,
bool fixedSize = false, int32 count = 1);
status_t RemoveData(const char *name, int32 index = 0);
bool HasData(const char *name, type_code t, int32 n) const;
status_t FindData(const char *name, type_code type,
int32 index, const void **data,
ssize_t *numBytes) const;
status_t ReplaceData(const char *name, int32 index,
BSimpleMallocIO *buffer, type_code type);
status_t ReplaceData(const char *name, type_code type,
int32 index, size_t length, void **buffer);
status_t Rename(const char *oldName, const char *newName);
status_t RemoveName(const char *name);

View File

@ -11,8 +11,8 @@
#ifndef _MESSAGE_FIELD_H_
#define _MESSAGE_FIELD_H_
#include <DataIO.h>
#include <List.h>
#include <String.h>
#include <SupportDefs.h>
#define MSG_FLAG_VALID 0x01
@ -25,36 +25,47 @@
namespace BPrivate {
class BSimpleMallocIO;
typedef struct field_header_s {
uint8 flags;
type_code type;
int32 count;
ssize_t dataSize;
uint8 nameLength;
char name[255];
} __attribute__((__packed__)) FieldHeader;
class BMessageField {
public:
BMessageField();
BMessageField(const char *name, type_code type);
BMessageField(uint8 flags, BDataIO *stream);
BMessageField(const BMessageField &other);
~BMessageField();
BMessageField &operator=(const BMessageField &other);
uint8 Flags();
void Flatten(BDataIO *stream);
void Unflatten(uint8 flags, BDataIO *stream);
uint8 Flags() { return fHeader.flags; };
void SetName(const char *name);
const char *Name() const { return fName.String(); };
uint8 NameLength() const { return fName.Length(); };
type_code Type() const { return fType; };
const char *Name() const { return fHeader.name; };
uint8 NameLength() const { return fHeader.nameLength; };
type_code Type() const { return fHeader.type; };
void AddItem(BSimpleMallocIO *item);
void ReplaceItem(int32 index, BSimpleMallocIO *item);
void *AddItem(size_t length);
void *ReplaceItem(int32 index, size_t newLength);
void RemoveItem(int32 index);
int32 CountItems() const { return fItems.CountItems(); };
size_t SizeAt(int32 index) const;
const void *BufferAt(int32 index) const;
int32 CountItems() const { return fHeader.count; };
const void *BufferAt(int32 index, ssize_t *size) const;
void MakeEmpty();
bool IsFixedSize() const { return fFixedSize; };
size_t TotalSize() const { return fTotalSize; };
size_t TotalPadding() const { return fTotalPadding; };
status_t SetFixedSize(int32 itemSize, int32 count);
bool IsFixedSize() const { return fHeader.flags & MSG_FLAG_FIXED_SIZE; };
size_t TotalSize() const { return fHeader.dataSize; };
void PrintToStream() const;
@ -63,15 +74,20 @@ public:
BMessageField *Next() const { return fNext; };
private:
bool IsFixedSize(type_code type);
void ResetHeader(const char *name, type_code type);
void FlatResize(int32 offset, size_t oldLength,
size_t newLength);
BString fName;
type_code fType;
BList fItems;
bool fFixedSize;
size_t fTotalSize;
size_t fTotalPadding;
FieldHeader fHeader;
mutable BMallocIO fFlatBuffer;
// fixed size items
int32 fItemSize;
// variable sized items
BList *fOffsets;
// hash table support
BMessageField *fNext;
};

View File

@ -39,7 +39,6 @@
#include "MessageBody2.h"
#include "MessageField2.h"
#include "MessageUtils2.h"
#include "SimpleMallocIO.h"
#include "dano_message.h"
// flags for the overall message (the bitfield is 1 byte)
@ -82,6 +81,22 @@ static status_t convert_message(const KMessage *fromMessage,
BMessage *toMessage);
static ssize_t min_hdr_size();
typedef struct message_header_s {
int32 checkSum;
int32 flattenedSize;
uint32 what;
uint8 flags;
} __attribute__((__packed__)) MessageHeader;
typedef struct reply_data_s {
port_id replyPort;
int32 replyToken;
team_id replyTeam;
bool preferredTarget;
bool replyRequired;
bool replyDone;
bool isReply;
} __attribute__((__packed__)) ReplyData;
class BMessage::Header {
public:
@ -1028,7 +1043,7 @@ BMessage::PopSpecifier()
status_t \
BMessage::Add ## fnName(const char *name, TYPE val) \
{ \
return AddData(name, TYPESPEC, &val, sizeof(TYPE)); \
return AddData(name, TYPESPEC, &val, sizeof(TYPE), true); \
} \
\
status_t \
@ -1122,44 +1137,46 @@ DEFINE_LAZY_FIND_FUNCTION(const char *, String);
status_t
BMessage::AddString(const char *name, const char *string)
{
return AddData(name, B_STRING_TYPE, string, strlen(string) + 1);
return AddData(name, B_STRING_TYPE, string, strlen(string) + 1, false);
}
status_t
BMessage::AddString(const char* name, const BString &string)
{
return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1);
return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
}
status_t
BMessage::AddPointer(const char *name, const void *pointer)
{
return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer));
return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
}
status_t
BMessage::AddMessenger(const char *name, BMessenger messenger)
{
return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger));
return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
}
status_t
BMessage::AddRef(const char* name, const entry_ref* ref)
BMessage::AddRef(const char *name, const entry_ref *ref)
{
size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = entry_ref_flatten(buffer->Buffer(), &size, ref);
buffer->SetSize(size);
if (error >= B_OK)
error = fBody->AddData(name, buffer, B_REF_TYPE);
char flatRef[size];
status_t error = entry_ref_flatten(flatRef, &size, ref);
if (error < B_OK)
delete buffer;
return error;
void *buffer;
error = fBody->AddData(name, B_REF_TYPE, size, &buffer, false);
if (error >= B_OK)
memcpy(buffer, flatRef, size);
return error;
}
@ -1169,16 +1186,14 @@ status_t
BMessage::AddMessage(const char *name, const BMessage *msg)
{
size_t size = msg->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = msg->Flatten(buffer->Buffer(), size);
if (error >= B_OK)
error = fBody->AddData(name, buffer, B_MESSAGE_TYPE);
void *buffer;
status_t error = fBody->AddData(name, B_MESSAGE_TYPE, size, &buffer, false);
if (error < B_OK)
delete buffer;
return error;
return error;
return msg->Flatten((char *)buffer, size);
}
@ -1186,36 +1201,29 @@ status_t
BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
{
ssize_t size = object->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = object->Flatten(buffer->Buffer(), size);
if (error >= B_OK)
error = fBody->AddData(name, buffer, object->TypeCode());
void *buffer;
status_t error = fBody->AddData(name, object->TypeCode(), size, &buffer, false);
if (error < B_OK)
delete buffer;
return error;
return error;
return object->Flatten(buffer, size);
}
status_t
BMessage::AddData(const char *name, type_code type, const void *data,
ssize_t numBytes, bool is_fixed_size, int32 /*count*/)
ssize_t numBytes, bool is_fixed_size, int32 count)
{
// TODO: test
// In particular, we want to see what happens if is_fixed_size == true and
// the user attempts to add something bigger or smaller. We may need to
// enforce the size thing.
BSimpleMallocIO *buffer = new BSimpleMallocIO(numBytes);
buffer->Write(data);
status_t error = fBody->AddData(name, buffer, type);
void *buffer;
status_t error = fBody->AddData(name, type, numBytes, &buffer, is_fixed_size, count);
if (error < B_OK)
delete buffer;
return error;
return error;
memcpy(buffer, data, numBytes);
return B_OK;
}
@ -1490,17 +1498,20 @@ status_t
BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
{
size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = entry_ref_flatten(buffer->Buffer(), &size, ref);
buffer->SetSize(size);
if (error >= B_OK)
error = fBody->ReplaceData(name, index, buffer, B_REF_TYPE);
char flatRef[size];
status_t error = entry_ref_flatten(flatRef, &size, ref);
if (error < B_OK)
delete buffer;
return error;
return error;
void *buffer;
error = fBody->ReplaceData(name, B_REF_TYPE, index, size, &buffer);
if (error < B_OK)
return error;
memcpy(buffer, flatRef, size);
return B_OK;
}
@ -1515,16 +1526,14 @@ status_t
BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *msg)
{
size_t size = msg->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = msg->Flatten(buffer->Buffer(), size);
if (error >= B_OK)
error = fBody->ReplaceData(name, index, buffer, B_MESSAGE_TYPE);
void *buffer;
status_t error = fBody->ReplaceData(name, B_MESSAGE_TYPE, index, size, &buffer);
if (error < B_OK)
delete buffer;
return error;
return error;
return msg->Flatten((char *)buffer, size);
}
@ -1539,16 +1548,14 @@ status_t
BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
{
ssize_t size = object->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = object->Flatten(buffer->Buffer(), size);
if (error >= B_OK)
error = fBody->ReplaceData(name, index, buffer, object->TypeCode());
void *buffer;
status_t error = fBody->ReplaceData(name, object->TypeCode(), index, size, &buffer);
if (error < B_OK)
delete buffer;
return error;
return error;
return object->Flatten(buffer, size);
}
@ -1564,14 +1571,14 @@ status_t
BMessage::ReplaceData(const char *name, type_code type, int32 index,
const void *data, ssize_t data_size)
{
BSimpleMallocIO *buffer = new BSimpleMallocIO(data_size);
buffer->Write(data);
status_t error = fBody->ReplaceData(name, index, buffer, type);
void *buffer;
status_t error = fBody->ReplaceData(name, type, index, data_size, &buffer);
if (error < B_OK)
delete buffer;
return error;
return error;
memcpy(buffer, data, data_size);
return B_OK;
}

View File

@ -9,18 +9,13 @@
/* BMessageBody handles data storage and retrieval for BMessage. */
#include <stdio.h>
#include <string.h>
#include <TypeConstants.h>
#include "MessageBody2.h"
#include "MessageUtils2.h"
#include "SimpleMallocIO.h"
namespace BPrivate {
static int64 sPadding[2] = { 0, 0 };
static uint8 sPadLengths[8] = { 4, 3, 2, 1, 0, 7, 6, 5 };
#define CALC_PADDING_8(x) sPadLengths[x % 8]
BMessageBody::BMessageBody()
{
InitCommon();
@ -254,55 +249,8 @@ BMessageBody::FlattenedSize() const
status_t
BMessageBody::Flatten(BDataIO *stream) const
{
for (int32 index = 0; index < fFieldList.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index);
uint8 flags = field->Flags();
stream->Write(&flags, sizeof(flags));
type_code type = field->Type();
stream->Write(&type, sizeof(type));
// add item count if not a single item
int32 count = field->CountItems();
if (!(flags & MSG_FLAG_SINGLE_ITEM)) {
if (flags & MSG_FLAG_MINI_DATA) {
uint8 miniCount = (uint8)count;
stream->Write(&miniCount, sizeof(miniCount));
} else
stream->Write(&count, sizeof(count));
}
// overall data size (includes padding for non fixed size fields)
size_t size = field->TotalSize();
if (flags & MSG_FLAG_MINI_DATA) {
uint8 miniSize = (uint8)size;
stream->Write(&miniSize, sizeof(miniSize));
} else
stream->Write(&size, sizeof(size));
// name length
uint8 nameLength = field->NameLength();
stream->Write(&nameLength, sizeof(nameLength));
// name
stream->Write(field->Name(), nameLength);
// data items
if (flags & MSG_FLAG_FIXED_SIZE) {
size = field->SizeAt(0);
for (int32 dataIndex = 0; dataIndex < count; dataIndex++)
stream->Write(field->BufferAt(dataIndex), size);
} else {
for (int32 dataIndex = 0; dataIndex < count; dataIndex++) {
size = field->SizeAt(dataIndex);
stream->Write(&size, sizeof(size));
stream->Write(field->BufferAt(dataIndex), size);
size_t error = stream->Write(sPadding, CALC_PADDING_8(size));
}
}
}
for (int32 index = 0; index < fFieldList.CountItems(); index++)
((BMessageField *)fFieldList.ItemAt(index))->Flatten(stream);
uint8 lastEntry = 0;
size_t error = stream->Write(&lastEntry, sizeof(lastEntry));
@ -322,95 +270,21 @@ BMessageBody::Unflatten(BDataIO *stream)
if (!IsEmpty())
MakeEmpty();
BMessageField *newField = NULL;
try {
TReadHelper reader(stream);
char name[255];
uint8 flags;
reader(flags);
while (flags != MSG_LAST_ENTRY) {
type_code type;
reader(type);
int32 itemCount;
int32 dataLength;
uint8 littleData;
if (flags & MSG_FLAG_SINGLE_ITEM) {
itemCount = 1;
if (flags & MSG_FLAG_MINI_DATA) {
reader(littleData);
dataLength = littleData;
} else
reader(dataLength);
} else {
if (flags & MSG_FLAG_MINI_DATA) {
reader(littleData);
itemCount = littleData;
reader(littleData);
dataLength = littleData;
} else {
reader(itemCount);
reader(dataLength);
}
}
// get the name length (1 byte) and name
uint8 nameLength;
reader(nameLength);
reader(name, nameLength);
name[nameLength] = '\0';
#if 0
// ToDo: Add these swapping capabilities again
if (swap) {
// Is the data fixed size?
if ((flags & MSG_FLAG_FIXED_SIZE) != 0) {
// Make sure to swap the data
status = swap_data(type, (void*)databuffer, dataLen,
B_SWAP_ALWAYS);
if (status < B_OK)
throw status;
} else if (type == B_REF_TYPE) {
// Is the data variable size?
// Apparently, entry_refs are the only variable-length data
// explicitely swapped -- the dev_t and ino_t specifically
byte_swap(*(entry_ref*)databuffer);
}
}
#endif
status_t error = B_ERROR;
BMessageField *field = AddField(name, type, error);
if (error < B_OK)
return error;
if (flags & MSG_FLAG_FIXED_SIZE) {
int32 itemSize = dataLength / itemCount;
for (int32 index = 0; index < itemCount; index++) {
BSimpleMallocIO *buffer = new BSimpleMallocIO(itemSize);
reader(buffer->Buffer(), itemSize);
field->AddItem(buffer);
}
} else {
char padding[8];
ssize_t dataLength;
for (int32 index = 0; index < itemCount; index++) {
reader(dataLength);
BSimpleMallocIO *buffer = new BSimpleMallocIO(dataLength);
reader(buffer->Buffer(), dataLength);
reader(padding, CALC_PADDING_8(dataLength));
field->AddItem(buffer);
}
}
newField = new BMessageField(flags, stream);
fFieldList.AddItem(newField);
HashInsert(newField);
reader(flags);
}
} catch (status_t &error) {
delete newField;
return error;
}
@ -419,34 +293,22 @@ BMessageBody::Unflatten(BDataIO *stream)
status_t
BMessageBody::AddData(const char *name, BSimpleMallocIO *buffer, type_code type)
BMessageBody::AddData(const char *name, type_code type, size_t length,
void **buffer, bool fixedSize, int32 count)
{
status_t error = B_OK;
BMessageField *foundField = FindData(name, type, error);
BMessageField *newField = AddField(name, type, error);
if (error < B_OK) {
if (error == B_NAME_NOT_FOUND) {
// reset the error - we will create the field
error = B_OK;
} else {
// looking for B_BAD_TYPE here in particular, which would indicate
// that we tried to add data of type X when we already had data of
// type Y with the same name
if (error < B_OK)
return error;
if (fixedSize) {
error = newField->SetFixedSize(length, count);
if (error < B_OK)
return error;
}
}
if (!foundField) {
// add a new field if it's not yet present
BMessageField *newField = new BMessageField(name, type);
newField->AddItem(buffer);
fFieldList.AddItem(newField);
HashInsert(newField);
} else {
// add to the existing field otherwise
foundField->AddItem(buffer);
}
*buffer = newField->AddItem(length);
fFlattenedSize = -1;
return error;
}
@ -476,8 +338,8 @@ BMessageBody::AddField(const char *name, type_code type, status_t &error)
status_t
BMessageBody::ReplaceData(const char *name, int32 index, BSimpleMallocIO *buffer,
type_code type)
BMessageBody::ReplaceData(const char *name, type_code type, int32 index,
size_t length, void **buffer)
{
if (type == B_ANY_TYPE)
return B_BAD_VALUE;
@ -491,7 +353,7 @@ BMessageBody::ReplaceData(const char *name, int32 index, BSimpleMallocIO *buffer
if (!field)
return B_ERROR;
field->ReplaceItem(index, buffer);
*buffer = field->ReplaceItem(index, length);
fFlattenedSize = -1;
return error;
}
@ -584,11 +446,7 @@ BMessageBody::FindData(const char *name, type_code type, int32 index,
if (index >= field->CountItems())
return B_BAD_INDEX;
if (data)
*data = field->BufferAt(index);
if (numBytes)
*numBytes = field->SizeAt(index);
*data = field->BufferAt(index, numBytes);
}
return error;

View File

@ -7,35 +7,52 @@
*/
#include <stdio.h>
#include <string.h>
#include <TypeConstants.h>
#include "MessageField2.h"
#include "SimpleMallocIO.h"
#include "MessageUtils2.h"
namespace BPrivate {
#define ROUND_TO_8(x) (fFixedSize ? x : (x + 11) & ~7)
inline int32
round_to_8(int32 length)
{
// already includes the + 4 for size_t length field
return (length + 11) & ~7;
}
BMessageField::BMessageField()
: fType(0),
fFixedSize(false),
fTotalSize(0),
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{
SetName("");
ResetHeader("", 0);
}
BMessageField::BMessageField(const char *name, type_code type)
: fType(type),
fTotalSize(0),
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{
SetName(name);
fFixedSize = IsFixedSize(type);
ResetHeader(name, type);
}
BMessageField::BMessageField(uint8 flags, BDataIO *stream)
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{
Unflatten(flags, stream);
}
BMessageField::BMessageField(const BMessageField &other)
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{
*this = other;
}
@ -52,18 +69,20 @@ BMessageField::operator=(const BMessageField &other)
{
if (this != &other) {
MakeEmpty();
fName = other.fName;
fType = other.fType;
fFixedSize = other.fFixedSize;
fTotalSize = other.fTotalSize;
fNext = NULL;
for (int32 index = 0; index < other.fItems.CountItems(); index++) {
BSimpleMallocIO *otherBuffer = (BSimpleMallocIO *)other.fItems.ItemAt(index);
BSimpleMallocIO *newBuffer = new BSimpleMallocIO(otherBuffer->BufferLength());
newBuffer->Write(otherBuffer->Buffer());
fItems.AddItem((void *)newBuffer);
memcpy(&fHeader, &other.fHeader, sizeof(FieldHeader));
fFlatBuffer.Write(other.fFlatBuffer.Buffer(), other.fFlatBuffer.BufferLength());
if (other.fOffsets) {
int32 count = other.fOffsets->CountItems();
fOffsets = new BList(count);
for (int32 index = 0; index < count; index++)
fOffsets->AddItem(other.fOffsets->ItemAt(index));
} else {
fItemSize = other.fItemSize;
}
}
@ -72,97 +91,218 @@ BMessageField::operator=(const BMessageField &other)
void
BMessageField::MakeEmpty()
BMessageField::Flatten(BDataIO *stream)
{
for (int32 index = 0; index < fItems.CountItems(); index++) {
BSimpleMallocIO *item = (BSimpleMallocIO *)fItems.ItemAt(index);
delete item;
}
// write flat header including name
stream->Write(&fHeader, sizeof(fHeader) - sizeof(fHeader.name) + fHeader.nameLength);
fItems.MakeEmpty();
// write flat data
stream->Write(fFlatBuffer.Buffer(), fHeader.dataSize);
}
uint8
BMessageField::Flags()
void
BMessageField::Unflatten(uint8 flags, BDataIO *stream)
{
uint8 flags = MSG_FLAG_VALID;
TReadHelper reader(stream);
if (fItems.CountItems() == 1)
flags |= MSG_FLAG_SINGLE_ITEM;
// read the header
if (flags == MSG_FLAG_VALID
|| flags == MSG_FLAG_VALID | MSG_FLAG_FIXED_SIZE) {
// we can read the header as flat data
fHeader.flags = flags;
stream->Read(&fHeader.type, sizeof(fHeader) - sizeof(fHeader.flags) - sizeof(fHeader.name));
stream->Read(&fHeader.name, fHeader.nameLength);
fItemSize = fHeader.dataSize / fHeader.count;
} else {
// we have to disassemble the header
type_code type;
reader(type);
ResetHeader("", type);
if (fTotalSize < 255)
flags |= MSG_FLAG_MINI_DATA;
if (flags & MSG_FLAG_SINGLE_ITEM) {
fHeader.count = 1;
if (fFixedSize)
flags |= MSG_FLAG_FIXED_SIZE;
if (flags & MSG_FLAG_MINI_DATA) {
uint8 littleData;
reader(littleData);
fHeader.dataSize = littleData;
} else
reader(fHeader.dataSize);
} else {
if (flags & MSG_FLAG_MINI_DATA) {
uint8 littleData;
reader(littleData);
fHeader.count = littleData;
return flags;
reader(littleData);
fHeader.dataSize = littleData;
} else {
reader(fHeader.count);
reader(fHeader.dataSize);
}
}
reader(fHeader.nameLength);
reader(fHeader.name, fHeader.nameLength);
}
// now read the data
fFlatBuffer.SetSize(fHeader.dataSize);
stream->Read((void *)fFlatBuffer.Buffer(), fHeader.dataSize);
// ToDo: enable swapping
// swap the data if necessary
if (false) {
// is the data fixed size?
if (flags & MSG_FLAG_FIXED_SIZE) {
// make sure to swap the data
status_t status = swap_data(fHeader.type,
(void *)fFlatBuffer.Buffer(), fHeader.dataSize, B_SWAP_ALWAYS);
if (status < B_OK)
throw status;
} else if (fHeader.type == B_REF_TYPE) {
// apparently, entry_refs are the only variable-length data
// explicitely swapped -- the dev_t and ino_t specifically
// ToDo: this looks broken
byte_swap(*(entry_ref *)fFlatBuffer.Buffer());
}
}
}
void
BMessageField::ResetHeader(const char *name, type_code type)
{
memset(&fHeader, 0, sizeof(fHeader));
fHeader.flags |= MSG_FLAG_VALID;
fHeader.type = type;
SetName(name);
}
void
BMessageField::MakeEmpty()
{
fFlatBuffer.SetSize(0);
if (fOffsets)
fOffsets->MakeEmpty();
fHeader.dataSize = 0;
fHeader.count = 0;
}
status_t
BMessageField::SetFixedSize(int32 itemSize, int32 /*count*/)
{
// ToDo: use count here to preallocate the buffer
if (fHeader.count > 0 && itemSize != fItemSize) {
debugger("not allowed\n");
return B_BAD_VALUE;
}
fItemSize = itemSize;
fHeader.flags |= MSG_FLAG_FIXED_SIZE;
return B_OK;
}
void
BMessageField::SetName(const char *name)
{
fName = name;
// the name length field is only 1 byte long
// ToDo: change this? (BC problem)
fName.Truncate(255 - 1);
fHeader.nameLength = min_c(strlen(name), 254);
memcpy(fHeader.name, name, fHeader.nameLength);
}
void
BMessageField::AddItem(BSimpleMallocIO *item)
void *
BMessageField::AddItem(size_t length)
{
fItems.AddItem((void *)item);
fTotalSize += ROUND_TO_8(item->BufferLength());
fHeader.count++;
int32 offset = fFlatBuffer.BufferLength();
if (fHeader.flags & MSG_FLAG_FIXED_SIZE) {
fHeader.dataSize += length;
fFlatBuffer.SetSize(offset + length);
return (char *)fFlatBuffer.Buffer() + offset;
}
if (!fOffsets)
fOffsets = new BList();
fOffsets->AddItem((void *)offset);
size_t newLength = round_to_8(length);
fHeader.dataSize += newLength;
FlatResize(offset, 0, newLength);
fFlatBuffer.WriteAt(offset, &length, sizeof(length));
return (char *)fFlatBuffer.Buffer() + offset + sizeof(newLength);
}
void
BMessageField::ReplaceItem(int32 index, BSimpleMallocIO *item)
void *
BMessageField::ReplaceItem(int32 index, size_t newLength)
{
BSimpleMallocIO *oldItem = (BSimpleMallocIO *)fItems.ItemAt(index);
fItems.ReplaceItem(index, item);
if (fHeader.flags & MSG_FLAG_FIXED_SIZE)
return (char *)fFlatBuffer.Buffer() + (index * fItemSize);
fTotalSize -= ROUND_TO_8(oldItem->BufferLength());
fTotalSize += ROUND_TO_8(item->BufferLength());
int32 offset = (int32)fOffsets->ItemAt(index);
delete oldItem;
size_t oldLength;
fFlatBuffer.ReadAt(offset, &oldLength, sizeof(oldLength));
fFlatBuffer.WriteAt(offset, &newLength, sizeof(newLength));
oldLength = round_to_8(oldLength);
newLength = round_to_8(newLength);
if (oldLength == newLength)
return (char *)fFlatBuffer.Buffer() + offset + sizeof(newLength);
FlatResize(offset, oldLength, newLength);
fHeader.dataSize += newLength - oldLength;
return (char *)fFlatBuffer.Buffer() + offset + sizeof(newLength);
}
void
BMessageField::RemoveItem(int32 index)
{
BSimpleMallocIO *item = (BSimpleMallocIO *)fItems.RemoveItem(index);
fTotalSize -= ROUND_TO_8(item->BufferLength());
delete item;
}
fHeader.count--;
if (fHeader.flags & MSG_FLAG_FIXED_SIZE) {
FlatResize(index * fItemSize, fItemSize, 0);
fHeader.dataSize -= fItemSize;
return;
}
size_t
BMessageField::SizeAt(int32 index) const
{
BSimpleMallocIO *buffer = (BSimpleMallocIO *)fItems.ItemAt(index);
size_t oldLength;
int32 offset = (int32)fOffsets->ItemAt(index);
fFlatBuffer.ReadAt(offset, &oldLength, sizeof(oldLength));
oldLength = round_to_8(oldLength);
if (buffer)
return buffer->BufferLength();
return 0;
FlatResize(offset, oldLength, 0);
fHeader.dataSize -= oldLength;
}
const void *
BMessageField::BufferAt(int32 index) const
BMessageField::BufferAt(int32 index, ssize_t *size) const
{
BSimpleMallocIO *buffer = (BSimpleMallocIO *)fItems.ItemAt(index);
if (fHeader.flags & MSG_FLAG_FIXED_SIZE) {
if (size)
*size = fItemSize;
if (buffer)
return buffer->Buffer();
return (char *)fFlatBuffer.Buffer() + (index * fItemSize);
}
return NULL;
int32 offset = (int32)fOffsets->ItemAt(index);
if (size)
fFlatBuffer.ReadAt(offset, size, sizeof(ssize_t));
return (char *)fFlatBuffer.Buffer() + offset + sizeof(ssize_t);
}
@ -173,53 +313,36 @@ BMessageField::PrintToStream() const
}
bool
BMessageField::IsFixedSize(type_code type)
void
BMessageField::FlatResize(int32 offset, size_t oldLength, size_t newLength)
{
switch (type) {
case B_ANY_TYPE:
case B_MESSAGE_TYPE:
case B_MIME_TYPE:
case B_OBJECT_TYPE:
case B_RAW_TYPE:
case B_STRING_TYPE:
case B_ASCII_TYPE: return false;
ssize_t change = newLength - oldLength;
ssize_t bufferLength = fFlatBuffer.BufferLength();
case B_BOOL_TYPE:
case B_CHAR_TYPE:
case B_COLOR_8_BIT_TYPE:
case B_DOUBLE_TYPE:
case B_FLOAT_TYPE:
case B_GRAYSCALE_8_BIT_TYPE:
case B_INT64_TYPE:
case B_INT32_TYPE:
case B_INT16_TYPE:
case B_INT8_TYPE:
case B_MESSENGER_TYPE: // ToDo: test
case B_MONOCHROME_1_BIT_TYPE:
case B_OFF_T_TYPE:
case B_PATTERN_TYPE:
case B_POINTER_TYPE:
case B_POINT_TYPE:
case B_RECT_TYPE:
case B_REF_TYPE: // ToDo: test
case B_RGB_32_BIT_TYPE:
case B_RGB_COLOR_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
case B_UINT64_TYPE:
case B_UINT32_TYPE:
case B_UINT16_TYPE:
case B_UINT8_TYPE: return true;
if (change > 0)
fFlatBuffer.SetSize(bufferLength + change);
// ToDo: test
case B_MEDIA_PARAMETER_TYPE:
case B_MEDIA_PARAMETER_WEB_TYPE:
case B_MEDIA_PARAMETER_GROUP_TYPE: return false;
if (offset == bufferLength) {
// the easy case for adds
return;
}
return false;
ssize_t length = bufferLength - offset - oldLength;
if (length > 0) {
uint8 *location = (uint8 *)fFlatBuffer.Buffer() + offset;
memmove(location + newLength, location + oldLength, length);
}
if (change < 0)
fFlatBuffer.SetSize(bufferLength + change);
for (int32 index = fOffsets->CountItems() - 1; index >= 0; index--) {
int32 oldOffset = (int32)fOffsets->ItemAt(index);
if (oldOffset <= offset)
break;
fOffsets->ReplaceItem(index, (void *)(offset + change));
}
}
} // namespace BPrivate