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
+5 -4
View File
@@ -43,16 +43,17 @@ public:
status_t Flatten(BDataIO *stream) const; status_t Flatten(BDataIO *stream) const;
status_t Unflatten(BDataIO *stream); status_t Unflatten(BDataIO *stream);
status_t AddData(const char *name, BSimpleMallocIO *buffer, status_t AddData(const char *name, type_code type,
type_code type); size_t length, void **buffer,
bool fixedSize = false, int32 count = 1);
status_t RemoveData(const char *name, int32 index = 0); status_t RemoveData(const char *name, int32 index = 0);
bool HasData(const char *name, type_code t, int32 n) const; bool HasData(const char *name, type_code t, int32 n) const;
status_t FindData(const char *name, type_code type, status_t FindData(const char *name, type_code type,
int32 index, const void **data, int32 index, const void **data,
ssize_t *numBytes) const; ssize_t *numBytes) const;
status_t ReplaceData(const char *name, int32 index, status_t ReplaceData(const char *name, type_code type,
BSimpleMallocIO *buffer, type_code type); int32 index, size_t length, void **buffer);
status_t Rename(const char *oldName, const char *newName); status_t Rename(const char *oldName, const char *newName);
status_t RemoveName(const char *name); status_t RemoveName(const char *name);
+37 -21
View File
@@ -11,8 +11,8 @@
#ifndef _MESSAGE_FIELD_H_ #ifndef _MESSAGE_FIELD_H_
#define _MESSAGE_FIELD_H_ #define _MESSAGE_FIELD_H_
#include <DataIO.h>
#include <List.h> #include <List.h>
#include <String.h>
#include <SupportDefs.h> #include <SupportDefs.h>
#define MSG_FLAG_VALID 0x01 #define MSG_FLAG_VALID 0x01
@@ -25,36 +25,47 @@
namespace BPrivate { 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 { class BMessageField {
public: public:
BMessageField(); BMessageField();
BMessageField(const char *name, type_code type); BMessageField(const char *name, type_code type);
BMessageField(uint8 flags, BDataIO *stream);
BMessageField(const BMessageField &other); BMessageField(const BMessageField &other);
~BMessageField(); ~BMessageField();
BMessageField &operator=(const BMessageField &other); 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); void SetName(const char *name);
const char *Name() const { return fName.String(); }; const char *Name() const { return fHeader.name; };
uint8 NameLength() const { return fName.Length(); }; uint8 NameLength() const { return fHeader.nameLength; };
type_code Type() const { return fType; }; type_code Type() const { return fHeader.type; };
void AddItem(BSimpleMallocIO *item); void *AddItem(size_t length);
void ReplaceItem(int32 index, BSimpleMallocIO *item); void *ReplaceItem(int32 index, size_t newLength);
void RemoveItem(int32 index); void RemoveItem(int32 index);
int32 CountItems() const { return fItems.CountItems(); }; int32 CountItems() const { return fHeader.count; };
size_t SizeAt(int32 index) const;
const void *BufferAt(int32 index) const; const void *BufferAt(int32 index, ssize_t *size) const;
void MakeEmpty(); void MakeEmpty();
bool IsFixedSize() const { return fFixedSize; }; status_t SetFixedSize(int32 itemSize, int32 count);
size_t TotalSize() const { return fTotalSize; }; bool IsFixedSize() const { return fHeader.flags & MSG_FLAG_FIXED_SIZE; };
size_t TotalPadding() const { return fTotalPadding; }; size_t TotalSize() const { return fHeader.dataSize; };
void PrintToStream() const; void PrintToStream() const;
@@ -63,15 +74,20 @@ public:
BMessageField *Next() const { return fNext; }; BMessageField *Next() const { return fNext; };
private: 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; FieldHeader fHeader;
type_code fType; mutable BMallocIO fFlatBuffer;
BList fItems;
bool fFixedSize;
size_t fTotalSize;
size_t fTotalPadding;
// fixed size items
int32 fItemSize;
// variable sized items
BList *fOffsets;
// hash table support
BMessageField *fNext; BMessageField *fNext;
}; };
+69 -62
View File
@@ -39,7 +39,6 @@
#include "MessageBody2.h" #include "MessageBody2.h"
#include "MessageField2.h" #include "MessageField2.h"
#include "MessageUtils2.h" #include "MessageUtils2.h"
#include "SimpleMallocIO.h"
#include "dano_message.h" #include "dano_message.h"
// flags for the overall message (the bitfield is 1 byte) // flags for the overall message (the bitfield is 1 byte)
@@ -82,6 +81,22 @@ static status_t convert_message(const KMessage *fromMessage,
BMessage *toMessage); BMessage *toMessage);
static ssize_t min_hdr_size(); 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 { class BMessage::Header {
public: public:
@@ -1028,7 +1043,7 @@ BMessage::PopSpecifier()
status_t \ status_t \
BMessage::Add ## fnName(const char *name, TYPE val) \ 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 \ status_t \
@@ -1122,44 +1137,46 @@ DEFINE_LAZY_FIND_FUNCTION(const char *, String);
status_t status_t
BMessage::AddString(const char *name, const char *string) 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 status_t
BMessage::AddString(const char* name, const BString &string) 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 status_t
BMessage::AddPointer(const char *name, const void *pointer) 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 status_t
BMessage::AddMessenger(const char *name, BMessenger messenger) 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 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; size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
BSimpleMallocIO *buffer = new BSimpleMallocIO(size); char flatRef[size];
status_t error = entry_ref_flatten(buffer->Buffer(), &size, ref); status_t error = entry_ref_flatten(flatRef, &size, ref);
buffer->SetSize(size);
if (error >= B_OK)
error = fBody->AddData(name, buffer, B_REF_TYPE);
if (error < B_OK) 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; return error;
} }
@@ -1169,16 +1186,14 @@ status_t
BMessage::AddMessage(const char *name, const BMessage *msg) BMessage::AddMessage(const char *name, const BMessage *msg)
{ {
size_t size = msg->FlattenedSize(); size_t size = msg->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = msg->Flatten(buffer->Buffer(), size);
if (error >= B_OK) void *buffer;
error = fBody->AddData(name, buffer, B_MESSAGE_TYPE); status_t error = fBody->AddData(name, B_MESSAGE_TYPE, size, &buffer, false);
if (error < B_OK) 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) BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
{ {
ssize_t size = object->FlattenedSize(); ssize_t size = object->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = object->Flatten(buffer->Buffer(), size);
if (error >= B_OK) void *buffer;
error = fBody->AddData(name, buffer, object->TypeCode()); status_t error = fBody->AddData(name, object->TypeCode(), size, &buffer, false);
if (error < B_OK) if (error < B_OK)
delete buffer; return error;
return error; return object->Flatten(buffer, size);
} }
status_t status_t
BMessage::AddData(const char *name, type_code type, const void *data, 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 void *buffer;
// In particular, we want to see what happens if is_fixed_size == true and status_t error = fBody->AddData(name, type, numBytes, &buffer, is_fixed_size, count);
// 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);
if (error < B_OK) 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) BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
{ {
size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH; size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
BSimpleMallocIO *buffer = new BSimpleMallocIO(size); char flatRef[size];
status_t error = entry_ref_flatten(buffer->Buffer(), &size, ref); status_t error = entry_ref_flatten(flatRef, &size, ref);
buffer->SetSize(size);
if (error >= B_OK)
error = fBody->ReplaceData(name, index, buffer, B_REF_TYPE);
if (error < B_OK) 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) BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *msg)
{ {
size_t size = msg->FlattenedSize(); size_t size = msg->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = msg->Flatten(buffer->Buffer(), size);
if (error >= B_OK) void *buffer;
error = fBody->ReplaceData(name, index, buffer, B_MESSAGE_TYPE); status_t error = fBody->ReplaceData(name, B_MESSAGE_TYPE, index, size, &buffer);
if (error < B_OK) 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) BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
{ {
ssize_t size = object->FlattenedSize(); ssize_t size = object->FlattenedSize();
BSimpleMallocIO *buffer = new BSimpleMallocIO(size);
status_t error = object->Flatten(buffer->Buffer(), size);
if (error >= B_OK) void *buffer;
error = fBody->ReplaceData(name, index, buffer, object->TypeCode()); status_t error = fBody->ReplaceData(name, object->TypeCode(), index, size, &buffer);
if (error < B_OK) 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, BMessage::ReplaceData(const char *name, type_code type, int32 index,
const void *data, ssize_t data_size) const void *data, ssize_t data_size)
{ {
BSimpleMallocIO *buffer = new BSimpleMallocIO(data_size); void *buffer;
buffer->Write(data); status_t error = fBody->ReplaceData(name, type, index, data_size, &buffer);
status_t error = fBody->ReplaceData(name, index, buffer, type);
if (error < B_OK) if (error < B_OK)
delete buffer; return error;
return error; memcpy(buffer, data, data_size);
return B_OK;
} }
+22 -164
View File
@@ -9,18 +9,13 @@
/* BMessageBody handles data storage and retrieval for BMessage. */ /* BMessageBody handles data storage and retrieval for BMessage. */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <TypeConstants.h> #include <TypeConstants.h>
#include "MessageBody2.h" #include "MessageBody2.h"
#include "MessageUtils2.h" #include "MessageUtils2.h"
#include "SimpleMallocIO.h"
namespace BPrivate { 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() BMessageBody::BMessageBody()
{ {
InitCommon(); InitCommon();
@@ -254,55 +249,8 @@ BMessageBody::FlattenedSize() const
status_t status_t
BMessageBody::Flatten(BDataIO *stream) const BMessageBody::Flatten(BDataIO *stream) const
{ {
for (int32 index = 0; index < fFieldList.CountItems(); index++) { for (int32 index = 0; index < fFieldList.CountItems(); index++)
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index); ((BMessageField *)fFieldList.ItemAt(index))->Flatten(stream);
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));
}
}
}
uint8 lastEntry = 0; uint8 lastEntry = 0;
size_t error = stream->Write(&lastEntry, sizeof(lastEntry)); size_t error = stream->Write(&lastEntry, sizeof(lastEntry));
@@ -322,95 +270,21 @@ BMessageBody::Unflatten(BDataIO *stream)
if (!IsEmpty()) if (!IsEmpty())
MakeEmpty(); MakeEmpty();
BMessageField *newField = NULL;
try { try {
TReadHelper reader(stream); TReadHelper reader(stream);
char name[255];
uint8 flags; uint8 flags;
reader(flags); reader(flags);
while (flags != MSG_LAST_ENTRY) { while (flags != MSG_LAST_ENTRY) {
type_code type; newField = new BMessageField(flags, stream);
reader(type); fFieldList.AddItem(newField);
HashInsert(newField);
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);
}
}
reader(flags); reader(flags);
} }
} catch (status_t &error) { } catch (status_t &error) {
delete newField;
return error; return error;
} }
@@ -419,34 +293,22 @@ BMessageBody::Unflatten(BDataIO *stream)
status_t 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; status_t error = B_OK;
BMessageField *foundField = FindData(name, type, error); BMessageField *newField = AddField(name, type, error);
if (error < B_OK) { if (error < B_OK)
if (error == B_NAME_NOT_FOUND) { return error;
// reset the error - we will create the field
error = B_OK; if (fixedSize) {
} else { error = newField->SetFixedSize(length, count);
// looking for B_BAD_TYPE here in particular, which would indicate if (error < B_OK)
// that we tried to add data of type X when we already had data of
// type Y with the same name
return error; 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; fFlattenedSize = -1;
return error; return error;
} }
@@ -476,8 +338,8 @@ BMessageBody::AddField(const char *name, type_code type, status_t &error)
status_t status_t
BMessageBody::ReplaceData(const char *name, int32 index, BSimpleMallocIO *buffer, BMessageBody::ReplaceData(const char *name, type_code type, int32 index,
type_code type) size_t length, void **buffer)
{ {
if (type == B_ANY_TYPE) if (type == B_ANY_TYPE)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -491,7 +353,7 @@ BMessageBody::ReplaceData(const char *name, int32 index, BSimpleMallocIO *buffer
if (!field) if (!field)
return B_ERROR; return B_ERROR;
field->ReplaceItem(index, buffer); *buffer = field->ReplaceItem(index, length);
fFlattenedSize = -1; fFlattenedSize = -1;
return error; return error;
} }
@@ -584,11 +446,7 @@ BMessageBody::FindData(const char *name, type_code type, int32 index,
if (index >= field->CountItems()) if (index >= field->CountItems())
return B_BAD_INDEX; return B_BAD_INDEX;
if (data) *data = field->BufferAt(index, numBytes);
*data = field->BufferAt(index);
if (numBytes)
*numBytes = field->SizeAt(index);
} }
return error; return error;
+234 -111
View File
@@ -7,35 +7,52 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <TypeConstants.h> #include <TypeConstants.h>
#include "MessageField2.h" #include "MessageField2.h"
#include "SimpleMallocIO.h" #include "MessageUtils2.h"
namespace BPrivate { 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() BMessageField::BMessageField()
: fType(0), : fItemSize(0),
fFixedSize(false), fOffsets(NULL),
fTotalSize(0),
fNext(NULL) fNext(NULL)
{ {
SetName(""); ResetHeader("", 0);
} }
BMessageField::BMessageField(const char *name, type_code type) BMessageField::BMessageField(const char *name, type_code type)
: fType(type), : fItemSize(0),
fTotalSize(0), fOffsets(NULL),
fNext(NULL) fNext(NULL)
{ {
SetName(name); ResetHeader(name, type);
fFixedSize = IsFixedSize(type); }
BMessageField::BMessageField(uint8 flags, BDataIO *stream)
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{
Unflatten(flags, stream);
} }
BMessageField::BMessageField(const BMessageField &other) BMessageField::BMessageField(const BMessageField &other)
: fItemSize(0),
fOffsets(NULL),
fNext(NULL)
{ {
*this = other; *this = other;
} }
@@ -52,18 +69,20 @@ BMessageField::operator=(const BMessageField &other)
{ {
if (this != &other) { if (this != &other) {
MakeEmpty(); MakeEmpty();
fName = other.fName;
fType = other.fType;
fFixedSize = other.fFixedSize;
fTotalSize = other.fTotalSize;
fNext = NULL; fNext = NULL;
for (int32 index = 0; index < other.fItems.CountItems(); index++) { memcpy(&fHeader, &other.fHeader, sizeof(FieldHeader));
BSimpleMallocIO *otherBuffer = (BSimpleMallocIO *)other.fItems.ItemAt(index);
BSimpleMallocIO *newBuffer = new BSimpleMallocIO(otherBuffer->BufferLength()); fFlatBuffer.Write(other.fFlatBuffer.Buffer(), other.fFlatBuffer.BufferLength());
newBuffer->Write(otherBuffer->Buffer());
fItems.AddItem((void *)newBuffer); 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 void
BMessageField::MakeEmpty() BMessageField::Flatten(BDataIO *stream)
{ {
for (int32 index = 0; index < fItems.CountItems(); index++) { // write flat header including name
BSimpleMallocIO *item = (BSimpleMallocIO *)fItems.ItemAt(index); stream->Write(&fHeader, sizeof(fHeader) - sizeof(fHeader.name) + fHeader.nameLength);
delete item;
}
fItems.MakeEmpty(); // write flat data
stream->Write(fFlatBuffer.Buffer(), fHeader.dataSize);
} }
uint8 void
BMessageField::Flags() BMessageField::Unflatten(uint8 flags, BDataIO *stream)
{ {
uint8 flags = MSG_FLAG_VALID; TReadHelper reader(stream);
if (fItems.CountItems() == 1) // read the header
flags |= MSG_FLAG_SINGLE_ITEM; 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) if (flags & MSG_FLAG_SINGLE_ITEM) {
flags |= MSG_FLAG_MINI_DATA; fHeader.count = 1;
if (fFixedSize) if (flags & MSG_FLAG_MINI_DATA) {
flags |= MSG_FLAG_FIXED_SIZE; 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 void
BMessageField::SetName(const char *name) BMessageField::SetName(const char *name)
{ {
fName = name; fHeader.nameLength = min_c(strlen(name), 254);
memcpy(fHeader.name, name, fHeader.nameLength);
// the name length field is only 1 byte long
// ToDo: change this? (BC problem)
fName.Truncate(255 - 1);
} }
void void *
BMessageField::AddItem(BSimpleMallocIO *item) BMessageField::AddItem(size_t length)
{ {
fItems.AddItem((void *)item); fHeader.count++;
fTotalSize += ROUND_TO_8(item->BufferLength());
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 void *
BMessageField::ReplaceItem(int32 index, BSimpleMallocIO *item) BMessageField::ReplaceItem(int32 index, size_t newLength)
{ {
BSimpleMallocIO *oldItem = (BSimpleMallocIO *)fItems.ItemAt(index); if (fHeader.flags & MSG_FLAG_FIXED_SIZE)
fItems.ReplaceItem(index, item); return (char *)fFlatBuffer.Buffer() + (index * fItemSize);
fTotalSize -= ROUND_TO_8(oldItem->BufferLength()); int32 offset = (int32)fOffsets->ItemAt(index);
fTotalSize += ROUND_TO_8(item->BufferLength());
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 void
BMessageField::RemoveItem(int32 index) BMessageField::RemoveItem(int32 index)
{ {
BSimpleMallocIO *item = (BSimpleMallocIO *)fItems.RemoveItem(index); fHeader.count--;
fTotalSize -= ROUND_TO_8(item->BufferLength());
delete item;
}
if (fHeader.flags & MSG_FLAG_FIXED_SIZE) {
FlatResize(index * fItemSize, fItemSize, 0);
fHeader.dataSize -= fItemSize;
return;
}
size_t size_t oldLength;
BMessageField::SizeAt(int32 index) const int32 offset = (int32)fOffsets->ItemAt(index);
{ fFlatBuffer.ReadAt(offset, &oldLength, sizeof(oldLength));
BSimpleMallocIO *buffer = (BSimpleMallocIO *)fItems.ItemAt(index); oldLength = round_to_8(oldLength);
if (buffer) FlatResize(offset, oldLength, 0);
return buffer->BufferLength(); fHeader.dataSize -= oldLength;
return 0;
} }
const void * 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 (char *)fFlatBuffer.Buffer() + (index * fItemSize);
return buffer->Buffer(); }
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 void
BMessageField::IsFixedSize(type_code type) BMessageField::FlatResize(int32 offset, size_t oldLength, size_t newLength)
{ {
switch (type) { ssize_t change = newLength - oldLength;
case B_ANY_TYPE: ssize_t bufferLength = fFlatBuffer.BufferLength();
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;
case B_BOOL_TYPE: if (change > 0)
case B_CHAR_TYPE: fFlatBuffer.SetSize(bufferLength + change);
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;
// ToDo: test if (offset == bufferLength) {
case B_MEDIA_PARAMETER_TYPE: // the easy case for adds
case B_MEDIA_PARAMETER_WEB_TYPE: return;
case B_MEDIA_PARAMETER_GROUP_TYPE: return false;
} }
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 } // namespace BPrivate