From dc9e836b3543e2a83968255cc96906311beac891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 4 Jul 2005 21:41:41 +0000 Subject: [PATCH] *Very* basic read-only Dano/Zeta message support. Only briefly tested. Not really suited for message sending/retrieval (because target stuff is missing), but should work more or less with disk based messages. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13428 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/app/Message.cpp | 382 ++++++++++++++++++---------------- src/kits/app/app.src | 1 + src/kits/app/dano_message.cpp | 122 +++++++++++ src/kits/app/dano_message.h | 11 + 4 files changed, 331 insertions(+), 185 deletions(-) create mode 100644 src/kits/app/dano_message.cpp create mode 100644 src/kits/app/dano_message.h diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp index 391cd7e4ed..055577ebb4 100644 --- a/src/kits/app/Message.cpp +++ b/src/kits/app/Message.cpp @@ -1,43 +1,26 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2005, 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: Message.h -// Author(s): Erik Jaesler (erik@cgsoftware.com) -// DarkWyrm -// Ingo Weinhold -// Description: BMessage class creates objects that store data and that -// can be processed in a message loop. BMessage objects -// are also used as data containers by the archiving and -// the scripting mechanisms. -//------------------------------------------------------------------------------ +/* + * Copyright 2001-2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Erik Jaesler (erik@cgsoftware.com) + * DarkWyrm + * Ingo Weinhold + */ + +/** BMessage class creates objects that store data and that + * can be processed in a message loop. BMessage objects + * are also used as data containers by the archiving and + * the scripting mechanisms. + */ // debugging //#define DBG(x) x #define DBG(x) ; #define PRINT(x) DBG({ printf("[%6ld] ", find_thread(NULL)); printf x; }) -// Standard Includes ----------------------------------------------------------- #include -// System Includes ------------------------------------------------------------- #include #include #include @@ -47,9 +30,6 @@ #include #include -//#include - -// Project Includes ------------------------------------------------------------ #include #include #include @@ -57,10 +37,14 @@ #include #include -// Local Includes -------------------------------------------------------------- +#include "dano_message.h" -// Local Defines --------------------------------------------------------------- -#define MSG_FIELD_VERSION 'FOB1' + +static const uint32 kMessageMagic = 'FOB1'; +static const uint32 kMessageMagicSwapped = '1BOF'; + +static const uint32 kMessageMagicDano = 'FOB2'; +static const uint32 kMessageMagicDanoSwapped = '2BOF'; // flags for the overall message (the bitfield is 1 byte) #define MSG_FLAG_BIG_ENDIAN 0x01 @@ -111,6 +95,8 @@ public: Header() {} Header(const BMessage &message) { ReadFrom(message); } + status_t SetMagic(uint32 magic); + status_t ReadFrom(BDataIO &stream); void ReadFrom(const BMessage &message); status_t WriteTo(BDataIO &stream, bool calculateCheckSum = true) const; @@ -127,7 +113,7 @@ public: void Dump() const; private: - int32 fMagic; + uint32 fMagic; int32 fBodySize; uint32 fWhat; uint8 fFlags; @@ -142,6 +128,24 @@ private: bool fSwapped; }; + +status_t +BMessage::Header::SetMagic(uint32 magic) +{ + if (magic == kMessageMagicSwapped) { + fSwapped = true; + } else if (magic == kMessageMagic) { + fSwapped = false; + } else { + // This is *not* a message + return B_NOT_A_MESSAGE; + } + + fMagic = magic; + return B_OK; +} + + // ReadFrom status_t BMessage::Header::ReadFrom(BDataIO &stream) @@ -154,19 +158,6 @@ BMessage::Header::ReadFrom(BDataIO &stream) int32 flattenedSize; try { - // Get the message version - read_helper(fMagic); - - fSwapped = false; - if (fMagic == '1BOF') { - fSwapped = true; - } else if (fMagic == 'FOB1') { - fSwapped = false; - } else { - // This is *not* a message - return B_NOT_A_MESSAGE; - } - read_helper.SetSwap(fSwapped); // get the checksum @@ -237,7 +228,7 @@ BMessage::Header::ReadFrom(BDataIO &stream) void BMessage::Header::ReadFrom(const BMessage &message) { - fMagic = MSG_FIELD_VERSION; + fMagic = kMessageMagic; fBodySize = message.fBody->FlattenedSize(); fWhat = message.what; @@ -909,172 +900,192 @@ status_t BMessage::Flatten(BDataIO* stream, ssize_t* size) const return err; } -//------------------------------------------------------------------------------ -status_t BMessage::Unflatten(const char* flat_buffer) + + +status_t +BMessage::Unflatten(const char* buffer) { - if (!flat_buffer) + if (!buffer) return B_BAD_VALUE; - // check whether this is a KMessage - if (((KMessage::Header*)flat_buffer)->magic - == KMessage::kMessageHeaderMagic) { - return _UnflattenKMessage(flat_buffer); + uint32 magic = *(uint32*)buffer; + + // we support several message formats - this list is ordered + // by importance and frequency + + if (magic == kMessageMagic) { + // it appears to be a normal flattened BMessage + BMemoryIO memoryStream(buffer, ((uint32*)buffer)[2]); + return Unflatten(&memoryStream); } - // assume it's a normal flattened BMessage - uint32 size = ((uint32*)flat_buffer)[2]; + // check whether this is a KMessage + if (((KMessage::Header*)buffer)->magic + == KMessage::kMessageHeaderMagic) + return _UnflattenKMessage(buffer); - BMemoryIO MemIO(flat_buffer, size); - return Unflatten(&MemIO); + if (magic == kMessageMagicSwapped) { + // it appears to be a swapped flattened BMessage + uint32 size = ((uint32*)buffer)[2]; + + BMemoryIO memoryStream(buffer, __swap_int32(size)); + return Unflatten(&memoryStream); + } + + if (magic == kMessageMagicDano || magic == kMessageMagicDanoSwapped) { + // dano style message + BMemoryIO memoryStream(buffer, BPrivate::dano_message_size(buffer)); + return Unflatten(&memoryStream); + } + + return B_NOT_A_MESSAGE; } -//------------------------------------------------------------------------------ -status_t BMessage::Unflatten(BDataIO* stream) + + +status_t +BMessage::Unflatten(BDataIO* stream) { + TReadHelper reader(stream); Header header; - status_t err = header.ReadFrom(*stream); + status_t status = B_OK; -if (err) { - printf("BMessage::Unflatten(): Reading the header failed: %lx\n", err); -} + // ToDo: while reading from a stream is certainly more convenient than + // from a buffer, it causes a lot of unnecessary copies, and therefore + // probably shouldn't be the preferred (or only) route. + + try { + uint32 magic; + reader(magic); + + status = header.SetMagic(magic); + if (status < B_OK) { + // we support reading Dano messages from disk as well + if (magic == kMessageMagicDano) + return BPrivate::unflatten_dano_message(magic, *stream, *this); + + return status; + } + + status = header.ReadFrom(*stream); + if (status < B_OK) { + printf("BMessage::Unflatten(): Reading the header failed: %lx\n", status); + return status; + } - if (!err) - { header.WriteTo(*this); bool swap = header.IsSwapped(); - 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); - } + int8 flags; + reader(flags); + + while (flags != MSG_LAST_ENTRY) { + type_code type; + reader(type); + + // Is there more than one data 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? + 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? + // Get item count (4 bytes) + reader(count); + // Get data length (4 bytes) + 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'; - // 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); - // 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) - { + if (swap) { + // Is the data fixed size? + if ((flags & MSG_FLAG_FIXED_SIZE) != 0) { // Make sure to swap the data - err = swap_data(type, (void*)databuffer, dataLen, + status = 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) - { + if (status < B_OK) + throw status; + } else if (type == B_REF_TYPE) { + // Is the data variable size? // Apparently, entry_refs are the only variable-length data // explicitely swapped -- the dev_t and ino_t // specifically byte_swap(*(entry_ref*)databuffer); } - - // Add each data field to the message - uint32 itemSize = 0; - 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 - // We add 4 because padding as calculated during - // flattening includes the four-byte size header - dataPtr += itemSize + calc_padding(itemSize + 4, 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); } + + // Add each data field to the message + uint32 itemSize = 0; + 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 + // We add 4 because padding as calculated during + // flattening includes the four-byte size header + dataPtr += itemSize + calc_padding(itemSize + 4, 8); + } + } + + if ((flags & MSG_FLAG_FIXED_SIZE) == 0) { + itemSize = *(uint32*)dataPtr; + dataPtr += sizeof (uint32); + } + + status = AddData(name, type, dataPtr, itemSize, + flags & MSG_FLAG_FIXED_SIZE); + if (status < B_OK) + throw status; + } + + reader(flags); } - catch (status_t& e) - { - err = e; - } + } catch (status_t& e) { + status = e; } - return err; + return status; } //------------------------------------------------------------------------------ status_t BMessage::AddSpecifier(const char* property) @@ -2024,7 +2035,8 @@ BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port, // a KMessage KMessage::Header *header = (KMessage::Header*)data; header->targetToken = (preferred ? B_PREFERRED_TOKEN : token); - } else if (*(int32*)data == '1BOF' || *(int32*)data == 'FOB1') { + } else if (*(uint32*)data == kMessageMagic + || *(uint32*)data == kMessageMagicSwapped) { // get the header BMemoryIO stream(data, size); Header header; diff --git a/src/kits/app/app.src b/src/kits/app/app.src index 51d790db0a..b43861d4ca 100644 --- a/src/kits/app/app.src +++ b/src/kits/app/app.src @@ -7,6 +7,7 @@ APP_KIT_SOURCE = Cursor.cpp DataBuffer.cpp Clipboard.cpp + dano_message.cpp Handler.cpp InitTerminateLibBe.cpp Invoker.cpp diff --git a/src/kits/app/dano_message.cpp b/src/kits/app/dano_message.cpp new file mode 100644 index 0000000000..3b69a5f700 --- /dev/null +++ b/src/kits/app/dano_message.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler + */ + + +#include "dano_message.h" + +#include + +#include +#include +#include + + +struct dano_header { + uint32 code; + int32 size; + uint32 what; + uint32 _unknown; +}; + +struct dano_field_header { + uint32 code; + int32 size; +}; + +struct dano_field { + uint32 type; + int32 data_size; + uint8 name_size; + char name[0]; +} _PACKED; + +static const uint32 kMessageFormat = 'FOB2'; +static const uint32 kMessageFormatSwapped = '2BOF'; + +static const uint32 kDataField = 'SGDa'; + + +size_t +BPrivate::dano_message_size(const char* buffer) +{ + dano_header* header = (dano_header*)buffer; + + if (header->code == kMessageFormatSwapped) + return __swap_int32(header->size); + + return header->size; +} + + +status_t +BPrivate::unflatten_dano_message(uint32 magic, BDataIO& stream, BMessage& message) +{ + TReadHelper reader(&stream); + message.MakeEmpty(); + + if (magic == kMessageFormatSwapped) + reader.SetSwap(true); + + int32 size; + reader(size); + reader(message.what); + + int32 value; + reader(value); // unknown + + size -= sizeof(dano_header); + int32 offset = 0; + + while (offset < size) { + dano_field_header fieldHeader; + reader(fieldHeader); +printf("field.code = %.4s (%lx), field.size = %ld\n", + (char*)&fieldHeader.code, fieldHeader.code, fieldHeader.size); + + if (fieldHeader.size + offset > size) + return B_BAD_DATA; + + uint32 fieldSize = fieldHeader.size - sizeof(dano_field_header); + char* fieldBuffer = (char*)malloc(fieldSize); + if (fieldBuffer == NULL) + throw (status_t)B_NO_MEMORY; + + reader(fieldBuffer, fieldSize); + + if (fieldHeader.code == kDataField) { + dano_field* field = (dano_field*)fieldBuffer; + + int32 dataOffset = sizeof(dano_field) + field->name_size + 1; + dataOffset = (dataOffset + 7) & ~7; + // padding + + if (field->data_size + dataOffset + offset > size) + return B_BAD_DATA; + + // ToDo: support fixed size for real + bool fixedSize = true; + if (field->type == B_STRING_TYPE) + fixedSize = false; + + status_t status = message.AddData(field->name, field->type, + fieldBuffer + dataOffset, field->data_size, fixedSize); + + if (status < B_OK) { + free(fieldBuffer); + throw status; + } + } + + free(fieldBuffer); + offset += fieldHeader.size; +printf("offset = %ld, size = %ld\n", offset, size); + } + message.PrintToStream(); + return B_OK; +} + diff --git a/src/kits/app/dano_message.h b/src/kits/app/dano_message.h new file mode 100644 index 0000000000..03a5a802be --- /dev/null +++ b/src/kits/app/dano_message.h @@ -0,0 +1,11 @@ + +#include + +class BMessage; +class BDataIO; + +namespace BPrivate { + status_t unflatten_dano_message(uint32 magic, BDataIO& stream, BMessage& message); + size_t dano_message_size(const char* buffer); +} +