Introducing Message4. The changes to the related sources are ifdefed with USING_MESSAGE4 which is defined in Message4.h. To use Message4 the Message4.cpp, Message4.h, MessageUtils4.cpp, MessageUtils4.h and MessagePrivate4.h have to be linked to their counterparts without 4 suffix. Then MessageBody.cpp and MessageField.cpp have to be commented out in the app kit Jamfile and r5_message.cpp has to be added. There remain some bugs to be found. Feel free to change that.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14882 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2005-11-13 11:31:07 +00:00
parent 4cfc480f5d
commit cf10934e5f
18 changed files with 3742 additions and 0 deletions
+330
View File
@@ -0,0 +1,330 @@
/*
* Copyright 2005, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#ifndef _MESSAGE_H
#define _MESSAGE_H
#define USING_MESSAGE4 1
#include <BeBuild.h>
#include <DataIO.h>
#include <Flattenable.h>
#include <OS.h>
#include <Rect.h>
#include <AppDefs.h> /* For convenience */
#include <TypeConstants.h> /* For convenience */
class BBlockCache;
class BMessenger;
class BHandler;
class BString;
struct message_header_s;
struct field_header_s;
// Private or reserved ---------------------------------------------------------
extern "C" void _msg_cache_cleanup_();
extern "C" int _init_message_();
extern "C" int _delete_message_();
//------------------------------------------------------------------------------
// Name lengths and Scripting specifiers ---------------------------------------
#define B_FIELD_NAME_LENGTH 255
#define B_PROPERTY_NAME_LENGTH 255
enum
{
B_NO_SPECIFIER = 0,
B_DIRECT_SPECIFIER = 1,
B_INDEX_SPECIFIER,
B_REVERSE_INDEX_SPECIFIER,
B_RANGE_SPECIFIER,
B_REVERSE_RANGE_SPECIFIER,
B_NAME_SPECIFIER,
B_ID_SPECIFIER,
B_SPECIFIERS_END = 128
// app-defined specifiers start at B_SPECIFIERS_END + 1
};
//------------------------------------------------------------------------------
class BMessage {
public:
uint32 what;
BMessage();
BMessage(uint32 what);
BMessage(const BMessage &other);
virtual ~BMessage();
BMessage &operator=(const BMessage &other);
// Statistics and misc info
status_t GetInfo(type_code typeRequested, int32 index,
char **nameFound, type_code *typeFound,
int32 *countFound = NULL) const;
status_t GetInfo(const char *name, type_code *typeFound,
int32 *countFound = NULL) const;
status_t GetInfo(const char *name, type_code *typeFound,
bool *fixedSize) const;
int32 CountNames(type_code type) const;
bool IsEmpty() const;
bool IsSystem() const;
bool IsReply() const;
void PrintToStream() const;
status_t Rename(const char *oldEntry, const char *newEntry);
// Delivery info
bool WasDelivered() const;
bool IsSourceWaiting() const;
bool IsSourceRemote() const;
BMessenger ReturnAddress() const;
const BMessage *Previous() const;
bool WasDropped() const;
BPoint DropPoint(BPoint *offset = NULL) const;
// Replying
status_t SendReply(uint32 command, BHandler *replyTo = NULL);
status_t SendReply(BMessage *reply, BHandler *replyTo = NULL,
bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t SendReply(BMessage *reply, BMessenger replyTo,
bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t SendReply(uint32 command, BMessage *replyToReply);
status_t SendReply(BMessage *the_reply, BMessage *replyToReply,
bigtime_t sendTimeout = B_INFINITE_TIMEOUT,
bigtime_t replyTimeout = B_INFINITE_TIMEOUT);
// Flattening data
ssize_t FlattenedSize() const;
status_t Flatten(char *buffer, ssize_t size) const;
status_t Flatten(BDataIO *stream, ssize_t *size = NULL) const;
status_t Unflatten(const char *flatBuffer);
status_t Unflatten(BDataIO *stream);
// Specifiers (scripting)
status_t AddSpecifier(const char *property);
status_t AddSpecifier(const char *property, int32 index);
status_t AddSpecifier(const char *property, int32 index, int32 range);
status_t AddSpecifier(const char *property, const char *name);
status_t AddSpecifier(const BMessage *specifier);
status_t SetCurrentSpecifier(int32 index);
status_t GetCurrentSpecifier(int32 *index,
BMessage *specifier = NULL, int32 *what = NULL,
const char **property = NULL) const;
bool HasSpecifiers() const;
status_t PopSpecifier();
// Adding data
status_t AddRect(const char *name, BRect aRect);
status_t AddPoint(const char *name, BPoint aPoint);
status_t AddString(const char *name, const char *aString);
status_t AddString(const char *name, const BString &aString);
status_t AddInt8(const char *name, int8 value);
status_t AddInt16(const char *name, int16 value);
status_t AddInt32(const char *name, int32 value);
status_t AddInt64(const char *name, int64 value);
status_t AddBool(const char *name, bool aBoolean);
status_t AddFloat(const char *name, float aFloat);
status_t AddDouble(const char *name, double aDouble);
status_t AddPointer(const char *name, const void *aPointer);
status_t AddMessenger(const char *name, BMessenger messenger);
status_t AddRef(const char *name, const entry_ref *ref);
status_t AddMessage(const char *name, const BMessage *message);
status_t AddFlat(const char *name, BFlattenable *object,
int32 count = 1);
status_t AddData(const char *name, type_code type,
const void *data, ssize_t numBytes,
bool isFixedSize = true, int32 count = 1);
// Removing data
status_t RemoveData(const char *name, int32 index = 0);
status_t RemoveName(const char *name);
status_t MakeEmpty();
// Finding data
status_t FindRect(const char *name, BRect *rect) const;
status_t FindRect(const char *name, int32 index, BRect *rect) const;
status_t FindPoint(const char *name, BPoint *point) const;
status_t FindPoint(const char *name, int32 index, BPoint *point) const;
status_t FindString(const char *name, const char **string) const;
status_t FindString(const char *name, int32 index, const char **string) const;
status_t FindString(const char *name, BString *string) const;
status_t FindString(const char *name, int32 index, BString *string) const;
status_t FindInt8(const char *name, int8 *value) const;
status_t FindInt8(const char *name, int32 index, int8 *value) const;
status_t FindInt16(const char *name, int16 *value) const;
status_t FindInt16(const char *name, int32 index, int16 *value) const;
status_t FindInt32(const char *name, int32 *value) const;
status_t FindInt32(const char *name, int32 index, int32 *value) const;
status_t FindInt64(const char *name, int64 *value) const;
status_t FindInt64(const char *name, int32 index, int64 *value) const;
status_t FindBool(const char *name, bool *value) const;
status_t FindBool(const char *name, int32 index, bool *value) const;
status_t FindFloat(const char *name, float *value) const;
status_t FindFloat(const char *name, int32 index, float *value) const;
status_t FindDouble(const char *name, double *value) const;
status_t FindDouble(const char *name, int32 index, double *value) const;
status_t FindPointer(const char *name, void **pointer) const;
status_t FindPointer(const char *name, int32 index, void **pointer) const;
status_t FindMessenger(const char *name, BMessenger *messenger) const;
status_t FindMessenger(const char *name, int32 index, BMessenger *messenger) const;
status_t FindRef(const char *name, entry_ref *ref) const;
status_t FindRef(const char *name, int32 index, entry_ref *ref) const;
status_t FindMessage(const char *name, BMessage *message) const;
status_t FindMessage(const char *name, int32 index, BMessage *message) const;
status_t FindFlat(const char *name, BFlattenable *object) const;
status_t FindFlat(const char *name, int32 index, BFlattenable *object) const;
status_t FindData(const char *name, type_code type,
const void **data, ssize_t *numBytes) const;
status_t FindData(const char *name, type_code type, int32 index,
const void **data, ssize_t *numBytes) const;
// Replacing data
status_t ReplaceRect(const char *name, BRect aRect);
status_t ReplaceRect(const char *name, int32 index, BRect aRect);
status_t ReplacePoint(const char *name, BPoint aPoint);
status_t ReplacePoint(const char *name, int32 index, BPoint aPoint);
status_t ReplaceString(const char *name, const char *aString);
status_t ReplaceString(const char *name, int32 index, const char *aString);
status_t ReplaceString(const char *name, const BString &aString);
status_t ReplaceString(const char *name, int32 index, const BString &aString);
status_t ReplaceInt8(const char *name, int8 value);
status_t ReplaceInt8(const char *name, int32 index, int8 value);
status_t ReplaceInt16(const char *name, int16 value);
status_t ReplaceInt16(const char *name, int32 index, int16 value);
status_t ReplaceInt32(const char *name, int32 value);
status_t ReplaceInt32(const char *name, int32 index, int32 value);
status_t ReplaceInt64(const char *name, int64 value);
status_t ReplaceInt64(const char *name, int32 index, int64 value);
status_t ReplaceBool(const char *name, bool aBoolean);
status_t ReplaceBool(const char *name, int32 index, bool aBoolean);
status_t ReplaceFloat(const char *name, float aFloat);
status_t ReplaceFloat(const char *name, int32 index, float aFloat);
status_t ReplaceDouble(const char *name, double aDouble);
status_t ReplaceDouble(const char *name, int32 index, double aDouble);
status_t ReplacePointer(const char *name, const void *pointer);
status_t ReplacePointer(const char *name,int32 index,const void *pointer);
status_t ReplaceMessenger(const char *name, BMessenger messenger);
status_t ReplaceMessenger(const char *name, int32 index, BMessenger messenger);
status_t ReplaceRef( const char *name,const entry_ref *ref);
status_t ReplaceRef( const char *name, int32 index, const entry_ref *ref);
status_t ReplaceMessage(const char *name, const BMessage *message);
status_t ReplaceMessage(const char *name, int32 index, const BMessage *message);
status_t ReplaceFlat(const char *name, BFlattenable *object);
status_t ReplaceFlat(const char *name, int32 index, BFlattenable *object);
status_t ReplaceData(const char *name, type_code type,
const void *data, ssize_t numBytes);
status_t ReplaceData(const char *name, type_code type, int32 index,
const void *data, ssize_t numBytes);
void *operator new(size_t size);
void *operator new(size_t, void *pointer);
void operator delete(void *pointer, size_t size);
// Private, reserved, or obsolete ----------------------------------------------
bool HasRect(const char *, int32 n = 0) const;
bool HasPoint(const char *, int32 n = 0) const;
bool HasString(const char *, int32 n = 0) const;
bool HasInt8(const char *, int32 n = 0) const;
bool HasInt16(const char *, int32 n = 0) const;
bool HasInt32(const char *, int32 n = 0) const;
bool HasInt64(const char *, int32 n = 0) const;
bool HasBool(const char *, int32 n = 0) const;
bool HasFloat(const char *, int32 n = 0) const;
bool HasDouble(const char *, int32 n = 0) const;
bool HasPointer(const char *, int32 n = 0) const;
bool HasMessenger(const char *, int32 n = 0) const;
bool HasRef(const char *, int32 n = 0) const;
bool HasMessage(const char *, int32 n = 0) const;
bool HasFlat(const char *, const BFlattenable *) const;
bool HasFlat(const char *, int32 n, const BFlattenable *) const;
bool HasData(const char *, type_code , int32 n = 0) const;
BRect FindRect(const char *, int32 n = 0) const;
BPoint FindPoint(const char *, int32 n = 0) const;
const char *FindString(const char *, int32 n = 0) const;
int8 FindInt8(const char *, int32 n = 0) const;
int16 FindInt16(const char *, int32 n = 0) const;
int32 FindInt32(const char *, int32 n = 0) const;
int64 FindInt64(const char *, int32 n = 0) const;
bool FindBool(const char *, int32 n = 0) const;
float FindFloat(const char *, int32 n = 0) const;
double FindDouble(const char *, int32 n = 0) const;
class Private;
private:
friend class Private;
friend class BMessageQueue;
status_t _InitCommon();
status_t _InitHeader();
status_t _Clear();
status_t _ResizeData(int32 offset, int32 change);
uint32 _HashName(const char *name) const;
status_t _FindField(const char *name, type_code type,
field_header_s **result) const;
status_t _AddField(const char *name, type_code type,
bool isFixedSize, field_header_s **result);
status_t _RemoveField(field_header_s *field);
ssize_t _NativeFlattenedSize() const;
status_t _NativeFlatten(char *buffer, ssize_t size) const;
status_t _NativeFlatten(BDataIO *stream, ssize_t *size = NULL) const;
message_header_s*fHeader;
field_header_s *fFields;
uint8 *fData;
mutable BMessage *fOriginal;
// fQueueLink is used by BMessageQueue to build a linked list
BMessage *fQueueLink;
uint32 fReserved[11];
// deprecated
BMessage(BMessage *a_message);
virtual void _ReservedMessage1();
virtual void _ReservedMessage2();
virtual void _ReservedMessage3();
status_t _SendMessage(port_id port, int32 token, bool preferred,
bigtime_t timeout, bool replyRequired,
BMessenger &replyTo) const;
status_t _SendMessage(port_id port, team_id portOwner,
int32 token, bool preferred, BMessage *reply,
bigtime_t sendTimeout, bigtime_t replyTimeout) const;
static status_t _SendFlattenedMessage(void *data, int32 size,
port_id port, int32 token, bool preferred,
bigtime_t timeout);
static void _StaticInit();
static void _StaticCleanup();
static void _StaticCacheCleanup();
static int32 _StaticGetCachedReplyPort();
enum { sNumReplyPorts = 3 };
static port_id sReplyPorts[sNumReplyPorts];
static long sReplyPortInUse[sNumReplyPorts];
static int32 sGetCachedReplyPort();
static BBlockCache *sMsgCache;
};
#endif // _MESSAGE_H
+201
View File
@@ -0,0 +1,201 @@
#ifndef _MESSAGE_PRIVATE_H_
#define _MESSAGE_PRIVATE_H_
#include <Message.h>
#include <Messenger.h>
#include <MessengerPrivate.h>
#include <TokenSpace.h>
#define MESSAGE_BODY_HASH_TABLE_SIZE 10
#define MAX_DATA_PREALLOCATION B_PAGE_SIZE * 10
#define MAX_FIELD_PREALLOCATION 50
#define MAX_ITEM_PREALLOCATION B_PAGE_SIZE
enum {
MESSAGE_FLAG_VALID = 0x0001,
MESSAGE_FLAG_REPLY_REQUIRED = 0x0002,
MESSAGE_FLAG_REPLY_DONE = 0x0004,
MESSAGE_FLAG_IS_REPLY = 0x0008,
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
MESSAGE_FLAG_READ_ONLY = 0x0040
};
enum {
FIELD_FLAG_VALID = 0x0001,
FIELD_FLAG_FIXED_SIZE = 0x0002,
};
typedef struct field_header_s {
uint32 flags;
type_code type;
int32 nameLength;
int32 count;
ssize_t dataSize;
ssize_t allocated;
int32 offset;
int32 nextField;
} FieldHeader;
typedef struct message_header_s {
uint32 format;
uint32 what;
uint32 flags;
ssize_t fieldsSize;
ssize_t dataSize;
ssize_t fieldsAvailable;
ssize_t dataAvailable;
int32 target;
int32 currentSpecifier;
// reply info
port_id replyPort;
int32 replyTarget;
team_id replyTeam;
// body info
int32 fieldCount;
int32 hashTableSize;
int32 hashTable[MESSAGE_BODY_HASH_TABLE_SIZE];
/* The hash table does contain indexes into the field list and
not direct offsets to the fields. This has the advantage
of not needing to update offsets in two locations.
The hash table must be reevaluated when we remove a field
though.
*/
} MessageHeader;
class BMessage::Private {
public:
Private(BMessage *msg)
: fMessage(msg)
{
}
Private(BMessage &msg)
: fMessage(&msg)
{
}
inline void SetTarget(int32 token, bool preferred)
{
fMessage->fHeader->target = (preferred
? B_PREFERRED_TOKEN : token);
}
inline void SetReply(BMessenger messenger)
{
BMessenger::Private messengerPrivate(messenger);
fMessage->fHeader->replyPort = messengerPrivate.Port();
fMessage->fHeader->replyTarget = messengerPrivate.Token();
fMessage->fHeader->replyTeam = messengerPrivate.Team();
}
inline int32 GetTarget()
{
return fMessage->fHeader->target;
}
inline bool UsePreferredTarget()
{
return fMessage->fHeader->target == B_PREFERRED_TOKEN;
}
inline status_t Clear()
{
return fMessage->_Clear();
}
inline status_t InitHeader()
{
return fMessage->_InitHeader();
}
inline MessageHeader *GetMessageHeader()
{
return fMessage->fHeader;
}
inline FieldHeader *GetMessageFields()
{
return fMessage->fFields;
}
inline uint8 *GetMessageData()
{
return fMessage->fData;
}
inline ssize_t NativeFlattenedSize() const
{
return fMessage->_NativeFlattenedSize();
}
inline status_t NativeFlatten(char *buffer, ssize_t size) const
{
return fMessage->_NativeFlatten(buffer, size);
}
inline status_t NativeFlatten(BDataIO *stream, ssize_t *size) const
{
return fMessage->_NativeFlatten(stream, size);
}
inline status_t SendMessage(port_id port, int32 token, bool preferred,
bigtime_t timeout, bool replyRequired,
BMessenger &replyTo) const
{
return fMessage->_SendMessage(port, token,
preferred, timeout, replyRequired, replyTo);
}
inline status_t SendMessage(port_id port, team_id portOwner,
int32 token, bool preferred, BMessage *reply,
bigtime_t sendTimeout, bigtime_t replyTimeout) const
{
return fMessage->_SendMessage(port, portOwner, token,
preferred, reply, sendTimeout, replyTimeout);
}
static
inline status_t SendFlattenedMessage(void *data, int32 size,
port_id port, int32 token, bool preferred,
bigtime_t timeout)
{
return BMessage::_SendFlattenedMessage(data, size,
port, token, preferred, timeout);
}
static
inline void StaticInit()
{
BMessage::_StaticInit();
}
static
inline void StaticCleanup()
{
BMessage::_StaticCleanup();
}
static
inline void StaticCacheCleanup()
{
BMessage::_StaticCacheCleanup();
}
private:
BMessage *fMessage;
};
#endif // _MESSAGE_PRIVATE_H_
+173
View File
@@ -0,0 +1,173 @@
#ifndef _MESSAGE_UTILS_H_
#define _MESSAGE_UTILS_H_
#include <ByteOrder.h>
#include <DataIO.h>
#include <Entry.h>
#include <Message.h>
#include <SupportDefs.h>
namespace BPrivate { // Only putting these here because Be did
status_t entry_ref_flatten(char* buffer, size_t* size, const entry_ref* ref);
status_t entry_ref_unflatten(entry_ref* ref, const char* buffer, size_t size);
status_t entry_ref_swap(char* buffer, size_t size);
uint32 CalculateChecksum(const uint8 *buffer, int32 size);
} // namespace BPrivate
template<class T>
inline void
byte_swap(T &/*data*/)
{
// Specialize for data types which actually swap
}
inline void
write_helper(BDataIO *stream, const void *data, size_t size)
{
status_t error = stream->Write(data, size);
if (error < B_OK)
throw error;
}
class TReadHelper {
public:
TReadHelper(BDataIO *stream)
: fStream(stream),
fError(B_OK),
fSwap(false)
{
}
TReadHelper(BDataIO *stream, bool swap)
: fStream(stream),
fError(B_OK),
fSwap(swap)
{
}
template<class T>
inline void operator()(T &data)
{
fError = fStream->Read((void *)&data, sizeof(T));
if (fError > B_OK) {
if (IsSwapping())
byte_swap(data);
return;
}
if (fError == 0)
throw B_ERROR;
throw fError;
}
template<class T>
inline void operator()(T data, size_t len)
{
fError = fStream->Read((void *)data, len);
if (fError > B_OK)
return;
if (fError == 0)
throw B_ERROR;
throw fError;
}
status_t Status() { return fError; };
void SetSwap(bool yesNo) { fSwap = yesNo; };
bool IsSwapping() { return fSwap; };
private:
BDataIO *fStream;
status_t fError;
bool fSwap;
};
class TChecksumHelper {
public:
TChecksumHelper(uchar* buffer)
: fBuffer(buffer),
fBufPtr(buffer)
{
}
template<class T>
inline void Cache(const T &data)
{
*((T*)fBufPtr) = data;
fBufPtr += sizeof (T);
}
int32 CheckSum();
private:
uchar *fBuffer;
uchar *fBufPtr;
};
template<class T>
inline status_t
read_helper(BDataIO *stream, T &data)
{
return normalize_err(stream->Read((void *)&data, sizeof(T)));
}
template<>
inline void
byte_swap(double &data)
{
data = __swap_double(data);
}
template<>
inline void
byte_swap(float &data)
{
data = __swap_float(data);
}
template<>
inline void
byte_swap(int64 &data)
{
data = __swap_int64(data);
}
template<>
inline void
byte_swap(int32 &data)
{
data = __swap_int32(data);
}
template<>
inline void
byte_swap(int16 &data)
{
data = __swap_int16(data);
}
template<>
inline void
byte_swap(entry_ref &data)
{
byte_swap(data.device);
byte_swap(data.directory);
}
#endif // _MESSAGE_UTILS_H_
+16
View File
@@ -60,8 +60,24 @@ using BPrivate::BObjectLocker;
using BPrivate::BLooperList;
port_id _get_looper_port_(const BLooper* looper);
#ifndef USING_MESSAGE4
bool _use_preferred_target_(BMessage* msg) { return msg->fPreferred; }
int32 _get_message_target_(BMessage* msg) { return msg->fTarget; }
#else
#include <MessagePrivate.h>
inline bool
_use_preferred_target_(BMessage *message)
{
return BMessage::Private(message).UsePreferredTarget();
}
inline int32
_get_message_target_(BMessage *message)
{
return BMessage::Private(message).GetTarget();
}
#endif
uint32 BLooper::sLooperID = (uint32)B_ERROR;
team_id BLooper::sTeamID = (team_id)B_ERROR;
File diff suppressed because it is too large Load Diff
+44
View File
@@ -71,7 +71,11 @@ BMessageQueue::~BMessageQueue()
BMessage *theMessage = fTheQueue;
while (theMessage != NULL) {
BMessage *messageToDelete = theMessage;
#ifndef USING_MESSAGE4
theMessage = theMessage->link;
#else
theMessage = theMessage->fQueueLink;
#endif
delete messageToDelete;
}
}
@@ -112,7 +116,11 @@ BMessageQueue::AddMessage(BMessage *message)
// The message passed in will be the last message on the queue so its
// link member should be set to null.
#ifndef USING_MESSAGE4
message->link = NULL;
#else
message->fQueueLink = NULL;
#endif
// We now have one more BMessage on the queue.
fMessageCount++;
@@ -127,7 +135,11 @@ BMessageQueue::AddMessage(BMessage *message)
// BMessage at the end. The last BMessage prior to this AddMessage()
// is fQueueTail. The BMessage at fQueueTail needs to point to the
// new last message, the one being added.
#ifndef USING_MESSAGE4
fQueueTail->link = message;
#else
fQueueTail->fQueueLink = message;
#endif
// Now update the fQueueTail to point to this new last message.
fQueueTail = message;
@@ -165,7 +177,11 @@ BMessageQueue::RemoveMessage(BMessage *message)
if (fTheQueue == message) {
// We need to special case the handling of removing the first element.
// First, the new front element will be the next one.
#ifndef USING_MESSAGE4
fTheQueue = fTheQueue->link;
#else
fTheQueue = fTheQueue->fQueueLink;
#endif
// Must decrement the count of elements since the front one is being
// removed.
@@ -191,7 +207,11 @@ BMessageQueue::RemoveMessage(BMessage *message)
while (messageIter != NULL) {
// If the next message after this (ie second, then third etc) is
// the one we are looking for.
#ifndef USING_MESSAGE4
if (messageIter->link == message) {
#else
if (messageIter->fQueueLink == message) {
#endif
// At this point, this is what we have:
// messageIter - the BMessage in the queue just before the
// match
@@ -202,13 +222,21 @@ BMessageQueue::RemoveMessage(BMessage *message)
// The next step is to link the BMessage just before the match
// to the one just after the match. This removes the match from
// the queue.
#ifndef USING_MESSAGE4
messageIter->link = message->link;
#else
messageIter->fQueueLink = message->fQueueLink;
#endif
// One less element on the queue.
fMessageCount--;
// If there is no BMessage after the match is the
#ifndef USING_MESSAGE4
if (message->link == NULL) {
#else
if (message->fQueueLink == NULL) {
#endif
// That means that we just removed the last element from the
// queue. The new last element then must be messageIter.
fQueueTail = messageIter;
@@ -219,7 +247,11 @@ BMessageQueue::RemoveMessage(BMessage *message)
}
// No match yet, go to the next element in the list.
#ifndef USING_MESSAGE4
messageIter = messageIter->link;
#else
messageIter = messageIter->fQueueLink;
#endif
}
}
}
@@ -290,7 +322,11 @@ BMessageQueue::FindMessage(int32 index) const
// reaches zero.
index--;
// Increment the messageIter to the next BMessage on the queue.
#ifndef USING_MESSAGE4
messageIter = messageIter->link;
#else
messageIter = messageIter->fQueueLink;
#endif
}
// If no match was found, messageIter will be NULL since that is the only
@@ -347,7 +383,11 @@ BMessageQueue::FindMessage(uint32 what,
index--;
}
// Increment the messageIter to the next BMessage on the queue.
#ifndef USING_MESSAGE4
messageIter = messageIter->link;
#else
messageIter = messageIter->fQueueLink;
#endif
}
// If no match was found, messageIter will be NULL since that is the only
@@ -422,7 +462,11 @@ BMessageQueue::NextMessage(void)
fMessageCount--;
// The new front of the list is moved forward thereby removing the
// first element from the queue.
#ifndef USING_MESSAGE4
fTheQueue = fTheQueue->link;
#else
fTheQueue = fTheQueue->fQueueLink;
#endif
// If the queue is empty after removing the front element.
if (fTheQueue == NULL) {
// We need to set the tail of the queue to NULL since the queue
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright 2001-2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Erik Jaesler (erik@cgsoftware.com)
*/
/** Extra messaging utility functions */
#include <string.h>
#include <ByteOrder.h>
#include <MessageUtils.h>
namespace BPrivate {
uint32
CalculateChecksum(const uint8 *buffer, int32 size)
{
uint32 sum = 0;
uint32 temp = 0;
while (size > 3) {
#if defined(__INTEL__)
sum += B_SWAP_INT32(*(int32 *)buffer);
#else
sum += *(int32 *)buffer;
#endif
buffer += 4;
size -= 4;
}
while (size > 0) {
temp = (temp << 8) + *buffer++;
size -= 1;
}
return sum + temp;
}
/* entry_ref support functions */
status_t
entry_ref_flatten(char *buffer, size_t *size, const entry_ref *ref)
{
memcpy((void *)buffer, (const void *)&ref->device, sizeof(ref->device));
buffer += sizeof(ref->device);
memcpy((void *)buffer, (const void *)&ref->directory, sizeof(ref->directory));
buffer += sizeof (ref->directory);
size_t nameLength = 0;
if (ref->name) {
nameLength = strlen(ref->name) + 1;
memcpy((void *)buffer, (const void *)ref->name, nameLength);
}
*size = sizeof(ref->device) + sizeof(ref->directory) + nameLength;
return B_OK;
}
status_t
entry_ref_unflatten(entry_ref *ref, const char *buffer, size_t size)
{
if (size < sizeof(ref->device) + sizeof(ref->directory)) {
*ref = entry_ref();
return B_BAD_VALUE;
}
memcpy((void *)&ref->device, (const void *)buffer, sizeof(ref->device));
buffer += sizeof (ref->device);
memcpy((void *)&ref->directory, (const void *)buffer, sizeof(ref->directory));
buffer += sizeof(ref->directory);
if (ref->device != -1 && size > sizeof(ref->device)
+ sizeof(ref->directory)) {
ref->set_name(buffer);
if (ref->name == NULL) {
*ref = entry_ref();
return B_NO_MEMORY;
}
} else
ref->set_name(NULL);
return B_OK;
}
status_t
entry_ref_swap(char *buffer, size_t size)
{
if (size < sizeof(dev_t) + sizeof(ino_t))
return B_BAD_VALUE;
dev_t *dev = (dev_t *)buffer;
*dev = B_SWAP_INT32(*dev);
buffer += sizeof(dev_t);
ino_t *ino = (ino_t *)buffer;
*ino = B_SWAP_INT64(*ino);
return B_OK;
}
} // namespace BPrivate
+15
View File
@@ -51,6 +51,10 @@
#include "ObjectLocker.h"
#include "TokenSpace.h"
#ifdef USING_MESSAGE4
#include <MessagePrivate.h>
#endif
// Local Includes --------------------------------------------------------------
// Local Defines ---------------------------------------------------------------
@@ -353,8 +357,13 @@ BMessenger::SendMessage(BMessage *message, BMessenger replyTo,
if (!message)
return B_BAD_VALUE;
#ifndef USING_MESSAGE4
return message->_send_(fPort, fHandlerToken, fPreferredTarget,
timeout, false, replyTo);
#else
return BMessage::Private(message).SendMessage(fPort, fHandlerToken,
fPreferredTarget, timeout, false, replyTo);
#endif
}
// SendMessage
@@ -413,9 +422,15 @@ BMessenger::SendMessage(BMessage *message, BMessage *reply,
{
status_t error = (message && reply ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
#ifndef USING_MESSAGE4
error = message->send_message(fPort, fTeam, fHandlerToken,
fPreferredTarget, reply, deliveryTimeout,
replyTimeout);
#else
error = BMessage::Private(message).SendMessage(fPort, fTeam,
fHandlerToken, fPreferredTarget, reply, deliveryTimeout,
replyTimeout);
#endif
// Map this error for now:
if (error == B_BAD_TEAM_ID)
error = B_BAD_PORT_ID;
+396
View File
@@ -0,0 +1,396 @@
#include <DataIO.h>
#include <MessagePrivate.h>
#include <MessageUtils.h>
#include <TokenSpace.h>
#include "r5_message.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';
typedef struct r5_message_header_s {
uint32 magic; // kR5MessageMagic
uint32 checksum;
ssize_t flattenedSize;
int32 what;
uint8 flags;
} _PACKED R5MessageHeader;
inline int32
pad_to_8(int32 value)
{
return (value + 7) & ~7;
}
ssize_t
R5MessageFlattenedSize(const BMessage *message)
{
BMessage::Private messagePrivate((BMessage *)message);
MessageHeader *header = messagePrivate.GetMessageHeader();
ssize_t flattenedSize = sizeof(R5MessageHeader);
if (header->target != B_NULL_TOKEN)
flattenedSize += sizeof(int32);
if (header->replyPort >= 0 && header->replyTarget != B_NULL_TOKEN
&& header->replyTeam >= 0) {
// reply info
flattenedSize += sizeof(port_id) + sizeof(int32) + sizeof(team_id);
// big flags
flattenedSize += 4;
}
uint8 *data = messagePrivate.GetMessageData();
FieldHeader *field = messagePrivate.GetMessageFields();
for (int32 i = 0; i < header->fieldCount; i++, field++) {
// flags and type
flattenedSize += 1 + sizeof(type_code);
// item count
#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
if (field->count > 1)
flattenedSize += (miniData ? sizeof(uint8) : sizeof(int32));
// data size
flattenedSize += (miniData ? sizeof(uint8) : sizeof(ssize_t));
// name length and name
flattenedSize += 1 + min_c(field->nameLength - 1, 255);
// data
if (field->flags & FIELD_FLAG_FIXED_SIZE)
flattenedSize += field->dataSize;
else {
uint8 *source = data + field->offset + field->nameLength;
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
R5MessageFlatten(const BMessage *message, char *buffer, ssize_t size)
{
BMessage::Private messagePrivate((BMessage *)message);
MessageHeader *header = messagePrivate.GetMessageHeader();
uint8 *data = messagePrivate.GetMessageData();
R5MessageHeader *r5header = (R5MessageHeader *)buffer;
uint8 *pointer = (uint8 *)buffer + sizeof(R5MessageHeader);
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->replyPort >= 0 && header->replyTarget != B_NULL_TOKEN
&& header->replyTeam >= 0) {
// reply info
*(port_id *)pointer = header->replyPort;
pointer += sizeof(port_id);
*(int32 *)pointer = header->replyTarget;
pointer += sizeof(int32);
*(team_id *)pointer = header->replyTeam;
pointer += sizeof(team_id);
// big flags
*pointer = (header->replyTarget == 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
FieldHeader *field = messagePrivate.GetMessageFields();
for (int32 i = 0; i < header->fieldCount; 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->dataSize <= 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->dataSize;
pointer++;
} else {
*(ssize_t *)pointer = field->dataSize;
pointer += sizeof(ssize_t);
}
// name
int32 nameLength = min_c(field->nameLength - 1, 255);
*pointer = (uint8)nameLength;
pointer++;
strncpy((char *)pointer, (char *)data + field->offset, nameLength);
pointer += nameLength;
// data
uint8 *source = data + field->offset + field->nameLength;
if (flags & R5_FIELD_FLAG_FIXED_SIZE) {
memcpy(pointer, source, field->dataSize);
pointer += field->dataSize;
} 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->flattenedSize = (uint32)pointer - (uint32)buffer;
r5header->checksum = BPrivate::CalculateChecksum((uint8 *)(buffer + 8),
headerSize - 8);
return B_OK;
}
status_t
R5MessageFlatten(const BMessage *message, BDataIO *stream, ssize_t *_size)
{
// ToDo: This is not very cheap...
ssize_t size = R5MessageFlattenedSize(message);
char *buffer = (char *)malloc(size);
if (!buffer)
return B_NO_MEMORY;
status_t result = R5MessageFlatten(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
R5MessageUnflatten(BMessage *message, const char *flatBuffer)
{
R5MessageHeader *r5header = (R5MessageHeader *)flatBuffer;
BMemoryIO stream(flatBuffer + 4, r5header->flattenedSize - 4);
return R5MessageUnflatten(message, &stream);
}
status_t
R5MessageUnflatten(BMessage *message, BDataIO *stream)
{
TReadHelper reader(stream);
BMessage::Private messagePrivate(message);
MessageHeader *header = messagePrivate.GetMessageHeader();
// the stream is already advanced by the size of the "format"
R5MessageHeader r5header;
reader(((uint8 *)&r5header) + sizeof(uint32),
sizeof(r5header) - sizeof(uint32));
messagePrivate.Clear();
messagePrivate.InitHeader();
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->replyPort);
reader(header->replyTarget);
reader(header->replyTeam);
// big flags
uint8 bigFlag;
reader(bigFlag);
if (bigFlag)
header->replyTarget = 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);
// 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
+17
View File
@@ -0,0 +1,17 @@
#ifndef _R5_MESSAGE_H_
#define _R5_MESSAGE_H_
class BMessage;
class BDataIO;
namespace BPrivate {
ssize_t R5MessageFlattenedSize(const BMessage *message);
status_t R5MessageFlatten(const BMessage *message, char *buffer, ssize_t size);
status_t R5MessageFlatten(const BMessage *message, BDataIO *stream, ssize_t *size);
status_t R5MessageUnflatten(BMessage *message, const char *flatBuffer);
status_t R5MessageUnflatten(BMessage *message, BDataIO *stream);
}
#endif
+12
View File
@@ -42,6 +42,10 @@
#include <PortLink.h>
#include <ServerProtocol.h>
#ifdef USING_MESSAGE4
#include <MessagePrivate.h>
#endif
#include <stdio.h>
@@ -1261,7 +1265,11 @@ BView::DragMessage(BMessage *message, BRect dragRect, BHandler *replyTo)
message->AddInt32("buttons", buttons);
}
#ifndef USING_MESSAGE4
_set_message_reply_(message, BMessenger(replyTo, replyTo->Looper()));
#else
BMessage::Private(message).SetReply(BMessenger(replyTo, replyTo->Looper()));
#endif
int32 bufferSize = message->FlattenedSize();
char *buffer = new char[bufferSize];
@@ -1314,7 +1322,11 @@ BView::DragMessage(BMessage *message, BBitmap *image,
message->AddInt32("buttons", buttons);
}
#ifndef USING_MESSAGE4
_set_message_reply_(message, BMessenger(replyTo, replyTo->Looper()));
#else
BMessage::Private(message).SetReply(BMessenger(replyTo, replyTo->Looper()));
#endif
int32 bufferSize = message->FlattenedSize();
char *buffer = new char[bufferSize];
+18
View File
@@ -34,6 +34,10 @@
#include <TokenSpace.h>
#include <MessageUtils.h>
#ifdef USING_MESSAGE4
#include <MessagePrivate.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <math.h>
@@ -2249,15 +2253,29 @@ BWindow::task_looper()
dispatchNextMessage = false;
} else {
// Get the target handler
#ifdef USING_MESSAGE4
// Use the private BMessage accessor to determine if we are
// using the preferred handler, or if a target has been
// specified
BHandler *handler;
BMessage::Private messagePrivate(fLastMessage);
bool usePreferred = messagePrivate.UsePreferredTarget();
#else
// Use BMessage friend functions to determine if we are using the
// preferred handler, or if a target has been specified
BHandler* handler;
bool usePreferred = _use_preferred_target_(fLastMessage);
#endif
if (usePreferred) {
handler = PreferredHandler();
} else {
#ifndef USING_MESSAGE4
gDefaultTokens.GetToken(_get_message_target_(fLastMessage),
B_HANDLER_TOKEN, (void **)&handler);
#else
gDefaultTokens.GetToken(messagePrivate.GetTarget(),
B_HANDLER_TOKEN, (void **)&handler);
#endif
}
// if a target was given, and we should not use the preferred
+7
View File
@@ -2094,6 +2094,7 @@ ServerWindow::SendMessageToClient(const BMessage* msg, int32 target, bool usePre
char* buffer = new(nothrow) char[size];
status_t ret;
#ifndef USING_MESSAGE4
if ((ret = msg->Flatten(buffer, size)) == B_OK) {
ret = BMessage::Private::SendFlattenedMessage(buffer, size,
fClientLooperPort, target, usePreferred, 100000);
@@ -2101,6 +2102,12 @@ ServerWindow::SendMessageToClient(const BMessage* msg, int32 target, bool usePre
fprintf(stderr, "ServerWindow::SendMessageToClient(): %s\n", strerror(ret));
} else
printf("PANIC: ServerWindow %s: can't flatten message in 'SendMessageToClient()'\n", fTitle);
#else
BMessenger reply;
BMessage::Private messagePrivate((BMessage *)msg);
ret = messagePrivate.SendMessage(fClientLooperPort, target, usePreferred,
100000, false, reply);
#endif
delete[] buffer;
+6
View File
@@ -31,10 +31,14 @@ SendMessage(port_id port, BMessage *message, int32 target)
if (!message)
return;
#ifndef USING_MESSAGE4
if (target == -1)
_set_message_target_(message, target, true);
else
_set_message_target_(message, target, false);
#else
BMessage::Private(message).SetTarget(target, target == -1);
#endif
ssize_t size = message->FlattenedSize();
char *buffer = new char[size];
@@ -47,6 +51,7 @@ SendMessage(port_id port, BMessage *message, int32 target)
}
#ifndef USING_MESSAGE4
/*
Below are friend functions for BMessage which currently are not in the Message.cpp
that we need to send messages to BLoopers and such. Placed here to allow compilation.
@@ -79,6 +84,7 @@ _use_preferred_target_(BMessage *msg)
{
return msg->fPreferred;
}
#endif
const char *
+4
View File
@@ -31,6 +31,10 @@
#include <OS.h>
#include <Accelerant.h>
#ifdef USING_MESSAGE4
#include <MessagePrivate.h>
#endif
void SendMessage(port_id port, BMessage *message, int32 target=-1);
const char *MsgCodeToString(int32 code);
BString MsgCodeToBString(int32 code);
@@ -605,6 +605,7 @@ MessageDeliverer::DeliverMessage(BMessage *message, MessagingTargetSet &targets,
if (!message)
return B_BAD_VALUE;
#ifndef USING_MESSAGE4
// Set the token now, so that the header contains room for it.
// It will be set when sending the message anyway, but if it is not set
// before flattening, the header will not contain room for it, and it
@@ -616,6 +617,13 @@ MessageDeliverer::DeliverMessage(BMessage *message, MessagingTargetSet &targets,
status_t error = message->Flatten(&mallocIO);
if (error != B_OK)
return error;
#else
// flatten the message
BMallocIO mallocIO;
status_t error = BMessage::Private(message).NativeFlatten(&mallocIO, NULL);
if (error < B_OK)
return error;
#endif
return DeliverMessage(mallocIO.Buffer(), mallocIO.BufferLength(), targets,
timeout);
+6
View File
@@ -42,10 +42,14 @@ void SendMessage(port_id port, BMessage *message, int32 target)
if(!message)
return;
#ifndef USING_MESSAGE4
if(target==-1)
_set_message_target_(message,target,true);
else
_set_message_target_(message,target,false);
#else
BMessage::Private(message).SetTarget(target, target == -1);
#endif
ssize_t flatsize=message->FlattenedSize();
char *buffer=new char[flatsize];
@@ -57,6 +61,7 @@ void SendMessage(port_id port, BMessage *message, int32 target)
delete message;
}
#ifndef USING_MESSAGE4
/*
Below are friend functions for BMessage which currently are not in the Message.cpp
that we need to send messages to BLoopers and such. Placed here to allow compilation.
@@ -87,6 +92,7 @@ bool _use_preferred_target_(BMessage *msg)
{
return msg->fPreferred;
}
#endif // !USING_MESSAGE4
const char *MsgCodeToString(int32 code)
{
+4
View File
@@ -31,6 +31,10 @@
#include <OS.h>
#include <Accelerant.h>
#ifdef USING_MESSAGE4
#include <MessagePrivate.h>
#endif
void SendMessage(port_id port, BMessage *message, int32 target=-1);
const char *MsgCodeToString(int32 code);
BString MsgCodeToBString(int32 code);