//------------------------------------------------------------------------------ // 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 #include #include #include // System Includes ------------------------------------------------------------- #include #include #include #include #include #include // Project Includes ------------------------------------------------------------ #include #include // 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 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 fData; }; }; //------------------------------------------------------------------------------ template struct BMessageFieldSizePolicy { typedef typename BMessageFieldStoragePolicy::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 struct BMessageFieldPrintPolicy { static void PrintData(const T& data) {;} }; //------------------------------------------------------------------------------ template struct BMessageFieldFlattenPolicy { typedef BMessageFieldSizePolicy SizePolicy; inline static status_t Flatten(BDataIO& stream, const T& data) { return stream.Write((const void*)&data, SizePolicy::Size(data)); } }; //------------------------------------------------------------------------------ template struct BMessageFieldGetDataPolicy { inline static const void* GetData(const T* data) { return (const void*)data; } }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ template < class T1, class StoragePolicy = BMessageFieldStoragePolicy, class SizePolicy = BMessageFieldSizePolicy, class PrintPolicy = BMessageFieldPrintPolicy, class FlattenPolicy = BMessageFieldFlattenPolicy, class GetDataPolicy = BMessageFieldGetDataPolicy > 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:: 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:: 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:: 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:: 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:: Clone() const { BMessageFieldImpl* BMF = new(nothrow) BMessageFieldImpl(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:: 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 { static void PrintData(const bool& b) { std::printf("%d", int(b)); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const int8& i) { std::printf("0x%X (%d, '%c')", int(i), int(i), char(i)); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const int16& i) { std::printf("0x%X (%d, '%c')", i, i, char(i)); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const int32& i) { std::printf("0x%lX (%ld, '%c')", i, i, char(i)); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const int64& i) { std::printf("0x%LX (%Ld, '%c')", i, i, char(i)); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const float& f) { std::printf("%.4f", f); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const double& d) { std::printf("%.8f", d); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const BString& s) { std::printf("\"%s\"", s.String()); } }; template<> struct BMessageFieldPrintPolicy { static void PrintData(const BPoint& p) { std::printf("BPoint(x:%.1f, y:%.1f)", p.x, p.y); } }; template<> struct BMessageFieldPrintPolicy { 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 { 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 { 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 fData; }; }; //------------------------------------------------------------------------------ template<> struct BMessageFieldStoragePolicy { 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 fData; }; }; // Size policy specializations ------------------------------------------------- template<> struct BMessageFieldSizePolicy { typedef BMessageFieldStoragePolicy::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 { typedef BMessageFieldStoragePolicy::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 { typedef BMessageFieldStoragePolicy::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 { typedef BMessageFieldSizePolicy 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 { typedef BMessageFieldSizePolicy 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 { typedef BMessageFieldSizePolicy 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 { inline static const void* GetData(const BDataBuffer* data) { return data->Buffer(); } }; //------------------------------------------------------------------------------ template<> struct BMessageFieldGetDataPolicy { inline static const void* GetData(const BString* data) { return data->String(); } }; //------------------------------------------------------------------------------ } // namespace BPrivate #endif // MESSAGEFIELD_H /* * $Log $ * * $Id $ * */