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:
parent
0401007080
commit
54ca2a11db
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user