diff --git a/headers/private/app/MessageBody2.h b/headers/private/app/MessageBody2.h index 5be5bb64c5..354c1cf9a1 100644 --- a/headers/private/app/MessageBody2.h +++ b/headers/private/app/MessageBody2.h @@ -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); diff --git a/headers/private/app/MessageField2.h b/headers/private/app/MessageField2.h index 8e95f8df4a..550f316902 100644 --- a/headers/private/app/MessageField2.h +++ b/headers/private/app/MessageField2.h @@ -11,8 +11,8 @@ #ifndef _MESSAGE_FIELD_H_ #define _MESSAGE_FIELD_H_ +#include #include -#include #include #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; }; diff --git a/src/kits/app/Message2.cpp b/src/kits/app/Message2.cpp index 8ffde92446..e1c0e2a7d7 100644 --- a/src/kits/app/Message2.cpp +++ b/src/kits/app/Message2.cpp @@ -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; } diff --git a/src/kits/app/MessageBody2.cpp b/src/kits/app/MessageBody2.cpp index b1f5096011..de24e0a952 100644 --- a/src/kits/app/MessageBody2.cpp +++ b/src/kits/app/MessageBody2.cpp @@ -9,18 +9,13 @@ /* BMessageBody handles data storage and retrieval for BMessage. */ #include +#include #include #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; diff --git a/src/kits/app/MessageField2.cpp b/src/kits/app/MessageField2.cpp index 40acd73c7c..c3b6a609e8 100644 --- a/src/kits/app/MessageField2.cpp +++ b/src/kits/app/MessageField2.cpp @@ -7,35 +7,52 @@ */ #include +#include #include #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