* Unified handling of different BMessage formats into MessageAdapter.cpp
* Removed r5_message.cpp and dano_message.cpp accordingly * Also moved out KMessage handling from Message.cpp to MessageAdapter.cpp * Fixed some minor style issues in Message.cpp git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21514 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <[email protected]>
|
||||
*/
|
||||
#ifndef _MESSAGE_ADAPTER_H_
|
||||
#define _MESSAGE_ADAPTER_H_
|
||||
|
||||
#include <Message.h>
|
||||
#include <util/KMessage.h>
|
||||
|
||||
// message formats
|
||||
#define MESSAGE_FORMAT_R5 'FOB1'
|
||||
#define MESSAGE_FORMAT_R5_SWAPPED '1BOF'
|
||||
#define MESSAGE_FORMAT_DANO 'FOB2'
|
||||
#define MESSAGE_FORMAT_DANO_SWAPPED '2BOF'
|
||||
#define MESSAGE_FORMAT_HAIKU '1FMH'
|
||||
#define MESSAGE_FORMAT_HAIKU_SWAPPED 'HMF1'
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
class MessageAdapter {
|
||||
public:
|
||||
static ssize_t FlattenedSize(uint32 format, const BMessage *from);
|
||||
|
||||
static status_t Flatten(uint32 format, const BMessage *from,
|
||||
char *buffer, ssize_t *size);
|
||||
static status_t Flatten(uint32 format, const BMessage *from,
|
||||
BDataIO *stream, ssize_t *size);
|
||||
|
||||
static status_t Unflatten(uint32 format, BMessage *into,
|
||||
const char *buffer);
|
||||
static status_t Unflatten(uint32 format, BMessage *into,
|
||||
BDataIO *stream);
|
||||
|
||||
private:
|
||||
static status_t _ConvertKMessage(const KMessage *from, BMessage *to);
|
||||
|
||||
static ssize_t _R5FlattenedSize(const BMessage *from);
|
||||
|
||||
static status_t _FlattenR5Message(uint32 format, const BMessage *from,
|
||||
char *buffer, ssize_t *size);
|
||||
|
||||
static status_t _UnflattenR5Message(uint32 format, BMessage *into,
|
||||
BDataIO *stream);
|
||||
static status_t _UnflattenDanoMessage(uint32 format, BMessage *into,
|
||||
BDataIO *stream);
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
#endif // _MESSAGE_ADAPTER_H_
|
||||
@@ -16,6 +16,7 @@ class BMessage;
|
||||
namespace BPrivate {
|
||||
|
||||
class KMessageField;
|
||||
class MessageAdapter;
|
||||
|
||||
// KMessage
|
||||
class KMessage {
|
||||
@@ -102,6 +103,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class KMessageField;
|
||||
friend class MessageAdapter;
|
||||
friend class ::BMessage; // not so nice, but makes things easier
|
||||
|
||||
struct Header {
|
||||
|
||||
@@ -30,7 +30,6 @@ MergeObject <libbe>app_kit.o :
|
||||
AreaLink.cpp
|
||||
Cursor.cpp
|
||||
Clipboard.cpp
|
||||
dano_message.cpp
|
||||
DesktopLink.cpp
|
||||
DirectMessageTarget.cpp
|
||||
Handler.cpp
|
||||
@@ -41,6 +40,7 @@ MergeObject <libbe>app_kit.o :
|
||||
Looper.cpp
|
||||
LooperList.cpp
|
||||
Message.cpp
|
||||
MessageAdapter.cpp
|
||||
MessageFilter.cpp
|
||||
MessageQueue.cpp
|
||||
MessageRunner.cpp
|
||||
@@ -48,7 +48,6 @@ MergeObject <libbe>app_kit.o :
|
||||
MessageUtils.cpp
|
||||
PropertyInfo.cpp
|
||||
PortLink.cpp
|
||||
r5_message.cpp
|
||||
RegistrarDefs.cpp
|
||||
RegistrarThread.cpp
|
||||
RegistrarThreadManager.cpp
|
||||
|
||||
+38
-153
@@ -5,12 +5,8 @@
|
||||
* Authors:
|
||||
* Michael Lotz <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include "dano_message.h"
|
||||
#include "r5_message.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <MessageAdapter.h>
|
||||
#include <MessagePrivate.h>
|
||||
#include <MessageUtils.h>
|
||||
|
||||
@@ -41,14 +37,6 @@
|
||||
#define DEBUG_FUNCTION_ENTER2 //debug_printf("thread: 0x%x; line: %04ld: func: %s\n", find_thread(NULL), __LINE__, __PRETTY_FUNCTION__);
|
||||
|
||||
|
||||
static const uint32 kMessageMagicR5 = 'FOB1';
|
||||
static const uint32 kMessageMagicR5Swapped = '1BOF';
|
||||
static const uint32 kMessageMagicDano = 'FOB2';
|
||||
static const uint32 kMessageMagicDanoSwapped = '2BOF';
|
||||
static const uint32 kMessageMagicHaiku = '1FMH';
|
||||
static const uint32 kMessageMagicHaikuSwapped = 'HMF1';
|
||||
|
||||
|
||||
const char *B_SPECIFIER_ENTRY = "specifiers";
|
||||
const char *B_PROPERTY_ENTRY = "property";
|
||||
const char *B_PROPERTY_NAME_ENTRY = "name";
|
||||
@@ -56,8 +44,6 @@ const char *B_PROPERTY_NAME_ENTRY = "name";
|
||||
|
||||
static status_t handle_reply(port_id replyPort, int32 *pCode,
|
||||
bigtime_t timeout, BMessage *reply);
|
||||
static status_t convert_message(const KMessage *fromMessage,
|
||||
BMessage *toMessage);
|
||||
|
||||
extern "C" {
|
||||
// private os function to set the owning team of an area
|
||||
@@ -77,6 +63,7 @@ BMessage::BMessage()
|
||||
_InitCommon();
|
||||
}
|
||||
|
||||
|
||||
BMessage::BMessage(BMessage *other)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
@@ -84,6 +71,7 @@ BMessage::BMessage(BMessage *other)
|
||||
*this = *other;
|
||||
}
|
||||
|
||||
|
||||
BMessage::BMessage(uint32 _what)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
@@ -195,7 +183,7 @@ BMessage::_InitHeader()
|
||||
fHeader = (message_header *)malloc(sizeof(message_header));
|
||||
memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
|
||||
|
||||
fHeader->format = kMessageMagicHaiku;
|
||||
fHeader->format = MESSAGE_FORMAT_HAIKU;
|
||||
fHeader->flags = MESSAGE_FLAG_VALID;
|
||||
fHeader->what = what;
|
||||
fHeader->current_specifier = -1;
|
||||
@@ -379,10 +367,10 @@ BMessage::IsReply() const
|
||||
}
|
||||
|
||||
|
||||
template<typename Type> static uint8 *
|
||||
template<typename Type> static uint8 *
|
||||
print_to_stream_type(uint8* pointer)
|
||||
{
|
||||
Type *item = (Type *)pointer;
|
||||
Type *item = (Type *)pointer;
|
||||
item->PrintToStream();
|
||||
return (uint8 *)(item+1);
|
||||
}
|
||||
@@ -417,7 +405,7 @@ BMessage::_PrintToStream(const char* indent) const
|
||||
} else
|
||||
printf("0x%lx", what);
|
||||
printf(") {\n");
|
||||
|
||||
|
||||
field_header *field = fFields;
|
||||
for (int32 i = 0; i < fHeader->field_count; i++, field++) {
|
||||
value = B_BENDIAN_TO_HOST_INT32(field->type);
|
||||
@@ -473,7 +461,7 @@ BMessage::_PrintToStream(const char* indent) const
|
||||
printf("bool(%s)\n", *((bool *)pointer)!= 0 ? "true" : "false");
|
||||
pointer += sizeof(bool);
|
||||
break;
|
||||
|
||||
|
||||
case B_FLOAT_TYPE:
|
||||
pointer = print_type<float>("float(%.4f)\n", pointer);
|
||||
break;
|
||||
@@ -481,27 +469,27 @@ BMessage::_PrintToStream(const char* indent) const
|
||||
case B_DOUBLE_TYPE:
|
||||
pointer = print_type<double>("double(%.8f)\n", pointer);
|
||||
break;
|
||||
|
||||
|
||||
case B_REF_TYPE: {
|
||||
ssize_t size = *(ssize_t *)pointer;
|
||||
pointer += sizeof(ssize_t);
|
||||
entry_ref ref;
|
||||
BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
|
||||
|
||||
|
||||
printf("entry_ref(device=%ld, directory=%lld, name=\"%s\", ",
|
||||
ref.device, ref.directory, ref.name);
|
||||
|
||||
|
||||
BPath path(&ref);
|
||||
printf("path=\"%s\")\n", path.Path());
|
||||
pointer += size;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case B_MESSAGE_TYPE:
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%s ", indent);
|
||||
|
||||
|
||||
BMessage message;
|
||||
const ssize_t size = *(const ssize_t *)pointer;
|
||||
pointer += sizeof(ssize_t);
|
||||
@@ -514,7 +502,7 @@ BMessage::_PrintToStream(const char* indent) const
|
||||
pointer += size;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
printf("(type = '%.4s')(size = %ld)\n", (char *)&value, size);
|
||||
}
|
||||
@@ -761,7 +749,7 @@ ssize_t
|
||||
BMessage::FlattenedSize() const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
return BPrivate::r5_message_flattened_size(this);
|
||||
return BPrivate::MessageAdapter::FlattenedSize(MESSAGE_FORMAT_R5, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -769,7 +757,8 @@ status_t
|
||||
BMessage::Flatten(char *buffer, ssize_t size) const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
return BPrivate::flatten_r5_message(this, buffer, size);
|
||||
return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, buffer,
|
||||
&size);
|
||||
}
|
||||
|
||||
|
||||
@@ -777,7 +766,8 @@ status_t
|
||||
BMessage::Flatten(BDataIO *stream, ssize_t *size) const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
return BPrivate::flatten_r5_message(this, stream, size);
|
||||
return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, stream,
|
||||
size);
|
||||
}
|
||||
|
||||
|
||||
@@ -801,8 +791,6 @@ BMessage::_NativeFlatten(char *buffer, ssize_t size) const
|
||||
|
||||
/* we have to sync the what code as it is a public member */
|
||||
fHeader->what = what;
|
||||
//fHeader->fields_checksum = BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size);
|
||||
//fHeader->data_checksum = BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size);
|
||||
|
||||
memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
|
||||
buffer += sizeof(message_header);
|
||||
@@ -832,8 +820,6 @@ BMessage::_NativeFlatten(BDataIO *stream, ssize_t *size) const
|
||||
|
||||
/* we have to sync the what code as it is a public member */
|
||||
fHeader->what = what;
|
||||
//fHeader->fields_checksum = BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size);
|
||||
//fHeader->data_checksum = BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size);
|
||||
|
||||
ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
|
||||
if (result1 != sizeof(message_header))
|
||||
@@ -962,6 +948,15 @@ BMessage::_Reference(message_header *header)
|
||||
fFields = (field_header *)address;
|
||||
address += fHeader->fields_size;
|
||||
fData = address;
|
||||
|
||||
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
||||
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
||||
debug_printf("checksum mismatch\n");
|
||||
_Clear();
|
||||
_InitHeader();
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1017,33 +1012,8 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint32 format = *(uint32 *)flatBuffer;
|
||||
if (format != kMessageMagicHaiku) {
|
||||
if (format == KMessage::kMessageHeaderMagic) {
|
||||
KMessage message;
|
||||
status_t result = message.SetTo(flatBuffer,
|
||||
((KMessage::Header*)flatBuffer)->size);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return convert_message(&message, this);
|
||||
}
|
||||
|
||||
try {
|
||||
if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped)
|
||||
return BPrivate::unflatten_r5_message(format, this, flatBuffer);
|
||||
|
||||
if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped) {
|
||||
BMemoryIO stream(flatBuffer + sizeof(uint32),
|
||||
BPrivate::dano_message_flattened_size(flatBuffer));
|
||||
return BPrivate::unflatten_dano_message(format, stream, *this);
|
||||
}
|
||||
} catch (status_t error) {
|
||||
MakeEmpty();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_NOT_A_MESSAGE;
|
||||
}
|
||||
if (format != MESSAGE_FORMAT_HAIKU)
|
||||
return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
|
||||
|
||||
// native message unflattening
|
||||
|
||||
@@ -1056,7 +1026,7 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
memcpy(fHeader, flatBuffer, sizeof(message_header));
|
||||
flatBuffer += sizeof(message_header);
|
||||
|
||||
if (fHeader->format != kMessageMagicHaiku
|
||||
if (fHeader->format != MESSAGE_FORMAT_HAIKU
|
||||
|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
||||
free(fHeader);
|
||||
fHeader = NULL;
|
||||
@@ -1093,14 +1063,6 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
/*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
||||
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
||||
debug_printf("checksum mismatch 1\n");
|
||||
_Clear();
|
||||
_InitHeader();
|
||||
return B_BAD_VALUE;
|
||||
}*/
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1114,20 +1076,8 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
|
||||
uint32 format = 0;
|
||||
stream->Read(&format, sizeof(uint32));
|
||||
if (format != kMessageMagicHaiku) {
|
||||
try {
|
||||
if (format == kMessageMagicR5 || format == kMessageMagicR5Swapped)
|
||||
return BPrivate::unflatten_r5_message(format, this, stream);
|
||||
|
||||
if (format == kMessageMagicDano || format == kMessageMagicDanoSwapped)
|
||||
return BPrivate::unflatten_dano_message(format, *stream, *this);
|
||||
} catch (status_t error) {
|
||||
MakeEmpty();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_NOT_A_MESSAGE;
|
||||
}
|
||||
if (format != MESSAGE_FORMAT_HAIKU)
|
||||
return BPrivate::MessageAdapter::Unflatten(format, this, stream);
|
||||
|
||||
// native message unflattening
|
||||
|
||||
@@ -1143,7 +1093,7 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
sizeof(message_header) - sizeof(uint32));
|
||||
result -= sizeof(message_header) - sizeof(uint32);
|
||||
|
||||
if (result != B_OK || fHeader->format != kMessageMagicHaiku
|
||||
if (result != B_OK || fHeader->format != MESSAGE_FORMAT_HAIKU
|
||||
|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
||||
free(fHeader);
|
||||
fHeader = NULL;
|
||||
@@ -1184,14 +1134,6 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
/*if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
||||
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
||||
debug_printf("checksum mismatch 2\n");
|
||||
_Clear();
|
||||
_InitHeader();
|
||||
return B_BAD_VALUE;
|
||||
}*/
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1329,7 +1271,7 @@ BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *what,
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1887,7 +1829,7 @@ BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
|
||||
port_info info;
|
||||
get_port_info(port, &info);
|
||||
void *address = NULL;
|
||||
_kern_transfer_area(header->shared_area, &address, B_ANY_ADDRESS,
|
||||
_kern_transfer_area(header->shared_area, &address, B_ANY_ADDRESS,
|
||||
info.team);
|
||||
#endif
|
||||
} else {
|
||||
@@ -2075,11 +2017,11 @@ BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
|
||||
|
||||
uint32 magic = *(uint32 *)data;
|
||||
|
||||
if (magic == kMessageMagicHaiku || magic == kMessageMagicHaikuSwapped) {
|
||||
if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
|
||||
message_header *header = (message_header *)data;
|
||||
header->target = token;
|
||||
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
|
||||
} else if (magic == kMessageMagicR5) {
|
||||
} else if (magic == MESSAGE_FORMAT_R5) {
|
||||
uint8 *header = (uint8 *)data;
|
||||
header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
|
||||
+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
|
||||
@@ -2134,63 +2076,6 @@ handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout,
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
convert_message(const KMessage *fromMessage, BMessage *toMessage)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
if (!fromMessage || !toMessage)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// make empty and init what of the target message
|
||||
toMessage->MakeEmpty();
|
||||
toMessage->what = fromMessage->What();
|
||||
|
||||
BMessage::Private toPrivate(toMessage);
|
||||
toPrivate.SetTarget(fromMessage->TargetToken());
|
||||
toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(),
|
||||
fromMessage->ReplyToken());
|
||||
|
||||
// iterate through the fields and import them in the target message
|
||||
KMessageField field;
|
||||
while (fromMessage->GetNextField(&field) == B_OK) {
|
||||
int32 elementCount = field.CountElements();
|
||||
if (elementCount > 0) {
|
||||
for (int32 i = 0; i < elementCount; i++) {
|
||||
int32 size;
|
||||
const void *data = field.ElementAt(i, &size);
|
||||
status_t result;
|
||||
|
||||
if (field.TypeCode() == B_MESSAGE_TYPE) {
|
||||
// message type: if it's a KMessage, convert it
|
||||
KMessage message;
|
||||
if (message.SetTo(data, size) == B_OK) {
|
||||
BMessage bMessage;
|
||||
result = convert_message(&message, &bMessage);
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
|
||||
result = toMessage->AddMessage(field.Name(), &bMessage);
|
||||
} else {
|
||||
// just add it
|
||||
result = toMessage->AddData(field.Name(),
|
||||
field.TypeCode(), data, size,
|
||||
field.HasFixedElementSize(), 1);
|
||||
}
|
||||
} else {
|
||||
result = toMessage->AddData(field.Name(), field.TypeCode(),
|
||||
data, size, field.HasFixedElementSize(), 1);
|
||||
}
|
||||
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void BMessage::_ReservedMessage1(void) {};
|
||||
void BMessage::_ReservedMessage2(void) {};
|
||||
void BMessage::_ReservedMessage3(void) {};
|
||||
|
||||
@@ -0,0 +1,772 @@
|
||||
/*
|
||||
* Copyright 2005-2007, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
#include <MessageAdapter.h>
|
||||
#include <MessagePrivate.h>
|
||||
#include <MessageUtils.h>
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
#define R5_MESSAGE_FLAG_VALID 0x01
|
||||
#define R5_MESSAGE_FLAG_INCLUDE_TARGET 0x02
|
||||
#define R5_MESSAGE_FLAG_INCLUDE_REPLY 0x04
|
||||
#define R5_MESSAGE_FLAG_SCRIPT_MESSAGE 0x08
|
||||
|
||||
#define R5_FIELD_FLAG_VALID 0x01
|
||||
#define R5_FIELD_FLAG_MINI_DATA 0x02
|
||||
#define R5_FIELD_FLAG_FIXED_SIZE 0x04
|
||||
#define R5_FIELD_FLAG_SINGLE_ITEM 0x08
|
||||
|
||||
|
||||
enum {
|
||||
SECTION_MESSAGE_HEADER = 'FOB2',
|
||||
SECTION_OFFSET_TABLE = 'STof',
|
||||
SECTION_TARGET_INFORMATION = 'ENwh',
|
||||
SECTION_SINGLE_ITEM_DATA = 'SGDa',
|
||||
SECTION_FIXED_SIZE_ARRAY_DATA = 'FADa',
|
||||
SECTION_VARIABLE_SIZE_ARRAY_DATA = 'VADa',
|
||||
SECTION_SORTED_INDEX_TABLE = 'DXIn',
|
||||
SECTION_END_OF_DATA = 'DDEn'
|
||||
};
|
||||
|
||||
|
||||
struct r5_message_header {
|
||||
uint32 magic;
|
||||
uint32 checksum;
|
||||
ssize_t flattened_size;
|
||||
int32 what;
|
||||
uint8 flags;
|
||||
} _PACKED;
|
||||
|
||||
struct dano_section_header {
|
||||
uint32 code;
|
||||
ssize_t size;
|
||||
uint8 data[0];
|
||||
} _PACKED;
|
||||
|
||||
struct dano_message_header {
|
||||
int32 what;
|
||||
int32 padding;
|
||||
} _PACKED;
|
||||
|
||||
typedef struct offset_table_s {
|
||||
int32 indexTable;
|
||||
int32 endOfData;
|
||||
int64 padding;
|
||||
} OffsetTable;
|
||||
|
||||
struct dano_single_item {
|
||||
type_code type;
|
||||
ssize_t item_size;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
struct dano_fixed_size_array {
|
||||
type_code type;
|
||||
ssize_t size_per_item;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
struct dano_variable_size_array {
|
||||
type_code type;
|
||||
int32 padding;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
inline int32
|
||||
pad_to_8(int32 value)
|
||||
{
|
||||
return (value + 7) & ~7;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
MessageAdapter::FlattenedSize(uint32 format, const BMessage *from)
|
||||
{
|
||||
switch (format) {
|
||||
case MESSAGE_FORMAT_R5:
|
||||
case MESSAGE_FORMAT_R5_SWAPPED:
|
||||
return _R5FlattenedSize(from);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::Flatten(uint32 format, const BMessage *from, char *buffer,
|
||||
ssize_t *size)
|
||||
{
|
||||
switch (format) {
|
||||
case MESSAGE_FORMAT_R5:
|
||||
case MESSAGE_FORMAT_R5_SWAPPED:
|
||||
return _FlattenR5Message(format, from, buffer, size);
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::Flatten(uint32 format, const BMessage *from, BDataIO *stream,
|
||||
ssize_t *size)
|
||||
{
|
||||
switch (format) {
|
||||
case MESSAGE_FORMAT_R5:
|
||||
case MESSAGE_FORMAT_R5_SWAPPED:
|
||||
{
|
||||
ssize_t flattenedSize = _R5FlattenedSize(from);
|
||||
char *buffer = (char *)malloc(flattenedSize);
|
||||
if (!buffer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t result = _FlattenR5Message(format, from, buffer,
|
||||
&flattenedSize);
|
||||
if (result < B_OK) {
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t written = stream->Write(buffer, flattenedSize);
|
||||
if (written != flattenedSize) {
|
||||
free(buffer);
|
||||
return (written >= 0 ? B_ERROR : written);
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = flattenedSize;
|
||||
|
||||
free(buffer);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::Unflatten(uint32 format, BMessage *into, const char *buffer)
|
||||
{
|
||||
if (format == KMessage::kMessageHeaderMagic) {
|
||||
KMessage message;
|
||||
status_t result = message.SetTo(buffer,
|
||||
((KMessage::Header *)buffer)->size);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return _ConvertKMessage(&message, into);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (format) {
|
||||
case MESSAGE_FORMAT_R5:
|
||||
case MESSAGE_FORMAT_R5_SWAPPED:
|
||||
{
|
||||
r5_message_header *header = (r5_message_header *)buffer;
|
||||
BMemoryIO stream(buffer + sizeof(uint32),
|
||||
header->flattened_size - sizeof(uint32));
|
||||
return _UnflattenR5Message(format, into, &stream);
|
||||
}
|
||||
|
||||
case MESSAGE_FORMAT_DANO:
|
||||
case MESSAGE_FORMAT_DANO_SWAPPED:
|
||||
{
|
||||
dano_section_header *header = (dano_section_header *)buffer;
|
||||
ssize_t size = header->size;
|
||||
if (header->code == MESSAGE_FORMAT_DANO_SWAPPED)
|
||||
size = __swap_int32(size);
|
||||
|
||||
BMemoryIO stream(buffer + sizeof(uint32), size - sizeof(uint32));
|
||||
return _UnflattenDanoMessage(format, into, &stream);
|
||||
}
|
||||
}
|
||||
} catch (status_t error) {
|
||||
into->MakeEmpty();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_NOT_A_MESSAGE;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::Unflatten(uint32 format, BMessage *into, BDataIO *stream)
|
||||
{
|
||||
try {
|
||||
switch (format) {
|
||||
case MESSAGE_FORMAT_R5:
|
||||
case MESSAGE_FORMAT_R5_SWAPPED:
|
||||
return _UnflattenR5Message(format, into, stream);
|
||||
|
||||
case MESSAGE_FORMAT_DANO:
|
||||
case MESSAGE_FORMAT_DANO_SWAPPED:
|
||||
return _UnflattenDanoMessage(format, into, stream);
|
||||
}
|
||||
} catch (status_t error) {
|
||||
into->MakeEmpty();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_NOT_A_MESSAGE;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::_ConvertKMessage(const KMessage *fromMessage,
|
||||
BMessage *toMessage)
|
||||
{
|
||||
if (!fromMessage || !toMessage)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// make empty and init what of the target message
|
||||
toMessage->MakeEmpty();
|
||||
toMessage->what = fromMessage->What();
|
||||
|
||||
BMessage::Private toPrivate(toMessage);
|
||||
toPrivate.SetTarget(fromMessage->TargetToken());
|
||||
toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(),
|
||||
fromMessage->ReplyToken());
|
||||
|
||||
// iterate through the fields and import them in the target message
|
||||
KMessageField field;
|
||||
while (fromMessage->GetNextField(&field) == B_OK) {
|
||||
int32 elementCount = field.CountElements();
|
||||
if (elementCount > 0) {
|
||||
for (int32 i = 0; i < elementCount; i++) {
|
||||
int32 size;
|
||||
const void *data = field.ElementAt(i, &size);
|
||||
status_t result;
|
||||
|
||||
if (field.TypeCode() == B_MESSAGE_TYPE) {
|
||||
// message type: if it's a KMessage, convert it
|
||||
KMessage message;
|
||||
if (message.SetTo(data, size) == B_OK) {
|
||||
BMessage bMessage;
|
||||
result = _ConvertKMessage(&message, &bMessage);
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
|
||||
result = toMessage->AddMessage(field.Name(), &bMessage);
|
||||
} else {
|
||||
// just add it
|
||||
result = toMessage->AddData(field.Name(),
|
||||
field.TypeCode(), data, size,
|
||||
field.HasFixedElementSize(), 1);
|
||||
}
|
||||
} else {
|
||||
result = toMessage->AddData(field.Name(), field.TypeCode(),
|
||||
data, size, field.HasFixedElementSize(), 1);
|
||||
}
|
||||
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
MessageAdapter::_R5FlattenedSize(const BMessage *from)
|
||||
{
|
||||
BMessage::Private messagePrivate((BMessage *)from);
|
||||
BMessage::message_header* header = messagePrivate.GetMessageHeader();
|
||||
|
||||
// header size (variable, depending on the flags)
|
||||
|
||||
ssize_t flattenedSize = sizeof(r5_message_header);
|
||||
|
||||
if (header->target != B_NULL_TOKEN)
|
||||
flattenedSize += sizeof(int32);
|
||||
|
||||
if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN
|
||||
&& header->reply_team >= 0) {
|
||||
// reply info + big flags
|
||||
flattenedSize += sizeof(port_id) + sizeof(int32) + sizeof(team_id) + 4;
|
||||
}
|
||||
|
||||
// field size
|
||||
|
||||
uint8 *data = messagePrivate.GetMessageData();
|
||||
BMessage::field_header *field = messagePrivate.GetMessageFields();
|
||||
for (int32 i = 0; i < header->field_count; i++, field++) {
|
||||
// flags and type
|
||||
flattenedSize += 1 + sizeof(type_code);
|
||||
|
||||
#if 0
|
||||
bool miniData = field->dataSize <= 255 && field->count <= 255;
|
||||
#else
|
||||
// ToDo: we don't know the R5 dataSize yet (padding)
|
||||
bool miniData = false;
|
||||
#endif
|
||||
|
||||
// item count
|
||||
if (field->count > 1)
|
||||
flattenedSize += (miniData ? sizeof(uint8) : sizeof(uint32));
|
||||
|
||||
// data size
|
||||
flattenedSize += (miniData ? sizeof(uint8) : sizeof(size_t));
|
||||
|
||||
// name length and name
|
||||
flattenedSize += 1 + min_c(field->name_length - 1, 255);
|
||||
|
||||
// data
|
||||
if (field->flags & FIELD_FLAG_FIXED_SIZE)
|
||||
flattenedSize += field->data_size;
|
||||
else {
|
||||
uint8 *source = data + field->offset + field->name_length;
|
||||
|
||||
for (int32 i = 0; i < field->count; i++) {
|
||||
ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t);
|
||||
flattenedSize += pad_to_8(itemSize);
|
||||
source += itemSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pseudo field with flags 0
|
||||
return flattenedSize + 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::_FlattenR5Message(uint32 format, const BMessage *from,
|
||||
char *buffer, ssize_t *size)
|
||||
{
|
||||
BMessage::Private messagePrivate((BMessage *)from);
|
||||
BMessage::message_header *header = messagePrivate.GetMessageHeader();
|
||||
uint8 *data = messagePrivate.GetMessageData();
|
||||
|
||||
r5_message_header *r5header = (r5_message_header *)buffer;
|
||||
uint8 *pointer = (uint8 *)buffer + sizeof(r5_message_header);
|
||||
|
||||
r5header->magic = MESSAGE_FORMAT_R5;
|
||||
r5header->what = from->what;
|
||||
r5header->checksum = 0;
|
||||
|
||||
uint8 flags = R5_MESSAGE_FLAG_VALID;
|
||||
if (header->target != B_NULL_TOKEN) {
|
||||
*(int32 *)pointer = header->target;
|
||||
pointer += sizeof(int32);
|
||||
flags |= R5_MESSAGE_FLAG_INCLUDE_TARGET;
|
||||
}
|
||||
|
||||
if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN
|
||||
&& header->reply_team >= 0) {
|
||||
// reply info
|
||||
*(port_id *)pointer = header->reply_port;
|
||||
pointer += sizeof(port_id);
|
||||
*(int32 *)pointer = header->reply_target;
|
||||
pointer += sizeof(int32);
|
||||
*(team_id *)pointer = header->reply_team;
|
||||
pointer += sizeof(team_id);
|
||||
|
||||
// big flags
|
||||
*pointer = (header->reply_target == B_PREFERRED_TOKEN ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_REPLY_REQUIRED ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_REPLY_DONE ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_IS_REPLY ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
flags |= R5_MESSAGE_FLAG_INCLUDE_REPLY;
|
||||
}
|
||||
|
||||
if (header->flags & MESSAGE_FLAG_HAS_SPECIFIERS)
|
||||
flags |= R5_MESSAGE_FLAG_SCRIPT_MESSAGE;
|
||||
|
||||
r5header->flags = flags;
|
||||
|
||||
// store the header size - used for the checksum later
|
||||
ssize_t headerSize = (uint32)pointer - (uint32)buffer;
|
||||
|
||||
// collect and add the data
|
||||
BMessage::field_header *field = messagePrivate.GetMessageFields();
|
||||
for (int32 i = 0; i < header->field_count; i++, field++) {
|
||||
flags = R5_FIELD_FLAG_VALID;
|
||||
|
||||
if (field->count == 1)
|
||||
flags |= R5_FIELD_FLAG_SINGLE_ITEM;
|
||||
// ToDo: we don't really know the data size now (padding missing)
|
||||
if (field->data_size <= 255 && field->count <= 255)
|
||||
;//flags |= R5_FIELD_FLAG_MINI_DATA;
|
||||
if (field->flags & FIELD_FLAG_FIXED_SIZE)
|
||||
flags |= R5_FIELD_FLAG_FIXED_SIZE;
|
||||
|
||||
*pointer = flags;
|
||||
pointer++;
|
||||
|
||||
*(type_code *)pointer = field->type;
|
||||
pointer += sizeof(type_code);
|
||||
|
||||
if (!(flags & R5_FIELD_FLAG_SINGLE_ITEM)) {
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA) {
|
||||
*pointer = (uint8)field->count;
|
||||
pointer++;
|
||||
} else {
|
||||
*(int32 *)pointer = field->count;
|
||||
pointer += sizeof(int32);
|
||||
}
|
||||
}
|
||||
|
||||
// we may have to adjust this to account for padding later
|
||||
uint8 *fieldSize = pointer;
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA) {
|
||||
*pointer = (uint8)field->data_size;
|
||||
pointer++;
|
||||
} else {
|
||||
*(ssize_t *)pointer = field->data_size;
|
||||
pointer += sizeof(ssize_t);
|
||||
}
|
||||
|
||||
// name
|
||||
int32 nameLength = min_c(field->name_length - 1, 255);
|
||||
*pointer = (uint8)nameLength;
|
||||
pointer++;
|
||||
|
||||
strncpy((char *)pointer, (char *)data + field->offset, nameLength);
|
||||
pointer += nameLength;
|
||||
|
||||
// data
|
||||
uint8 *source = data + field->offset + field->name_length;
|
||||
if (flags & R5_FIELD_FLAG_FIXED_SIZE) {
|
||||
memcpy(pointer, source, field->data_size);
|
||||
pointer += field->data_size;
|
||||
} else {
|
||||
uint8 *previous = pointer;
|
||||
for (int32 i = 0; i < field->count; i++) {
|
||||
ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t);
|
||||
memcpy(pointer, source, itemSize);
|
||||
pointer += pad_to_8(itemSize);
|
||||
source += itemSize;
|
||||
}
|
||||
|
||||
// adjust the field size to the padded value
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA)
|
||||
*fieldSize = (uint8)(pointer - previous);
|
||||
else
|
||||
*(ssize_t *)fieldSize = (pointer - previous);
|
||||
}
|
||||
}
|
||||
|
||||
// terminate the fields with a pseudo field with flags 0 (not valid)
|
||||
*pointer = 0;
|
||||
pointer++;
|
||||
|
||||
// calculate the flattened size from the pointers
|
||||
r5header->flattened_size = (uint32)pointer - (uint32)buffer;
|
||||
r5header->checksum = CalculateChecksum((uint8 *)(buffer + 8),
|
||||
headerSize - 8);
|
||||
|
||||
if (size)
|
||||
*size = r5header->flattened_size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::_UnflattenR5Message(uint32 format, BMessage *into,
|
||||
BDataIO *stream)
|
||||
{
|
||||
into->MakeEmpty();
|
||||
|
||||
BMessage::Private messagePrivate(into);
|
||||
BMessage::message_header *header = messagePrivate.GetMessageHeader();
|
||||
|
||||
TReadHelper reader(stream);
|
||||
if (format == MESSAGE_FORMAT_R5_SWAPPED)
|
||||
reader.SetSwap(true);
|
||||
|
||||
// the stream is already advanced by the size of the "format"
|
||||
r5_message_header r5header;
|
||||
reader(((uint8 *)&r5header) + sizeof(uint32),
|
||||
sizeof(r5header) - sizeof(uint32));
|
||||
|
||||
header->what = into->what = r5header.what;
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_TARGET)
|
||||
reader(header->target);
|
||||
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_REPLY) {
|
||||
// reply info
|
||||
reader(header->reply_port);
|
||||
reader(header->reply_target);
|
||||
reader(header->reply_team);
|
||||
|
||||
// big flags
|
||||
uint8 bigFlag;
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->reply_target = B_PREFERRED_TOKEN;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_REPLY_DONE;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_IS_REPLY;
|
||||
}
|
||||
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_SCRIPT_MESSAGE)
|
||||
header->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
|
||||
|
||||
uint8 flags;
|
||||
reader(flags);
|
||||
while (flags & R5_FIELD_FLAG_VALID) {
|
||||
bool fixedSize = flags & R5_FIELD_FLAG_FIXED_SIZE;
|
||||
bool miniData = flags & R5_FIELD_FLAG_MINI_DATA;
|
||||
bool singleItem = flags & R5_FIELD_FLAG_SINGLE_ITEM;
|
||||
|
||||
type_code type;
|
||||
reader(type);
|
||||
|
||||
int32 itemCount;
|
||||
if (!singleItem) {
|
||||
if (miniData) {
|
||||
uint8 miniCount;
|
||||
reader(miniCount);
|
||||
itemCount = miniCount;
|
||||
} else
|
||||
reader(itemCount);
|
||||
} else
|
||||
itemCount = 1;
|
||||
|
||||
ssize_t dataSize;
|
||||
if (miniData) {
|
||||
uint8 miniSize;
|
||||
reader(miniSize);
|
||||
dataSize = miniSize;
|
||||
} else
|
||||
reader(dataSize);
|
||||
|
||||
if (dataSize <= 0)
|
||||
return B_ERROR;
|
||||
|
||||
// name
|
||||
uint8 nameLength;
|
||||
reader(nameLength);
|
||||
|
||||
char nameBuffer[256];
|
||||
reader(nameBuffer, nameLength);
|
||||
nameBuffer[nameLength] = '\0';
|
||||
|
||||
uint8 *buffer = (uint8 *)malloc(dataSize);
|
||||
uint8 *pointer = buffer;
|
||||
reader(buffer, dataSize);
|
||||
|
||||
status_t result = B_OK;
|
||||
ssize_t itemSize = 0;
|
||||
if (fixedSize)
|
||||
itemSize = dataSize / itemCount;
|
||||
|
||||
for (int32 i = 0; i < itemCount; i++) {
|
||||
if (!fixedSize) {
|
||||
itemSize = *(ssize_t *)pointer;
|
||||
pointer += sizeof(ssize_t);
|
||||
}
|
||||
|
||||
result = into->AddData(nameBuffer, type, pointer, itemSize,
|
||||
fixedSize, itemCount);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fixedSize)
|
||||
pointer += itemSize;
|
||||
else
|
||||
pointer += pad_to_8(itemSize + sizeof(ssize_t)) - sizeof(ssize_t);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
// flags of next field or termination byte
|
||||
reader(flags);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MessageAdapter::_UnflattenDanoMessage(uint32 format, BMessage *into,
|
||||
BDataIO *stream)
|
||||
{
|
||||
into->MakeEmpty();
|
||||
|
||||
TReadHelper reader(stream);
|
||||
if (format == MESSAGE_FORMAT_DANO_SWAPPED)
|
||||
reader.SetSwap(true);
|
||||
|
||||
ssize_t size;
|
||||
reader(size);
|
||||
|
||||
dano_message_header header;
|
||||
reader(header);
|
||||
into->what = header.what;
|
||||
|
||||
size -= sizeof(dano_section_header) + sizeof(dano_message_header);
|
||||
int32 offset = 0;
|
||||
|
||||
while (offset < size) {
|
||||
dano_section_header sectionHeader;
|
||||
reader(sectionHeader);
|
||||
|
||||
// be safe. this shouldn't be necessary but in some testcases it was.
|
||||
sectionHeader.size = pad_to_8(sectionHeader.size);
|
||||
|
||||
if (offset + sectionHeader.size > size || sectionHeader.size < 0)
|
||||
return B_BAD_DATA;
|
||||
|
||||
ssize_t fieldSize = sectionHeader.size - sizeof(dano_section_header);
|
||||
uint8 *fieldBuffer = NULL;
|
||||
if (fieldSize > 0) {
|
||||
// there may be no data. we shouldn't fail because of that
|
||||
fieldBuffer = (uint8 *)malloc(fieldSize);
|
||||
if (fieldBuffer == NULL)
|
||||
throw (status_t)B_NO_MEMORY;
|
||||
|
||||
reader(fieldBuffer, fieldSize);
|
||||
}
|
||||
|
||||
switch (sectionHeader.code) {
|
||||
case SECTION_OFFSET_TABLE:
|
||||
case SECTION_TARGET_INFORMATION:
|
||||
case SECTION_SORTED_INDEX_TABLE:
|
||||
case SECTION_END_OF_DATA:
|
||||
// discard
|
||||
break;
|
||||
|
||||
case SECTION_SINGLE_ITEM_DATA: {
|
||||
dano_single_item *field = (dano_single_item *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(dano_single_item)
|
||||
+ field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
|
||||
if (offset + dataOffset + field->item_size > size)
|
||||
return B_BAD_DATA;
|
||||
|
||||
// support for fixed size is not possible with a single item
|
||||
bool fixedSize = false;
|
||||
switch (field->type) {
|
||||
case B_RECT_TYPE:
|
||||
case B_POINT_TYPE:
|
||||
case B_INT8_TYPE:
|
||||
case B_INT16_TYPE:
|
||||
case B_INT32_TYPE:
|
||||
case B_INT64_TYPE:
|
||||
case B_BOOL_TYPE:
|
||||
case B_FLOAT_TYPE:
|
||||
case B_DOUBLE_TYPE:
|
||||
case B_POINTER_TYPE:
|
||||
case B_MESSENGER_TYPE:
|
||||
fixedSize = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status_t result = into->AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset, field->item_size, fixedSize);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_FIXED_SIZE_ARRAY_DATA: {
|
||||
dano_fixed_size_array *field
|
||||
= (dano_fixed_size_array *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(dano_fixed_size_array)
|
||||
+ field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
int32 count = *(int32 *)(fieldBuffer + dataOffset);
|
||||
dataOffset += 8; /* count and padding */
|
||||
|
||||
if (offset + dataOffset + count * field->size_per_item > size)
|
||||
return B_BAD_DATA;
|
||||
|
||||
status_t result = B_OK;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
result = into->AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset, field->size_per_item, true,
|
||||
count);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
|
||||
dataOffset += field->size_per_item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_VARIABLE_SIZE_ARRAY_DATA: {
|
||||
dano_variable_size_array *field
|
||||
= (dano_variable_size_array *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(dano_variable_size_array)
|
||||
+ field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
int32 count = *(int32 *)(fieldBuffer + dataOffset);
|
||||
dataOffset += sizeof(int32);
|
||||
ssize_t totalSize = *(ssize_t *)(fieldBuffer + dataOffset);
|
||||
dataOffset += sizeof(ssize_t);
|
||||
|
||||
int32 *endPoints = (int32 *)(fieldBuffer + dataOffset
|
||||
+ totalSize);
|
||||
|
||||
status_t result = B_OK;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
int32 itemOffset = (i > 0 ? pad_to_8(endPoints[i - 1]) : 0);
|
||||
|
||||
result = into->AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset + itemOffset,
|
||||
endPoints[i] - itemOffset, false, count);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(fieldBuffer);
|
||||
offset += sectionHeader.size;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} // namespace BPrivate
|
||||
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005-2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
* Michael Lotz, mmlr@mlotz.ch
|
||||
*/
|
||||
|
||||
|
||||
#include "dano_message.h"
|
||||
|
||||
#include <MessageUtils.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
enum {
|
||||
SECTION_MESSAGE_HEADER = 'FOB2',
|
||||
SECTION_OFFSET_TABLE = 'STof',
|
||||
SECTION_TARGET_INFORMATION = 'ENwh',
|
||||
SECTION_SINGLE_ITEM_DATA = 'SGDa',
|
||||
SECTION_FIXED_SIZE_ARRAY_DATA = 'FADa',
|
||||
SECTION_VARIABLE_SIZE_ARRAY_DATA = 'VADa',
|
||||
SECTION_SORTED_INDEX_TABLE = 'DXIn',
|
||||
SECTION_END_OF_DATA = 'DDEn'
|
||||
};
|
||||
|
||||
|
||||
struct section_header {
|
||||
uint32 code;
|
||||
ssize_t size;
|
||||
uint8 data[0];
|
||||
} _PACKED;
|
||||
|
||||
struct message_header {
|
||||
int32 what;
|
||||
int32 padding;
|
||||
} _PACKED;
|
||||
|
||||
typedef struct offset_table_s {
|
||||
int32 indexTable;
|
||||
int32 endOfData;
|
||||
int64 padding;
|
||||
} OffsetTable;
|
||||
|
||||
struct single_item {
|
||||
type_code type;
|
||||
ssize_t item_size;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
struct fixed_size_array {
|
||||
type_code type;
|
||||
ssize_t size_per_item;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
struct variable_size_array {
|
||||
type_code type;
|
||||
int32 padding;
|
||||
uint8 name_length;
|
||||
char name[0];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
static const uint32 kMessageFormatSwapped = '2BOF';
|
||||
|
||||
|
||||
inline int32
|
||||
pad_to_8(int32 value)
|
||||
{
|
||||
return (value + 7) & ~7;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
BPrivate::dano_message_flattened_size(const char *buffer)
|
||||
{
|
||||
section_header *header = (section_header *)buffer;
|
||||
|
||||
// The size contains the message format that won't be part of
|
||||
// the buffer unflatten_dano_message() will get
|
||||
|
||||
if (header->code == kMessageFormatSwapped)
|
||||
return __swap_int32(header->size) - sizeof(header->code);
|
||||
|
||||
return header->size - sizeof(header->code);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BPrivate::unflatten_dano_message(uint32 format, BDataIO &stream,
|
||||
BMessage &message)
|
||||
{
|
||||
TReadHelper reader(&stream);
|
||||
message.MakeEmpty();
|
||||
|
||||
if (format == kMessageFormatSwapped)
|
||||
reader.SetSwap(true);
|
||||
|
||||
ssize_t size;
|
||||
reader(size);
|
||||
|
||||
message_header header;
|
||||
reader(header);
|
||||
message.what = header.what;
|
||||
|
||||
size -= sizeof(section_header) + sizeof(message_header);
|
||||
int32 offset = 0;
|
||||
|
||||
while (offset < size) {
|
||||
section_header sectionHeader;
|
||||
reader(sectionHeader);
|
||||
|
||||
// be safe. this shouldn't be necessary but in some testcases it was.
|
||||
sectionHeader.size = pad_to_8(sectionHeader.size);
|
||||
|
||||
if (offset + sectionHeader.size > size || sectionHeader.size < 0)
|
||||
return B_BAD_DATA;
|
||||
|
||||
ssize_t fieldSize = sectionHeader.size - sizeof(section_header);
|
||||
uint8 *fieldBuffer = NULL;
|
||||
if (fieldSize > 0) {
|
||||
// there may be no data. we shouldn't fail because of that
|
||||
fieldBuffer = (uint8 *)malloc(fieldSize);
|
||||
if (fieldBuffer == NULL)
|
||||
throw (status_t)B_NO_MEMORY;
|
||||
|
||||
reader(fieldBuffer, fieldSize);
|
||||
}
|
||||
|
||||
switch (sectionHeader.code) {
|
||||
case SECTION_OFFSET_TABLE:
|
||||
case SECTION_TARGET_INFORMATION:
|
||||
case SECTION_SORTED_INDEX_TABLE:
|
||||
case SECTION_END_OF_DATA:
|
||||
// discard
|
||||
break;
|
||||
|
||||
case SECTION_SINGLE_ITEM_DATA: {
|
||||
single_item *field = (single_item *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(single_item) + field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
|
||||
if (offset + dataOffset + field->item_size > size)
|
||||
return B_BAD_DATA;
|
||||
|
||||
// support for fixed size is not possible with a single item
|
||||
bool fixedSize = false;
|
||||
switch (field->type) {
|
||||
case B_RECT_TYPE:
|
||||
case B_POINT_TYPE:
|
||||
case B_INT8_TYPE:
|
||||
case B_INT16_TYPE:
|
||||
case B_INT32_TYPE:
|
||||
case B_INT64_TYPE:
|
||||
case B_BOOL_TYPE:
|
||||
case B_FLOAT_TYPE:
|
||||
case B_DOUBLE_TYPE:
|
||||
case B_POINTER_TYPE:
|
||||
case B_MESSENGER_TYPE:
|
||||
fixedSize = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status_t result = message.AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset, field->item_size, fixedSize);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_FIXED_SIZE_ARRAY_DATA: {
|
||||
fixed_size_array *field = (fixed_size_array *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(fixed_size_array) + field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
int32 count = *(int32 *)(fieldBuffer + dataOffset);
|
||||
dataOffset += 8; /* count and padding */
|
||||
|
||||
if (offset + dataOffset + count * field->size_per_item > size)
|
||||
return B_BAD_DATA;
|
||||
|
||||
status_t result = B_OK;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
result = message.AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset, field->size_per_item, true,
|
||||
count);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
|
||||
dataOffset += field->size_per_item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_VARIABLE_SIZE_ARRAY_DATA: {
|
||||
variable_size_array *field = (variable_size_array *)fieldBuffer;
|
||||
|
||||
int32 dataOffset = sizeof(variable_size_array) + field->name_length + 1;
|
||||
dataOffset = pad_to_8(dataOffset);
|
||||
int32 count = *(int32 *)(fieldBuffer + dataOffset);
|
||||
dataOffset += sizeof(int32);
|
||||
ssize_t totalSize = *(ssize_t *)(fieldBuffer + dataOffset);
|
||||
dataOffset += sizeof(ssize_t);
|
||||
|
||||
int32 *endPoints = (int32 *)(fieldBuffer + dataOffset
|
||||
+ totalSize);
|
||||
|
||||
status_t result = B_OK;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
int32 itemOffset = (i > 0 ? pad_to_8(endPoints[i - 1]) : 0);
|
||||
|
||||
result = message.AddData(field->name, field->type,
|
||||
fieldBuffer + dataOffset + itemOffset,
|
||||
endPoints[i] - itemOffset, false, count);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(fieldBuffer);
|
||||
throw result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(fieldBuffer);
|
||||
offset += sectionHeader.size;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
*/
|
||||
#ifndef DANO_MESSAGE_H
|
||||
#define DANO_MESSAGE_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BMessage;
|
||||
class BDataIO;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
status_t unflatten_dano_message(uint32 format, BDataIO& stream, BMessage& message);
|
||||
ssize_t dano_message_flattened_size(const char* buffer);
|
||||
|
||||
}
|
||||
|
||||
#endif // DANO_MESSAGE_H
|
||||
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
|
||||
#include "r5_message.h"
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <MessagePrivate.h>
|
||||
#include <MessageUtils.h>
|
||||
#include <TokenSpace.h>
|
||||
|
||||
#define R5_MESSAGE_FLAG_VALID 0x01
|
||||
#define R5_MESSAGE_FLAG_INCLUDE_TARGET 0x02
|
||||
#define R5_MESSAGE_FLAG_INCLUDE_REPLY 0x04
|
||||
#define R5_MESSAGE_FLAG_SCRIPT_MESSAGE 0x08
|
||||
|
||||
#define R5_FIELD_FLAG_VALID 0x01
|
||||
#define R5_FIELD_FLAG_MINI_DATA 0x02
|
||||
#define R5_FIELD_FLAG_FIXED_SIZE 0x04
|
||||
#define R5_FIELD_FLAG_SINGLE_ITEM 0x08
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
static const uint32 kR5MessageMagic = 'FOB1';
|
||||
static const uint32 kR5MessageMagicSwapped = '1BOF';
|
||||
|
||||
|
||||
struct r5_message_header {
|
||||
uint32 magic; // kR5MessageMagic
|
||||
uint32 checksum;
|
||||
ssize_t flattened_size;
|
||||
int32 what;
|
||||
uint8 flags;
|
||||
} _PACKED;
|
||||
|
||||
|
||||
inline int32
|
||||
pad_to_8(int32 value)
|
||||
{
|
||||
return (value + 7) & ~7;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
r5_message_flattened_size(const BMessage *message)
|
||||
{
|
||||
BMessage::Private messagePrivate((BMessage *)message);
|
||||
BMessage::message_header* header = messagePrivate.GetMessageHeader();
|
||||
|
||||
// header size (variable, depending on the flags)
|
||||
|
||||
ssize_t flattenedSize = sizeof(r5_message_header);
|
||||
|
||||
if (header->target != B_NULL_TOKEN)
|
||||
flattenedSize += sizeof(int32);
|
||||
|
||||
if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN
|
||||
&& header->reply_team >= 0) {
|
||||
// reply info + big flags
|
||||
flattenedSize += sizeof(port_id) + sizeof(int32) + sizeof(team_id) + 4;
|
||||
}
|
||||
|
||||
// field size
|
||||
|
||||
uint8 *data = messagePrivate.GetMessageData();
|
||||
BMessage::field_header* field = messagePrivate.GetMessageFields();
|
||||
for (int32 i = 0; i < header->field_count; i++, field++) {
|
||||
// flags and type
|
||||
flattenedSize += 1 + sizeof(type_code);
|
||||
|
||||
#if 0
|
||||
bool miniData = field->dataSize <= 255 && field->count <= 255;
|
||||
#else
|
||||
// ToDo: we don't know the R5 dataSize yet (padding)
|
||||
bool miniData = false;
|
||||
#endif
|
||||
|
||||
// item count
|
||||
if (field->count > 1)
|
||||
flattenedSize += (miniData ? sizeof(uint8) : sizeof(uint32));
|
||||
|
||||
// data size
|
||||
flattenedSize += (miniData ? sizeof(uint8) : sizeof(size_t));
|
||||
|
||||
// name length and name
|
||||
flattenedSize += 1 + min_c(field->name_length - 1, 255);
|
||||
|
||||
// data
|
||||
if (field->flags & FIELD_FLAG_FIXED_SIZE)
|
||||
flattenedSize += field->data_size;
|
||||
else {
|
||||
uint8 *source = data + field->offset + field->name_length;
|
||||
|
||||
for (int32 i = 0; i < field->count; i++) {
|
||||
ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t);
|
||||
flattenedSize += pad_to_8(itemSize);
|
||||
source += itemSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pseudo field with flags 0
|
||||
return flattenedSize + 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
flatten_r5_message(const BMessage *message, char *buffer, ssize_t size)
|
||||
{
|
||||
BMessage::Private messagePrivate((BMessage *)message);
|
||||
BMessage::message_header* header = messagePrivate.GetMessageHeader();
|
||||
uint8* data = messagePrivate.GetMessageData();
|
||||
|
||||
r5_message_header* r5header = (r5_message_header *)buffer;
|
||||
uint8* pointer = (uint8 *)buffer + sizeof(r5_message_header);
|
||||
|
||||
r5header->magic = kR5MessageMagic;
|
||||
r5header->what = message->what;
|
||||
r5header->checksum = 0;
|
||||
|
||||
uint8 flags = R5_MESSAGE_FLAG_VALID;
|
||||
if (header->target != B_NULL_TOKEN) {
|
||||
*(int32 *)pointer = header->target;
|
||||
pointer += sizeof(int32);
|
||||
flags |= R5_MESSAGE_FLAG_INCLUDE_TARGET;
|
||||
}
|
||||
|
||||
if (header->reply_port >= 0 && header->reply_target != B_NULL_TOKEN
|
||||
&& header->reply_team >= 0) {
|
||||
// reply info
|
||||
*(port_id *)pointer = header->reply_port;
|
||||
pointer += sizeof(port_id);
|
||||
*(int32 *)pointer = header->reply_target;
|
||||
pointer += sizeof(int32);
|
||||
*(team_id *)pointer = header->reply_team;
|
||||
pointer += sizeof(team_id);
|
||||
|
||||
// big flags
|
||||
*pointer = (header->reply_target == B_PREFERRED_TOKEN ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_REPLY_REQUIRED ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_REPLY_DONE ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
*pointer = (header->flags & MESSAGE_FLAG_IS_REPLY ? 1 : 0);
|
||||
pointer++;
|
||||
|
||||
flags |= R5_MESSAGE_FLAG_INCLUDE_REPLY;
|
||||
}
|
||||
|
||||
if (header->flags & MESSAGE_FLAG_HAS_SPECIFIERS)
|
||||
flags |= R5_MESSAGE_FLAG_SCRIPT_MESSAGE;
|
||||
|
||||
r5header->flags = flags;
|
||||
|
||||
// store the header size - used for the checksum later
|
||||
ssize_t headerSize = (uint32)pointer - (uint32)buffer;
|
||||
|
||||
// collect and add the data
|
||||
BMessage::field_header* field = messagePrivate.GetMessageFields();
|
||||
for (int32 i = 0; i < header->field_count; i++, field++) {
|
||||
flags = R5_FIELD_FLAG_VALID;
|
||||
|
||||
if (field->count == 1)
|
||||
flags |= R5_FIELD_FLAG_SINGLE_ITEM;
|
||||
// ToDo: we don't really know the data size now (padding missing)
|
||||
if (field->data_size <= 255 && field->count <= 255)
|
||||
;//flags |= R5_FIELD_FLAG_MINI_DATA;
|
||||
if (field->flags & FIELD_FLAG_FIXED_SIZE)
|
||||
flags |= R5_FIELD_FLAG_FIXED_SIZE;
|
||||
|
||||
*pointer = flags;
|
||||
pointer++;
|
||||
|
||||
*(type_code *)pointer = field->type;
|
||||
pointer += sizeof(type_code);
|
||||
|
||||
if (!(flags & R5_FIELD_FLAG_SINGLE_ITEM)) {
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA) {
|
||||
*pointer = (uint8)field->count;
|
||||
pointer++;
|
||||
} else {
|
||||
*(int32 *)pointer = field->count;
|
||||
pointer += sizeof(int32);
|
||||
}
|
||||
}
|
||||
|
||||
// we may have to adjust this to account for padding later
|
||||
uint8 *fieldSize = pointer;
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA) {
|
||||
*pointer = (uint8)field->data_size;
|
||||
pointer++;
|
||||
} else {
|
||||
*(ssize_t *)pointer = field->data_size;
|
||||
pointer += sizeof(ssize_t);
|
||||
}
|
||||
|
||||
// name
|
||||
int32 nameLength = min_c(field->name_length - 1, 255);
|
||||
*pointer = (uint8)nameLength;
|
||||
pointer++;
|
||||
|
||||
strncpy((char *)pointer, (char *)data + field->offset, nameLength);
|
||||
pointer += nameLength;
|
||||
|
||||
// data
|
||||
uint8 *source = data + field->offset + field->name_length;
|
||||
if (flags & R5_FIELD_FLAG_FIXED_SIZE) {
|
||||
memcpy(pointer, source, field->data_size);
|
||||
pointer += field->data_size;
|
||||
} else {
|
||||
uint8 *previous = pointer;
|
||||
for (int32 i = 0; i < field->count; i++) {
|
||||
ssize_t itemSize = *(ssize_t *)source + sizeof(ssize_t);
|
||||
memcpy(pointer, source, itemSize);
|
||||
pointer += pad_to_8(itemSize);
|
||||
source += itemSize;
|
||||
}
|
||||
|
||||
// adjust the field size to the padded value
|
||||
if (flags & R5_FIELD_FLAG_MINI_DATA)
|
||||
*fieldSize = (uint8)(pointer - previous);
|
||||
else
|
||||
*(ssize_t *)fieldSize = (pointer - previous);
|
||||
}
|
||||
}
|
||||
|
||||
// terminate the fields with a pseudo field with flags 0 (not valid)
|
||||
*pointer = 0;
|
||||
pointer++;
|
||||
|
||||
// calculate the flattened size from the pointers
|
||||
r5header->flattened_size = (uint32)pointer - (uint32)buffer;
|
||||
r5header->checksum = BPrivate::CalculateChecksum((uint8 *)(buffer + 8),
|
||||
headerSize - 8);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
flatten_r5_message(const BMessage *message, BDataIO *stream, ssize_t *_size)
|
||||
{
|
||||
// ToDo: This is not very cheap...
|
||||
ssize_t size = r5_message_flattened_size(message);
|
||||
char *buffer = (char *)malloc(size);
|
||||
if (!buffer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t result = flatten_r5_message(message, buffer, size);
|
||||
if (result < B_OK) {
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t written = stream->Write(buffer, size);
|
||||
if (written != size) {
|
||||
free(buffer);
|
||||
return (written >= 0 ? B_ERROR : written);
|
||||
}
|
||||
|
||||
if (_size)
|
||||
*_size = size;
|
||||
|
||||
free(buffer);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
unflatten_r5_message(uint32 format, BMessage *message, const char *flatBuffer)
|
||||
{
|
||||
r5_message_header *r5header = (r5_message_header *)flatBuffer;
|
||||
BMemoryIO stream(flatBuffer + 4, r5header->flattened_size - 4);
|
||||
return unflatten_r5_message(format, message, &stream);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
unflatten_r5_message(uint32 format, BMessage *message, BDataIO *stream)
|
||||
{
|
||||
message->MakeEmpty();
|
||||
|
||||
TReadHelper reader(stream);
|
||||
BMessage::Private messagePrivate(message);
|
||||
BMessage::message_header *header = messagePrivate.GetMessageHeader();
|
||||
|
||||
if (format == kR5MessageMagicSwapped)
|
||||
reader.SetSwap(true);
|
||||
|
||||
// the stream is already advanced by the size of the "format"
|
||||
r5_message_header r5header;
|
||||
reader(((uint8 *)&r5header) + sizeof(uint32),
|
||||
sizeof(r5header) - sizeof(uint32));
|
||||
|
||||
header->what = message->what = r5header.what;
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_TARGET)
|
||||
reader(header->target);
|
||||
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_INCLUDE_REPLY) {
|
||||
// reply info
|
||||
reader(header->reply_port);
|
||||
reader(header->reply_target);
|
||||
reader(header->reply_team);
|
||||
|
||||
// big flags
|
||||
uint8 bigFlag;
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->reply_target = B_PREFERRED_TOKEN;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_REPLY_DONE;
|
||||
|
||||
reader(bigFlag);
|
||||
if (bigFlag)
|
||||
header->flags |= MESSAGE_FLAG_IS_REPLY;
|
||||
}
|
||||
|
||||
if (r5header.flags & R5_MESSAGE_FLAG_SCRIPT_MESSAGE)
|
||||
header->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
|
||||
|
||||
uint8 flags;
|
||||
reader(flags);
|
||||
while (flags & R5_FIELD_FLAG_VALID) {
|
||||
bool fixedSize = flags & R5_FIELD_FLAG_FIXED_SIZE;
|
||||
bool miniData = flags & R5_FIELD_FLAG_MINI_DATA;
|
||||
bool singleItem = flags & R5_FIELD_FLAG_SINGLE_ITEM;
|
||||
|
||||
type_code type;
|
||||
reader(type);
|
||||
|
||||
int32 itemCount;
|
||||
if (!singleItem) {
|
||||
if (miniData) {
|
||||
uint8 miniCount;
|
||||
reader(miniCount);
|
||||
itemCount = miniCount;
|
||||
} else
|
||||
reader(itemCount);
|
||||
} else
|
||||
itemCount = 1;
|
||||
|
||||
ssize_t dataSize;
|
||||
if (miniData) {
|
||||
uint8 miniSize;
|
||||
reader(miniSize);
|
||||
dataSize = miniSize;
|
||||
} else
|
||||
reader(dataSize);
|
||||
|
||||
if (dataSize <= 0)
|
||||
return B_ERROR;
|
||||
|
||||
// name
|
||||
uint8 nameLength;
|
||||
reader(nameLength);
|
||||
|
||||
char nameBuffer[256];
|
||||
reader(nameBuffer, nameLength);
|
||||
nameBuffer[nameLength] = '\0';
|
||||
|
||||
uint8 *buffer = (uint8 *)malloc(dataSize);
|
||||
uint8 *pointer = buffer;
|
||||
reader(buffer, dataSize);
|
||||
|
||||
status_t result = B_OK;
|
||||
ssize_t itemSize = 0;
|
||||
if (fixedSize)
|
||||
itemSize = dataSize / itemCount;
|
||||
|
||||
for (int32 i = 0; i < itemCount; i++) {
|
||||
if (!fixedSize) {
|
||||
itemSize = *(ssize_t *)pointer;
|
||||
pointer += sizeof(ssize_t);
|
||||
}
|
||||
|
||||
result = message->AddData(nameBuffer, type, pointer, itemSize,
|
||||
fixedSize, itemCount);
|
||||
|
||||
if (result < B_OK) {
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fixedSize)
|
||||
pointer += itemSize;
|
||||
else
|
||||
pointer += pad_to_8(itemSize + sizeof(ssize_t)) - sizeof(ssize_t);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
// flags of next field or termination byte
|
||||
reader(flags);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} // namespace BPrivate
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
#ifndef _R5_MESSAGE_H_
|
||||
#define _R5_MESSAGE_H_
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BMessage;
|
||||
class BDataIO;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
ssize_t r5_message_flattened_size(const BMessage *message);
|
||||
status_t flatten_r5_message(const BMessage *message, char *buffer, ssize_t size);
|
||||
status_t flatten_r5_message(const BMessage *message, BDataIO *stream, ssize_t *size);
|
||||
status_t unflatten_r5_message(uint32 format, BMessage *message, const char *flatBuffer);
|
||||
status_t unflatten_r5_message(uint32 format, BMessage *message, BDataIO *stream);
|
||||
|
||||
}
|
||||
|
||||
#endif // _R5_MESSAGE_H_
|
||||
Reference in New Issue
Block a user