Added a new BMessageBody and BMessageField implementation and added a version of BMessage to

use it. It is not (yet) included in the build and won't break anything.
As we now only have thin wrappers around the *Data() functions, the templatized implementation does
not make much sense anymore and wouldn't work either.
I started this new implementation to be as clean as possible. Instead of using a std::map and
BDataBuffer it uses BList and BMallocIO. It passes the unit tests and it even seems to be a bit quicker
in some tests (but not as quick as the R5 one).
Flattening/Unflattening does not work yet so you can't use it under Haiku right now. It's completely work in progress (I started it just 4 hours ago).
Shout if you see something completely broken, reviews welcome.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2005-07-20 00:36:50 +00:00
parent 6ff2656c03
commit 1a3441a4a1
5 changed files with 3022 additions and 0 deletions

View File

@ -0,0 +1,71 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageBody handles data storage and retrieval for BMessage. */
#ifndef _MESSAGE_BODY_H_
#define _MESSAGE_BODY_H_
#include <List.h>
#include "MessageField.h"
enum {
B_FLATTENABLE_TYPE = 'FLAT'
};
namespace BPrivate {
class BMessageBody {
public:
BMessageBody();
BMessageBody(const BMessageBody &other);
~BMessageBody();
BMessageBody &operator=(const BMessageBody &other);
status_t GetInfo(type_code typeRequested, int32 which,
char **name, type_code *typeFound,
int32 *countFound = NULL) const;
status_t GetInfo(const char *name, type_code *typeFound,
int32 *countFound = NULL) const;
status_t GetInfo(const char *name, type_code *typeFound,
bool *fixedSize) const;
int32 CountNames(type_code type) const;
bool IsEmpty() const;
ssize_t FlattenedSize() const;
status_t Flatten(BDataIO *stream) const;
status_t AddData(const char *name, BMallocIO *buffer,
type_code type);
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,
BMallocIO *buffer, type_code type);
status_t Rename(const char *oldName, const char *newName);
status_t RemoveName(const char *name);
status_t MakeEmpty();
void PrintToStream() const;
private:
BMessageField *FindData(const char *name, type_code type,
status_t &error) const;
BList fFields;
};
} // namespace BPrivate
#endif // _MESSAGE_BODY_H_

View File

@ -0,0 +1,65 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageField contains the data for indiviual named fields in BMessageBody */
#ifndef _MESSAGE_FIELD_H_
#define _MESSAGE_FIELD_H_
#include <List.h>
#include <String.h>
#include <SupportDefs.h>
#define MSG_FLAG_VALID 0x01
#define MSG_FLAG_MINI_DATA 0x02
#define MSG_FLAG_FIXED_SIZE 0x04
#define MSG_FLAG_SINGLE_ITEM 0x08
#define MSG_FLAG_ALL 0x0F
#define MSG_LAST_ENTRY 0x00
namespace BPrivate {
class BMessageField {
public:
BMessageField(const char *name, type_code type);
~BMessageField();
uint8 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; };
void AddItem(BMallocIO *item);
void ReplaceItem(int32 index, BMallocIO *item,
bool deleteOld = true);
void RemoveItem(int32 index, bool deleteIt = true);
int32 CountItems() const { return fItems.CountItems(); };
size_t SizeAt(int32 index) const;
const void *BufferAt(int32 index) const;
bool IsFixedSize() const { return fFixedSize; };
size_t TotalSize() const { return fTotalSize; };
void PrintToStream() const;
private:
bool IsFixedSize(type_code type);
BString fName;
type_code fType;
BList fItems;
bool fFixedSize;
size_t fTotalSize;
};
} // namespace BPrivate
#endif // _MESSAGE_FIELD_H_

2232
src/kits/app/Message2.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,477 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageBody handles data storage and retrieval for BMessage. */
#include <stdio.h>
#include <DataIO.h>
#include <TypeConstants.h>
#include <MessageBody.h>
namespace BPrivate {
BMessageBody::BMessageBody()
{
}
BMessageBody::BMessageBody(const BMessageBody &other)
{
*this = other;
}
BMessageBody::~BMessageBody()
{
MakeEmpty();
}
BMessageBody &
BMessageBody::operator=(const BMessageBody &other)
{
if (this != &other) {
MakeEmpty();
for (int32 index = 0; index < other.fFields.CountItems(); index++) {
BMessageField *otherField = (BMessageField *)other.fFields.ItemAt(index);
BMessageField *newField = new BMessageField(*otherField);
fFields.AddItem((void *)newField);
}
}
return *this;
}
status_t
BMessageBody::GetInfo(type_code typeRequested, int32 which, char **name,
type_code *typeReturned, int32 *count) const
{
int32 index = 0;
int32 fieldCount = fFields.CountItems();
BMessageField *field = NULL;
bool found = false;
for (int32 fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
field = (BMessageField *)fFields.ItemAt(fieldIndex);
if (typeRequested == B_ANY_TYPE || field->Type() == typeRequested) {
if (index == which) {
found = true;
break;
}
index++;
}
}
// we couldn't find any appropriate data
if (!found) {
if (count)
*count = 0;
if (index > 0)
return B_BAD_INDEX;
else
return B_BAD_TYPE;
}
// ToDo: BC Break
// Change 'name' parameter to const char *
if (name)
*name = const_cast<char *>(field->Name());
if (typeReturned)
*typeReturned = field->Type();
if (count)
*count = field->CountItems();
return B_OK;
}
status_t
BMessageBody::GetInfo(const char *name, type_code *typeFound,
int32 *countFound) const
{
status_t error = B_OK;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (typeFound)
*typeFound = field->Type();
if (countFound)
*countFound = field->CountItems();
} else {
if (countFound)
*countFound = 0;
}
return error;
}
status_t
BMessageBody::GetInfo(const char *name, type_code *typeFound, bool *fixedSize) const
{
status_t error = B_OK;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (typeFound)
*typeFound = field->Type();
if (fixedSize)
*fixedSize = field->IsFixedSize();
}
return error;
}
int32
BMessageBody::CountNames(type_code type) const
{
if (type == B_ANY_TYPE) {
return fFields.CountItems();
}
int32 count = 0;
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.ItemAt(index);
if (field->Type() == type)
count++;
}
return count;
}
bool
BMessageBody::IsEmpty() const
{
return fFields.CountItems() == 0;
}
void
BMessageBody::PrintToStream() const
{
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.ItemAt(index);
field->PrintToStream();
printf("\n");
}
}
status_t
BMessageBody::Rename(const char *oldName, const char *newName)
{
status_t error = B_OK;
BMessageField *field = FindData(oldName, B_ANY_TYPE, error);
if (!field)
return B_NAME_NOT_FOUND;
field->SetName(newName);
return B_OK;
}
ssize_t
BMessageBody::FlattenedSize() const
{
ssize_t size = 1; // for MSG_LAST_ENTRY
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.ItemAt(index);
size += field->TotalSize();
size += field->NameLength();
// ToDo: too expensive?
uint8 flags = field->Flags();
size += sizeof(flags);
// count information
if (!(flags & MSG_FLAG_SINGLE_ITEM)) {
if (flags & MSG_FLAG_MINI_DATA)
size += sizeof(uint8);
else
size += sizeof(int32);
}
// total size
if (flags & MSG_FLAG_MINI_DATA)
size += sizeof(uint8);
else
size += sizeof(size_t);
// individual sizes
if (!(flags & MSG_FLAG_FIXED_SIZE))
size += field->CountItems() * sizeof(size_t);
}
return size;
}
status_t
BMessageBody::Flatten(BDataIO *stream) const
{
status_t error = B_OK;
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.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));
}
bool isFixed = flags & MSG_FLAG_FIXED_SIZE;
// overall data size
size_t size = field->TotalSize();
printf("totalsize: %ld\n", size);
if (!isFixed) {
// add bytes for holding each items size
size += count * sizeof(size_t);
// ToDo: add padding here
}
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);
// if we have a fixed size we initialize size once here
if (isFixed)
size = field->SizeAt(0);
// data items
for (int32 dataIndex = 0; dataIndex < count; dataIndex++) {
if (!isFixed) {
// set the size for each item
size = field->SizeAt(dataIndex);
stream->Write(&size, sizeof(size));
}
error = stream->Write(field->BufferAt(dataIndex), size);
// ToDo: add padding here too
}
}
if (error >= B_OK) {
error = stream->Write('\0', 1); // MSG_LAST_ENTRY
}
if (error >= B_OK)
return B_OK;
return error;
}
status_t
BMessageBody::AddData(const char *name, BMallocIO *buffer, type_code type)
{
status_t error = B_OK;
BMessageField *foundField = FindData(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
return error;
}
}
if (!foundField) {
// add a new field if it's not yet present
BMessageField *newField = new BMessageField(name, type);
newField->AddItem(buffer);
fFields.AddItem(newField);
} else {
// add to the existing field otherwise
foundField->AddItem(buffer);
}
return error;
}
status_t
BMessageBody::ReplaceData(const char *name, int32 index, BMallocIO *buffer,
type_code type)
{
if (type == B_ANY_TYPE)
return B_BAD_VALUE;
status_t error = B_OK;
BMessageField *field = FindData(name, type, error);
if (error < B_OK)
return error;
if (!field)
return B_ERROR;
field->ReplaceItem(index, buffer);
return error;
}
status_t
BMessageBody::RemoveData(const char *name, int32 index)
{
if (index < 0) {
return B_BAD_VALUE;
}
status_t error = B_OK;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (index < field->CountItems()) {
field->RemoveItem(index);
if (field->CountItems() == 0) {
RemoveName(name);
}
} else
error = B_BAD_INDEX;
}
return error;
}
status_t
BMessageBody::RemoveName(const char *name)
{
status_t error = B_OK;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
fFields.RemoveItem(field);
delete field;
}
return error;
}
status_t
BMessageBody::MakeEmpty()
{
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.ItemAt(index);
delete field;
}
fFields.MakeEmpty();
return B_OK;
}
bool
BMessageBody::HasData(const char *name, type_code type, int32 n) const
{
if (!name || n < 0)
return false;
status_t error;
BMessageField *field = FindData(name, type, error);
if (!field)
return false;
if (n >= field->CountItems())
return false;
return true;
}
status_t
BMessageBody::FindData(const char *name, type_code type, int32 index,
const void **data, ssize_t *numBytes) const
{
status_t error = B_OK;
*data = NULL;
BMessageField *field = FindData(name, type, error);
if (error >= B_OK) {
if (index >= field->CountItems())
return B_BAD_INDEX;
if (data)
*data = field->BufferAt(index);
if (numBytes)
*numBytes = field->SizeAt(index);
}
return error;
}
BMessageField *
BMessageBody::FindData(const char *name, type_code type, status_t &error) const
{
if (!name) {
error = B_BAD_VALUE;
return NULL;
}
for (int32 index = 0; index < fFields.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFields.ItemAt(index);
if (strcmp(name, field->Name()) == 0) {
if (type != B_ANY_TYPE && field->Type() != type) {
error = B_BAD_TYPE;
return NULL;
}
error = B_OK;
return field;
}
}
error = B_NAME_NOT_FOUND;
return NULL;
}
} // namespace BPrivate

View File

@ -0,0 +1,177 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include <DataIO.h>
#include <TypeConstants.h>
#include "MessageField.h"
namespace BPrivate {
BMessageField::BMessageField(const char *name, type_code type)
: fType(type),
fTotalSize(0)
{
SetName(name);
fFixedSize = IsFixedSize(type);
}
BMessageField::~BMessageField()
{
for (int32 index = 0; index < fItems.CountItems(); index++) {
BMallocIO *item = (BMallocIO *)fItems.ItemAt(index);
delete item;
}
fItems.MakeEmpty();
}
uint8
BMessageField::Flags()
{
uint8 flags = MSG_FLAG_VALID;
if (fItems.CountItems() == 1)
flags |= MSG_FLAG_SINGLE_ITEM;
if (fTotalSize < 255)
flags |= MSG_FLAG_MINI_DATA;
if (fFixedSize)
flags |= MSG_FLAG_FIXED_SIZE;
return flags;
}
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);
}
void
BMessageField::AddItem(BMallocIO *item)
{
fItems.AddItem((void *)item);
fTotalSize += item->BufferLength();
}
void
BMessageField::ReplaceItem(int32 index, BMallocIO *item, bool deleteOld)
{
BMallocIO *oldItem = (BMallocIO *)fItems.ItemAt(index);
fTotalSize -= oldItem->BufferLength();
fItems.ReplaceItem(index, item);
fTotalSize += item->BufferLength();
if (deleteOld)
delete oldItem;
}
void
BMessageField::RemoveItem(int32 index, bool deleteIt)
{
BMallocIO *item = (BMallocIO *)fItems.ItemAt(index);
fTotalSize -= item->BufferLength();
if (deleteIt)
delete item;
}
size_t
BMessageField::SizeAt(int32 index) const
{
BMallocIO *buffer = (BMallocIO *)fItems.ItemAt(index);
if (buffer)
return buffer->BufferLength();
return 0;
}
const void *
BMessageField::BufferAt(int32 index) const
{
BMallocIO *buffer = (BMallocIO *)fItems.ItemAt(index);
if (buffer)
return buffer->Buffer();
return NULL;
}
void
BMessageField::PrintToStream() const
{
// ToDo: implement
}
bool
BMessageField::IsFixedSize(type_code type)
{
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;
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;
// ToDo: test
case B_MEDIA_PARAMETER_TYPE:
case B_MEDIA_PARAMETER_WEB_TYPE:
case B_MEDIA_PARAMETER_GROUP_TYPE: return false;
}
return false;
}
} // namespace BPrivate