haiku/headers/private/app/MessageField.h
ejakowatz f936fa1261 A number of bug fixes. In particular:
-	only one byte was being used for total data length in a data field
	which had 'maxi' size data (total data > 255 bytes), rather than the
	correct four bytes.
-	Seem to have finally nailed the proper algorithm for calculating data
	item padding (four size bytes + bytes of data, padded to 8-byte
	boundary) in all places.
-	Was passing the address of the padding string, rather than the string
	itself, when writing out NULL padding bytes
-	Was incorrectly clearing the MSG_FLAG_MINI_DATA bit when the number of
	data items or the size of the largest data item exceeding 256 bytes.
	Bit is now cleared when total size of all item data (including size
	bytes and padding, if applicable) exceeds 256 bytes
-	Modified SizePolicy::Padding(const T&) to use calc_padding() from
	MessageUtils.h/.cpp
-	Added SizePolicy::Padding(const Store&) to calculate padding for data
	field's entire data store


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9743 a95241bf-73f2-0310-859d-f6bbb57e9c96
2004-11-02 21:35:28 +00:00

789 lines
21 KiB
C++

//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: MessageField.h
// Author(s): Erik Jaesler (erik@cgsoftware.com)
// Description: BMessageField contains and manages the data for indiviual
// named field in BMessageBody
//------------------------------------------------------------------------------
#ifndef MESSAGEFIELD_H
#define MESSAGEFIELD_H
// Standard Includes -----------------------------------------------------------
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <string>
// System Includes -------------------------------------------------------------
#include <Entry.h>
#include <Path.h>
#include <Point.h>
#include <Rect.h>
#include <String.h>
#include <SupportDefs.h>
// Project Includes ------------------------------------------------------------
#include <DataBuffer.h>
#include <MessageUtils.h>
// Local Includes --------------------------------------------------------------
// Local Defines ---------------------------------------------------------------
// flags for each entry (the bitfield is 1 byte)
#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 0x0
// Globals ---------------------------------------------------------------------
namespace BPrivate {
class BMessageField
{
public:
static const char* sNullData;
BMessageField(const std::string& name, type_code t)
: fType(t), fName(name)
{;}
virtual ~BMessageField() {}
virtual const std::string& Name() const { return fName; }
virtual type_code Type() const { return fType; }
virtual bool FixedSize() const { return true; }
virtual ssize_t FlattenedSize() const { return 0; }
virtual status_t Flatten(BDataIO& stream) const = 0;
virtual ssize_t CountItems() const { return 0; }
virtual void RemoveItem(ssize_t index) = 0;
virtual void PrintToStream(const char* name) const;
virtual const void* DataAt(int32 index, ssize_t* size) const = 0;
virtual BMessageField* Clone() const = 0;
protected:
virtual void PrintDataItem(int32 index) const = 0;
private:
type_code fType;
std::string fName;
};
//------------------------------------------------------------------------------
template<class T>
struct BMessageFieldStoragePolicy
{
class Store
{
public:
// Compiler-generated versions should be just fine
#if 0
Store();
Store(const Store& rhs);
~Store();
Store& operator=(const Store& rhs);
#endif
inline size_t Size() const { return fData.size(); }
inline T& operator[](uint index) { return fData[index]; }
inline const T& operator[](uint index) const { return fData[index]; }
inline void Add(const T& data) { fData.push_back(data); }
inline void Remove(uint index) { fData.erase(fData.begin() + index); }
inline void Copy(const Store& rhs) { fData = rhs.fData; }
private:
std::vector<T> fData;
};
};
//------------------------------------------------------------------------------
template<class T>
struct BMessageFieldSizePolicy
{
typedef typename BMessageFieldStoragePolicy<T>::Store Store;
inline static size_t Size(const T&) { return sizeof (T); }
inline static size_t Size(const Store& data)
{
return sizeof (T) * data.Size();
}
inline static bool Fixed() { return true; }
inline static size_t Padding(const T&) { return 0; }
inline static size_t Padding(const Store& data) { return 0; }
};
//------------------------------------------------------------------------------
template<class T>
struct BMessageFieldPrintPolicy
{
static void PrintData(const T& data) {;}
};
//------------------------------------------------------------------------------
template<class T>
struct BMessageFieldFlattenPolicy
{
typedef BMessageFieldSizePolicy<T> SizePolicy;
inline static status_t Flatten(BDataIO& stream, const T& data)
{
return stream.Write((const void*)&data, SizePolicy::Size(data));
}
};
//------------------------------------------------------------------------------
template<class T>
struct BMessageFieldGetDataPolicy
{
inline static const void* GetData(const T* data)
{ return (const void*)data; }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy = BMessageFieldStoragePolicy<T1>,
class SizePolicy = BMessageFieldSizePolicy<T1>,
class PrintPolicy = BMessageFieldPrintPolicy<T1>,
class FlattenPolicy = BMessageFieldFlattenPolicy<T1>,
class GetDataPolicy = BMessageFieldGetDataPolicy<T1>
>
class BMessageFieldImpl : public BMessageField
{
public:
typedef typename StoragePolicy::Store StorageType;
BMessageFieldImpl(const std::string& name, type_code type)
: BMessageField(name, type),
fMaxSize(0),
fFlags(MSG_FLAG_ALL)
{;}
virtual ~BMessageFieldImpl() {}
virtual bool FixedSize() const
{ return fFlags & MSG_FLAG_FIXED_SIZE; }
virtual ssize_t FlattenedSize() const;
virtual status_t Flatten(BDataIO& stream) const;
virtual ssize_t CountItems() const { return fData.Size(); }
virtual void AddItem(const T1& data);
virtual void RemoveItem(ssize_t index)
{ fData.Remove(index); };
virtual const void* DataAt(int32 index, ssize_t* size) const;
virtual BMessageField* Clone() const;
StorageType& Data() { return fData; }
protected:
virtual void PrintDataItem(int32 index) const;
private:
StorageType fData;
size_t fMaxSize;
uchar fFlags;
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
ssize_t
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
FlattenedSize() const
{
// Mandatory stuff
ssize_t size = 1; // field flags byte
size += sizeof (type_code); // field type bytes
if (!(fFlags & MSG_FLAG_SINGLE_ITEM)) // item count byte
{
if (fFlags & MSG_FLAG_MINI_DATA)
++size; // item count byte for mini data
else
size += 4; // item count bytes for maxi data
}
if (fFlags & MSG_FLAG_MINI_DATA)
++size; // data length byte for mini data
else
size += 4; // data length bytes for maxi data
++size; // name length byte
size += Name().length(); // name length
// item data length
size += SizePolicy::Size(fData);
// Calculate any necessary padding
if (!SizePolicy::Fixed())
{
size += 4 * fData.Size();
size += SizePolicy::Padding(fData);
#if 0
for (uint32 i = 0; i < fData.Size(); ++i)
{
// pad to 8-byte boundary, including size bytes in calculation
size += calc_padding(SizePolicy::Size(fData[i]) + 4, 8);
// item size bytes
size += 4;
}
#endif
}
return size;
}
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
status_t
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
Flatten(BDataIO& stream) const
{
status_t err = B_OK;
type_code type = Type();
uint32 count = fData.Size();
uint8 nameLen = Name().length();
size_t size = SizePolicy::Size(fData);
err = stream.Write(&fFlags, sizeof (fFlags));
// Field type_code
if (err >= 0)
err = stream.Write(&type, sizeof (type_code));
// Item count, if more than one
if (err >= 0 && !(fFlags & MSG_FLAG_SINGLE_ITEM))
{
if (fFlags & MSG_FLAG_MINI_DATA)
{
uint8 miniCount = count;
err = stream.Write(&miniCount, sizeof (miniCount));
}
else
{
err = stream.Write(&count, sizeof (count));
}
}
// Data length
if (err >= 0)
{
if (!(fFlags & MSG_FLAG_FIXED_SIZE))
{
// Add the bytes for holding the item size for each item
size += 4 * fData.Size();
size += SizePolicy::Padding(fData);
}
if (fFlags & MSG_FLAG_MINI_DATA)
{
uint8 miniSize = size;
err = stream.Write(&miniSize, sizeof (miniSize));
}
else
{
err = stream.Write(&size, sizeof (size));
}
}
// Name length
if (err >= 0)
err = stream.Write(&nameLen, sizeof (nameLen));
// Name
if (err >= 0)
err = stream.Write(Name().c_str(), Name().length());
// Actual data items
for (uint32 i = 0; i < fData.Size() && err >= 0; ++i)
{
if (!SizePolicy::Fixed())
{
size = (int32)SizePolicy::Size(fData[i]);
err = stream.Write(&size, sizeof (size));
}
if (err >= 0)
{
err = FlattenPolicy::Flatten(stream, fData[i]);
}
if (err >= 0 && !SizePolicy::Fixed())
{
// Add any necessary padding
err = stream.Write(BMessageField::sNullData,
SizePolicy::Padding(fData[i]));
}
}
if (err >= 0)
err = B_OK;
return err;
}
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
void
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
AddItem(const T1& data)
{
fData.Add(data);
if (fMaxSize)
{
if ((fFlags & MSG_FLAG_FIXED_SIZE) &&
(!SizePolicy::Fixed() ||
fMaxSize != SizePolicy::Size(data)))
{
fMaxSize = max(SizePolicy::Size(data), fMaxSize);
fFlags &= ~MSG_FLAG_FIXED_SIZE;
}
}
else
{
if (!SizePolicy::Fixed())
{
fFlags &= ~MSG_FLAG_FIXED_SIZE;
}
fMaxSize = SizePolicy::Size(data);
}
if (fFlags & MSG_FLAG_MINI_DATA)
{
int32 size = SizePolicy::Size(fData);
if (!(fFlags & MSG_FLAG_FIXED_SIZE))
{
size += 4 * fData.Size();
size += SizePolicy::Padding(fData);
}
if (size > 255)
fFlags &= ~MSG_FLAG_MINI_DATA;
}
if (fData.Size() > 1)
fFlags &= ~MSG_FLAG_SINGLE_ITEM;
}
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
const void*
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
DataAt(int32 index, ssize_t* size) const
{
if (index < CountItems())
{
*size = SizePolicy::Size(fData[index]);
const T1& ref = fData[index];
const T1* data = &ref;
return GetDataPolicy::GetData(data);//(const void*)data;
}
return NULL;
}
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
BMessageField*
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
Clone() const
{
BMessageFieldImpl<T1>* BMF =
new(nothrow) BMessageFieldImpl<T1>(Name(), Type());
if (BMF)
{
BMF->fMaxSize = fMaxSize;
BMF->fFlags = fFlags;
BMF->fData.Copy(fData);
}
return BMF;
}
//------------------------------------------------------------------------------
template
<
class T1,
class StoragePolicy,
class SizePolicy,
class PrintPolicy,
class FlattenPolicy,
class GetDataPolicy
>
void
BMessageFieldImpl<T1, StoragePolicy, SizePolicy, PrintPolicy, FlattenPolicy, GetDataPolicy>::
PrintDataItem(int32 index) const
{
if (index && FixedSize())
{
std::printf(" ");
}
else
{
std::printf("size=%2ld, ", SizePolicy::Size(fData[index]));
}
std::printf("data[%ld]: ", index);
PrintPolicy::PrintData(fData[index]);
}
//------------------------------------------------------------------------------
// Print policy specializations ------------------------------------------------
template<> struct BMessageFieldPrintPolicy<bool>
{
static void PrintData(const bool& b) { std::printf("%d", int(b)); }
};
template<> struct BMessageFieldPrintPolicy<int8>
{
static void PrintData(const int8& i)
{ std::printf("0x%X (%d, '%c')", int(i), int(i), char(i)); }
};
template<> struct BMessageFieldPrintPolicy<int16>
{
static void PrintData(const int16& i)
{ std::printf("0x%X (%d, '%c')", i, i, char(i)); }
};
template<> struct BMessageFieldPrintPolicy<int32>
{
static void PrintData(const int32& i)
{ std::printf("0x%lX (%ld, '%c')", i, i, char(i)); }
};
template<> struct BMessageFieldPrintPolicy<int64>
{
static void PrintData(const int64& i)
{ std::printf("0x%LX (%Ld, '%c')", i, i, char(i)); }
};
template<> struct BMessageFieldPrintPolicy<float>
{
static void PrintData(const float& f) { std::printf("%.4f", f); }
};
template<> struct BMessageFieldPrintPolicy<double>
{
static void PrintData(const double& d) { std::printf("%.8f", d); }
};
template<> struct BMessageFieldPrintPolicy<BString>
{
static void PrintData(const BString& s) { std::printf("\"%s\"", s.String()); }
};
template<> struct BMessageFieldPrintPolicy<BPoint>
{
static void PrintData(const BPoint& p) { std::printf("BPoint(x:%.1f, y:%.1f)", p.x, p.y); }
};
template<> struct BMessageFieldPrintPolicy<BRect>
{
static void PrintData(const BRect& r)
{ std::printf("BRect(l:%.1f, t:%.1f, r:%.1f, b:%.1f)", r.left, r.top, r.right, r.bottom); }
};
template<> struct BMessageFieldPrintPolicy<entry_ref>
{
static void PrintData(const entry_ref& ref)
{
std::printf("device=%ld, directory=%Ld, name=\"%s\", path=\"%s\"",
ref.device, ref.directory, ref.name, BPath(&ref).Path());
}
};
// Storage policy specializations ----------------------------------------------
template<>
struct BMessageFieldStoragePolicy<bool>
{
class Store
{
private:
struct Boolean
{
Boolean() : data(bool()) {;}
Boolean(bool b) : data(b) {;}
bool data;
};
public:
inline size_t Size() const
{ return fData.size(); }
inline bool& operator[](uint index)
{ return fData[index].data; }
inline const bool& operator[](uint index) const
{ return fData[index].data; }
inline void Add(const bool& data)
{
fData.push_back(data);
}
inline void Remove(uint index)
{
fData.erase(fData.begin() + index);
}
inline void Copy(const Store& rhs)
{
if (&fData != &rhs.fData)
{
fData = rhs.fData;
}
}
private:
std::vector<Boolean> fData;
};
};
//------------------------------------------------------------------------------
template<>
struct BMessageFieldStoragePolicy<BDataBuffer>
{
class Store
{
public:
inline size_t Size() const
{ return fData.size(); }
inline BDataBuffer& operator[](uint index)
{ return fData[index]; }
inline const BDataBuffer& operator[](uint index) const
{ return fData[index]; }
inline void Add(const BDataBuffer& data)
{ fData.push_back(data); }
inline void Remove(uint index)
{ fData.erase(fData.begin() + index); }
void Copy(const Store& rhs)
{
if (&fData == &rhs.fData)
{
return;
}
fData.clear();
for (size_t i = 0; i < rhs.Size(); ++i)
{
Add(BDataBuffer(rhs[i], true));
}
}
private:
std::vector<BDataBuffer> fData;
};
};
// Size policy specializations -------------------------------------------------
template<> struct BMessageFieldSizePolicy<BString>
{
typedef BMessageFieldStoragePolicy<BString>::Store Store;
inline static size_t Size(const BString& s) { return s.Length() + 1; }
inline static size_t Size(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Size(data[i]);
}
return size;
}
inline static bool Fixed() { return false; }
inline static size_t Padding(const BString& s)
{
// Padding calculations are only done for variable-sized items,
// which by definition have four bytes of size info preceeding the
// actual data; those four bytes are included in the padding
// calculation. Padding is calculated to an 8-byte boundary
return calc_padding(Size(s) + 4, 8);
}
inline static size_t Padding(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Padding(data[i]);
}
return size;
}
};
//------------------------------------------------------------------------------
template<> struct BMessageFieldSizePolicy<BDataBuffer>
{
typedef BMessageFieldStoragePolicy<BDataBuffer>::Store Store;
inline static size_t Size(const BDataBuffer& db)
{ return db.BufferSize(); }
inline static size_t Size(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Size(data[i]);
}
return size;
}
inline static bool Fixed() { return false; }
inline static size_t Padding(const BDataBuffer& db)
{
// Padding calculations are only done for variable-sized items,
// which by definition have four bytes of size info preceeding the
// actual data; those four bytes are included in the padding
// calculation. Padding is calculated to an 8-byte boundary
return calc_padding(Size(db) + 4, 8);
}
inline static size_t Padding(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Padding(data[i]);
}
return size;
}
};
//------------------------------------------------------------------------------
template<> struct BMessageFieldSizePolicy<BMessage*>
{
typedef BMessageFieldStoragePolicy<BMessage*>::Store Store;
inline static size_t Size(const BMessage* msg)
{ return msg->FlattenedSize(); }
inline static size_t Size(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Size(data[i]);
}
return size;
}
inline static bool Fixed() { return false; }
inline static size_t Padding(const BMessage* msg)
{
// Padding calculations are only done for variable-sized items,
// which by definition have four bytes of size info preceeding the
// actual data; those four bytes are included in the padding
// calculation. Padding is calculated to an 8-byte boundary
return calc_padding(Size(msg) + 4, 8);
}
inline static size_t Padding(const Store& data)
{
size_t size = 0;
for (uint32 i = 0; i < data.Size(); ++i)
{
size += Padding(data[i]);
}
return size;
}
};
// Flatten policy specializations ----------------------------------------------
template<>
struct BMessageFieldFlattenPolicy<BString>
{
typedef BMessageFieldSizePolicy<BString> SizePolicy;
static status_t Flatten(BDataIO& stream, const BString& data)
{
size_t size = SizePolicy::Size(data);
status_t err = stream.Write((const void*)data.String(), size);
if (err > 0)
err = B_OK;
return err;
}
};
//------------------------------------------------------------------------------
template<>
struct BMessageFieldFlattenPolicy<BMessage*>
{
typedef BMessageFieldSizePolicy<BMessage*> SizePolicy;
static status_t Flatten(BDataIO& stream, const BMessage* data)
{
status_t err = data->Flatten(&stream);
if (err > 0)
err = B_OK;
return err;
}
};
//------------------------------------------------------------------------------
template<>
struct BMessageFieldFlattenPolicy<BDataBuffer>
{
typedef BMessageFieldSizePolicy<BDataBuffer> SizePolicy;
static status_t Flatten(BDataIO& stream, const BDataBuffer& db)
{
size_t size = SizePolicy::Size(db);
status_t err = stream.Write(db.Buffer(), size);
if (err > 0)
err = B_OK;
return err;
}
};
// GetData policy specializations ----------------------------------------------
template<>
struct BMessageFieldGetDataPolicy<BDataBuffer>
{
inline static const void* GetData(const BDataBuffer* data)
{ return data->Buffer(); }
};
//------------------------------------------------------------------------------
template<>
struct BMessageFieldGetDataPolicy<BString>
{
inline static const void* GetData(const BString* data)
{ return data->String(); }
};
//------------------------------------------------------------------------------
} // namespace BPrivate
#endif // MESSAGEFIELD_H
/*
* $Log $
*
* $Id $
*
*/