From 9abaf1dfa742ded57034c4f1208ece3eb126a9a9 Mon Sep 17 00:00:00 2001 From: ejakowatz Date: Wed, 19 Mar 2003 05:02:31 +0000 Subject: [PATCH] Resolved conflict. DarkWyrm tweaked the old version (which I had #if 0'd out all over the place). There is now a giant #ifdef USING_TEMPLATE_MADNESS separating the two versions. At some point, the common code should be reconciled. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2953 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/app/Message.cpp | 1349 +++++++++++++++++++++++++++++++++++++- 1 file changed, 1345 insertions(+), 4 deletions(-) diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp index a0ab1a7faa..afdd471539 100644 --- a/src/kits/app/Message.cpp +++ b/src/kits/app/Message.cpp @@ -19,7 +19,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // -// File Name: Message.cpp +// File Name: Message.h // Author(s): Erik Jaesler (erik@cgsoftware.com) // DarkWyrm // Description: BMessage class creates objects that store data and that @@ -29,23 +29,57 @@ //------------------------------------------------------------------------------ // Standard Includes ----------------------------------------------------------- +#include // System Includes ------------------------------------------------------------- +#include +#include #include #include -#include +#include -#include -#include //#include // Project Includes ------------------------------------------------------------ +#ifdef USING_TEMPLATE_MADNESS +#include +#include +#include +#include +#include +#endif // USING_TEMPLATE_MADNESS // Local Includes -------------------------------------------------------------- // Local Defines --------------------------------------------------------------- +#define MSG_FIELD_VERSION 'FOB1' + +// flags for the overall message (the bitfield is 1 byte) +#define MSG_FLAG_BIG_ENDIAN 0x01 +#define MSG_FLAG_INCL_TARGET 0x02 +#define MSG_FLAG_INCL_REPLY 0x04 +#define MSG_FLAG_SCRIPT_MSG 0x08 +// These are for future improvement +#if 0 +#define MSG_FLAG_USE_PREFERRED 0x10 +#define MSG_FLAG_REPLY_WANTED 0x20 +#define MSG_FLAG_REPLY_DONE 0x40 +#define MSG_FLAG_IS_REPLY 0x80 + +#define MSG_FLAG_HDR_MASK 0xF0 +#endif + +#define MSG_HEADER_MAX_SIZE 38 +#define MSG_NAME_MAX_SIZE 256 // Globals --------------------------------------------------------------------- + +#ifdef USING_TEMPLATE_MADNESS +using BPrivate::BDataBuffer; +#endif // USING_TEMPLATE_MADNESS + + +//------------------------------------------------------------------------------ void _msg_cache_cleanup_() { } @@ -90,6 +124,1311 @@ bool _use_preferred_target_(BMessage *msg) { return msg->fPreferred; } +//------------------------------------------------------------------------------ + +#ifdef USING_TEMPLATE_MADNESS +//------------------------------------------------------------------------------ +BMessage::BMessage() + : what(0) +{ + init_data(); +} +//------------------------------------------------------------------------------ +BMessage::BMessage(uint32 w) +{ + init_data(); + what = w; +} +//------------------------------------------------------------------------------ +BMessage::BMessage(const BMessage& a_message) +{ + init_data(); + *this = a_message; +} +//------------------------------------------------------------------------------ +BMessage::BMessage(BMessage *a_message) +{ + init_data(); + *this = *a_message; +} +//------------------------------------------------------------------------------ +BMessage::~BMessage() +{ + if (fBody) + delete fBody; +} +//------------------------------------------------------------------------------ +BMessage& BMessage::operator=(const BMessage& msg) +{ + what = msg.what; + + link = msg.link; + fTarget = msg.fTarget; + fOriginal = msg.fOriginal; + fChangeCount = msg.fChangeCount; + fCurSpecifier = msg.fCurSpecifier; + fPtrOffset = msg.fPtrOffset; + + fEntries = msg.fEntries; + + fReplyTo.port = msg.fReplyTo.port; + fReplyTo.target = msg.fReplyTo.target; + fReplyTo.team = msg.fReplyTo.team; + fReplyTo.preferred = msg.fReplyTo.preferred; + + fPreferred = msg.fPreferred; + fReplyRequired = msg.fReplyRequired; + fReplyDone = msg.fReplyDone; + fIsReply = msg.fIsReply; + fWasDelivered = msg.fWasDelivered; + fReadOnly = msg.fReadOnly; + fHasSpecifiers = msg.fHasSpecifiers; + + *fBody = *(msg.fBody); +} +//------------------------------------------------------------------------------ +void BMessage::init_data() +{ + what = 0; + + link = NULL; + fTarget = B_NULL_TOKEN; + fOriginal = NULL; + fChangeCount = 0; + fCurSpecifier = -1; + fPtrOffset = 0; + + fEntries = NULL; + + fReplyTo.port = -1; + fReplyTo.target = B_NULL_TOKEN; + fReplyTo.team = -1; + fReplyTo.preferred = false; + + fPreferred = false; + fReplyRequired = false; + fReplyDone = false; + fIsReply = false; + fWasDelivered = false; + fReadOnly = false; + fHasSpecifiers = false; + + fBody = new BPrivate::BMessageBody; +} +//------------------------------------------------------------------------------ +status_t BMessage::GetInfo(type_code typeRequested, int32 which, char** name, + type_code* typeReturned, int32* count) const +{ + return fBody->GetInfo(typeRequested, which, name, typeReturned, count); +} +//------------------------------------------------------------------------------ +status_t BMessage::GetInfo(const char* name, type_code* type, int32* c) const +{ + return fBody->GetInfo(name, type, c); +} +//------------------------------------------------------------------------------ +status_t BMessage::GetInfo(const char* name, type_code* type, + bool* fixed_size) const +{ + return fBody->GetInfo(name, type, fixed_size); +} +//------------------------------------------------------------------------------ +int32 BMessage::CountNames(type_code type) const +{ + return fBody->CountNames(type); +} +//------------------------------------------------------------------------------ +bool BMessage::IsEmpty() const +{ + return fBody->IsEmpty(); +} +//------------------------------------------------------------------------------ +bool BMessage::IsSystem() const +{ + char a = char(what >> 24); + char b = char(what >> 16); + char c = char(what >> 8); + char d = char(what); + + // The BeBook says: + // ... we've adopted a strict convention for assigning values to all + // Be-defined constants. The value assigned will always be formed by + // combining four characters into a multicharacter constant, with the + // characters limited to uppercase letters and the underbar + // Between that and what's in AppDefs.h, this algo seems like a safe bet: + if (a == '_' && isupper(b) && isupper(c) && isupper(d)) + { + return true; + } + + return false; +} +//------------------------------------------------------------------------------ +bool BMessage::IsReply() const +{ + return fIsReply; +} +//------------------------------------------------------------------------------ +void BMessage::PrintToStream() const +{ + printf("\nBMessage: what = (0x%lX or %ld)\n", what, what); + fBody->PrintToStream(); +} +//------------------------------------------------------------------------------ +status_t BMessage::Rename(const char* old_entry, const char* new_entry) +{ + return fBody->Rename(old_entry, new_entry); +} +//------------------------------------------------------------------------------ +bool BMessage::WasDelivered() const +{ + return fWasDelivered; +} +//------------------------------------------------------------------------------ +bool BMessage::IsSourceWaiting() const +{ + return fReplyRequired && !fReplyDone; +} +//------------------------------------------------------------------------------ +bool BMessage::IsSourceRemote() const +{ + return WasDelivered() && fReplyTo.team != BPrivate::current_team(); +} +//------------------------------------------------------------------------------ +BMessenger BMessage::ReturnAddress() const +{ + if (WasDelivered()) + { + return BMessenger(fReplyTo.team, fReplyTo.port, fReplyTo.target, + fReplyTo.preferred); + } + + return BMessenger(); +} +//------------------------------------------------------------------------------ +const BMessage* BMessage::Previous() const +{ + // TODO: test + // In particular, look to see if the "_previous_" field is used in R5 + if (!fOriginal) + { + BMessage* fOriginal = new BMessage; + if (FindMessage("_previous_", fOriginal) != B_OK) + { + delete fOriginal; + fOriginal = NULL; + } + } + + return fOriginal; +} +//------------------------------------------------------------------------------ +bool BMessage::WasDropped() const +{ + return fReadOnly; +} +//------------------------------------------------------------------------------ +BPoint BMessage::DropPoint(BPoint* offset) const +{ + // TODO: Where do we get this stuff??? + if (offset) + { + *offset = FindPoint("_drop_offset_"); + } + return FindPoint("_drop_point_"); +} +//------------------------------------------------------------------------------ +status_t BMessage::SendReply(uint32 command, BHandler* reply_to) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +status_t BMessage::SendReply(BMessage* the_reply, BHandler* reply_to, + bigtime_t timeout) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +status_t BMessage::SendReply(BMessage* the_reply, BMessenger reply_to, + bigtime_t timeout) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +status_t BMessage::SendReply(uint32 command, BMessage* reply_to_reply) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +status_t BMessage::SendReply(BMessage* the_reply, BMessage* reply_to_reply, + bigtime_t send_timeout, bigtime_t reply_timeout) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +ssize_t BMessage::FlattenedSize() const +{ + return calc_hdr_size(0) + fBody->FlattenedSize(); +} +//------------------------------------------------------------------------------ +status_t BMessage::Flatten(char* buffer, ssize_t size) const +{ + return real_flatten(buffer, size); +} +//------------------------------------------------------------------------------ +status_t BMessage::Flatten(BDataIO* stream, ssize_t* size) const +{ + status_t err = B_OK; + ssize_t len = FlattenedSize(); + char* buffer = new(nothrow) char[len]; + if (buffer) + { + err = Flatten(buffer, len); + if (!err) + { + *size = len; + err = stream->Write(buffer, len); + if (err > B_OK) + err = B_OK; + } + + delete[] buffer; + } + else + { + err = B_NO_MEMORY; + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::Unflatten(const char* flat_buffer) +{ + uint32 size = ((uint32*)flat_buffer)[2]; + + BMemoryIO MemIO(flat_buffer, size); + return Unflatten(&MemIO); +} +//------------------------------------------------------------------------------ +status_t BMessage::Unflatten(BDataIO* stream) +{ + bool swap; + status_t err = unflatten_hdr(stream, swap); + + if (!err) + { + TReadHelper reader(stream, swap); + int8 flags; + type_code type; + uint32 count; + uint32 dataLen; + uint8 nameLen; + char name[MSG_NAME_MAX_SIZE]; + unsigned char* databuffer = NULL; + + try + { + reader(flags); + while (flags != MSG_LAST_ENTRY) + { + reader(type); + // Is there more than one data item? (!flags & MSG_FLAG_SINGLE_ITEM) + if (flags & MSG_FLAG_SINGLE_ITEM) + { + count = 1; + if (flags & MSG_FLAG_MINI_DATA) + { + uint8 littleLen; + reader(littleLen); + dataLen = littleLen; + } + else + { + reader(dataLen); + } + } + else + { + // Is there a little data? (flags & MSG_FLAG_MINI_DATA) + if (flags & MSG_FLAG_MINI_DATA) + { + // Get item count (1 byte) + uint8 littleCount; + reader(littleCount); + count = littleCount; + + // Get data length (1 byte) + uint8 littleLen; + reader(littleLen); + dataLen = littleLen; + } + else + { + // Is there a lot of data? (!flags & MSG_FLAG_MINI_DATA) + // Get item count (4 bytes) + reader(count); + // Get data length (4 bytes) + reader(dataLen); + } + } + + // Get the name length (1 byte) + reader(nameLen); + // Get the name (name length bytes) + reader(name, nameLen); + name[nameLen] = '\0'; + + // Copy the data into a new buffer to byte align it + databuffer = (unsigned char*)realloc(databuffer, dataLen); + if (!databuffer) + throw B_NO_MEMORY; + // Get the data + reader(databuffer, dataLen); + + // Is the data fixed size? (flags & MSG_FLAG_FIXED_SIZE) + if (flags & MSG_FLAG_FIXED_SIZE && swap) + { + // Make sure to swap the data + err = swap_data(type, (void*)databuffer, dataLen, + B_SWAP_ALWAYS); + if (err) + throw err; + } + // Is the data variable size? (!flags & MSG_FLAG_FIXED_SIZE) + else if (swap && type == B_REF_TYPE) + { + // Apparently, entry_refs are the only variable-length data + // explicitely swapped -- the dev_t and ino_t + // specifically + byte_swap(*(entry_ref*)databuffer); + } + + // Add each data field to the message + uint32 itemSize; + if (flags & MSG_FLAG_FIXED_SIZE) + { + itemSize = dataLen / count; + } + unsigned char* dataPtr = databuffer; + for (uint32 i = 0; i < count; ++i) + { + // Line up for the next item + if (i) + { + if (flags & MSG_FLAG_FIXED_SIZE) + { + dataPtr += itemSize; + } + else + { + // Have to account for 8-byte boundary padding + dataPtr += itemSize + (8 - (itemSize % 8)); + } + } + + if ((flags & MSG_FLAG_FIXED_SIZE) == 0) + { + itemSize = *(uint32*)dataPtr; + dataPtr += sizeof (uint32); + } + + err = AddData(name, type, dataPtr, itemSize, + flags & MSG_FLAG_FIXED_SIZE); + if (err) + throw err; + } + + reader(flags); + } + } + catch (status_t& e) + { + err = e; + } + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::AddSpecifier(const char* property) +{ + BMessage message(B_DIRECT_SPECIFIER); + message.AddString("property", property); + + fCurSpecifier ++; + fHasSpecifiers = true; + + return AddSpecifier(&message); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddSpecifier(const char* property, int32 index) +{ + BMessage message(B_INDEX_SPECIFIER); + message.AddString("property", property); + message.AddInt32("index", index); + + fCurSpecifier++; + fHasSpecifiers = true; + + return AddSpecifier(&message); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddSpecifier(const char* property, int32 index, int32 range) +{ + BMessage message(B_RANGE_SPECIFIER); + message.AddString("property", property); + message.AddInt32("index", index); + message.AddInt32("range", range); + + fCurSpecifier ++; + fHasSpecifiers = true; + + return AddSpecifier(&message); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddSpecifier(const char* property, const char* name) +{ + BMessage message(B_NAME_SPECIFIER); + message.AddString("property", property); + message.AddString("name", name); + + fCurSpecifier ++; + fHasSpecifiers = true; + + return AddSpecifier(&message); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddSpecifier(const BMessage* specifier) +{ + return AddMessage("specifiers", specifier); +} +//------------------------------------------------------------------------------ +status_t SetCurrentSpecifier(int32 index) +{ + // TODO: implement + return B_ERROR; +} +//------------------------------------------------------------------------------ +status_t BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, + int32* what, const char** property) const +{ + if (fCurSpecifier == -1 || !WasDelivered()) + return B_BAD_SCRIPT_SYNTAX; + + if (index) + *index = fCurSpecifier; + + if (specifier) + { + FindMessage("specifiers", fCurSpecifier, specifier); + + if (what) + *what = specifier->what; + + if (property) + specifier->FindString("property", property); + } + + return B_OK; +} +//------------------------------------------------------------------------------ +bool BMessage::HasSpecifiers() const +{ + return fHasSpecifiers; +} +//------------------------------------------------------------------------------ +status_t BMessage::PopSpecifier() +{ + if (fCurSpecifier && WasDelivered()) + { + fCurSpecifier--; + return B_OK; + } + else + return B_BAD_VALUE; +} +//------------------------------------------------------------------------------ +// return fBody->AddData(name, val, TYPESPEC); +// return fBody->FindData(name, index, val, TYPESPEC); +// return fBody->ReplaceData(name, index, val, TYPESPEC); +// return fBody->HasData(name, TYPESPEC, n); + +#define DEFINE_FUNCTIONS(TYPE, fnName, TYPESPEC) \ + status_t BMessage::Add ## fnName(const char* name, TYPE val) \ + { return fBody->AddData(name, val, TYPESPEC); } \ + status_t BMessage::Find ## fnName(const char* name, TYPE* p) const \ + { return Find ## fnName(name, 0, p); } \ + status_t BMessage::Find ## fnName(const char* name, int32 index, TYPE* p) const \ + { \ + *p = TYPE(); \ + return fBody->FindData(name, index, p, TYPESPEC); \ + } \ + status_t BMessage::Replace ## fnName(const char* name, TYPE val) \ + { return ReplaceData(name, TYPESPEC, 0, &val, sizeof(TYPE)); } \ + status_t BMessage::Replace ## fnName(const char *name, int32 index, TYPE val) \ + { return fBody->ReplaceData(name, index, val, TYPESPEC); } \ + bool BMessage::Has ## fnName(const char* name, int32 n) const \ + { return fBody->HasData(name, TYPESPEC, n); } + +DEFINE_FUNCTIONS(int8 , Int8 , B_INT8_TYPE) +DEFINE_FUNCTIONS(int16 , Int16 , B_INT16_TYPE) +DEFINE_FUNCTIONS(int32 , Int32 , B_INT32_TYPE) +DEFINE_FUNCTIONS(int64 , Int64 , B_INT64_TYPE) +DEFINE_FUNCTIONS(BPoint, Point , B_POINT_TYPE) +DEFINE_FUNCTIONS(BRect , Rect , B_RECT_TYPE) +DEFINE_FUNCTIONS(float , Float , B_FLOAT_TYPE) +DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE) +DEFINE_FUNCTIONS(bool , Bool , B_BOOL_TYPE) + +#undef DEFINE_FUNCTIONS + + +#define DEFINE_HAS_FUNCTION(fnName, TYPESPEC) \ + bool BMessage::Has ## fnName(const char* name, int32 n) const \ + { return HasData(name, TYPESPEC, n); } + +DEFINE_HAS_FUNCTION(Message , B_MESSAGE_TYPE) +DEFINE_HAS_FUNCTION(String , B_STRING_TYPE) +DEFINE_HAS_FUNCTION(Pointer , B_POINTER_TYPE) +DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE) +DEFINE_HAS_FUNCTION(Ref , B_REF_TYPE) + +#undef DEFINE_HAS_FUNCTION + +#define DEFINE_LAZY_FIND_FUNCTION(TYPE, fnName) \ + TYPE BMessage::Find ## fnName(const char* name, int32 n) const \ + { \ + TYPE i = 0; \ + Find ## fnName(name, n, &i); \ + return i; \ + } + +DEFINE_LAZY_FIND_FUNCTION(int8 , Int8) +DEFINE_LAZY_FIND_FUNCTION(int16 , Int16) +DEFINE_LAZY_FIND_FUNCTION(int32 , Int32) +DEFINE_LAZY_FIND_FUNCTION(int64 , Int64) +DEFINE_LAZY_FIND_FUNCTION(float , Float) +DEFINE_LAZY_FIND_FUNCTION(double , Double) +DEFINE_LAZY_FIND_FUNCTION(bool , Bool) +DEFINE_LAZY_FIND_FUNCTION(const char* , String) + +#undef DEFINE_LAZY_FIND_FUNCTION + +//------------------------------------------------------------------------------ +status_t BMessage::AddString(const char* name, const char* a_string) +{ + return fBody->AddData(name, a_string, B_STRING_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddString(const char* name, const BString& a_string) +{ + return AddString(name, a_string.String()); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddPointer(const char* name, const void* ptr) +{ + return fBody->AddData(name, ptr, B_POINTER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddMessenger(const char* name, BMessenger messenger) +{ + return fBody->AddData(name, messenger, B_MESSENGER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddRef(const char* name, const entry_ref* ref) +{ + return fBody->AddData(name, *ref, B_REF_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::AddMessage(const char* name, const BMessage* msg) +{ + BMessage* data = new BMessage(*msg); + status_t err = fBody->AddData(name, msg, B_MESSAGE_TYPE); + if (err) + { + delete data; + } + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::AddFlat(const char* name, BFlattenable* obj, int32 count) +{ + status_t err = B_OK; + ssize_t size = obj->FlattenedSize(); + char* buffer = new(nothrow) char[size]; + if (buffer) + { + err = AddData(name, obj->TypeCode(), (void*)buffer, size, + obj->IsFixedSize(), count); + delete[] buffer; + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::AddData(const char* name, type_code type, const void* data, + ssize_t numBytes, bool is_fixed_size, int32 /*count*/) +{ +/** + @note Because we're using vectors for our item storage, the count param + is no longer useful to us: dynamically adding more items is not + really a performance issue, so pre-allocating space for objects + gives us no real advantage. + */ + + // TODO: test & implement + // 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. + //-------------------------------------------------------------------------- + // voidref suggests creating a BDataBuffer type which we can use here to + // avoid having to specialize BMessageBody::AddData(). + //-------------------------------------------------------------------------- + + // TODO: Fix this horrible hack + status_t err = B_OK; + switch (type) + { + case B_BOOL_TYPE: + err = AddBool(name, *(bool*)data); + break; + case B_INT8_TYPE: + case B_UINT8_TYPE: + err = AddInt8(name, *(int8*)data); + break; + case B_INT16_TYPE: + case B_UINT16_TYPE: + err = AddInt16(name, *(int16*)data); + break; + case B_INT32_TYPE: + case B_UINT32_TYPE: + err = AddInt32(name, *(int32*)data); + break; + case B_INT64_TYPE: + case B_UINT64_TYPE: + err = AddInt64(name, *(int64*)data); + break; + case B_FLOAT_TYPE: + err = AddFloat(name, *(float*)data); + break; + case B_DOUBLE_TYPE: + err = AddDouble(name, *(double*)data); + break; + case B_POINT_TYPE: + err = AddPoint(name, *(BPoint*)data); + break; + case B_RECT_TYPE: + err = AddRect(name, *(BRect*)data); + break; + case B_REF_TYPE: + { + entry_ref ref; + uchar* dp = (uchar*)data; + ref.device = *(dev_t*)dp; dp += sizeof (dev_t); + ref.directory = *(ino_t*)dp; dp += sizeof (ino_t); + ref.set_name((const char*)dp); + err = AddRef(name, &ref); + break; + } + case B_MESSAGE_TYPE: + { + BMessage msg; + msg.Unflatten((const char*)data); + err = AddMessage(name, &msg); + break; + } + case B_MESSENGER_TYPE: + err = AddMessenger(name, *(BMessenger*)data); + break; + case B_POINTER_TYPE: + err = AddPointer(name, (void**)data); + break; + case B_STRING_TYPE: + err = AddString(name, (const char*)data); + break; + default: + // TODO: implement + // Using the mythical BDataBuffer + BDataBuffer DB((void*)data, numBytes); + err = fBody->AddData(name, DB, type); + break; + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::RemoveData(const char* name, int32 index) +{ + return fReadOnly ? B_ERROR : fBody->RemoveData(name, index); +} +//------------------------------------------------------------------------------ +status_t BMessage::RemoveName(const char* name) +{ + return fReadOnly ? B_ERROR : fBody->RemoveName(name); +} +//------------------------------------------------------------------------------ +status_t BMessage::MakeEmpty() +{ + return fReadOnly ? B_ERROR : fBody->MakeEmpty(); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindString(const char* name, const char** str) const +{ + return FindString(name, 0, str); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindString(const char* name, int32 index, + const char** str) const +{ + ssize_t bytes; + return FindData(name, B_STRING_TYPE, index, + (const void**)str, &bytes); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindString(const char* name, BString* str) const +{ + return FindString(name, 0, str); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindString(const char* name, int32 index, BString* str) const +{ + const char* cstr; + status_t err = FindString(name, index, &cstr); + if (!err) + { + *str = cstr; + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::FindPointer(const char* name, void** ptr) const +{ + return FindPointer(name, 0, ptr); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindPointer(const char* name, int32 index, void** ptr) const +{ + return fBody->FindData(name, index, ptr, B_POINTER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindMessenger(const char* name, BMessenger* m) const +{ + return FindMessenger(name, 0, m); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindMessenger(const char* name, int32 index, BMessenger* m) const +{ + return fBody->FindData(name, index, m, B_MESSENGER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindRef(const char* name, entry_ref* ref) const +{ + return FindRef(name, 0, ref); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const +{ + return fBody->FindData(name, index, ref, B_REF_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindMessage(const char* name, BMessage* msg) const +{ + return FindMessage(name, 0, msg); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindMessage(const char* name, int32 index, BMessage* msg) const +{ + return fBody->FindData(name, index, msg, B_MESSAGE_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindFlat(const char* name, BFlattenable* obj) const +{ + return FindFlat(name, 0, obj); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindFlat(const char* name, int32 index, + BFlattenable* obj) const +{ + const void* data; + ssize_t numBytes; + status_t err = FindData(name, obj->TypeCode(), index, &data, &numBytes); + if (!err) + { + err = obj->Unflatten(obj->TypeCode(), data, numBytes); + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::FindData(const char* name, type_code type, const void** data, + ssize_t* numBytes) const +{ + return FindData(name, type, 0, data, numBytes); +} +//------------------------------------------------------------------------------ +status_t BMessage::FindData(const char* name, type_code type, int32 index, + const void** data, ssize_t* numBytes) const +{ + status_t err = B_OK; + // Oh, the humanity! + err = fBody->FindData(name, type, index, data, numBytes); + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceString(const char* name, const char* string) +{ + return ReplaceString(name, 0, string); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceString(const char* name, int32 index, + const char* string) +{ + return fBody->ReplaceData(name, index, string, B_STRING_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceString(const char* name, const BString& string) +{ + return ReplaceString(name, 0, string); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceString(const char* name, int32 index, const BString& string) +{ + return fBody->ReplaceData(name, index, string, B_STRING_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplacePointer(const char* name, const void* ptr) +{ + return ReplacePointer(name, 0, ptr); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplacePointer(const char* name, int32 index, + const void* ptr) +{ + return fBody->ReplaceData(name, index, ptr, B_POINTER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceMessenger(const char* name, BMessenger messenger) +{ + // Don't want to copy the BMessenger + return fBody->ReplaceData(name, 0, messenger, B_MESSENGER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceMessenger(const char* name, int32 index, + BMessenger msngr) +{ + return fBody->ReplaceData(name, index, msngr, B_MESSENGER_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceRef(const char* name, const entry_ref* ref) +{ + return ReplaceRef(name, 0, ref); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref) +{ + // TODO: redo + // Use voidref's theoretical BDataBuffer + return fBody->ReplaceData(name, index, *ref, B_REF_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceMessage(const char* name, const BMessage* msg) +{ + return ReplaceMessage(name, 0, msg); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceMessage(const char* name, int32 index, + const BMessage* msg) +{ + return fBody->ReplaceData(name, index, *msg, B_MESSAGE_TYPE); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceFlat(const char* name, BFlattenable* obj) +{ + return ReplaceFlat(name, 0, obj); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* obj) +{ + // TODO: implement + status_t err = B_OK; + ssize_t size = obj->FlattenedSize(); + char* buffer = new(nothrow) char[size]; + if (buffer) + { + err = ReplaceData(name, obj->TypeCode(), index, (void*)buffer, size); + delete[] buffer; + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceData(const char* name, type_code type, + const void* data, ssize_t data_size) +{ + return ReplaceData(name, type, 0, data, data_size); +} +//------------------------------------------------------------------------------ +status_t BMessage::ReplaceData(const char* name, type_code type, int32 index, + const void* data, ssize_t data_size) +{ + // TODO: Fix this horrible hack + status_t err = B_OK; + switch (type) + { + case B_BOOL_TYPE: + err = ReplaceBool(name, index, *(bool*)data); + break; + case B_INT8_TYPE: + case B_UINT8_TYPE: + err = ReplaceInt8(name, index, *(int8*)data); + break; + case B_INT16_TYPE: + case B_UINT16_TYPE: + err = ReplaceInt16(name, index, *(int16*)data); + break; + case B_INT32_TYPE: + case B_UINT32_TYPE: + err = ReplaceInt32(name, index, *(int32*)data); + break; + case B_INT64_TYPE: + case B_UINT64_TYPE: + err = ReplaceInt64(name, index, *(int64*)data); + break; + case B_FLOAT_TYPE: + err = ReplaceFloat(name, index, *(float*)data); + break; + case B_DOUBLE_TYPE: + err = ReplaceDouble(name, index, *(double*)data); + break; + case B_POINT_TYPE: + err = ReplacePoint(name, index, *(BPoint*)data); + break; + case B_RECT_TYPE: + err = ReplaceRect(name, index, *(BRect*)data); + break; + case B_REF_TYPE: + err = ReplaceRef(name, index, (entry_ref*)data); + break; + case B_MESSAGE_TYPE: + err = ReplaceMessage(name, index, (BMessage*)data); + break; + case B_MESSENGER_TYPE: + err = ReplaceMessenger(name, index, *(BMessenger*)data); + break; + case B_POINTER_TYPE: + err = ReplacePointer(name, index, (void**)data); + break; + default: + // TODO: implement + // Using the mythical BDataBuffer + BDataBuffer DB((void*)data, data_size); + err = fBody->ReplaceData(name, index, DB, type); + break; + } + + return err; +} +//------------------------------------------------------------------------------ +void* BMessage::operator new(size_t size) +{ + return ::new char[size]; +} +//------------------------------------------------------------------------------ +void BMessage::operator delete(void* ptr, size_t size) +{ + ::delete(ptr); +} +//------------------------------------------------------------------------------ +bool BMessage::HasFlat(const char* name, const BFlattenable* flat) const +{ + return HasFlat(name, 0, flat); +} +//------------------------------------------------------------------------------ +bool BMessage::HasFlat(const char* name, int32 n, const BFlattenable* flat) const +{ + return fBody->HasData(name, flat->TypeCode(), n); +} +//------------------------------------------------------------------------------ +bool BMessage::HasData(const char* name, type_code t, int32 n) const +{ + return fBody->HasData(name, t, n); +} +//------------------------------------------------------------------------------ +BRect BMessage::FindRect(const char* name, int32 n) const +{ + BRect r(0, 0, -1, -1); + FindRect(name, n, &r); + return r; +} +//------------------------------------------------------------------------------ +BPoint BMessage::FindPoint(const char* name, int32 n) const +{ + BPoint p(0, 0); + FindPoint(name, n, &p); + return p; +} +//------------------------------------------------------------------------------ +status_t BMessage::flatten_hdr(BDataIO* stream) const +{ + status_t err = B_OK; + int32 data = MSG_FIELD_VERSION; + + write_helper(stream, (const void*)&data, sizeof (data), err); + if (!err) + { + // faked up checksum; we'll fix it up later + write_helper(stream, (const void*)&data, sizeof (data), err); + } + if (!err) + { + data = fBody->FlattenedSize() + calc_hdr_size(0); + write_helper(stream, (const void*)&data, sizeof (data), err); + } + if (!err) + { + write_helper(stream, (const void*)&what, sizeof (what), err); + } + + uint8 flags = 0; +#ifdef B_HOST_IS_BENDIAN + flags |= MSG_FLAG_BIG_ENDIAN; +#endif + if (HasSpecifiers()) + { + flags |= MSG_FLAG_SCRIPT_MSG; + } + + if (fTarget != B_NULL_TOKEN) + { + flags |= MSG_FLAG_INCL_TARGET; + } + + if (fReplyTo.port >= 0 && + fReplyTo.target != B_NULL_TOKEN && + fReplyTo.team >= 0) + { + flags |= MSG_FLAG_INCL_REPLY; + } + + write_helper(stream, (const void*)&flags, sizeof (flags), err); + + // Write targeting and reply info if necessary + if (!err && (flags & MSG_FLAG_INCL_TARGET)) + { + data = fPreferred ? B_PREFERRED_TOKEN : fTarget; + write_helper(stream, (const void*)&data, sizeof (data), err); + } + + if (!err && (flags & MSG_FLAG_INCL_REPLY)) + { + write_helper(stream, (const void*)&fReplyTo.port, + sizeof (fReplyTo.port), err); + if (!err) + { + write_helper(stream, (const void*)&fReplyTo.target, + sizeof (fReplyTo.target), err); + } + if (!err) + { + write_helper(stream, (const void*)&fReplyTo.team, + sizeof (fReplyTo.team), err); + } + + uint8 bigFlags; + if (!err) + { + bigFlags = fPreferred ? 1 : 0; + write_helper(stream, (const void*)&bigFlags, + sizeof (bigFlags), err); + } + if (!err) + { + bigFlags = fReplyRequired ? 1 : 0; + write_helper(stream, (const void*)&bigFlags, + sizeof (bigFlags), err); + } + if (!err) + { + bigFlags = fReplyDone ? 1 : 0; + write_helper(stream, (const void*)&bigFlags, + sizeof (bigFlags), err); + } + if (!err) + { + bigFlags = fIsReply ? 1 : 0; + write_helper(stream, (const void*)&bigFlags, + sizeof (bigFlags), err); + } + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::unflatten_hdr(BDataIO* stream, bool& swap) +{ + status_t err = B_OK; + int32 data; + int32 checksum; + uchar csBuffer[MSG_HEADER_MAX_SIZE]; + + TReadHelper read_helper(stream); + TChecksumHelper checksum_helper(csBuffer); + + try { + + // Get the message version + read_helper(data); + // TODO: Check whether we need to do byte-swapping + if (data == '1BOF') + { + swap = true; + } + else + { + swap = false; + } + read_helper.SetSwap(swap); + + // get the checksum + read_helper(checksum); + // get the size + read_helper(data); + checksum_helper.Cache(data); + // Get the what + read_helper(what); + checksum_helper.Cache(what); + // Get the flags + uint8 flags = 0; + read_helper(flags); + checksum_helper.Cache(flags); + + fHasSpecifiers = flags & MSG_FLAG_SCRIPT_MSG; + + if (flags & MSG_FLAG_BIG_ENDIAN) + { + // TODO: ??? + } + if (flags & MSG_FLAG_INCL_TARGET) + { + // Get the target data + read_helper(data); + checksum_helper.Cache(data); + fTarget = data; + } + if (flags & MSG_FLAG_INCL_REPLY) + { + // Get the reply port + read_helper(fReplyTo.port); + read_helper(fReplyTo.target); + read_helper(fReplyTo.team); + checksum_helper.Cache(fReplyTo.port); + checksum_helper.Cache(fReplyTo.target); + checksum_helper.Cache(fReplyTo.team); + + // Get the "big flags" + uint8 bigFlags; + // Get the preferred flag + read_helper(bigFlags); + checksum_helper.Cache(bigFlags); + fPreferred = bigFlags; + if (fPreferred) + { + fTarget = B_PREFERRED_TOKEN; + } + // Get the reply requirement flag + read_helper(bigFlags); + checksum_helper.Cache(bigFlags); + fReplyRequired = bigFlags; + // Get the reply done flag + read_helper(bigFlags); + checksum_helper.Cache(bigFlags); + fReplyDone = bigFlags; + // Get the "is reply" flag + read_helper(bigFlags); + checksum_helper.Cache(bigFlags); + fIsReply = bigFlags; + } + } + catch (status_t& e) + { + err = e; + } + + if (checksum != checksum_helper.CheckSum()) + err = B_NOT_A_MESSAGE; + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::real_flatten(char* result, ssize_t size) const +{ + BMemoryIO stream((void*)result, size); + status_t err = real_flatten(&stream); + + if (!err) + { + // Fixup the checksum; it is calculated on data size, what, flags, + // and target info (including big flags if appropriate) + ((uint32*)result)[1] = _checksum_((uchar*)result + (sizeof (uint32) * 2), + calc_hdr_size(0) - (sizeof (uint32) * 2)); + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BMessage::real_flatten(BDataIO* stream) const +{ + status_t err = flatten_hdr(stream); + + if (!err) + { + err = fBody->Flatten(stream); + } + + return err; +} +//------------------------------------------------------------------------------ +ssize_t BMessage::calc_hdr_size(uchar flags) const +{ + ssize_t size = min_hdr_size(); + + if (fTarget != B_NULL_TOKEN) + { + size += sizeof (fTarget); + } + + if (fReplyTo.port >= 0 && + fReplyTo.target != B_NULL_TOKEN && + fReplyTo.team >= 0) + { + size += sizeof (fReplyTo.port); + size += sizeof (fReplyTo.target); + size += sizeof (fReplyTo.team); + + size += 4; // For the "big" flags + } + + return size; +} +//------------------------------------------------------------------------------ +ssize_t BMessage::min_hdr_size() const +{ + ssize_t size = 0; + + size += 4; // version + size += 4; // checksum + size += 4; // flattened size + size += 4; // 'what' + size += 1; // flags + + return size; +} +//------------------------------------------------------------------------------ + +#else // USING_TEMPLATE_MADNESS + //------------------------------------------------------------------------------ BMessage::BMessage(uint32 command) { @@ -1528,3 +2867,5 @@ void BMessage::da_swap_fixed_sized(dyn_array *da) { } //------------------------------------------------------------------------------ + +#endif // USING_TEMPLATE_MADNESS