This is the third implementation of BMessage. It operates purly on a flat buffer. It should be completely working and it is fast. See: http://haiku.mlotz.ch/messagespeed.html

Sorry to pollute the repository with all those extra files, they will be (re-)moved when the decision about which implementation to use is made.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13916 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2005-08-08 01:34:09 +00:00
parent 896d777151
commit 3019039f4f
7 changed files with 3834 additions and 0 deletions

View File

@ -0,0 +1,454 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2005, Haiku
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Message.h
// Author(s): Erik Jaesler (erik@cgsoftware.com)
// DarkWyrm <bpmagic@columbus.rr.com>
// Description: BMessage class creates objects that store data and that
// can be processed in a message loop. BMessage objects
// are also used as data containers by the archiving and
// the scripting mechanisms.
//------------------------------------------------------------------------------
#ifndef _MESSAGE_H
#define _MESSAGE_H
#include <BeBuild.h>
#include <OS.h>
#include <Rect.h>
#include <DataIO.h>
#include <Flattenable.h>
#include <AppDefs.h> /* For convenience */
#include <TypeConstants.h> /* For convenience */
class BBlockCache;
class BMessenger;
class BHandler;
class BString;
// 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
};
namespace BPrivate {
class BMessageBody;
}
// BMessage class --------------------------------------------------------------
class BMessage
{
public:
uint32 what;
BMessage();
BMessage(uint32 what);
BMessage(const BMessage &a_message);
virtual ~BMessage();
BMessage &operator=(const BMessage &msg);
// Statistics and misc info
status_t GetInfo(type_code typeRequested, int32 which, char **name,
type_code *typeReturned, int32 *count = NULL) const;
status_t GetInfo(const char *name, type_code *type, int32 *c = 0) const;
status_t GetInfo(const char *name, type_code *type, bool *fixed_size) const;
int32 CountNames(type_code type) const;
bool IsEmpty() const;
bool IsSystem() const;
bool IsReply() const;
void PrintToStream() const;
status_t Rename(const char *old_entry, const char *new_entry);
// 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 *reply_to = NULL);
status_t SendReply(BMessage *the_reply, BHandler *reply_to = NULL,
bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t SendReply(BMessage *the_reply, BMessenger reply_to,
bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t SendReply(uint32 command, BMessage *reply_to_reply);
status_t SendReply(BMessage *the_reply, BMessage *reply_to_reply,
bigtime_t send_timeout = B_INFINITE_TIMEOUT,
bigtime_t reply_timeout = 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 *flat_buffer);
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 *form = NULL, const char **property = NULL) const;
bool HasSpecifiers() const;
status_t PopSpecifier();
// Adding data
status_t AddRect(const char *name, BRect a_rect);
status_t AddPoint(const char *name, BPoint a_point);
status_t AddString(const char *name, const char *a_string);
status_t AddString(const char *name, const BString& a_string);
status_t AddInt8(const char *name, int8 val);
status_t AddInt16(const char *name, int16 val);
status_t AddInt32(const char *name, int32 val);
status_t AddInt64(const char *name, int64 val);
status_t AddBool(const char *name, bool a_boolean);
status_t AddFloat(const char *name, float a_float);
status_t AddDouble(const char *name, double a_double);
status_t AddPointer(const char *name, const void *ptr);
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 *msg);
status_t AddFlat(const char *name, BFlattenable *obj, int32 count = 1);
status_t AddData(const char *name, type_code type, const void *data,
ssize_t numBytes, bool is_fixed_size = 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 *pt) const;
status_t FindPoint(const char *name, int32 index, BPoint *pt) const;
status_t FindString(const char *name, const char **str) const;
status_t FindString(const char *name, int32 index, const char **str) const;
status_t FindString(const char *name, BString *str) const;
status_t FindString(const char *name, int32 index, BString *str) const;
status_t FindInt8(const char *name, int8 *value) const;
status_t FindInt8(const char *name, int32 index, int8 *val) const;
status_t FindInt16(const char *name, int16 *value) const;
status_t FindInt16(const char *name, int32 index, int16 *val) const;
status_t FindInt32(const char *name, int32 *value) const;
status_t FindInt32(const char *name, int32 index, int32 *val) const;
status_t FindInt64(const char *name, int64 *value) const;
status_t FindInt64(const char *name, int32 index, int64 *val) 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 *f) const;
status_t FindFloat(const char *name, int32 index, float *f) const;
status_t FindDouble(const char *name, double *d) const;
status_t FindDouble(const char *name, int32 index, double *d) const;
status_t FindPointer(const char *name, void **ptr) const;
status_t FindPointer(const char *name, int32 index, void **ptr) const;
status_t FindMessenger(const char *name, BMessenger *m) const;
status_t FindMessenger(const char *name, int32 index, BMessenger *m) 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 *msg) const;
status_t FindMessage(const char *name, int32 index, BMessage *msg) const;
status_t FindFlat(const char *name, BFlattenable *obj) const;
status_t FindFlat(const char *name, int32 index, BFlattenable *obj) 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 a_rect);
status_t ReplaceRect(const char *name, int32 index, BRect a_rect);
status_t ReplacePoint(const char *name, BPoint a_point);
status_t ReplacePoint(const char *name, int32 index, BPoint a_point);
status_t ReplaceString(const char *name, const char *string);
status_t ReplaceString(const char *name, int32 index, const char *string);
status_t ReplaceString(const char *name, const BString& string);
status_t ReplaceString(const char *name, int32 index, const BString& string);
status_t ReplaceInt8(const char *name, int8 val);
status_t ReplaceInt8(const char *name, int32 index, int8 val);
status_t ReplaceInt16(const char *name, int16 val);
status_t ReplaceInt16(const char *name, int32 index, int16 val);
status_t ReplaceInt32(const char *name, int32 val);
status_t ReplaceInt32(const char *name, int32 index, int32 val);
status_t ReplaceInt64(const char *name, int64 val);
status_t ReplaceInt64(const char *name, int32 index, int64 val);
status_t ReplaceBool(const char *name, bool a_bool);
status_t ReplaceBool(const char *name, int32 index, bool a_bool);
status_t ReplaceFloat(const char *name, float a_float);
status_t ReplaceFloat(const char *name, int32 index, float a_float);
status_t ReplaceDouble(const char *name, double a_double);
status_t ReplaceDouble(const char *name, int32 index, double a_double);
status_t ReplacePointer(const char *name, const void *ptr);
status_t ReplacePointer(const char *name,int32 index,const void *ptr);
status_t ReplaceMessenger(const char *name, BMessenger messenger);
status_t ReplaceMessenger(const char *name, int32 index, BMessenger msngr);
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 *msg);
status_t ReplaceMessage(const char *name, int32 index, const BMessage *msg);
status_t ReplaceFlat(const char *name, BFlattenable *obj);
status_t ReplaceFlat(const char *name, int32 index, BFlattenable *obj);
status_t ReplaceData(const char *name, type_code type,
const void *data, ssize_t data_size);
status_t ReplaceData(const char *name, type_code type, int32 index,
const void *data, ssize_t data_size);
void *operator new(size_t size);
void *operator new(size_t, void* p);
void operator delete(void *ptr, 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 ,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:
class Header;
friend class BMessageQueue;
friend class BMessenger;
friend class BApplication;
friend class Header;
friend class Private;
friend inline void _set_message_target_(BMessage *, int32, bool);
friend inline void _set_message_reply_(BMessage *, BMessenger);
friend inline int32 _get_message_target_(BMessage *);
friend inline bool _use_preferred_target_(BMessage *);
// deprecated
BMessage(BMessage *a_message);
virtual void _ReservedMessage1();
virtual void _ReservedMessage2();
virtual void _ReservedMessage3();
void init_data();
status_t flatten_target_info(BDataIO *stream,
ssize_t size,
uchar flags) const;
status_t real_flatten(char *result, ssize_t size) const;
status_t real_flatten(BDataIO *stream, ssize_t *size) const;
char *stack_flatten(char *stack_ptr,
ssize_t stack_size,
bool incl_reply,
ssize_t *size = NULL) const;
status_t _UnflattenKMessage(const char *buffer);
ssize_t calc_size(uchar flags) const;
ssize_t calc_hdr_size(uchar flags) const;
status_t nfind_data( const char *name,
type_code type,
int32 index,
const void **data,
ssize_t *data_size) const;
status_t copy_data( const char *name,
type_code type,
int32 index,
void *data,
ssize_t data_size) const;
status_t _send_(port_id port,
int32 token,
bool preferred,
bigtime_t timeout,
bool reply_required,
BMessenger &reply_to) const;
status_t send_message(port_id port,
team_id port_owner,
int32 token,
bool preferred,
BMessage *reply,
bigtime_t send_timeout,
bigtime_t reply_timeout) 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();
enum { sNumReplyPorts = 3 };
static port_id sReplyPorts[sNumReplyPorts];
static long sReplyPortInUse[sNumReplyPorts];
static int32 sGetCachedReplyPort();
static BBlockCache *sMsgCache;
struct dyn_array {
int32 fLogicalBytes;
int32 fPhysicalBytes;
int32 fChunkSize;
int32 fCount;
int32 fEntryHdrSize;
};
struct entry_hdr : public dyn_array {
entry_hdr *fNext;
uint32 fType;
uchar fNameLength;
char fName[1];
};
struct var_chunk {
int32 fDataSize;
char fData[1];
};
entry_hdr *entry_find(const char *name, uint32 type,status_t *result=NULL) const;
void entry_remove(entry_hdr *entry);
void *da_create(int32 header_size, int32 chunk_size,
bool fixed, int32 nchunks);
status_t da_add_data(dyn_array **da, const void *data, int32 size);
void *da_find_data(dyn_array *da, int32 index,
int32 *size = NULL) const;
status_t da_delete_data(dyn_array **pda, int32 index);
status_t da_replace_data(dyn_array **pda, int32 index,
const void *data, int32 dsize);
int32 da_calc_size(int32 hdr_size, int32 chunksize,
bool is_fixed, int32 nchunks) const;
void *da_grow(dyn_array **pda, int32 increase);
void da_dump(dyn_array *da);
int32 da_chunk_hdr_size() const
{ return sizeof(int32); }
int32 da_chunk_size(var_chunk *v) const
{ return (v->fDataSize + da_chunk_hdr_size() + 7) & ~7; }
var_chunk *da_first_chunk(dyn_array *da) const
{ return (var_chunk *) da_start_of_data(da); }
var_chunk *da_next_chunk(var_chunk *v) const
{ return (var_chunk *) (((char*) v) + da_chunk_size(v)); }
var_chunk *da_chunk_ptr(void *data) const
{ return (var_chunk*) (((char *) data) - da_chunk_hdr_size()); }
int32 da_pad_8(int32 val) const
{ return (val + 7) & ~7; }
int32 da_total_size(dyn_array *da) const
{ return (int32)sizeof(dyn_array) + da->fEntryHdrSize +
da->fPhysicalBytes; }
int32 da_total_logical_size(dyn_array *da) const
{ return (int32)sizeof(dyn_array) + da->fEntryHdrSize +
da->fLogicalBytes; }
char *da_start_of_data(dyn_array *da) const
{ return ((char *) da) + (sizeof(dyn_array) +
da->fEntryHdrSize); }
bool da_is_mini_data(dyn_array *da) const
{ return ((da->fLogicalBytes <= (int32) UCHAR_MAX) &&
(da->fCount <= (int32) UCHAR_MAX));}
void da_swap_var_sized(dyn_array *da);
void da_swap_fixed_sized(dyn_array *da);
BMessage *link;
int32 fTarget;
BMessage *fOriginal;
uint32 fChangeCount;
int32 fCurSpecifier;
uint32 fPtrOffset;
// ejaesler: Stealing one for my whacky BMessageBody l33tness
uint32 _reserved[2];
BPrivate::BMessageBody* fBody;
BMessage::entry_hdr *fEntries;
struct reply_to_info {
port_id port;
int32 target;
team_id team;
bool preferred;
} fReplyTo;
bool fPreferred;
bool fReplyRequired;
bool fReplyDone;
bool fIsReply;
bool fWasDelivered;
bool fReadOnly;
bool fHasSpecifiers;
};
//------------------------------------------------------------------------------
#endif // _MESSAGE_H

View File

@ -0,0 +1,98 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageBody handles data storage and retrieval for BMessage. */
#ifndef _MESSAGE_BODY_H_
#define _MESSAGE_BODY_H_
#include <List.h>
#include "MessageField3.h"
enum {
B_FLATTENABLE_TYPE = 'FLAT'
};
namespace BPrivate {
class BMessageBody {
public:
BMessageBody();
BMessageBody(const BMessageBody &other);
~BMessageBody();
BMessageBody &operator=(const BMessageBody &other);
status_t GetInfo(type_code typeRequested, int32 which,
char **name, 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;
ssize_t FlattenedSize() const;
status_t Flatten(BDataIO *stream) const;
status_t Unflatten(BDataIO *stream, int32 length);
status_t AddData(const char *name, type_code type,
const void *item, ssize_t length,
bool fixedSize);
status_t AddData(const char *name, type_code type,
void **buffer, ssize_t length);
status_t ReplaceData(const char *name, type_code type,
int32 index, const void *item, ssize_t length);
status_t ReplaceData(const char *name, type_code type,
int32 index, void **buffer, ssize_t length);
status_t RemoveData(const char *name, int32 index = 0);
bool HasData(const char *name, type_code t,
int32 index) const;
status_t FindData(const char *name, type_code type,
int32 index, const void **data,
ssize_t *numBytes) const;
status_t Rename(const char *oldName, const char *newName);
status_t RemoveName(const char *name);
status_t MakeEmpty();
void PrintToStream() const;
// flat buffer management
uint8 *FlatBuffer() const { return (uint8 *)fFlatBuffer.Buffer(); };
uint8 *FlatInsert(int32 offset, ssize_t oldLength,
ssize_t newLength);
// hash table support
void HashInsert(BMessageField *field);
BMessageField *HashLookup(const char *name) const;
BMessageField *HashRemove(const char *name);
uint32 HashString(const char *string) const;
void HashClear();
private:
status_t InitCommon();
BMessageField *AddData(const char *name, type_code type,
status_t &error);
BMessageField *FindData(const char *name, type_code type,
status_t &error) const;
BList fFieldList;
BMessageField **fFieldTable;
int32 fFieldTableSize;
BMallocIO fFlatBuffer;
};
} // namespace BPrivate
#endif // _MESSAGE_BODY_H_

View File

@ -0,0 +1,121 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageField contains the data for indiviual named fields in BMessageBody */
#ifndef _MESSAGE_FIELD_H_
#define _MESSAGE_FIELD_H_
#include <List.h>
#include <String.h>
#include <SupportDefs.h>
// we only support those
#define MSG_FLAG_VALID 0x01
#define MSG_FLAG_FIXED_SIZE 0x04
#define MSG_FLAG_ALL 0x05
// these are for R5 compatibility
#define MSG_FLAG_MINI_DATA 0x02
#define MSG_FLAG_SINGLE_ITEM 0x08
#define MSG_LAST_ENTRY 0x00
namespace BPrivate {
struct field_header_s {
uint8 flags;
type_code type;
int32 count;
ssize_t dataSize;
uint8 nameLength;
} __attribute__((__packed__));
struct item_info_s {
item_info_s(int32 _offset)
: offset(_offset)
{
}
item_info_s(int32 _offset, int32 _length)
: offset(_offset),
length(_length)
{
}
int32 offset;
int32 length;
int32 paddedLength;
};
typedef field_header_s FieldHeader;
typedef item_info_s ItemInfo;
class BMessageBody;
class BMessageField {
public:
BMessageField(BMessageBody *parent,
int32 offset, const char *name,
type_code type);
BMessageField(BMessageBody *parent);
~BMessageField();
int32 Unflatten(int32 offset);
uint8 Flags() const { return fHeader->flags; };
status_t SetFixedSize(int32 itemSize);
bool FixedSize() const { return fHeader->flags & MSG_FLAG_FIXED_SIZE; };
void SetName(const char *newName);
const char *Name() const;
uint8 NameLength() const { return fHeader->nameLength; };
type_code Type() const { return fHeader->type; };
void AddItem(const void *item, ssize_t length);
uint8 *AddItem(ssize_t length);
void ReplaceItem(int32 index, const void *newItem,
ssize_t length);
uint8 *ReplaceItem(int32 index, ssize_t length);
void *ItemAt(int32 index, ssize_t *size);
void RemoveItem(int32 index);
int32 CountItems() const { return fHeader->count; };
void PrintToStream() const;
void SetOffset(int32 offset);
int32 Offset() const { return fOffset; };
// always do MakeEmpty -> RemoveSelf -> delete
void MakeEmpty();
void RemoveSelf();
// hash table support
void SetNext(BMessageField *next) { fNext = next; };
BMessageField *Next() const { return fNext; };
private:
bool IsFixedSize(type_code type);
BMessageBody *fParent;
int32 fOffset;
FieldHeader *fHeader;
int32 fItemSize;
BList fItemInfos;
BMessageField *fNext;
};
} // namespace BPrivate
#endif // _MESSAGE_FIELD_H_

View File

@ -0,0 +1,230 @@
#ifndef MESSAGEUTILS_H
#define MESSAGEUTILS_H
#include <ByteOrder.h>
#include <DataIO.h>
#include <Entry.h>
#include <Message.h>
#include <Messenger.h>
#include <MessengerPrivate.h>
#include <SupportDefs.h>
uint32 _checksum_(const uchar *buf, int32 size);
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);
size_t calc_padding(size_t size, size_t boundary);
} // namespace BPrivate
//------------------------------------------------------------------------------
// _set_message_target_
/*! \brief Sets the target of a message.
\param message The message.
\param token The target handler token.
\param preferred Indicates whether to use the looper's preferred handler.
*/
inline void
_set_message_target_(BMessage *message, int32 token, bool preferred)
{
message->fTarget = token;
message->fPreferred = preferred;
}
// _set_message_reply_
/*! \brief Sets a message's reply target.
\param message The message.
\param messenger The reply messenger.
*/
inline void
_set_message_reply_(BMessage *message, BMessenger messenger)
{
BMessenger::Private messengerPrivate(messenger);
message->fReplyTo.port = messengerPrivate.Port();
message->fReplyTo.target = messengerPrivate.Token();
message->fReplyTo.team = messengerPrivate.Team();
message->fReplyTo.preferred = messengerPrivate.IsPreferredTarget();
}
inline int32
_get_message_target_(BMessage *msg)
{
return msg->fTarget;
}
inline bool
_use_preferred_target_(BMessage *msg)
{
return msg->fPreferred;
}
inline status_t
normalize_err(status_t err)
{
return err >= 0 ? B_OK : err;
}
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 // MESSAGEUTILS_H

2042
src/kits/app/Message3.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,616 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
/* BMessageBody handles data storage and retrieval for BMessage. */
#include <stdio.h>
#include <DataIO.h>
#include <TypeConstants.h>
#include "MessageBody3.h"
#include "MessageUtils3.h"
namespace BPrivate {
BMessageBody::BMessageBody()
{
InitCommon();
}
BMessageBody::BMessageBody(const BMessageBody &other)
{
InitCommon();
*this = other;
}
BMessageBody::~BMessageBody()
{
MakeEmpty();
delete fFieldTable;
}
BMessageBody &
BMessageBody::operator=(const BMessageBody &other)
{
if (this != &other) {
MakeEmpty();
// the flat buffer has no last entry flag included
BMemoryIO memoryIO(other.FlatBuffer(), other.FlattenedSize() - 1);
Unflatten(&memoryIO, other.FlattenedSize() - 1);
}
return *this;
}
status_t
BMessageBody::InitCommon()
{
fFieldTableSize = 100;
fFieldTable = new BMessageField *[fFieldTableSize];
HashClear();
return B_OK;
}
status_t
BMessageBody::GetInfo(type_code typeRequested, int32 which, char **name,
type_code *typeReturned, int32 *count) const
{
int32 index = 0;
int32 fieldCount = fFieldList.CountItems();
BMessageField *field = NULL;
bool found = false;
for (int32 fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
field = (BMessageField *)fFieldList.ItemAt(fieldIndex);
if (typeRequested == B_ANY_TYPE || field->Type() == typeRequested) {
if (index == which) {
found = true;
break;
}
index++;
}
}
// we couldn't find any appropriate data
if (!found) {
if (count)
*count = 0;
if (index > 0)
return B_BAD_INDEX;
else
return B_BAD_TYPE;
}
// ToDo: BC Break
// Change 'name' parameter to const char *
if (name)
*name = const_cast<char *>(field->Name());
if (typeReturned)
*typeReturned = field->Type();
if (count)
*count = field->CountItems();
return B_OK;
}
status_t
BMessageBody::GetInfo(const char *name, type_code *typeFound,
int32 *countFound) const
{
status_t error = B_ERROR;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (typeFound)
*typeFound = field->Type();
if (countFound)
*countFound = field->CountItems();
} else {
if (countFound)
*countFound = 0;
}
return error;
}
status_t
BMessageBody::GetInfo(const char *name, type_code *typeFound, bool *fixedSize) const
{
status_t error = B_ERROR;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (typeFound)
*typeFound = field->Type();
if (fixedSize)
*fixedSize = field->FixedSize();
}
return error;
}
int32
BMessageBody::CountNames(type_code type) const
{
if (type == B_ANY_TYPE)
return fFieldList.CountItems();
int32 count = 0;
for (int32 index = 0; index < fFieldList.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index);
if (field->Type() == type)
count++;
}
return count;
}
bool
BMessageBody::IsEmpty() const
{
return fFieldList.CountItems() == 0;
}
void
BMessageBody::PrintToStream() const
{
for (int32 index = 0; index < fFieldList.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index);
field->PrintToStream();
printf("\n");
}
}
status_t
BMessageBody::Rename(const char *oldName, const char *newName)
{
status_t error = B_ERROR;
BMessageField *field = FindData(oldName, B_ANY_TYPE, error);
if (!field)
return error;
field->SetName(newName);
HashInsert(HashRemove(oldName));
return B_OK;
}
ssize_t
BMessageBody::FlattenedSize() const
{
// one more for the last entry flag
return fFlatBuffer.BufferLength() + 1;
}
status_t
BMessageBody::Flatten(BDataIO *stream) const
{
stream->Write(fFlatBuffer.Buffer(), fFlatBuffer.BufferLength());
uint8 lastField = MSG_LAST_ENTRY;
status_t error = stream->Write(&lastField, sizeof(lastField));
if (error < B_OK)
return error;
if (error == 0)
return B_ERROR;
return B_OK;
}
status_t
BMessageBody::Unflatten(BDataIO *stream, int32 length)
{
if (length <= 0)
return B_OK;
fFlatBuffer.SetSize(length);
status_t error = stream->Read((void *)fFlatBuffer.Buffer(), length);
if (error < B_OK)
return B_ERROR;
int32 offset = 0;
uint8 *location = (uint8 *)fFlatBuffer.Buffer();
while (offset < length && *location & MSG_FLAG_VALID) {
BMessageField *field = new BMessageField(this);
int32 fieldLength = field->Unflatten(offset);
//PrintToStream();
if (fieldLength <= 0) {
field->MakeEmpty();
delete field;
MakeEmpty();
return B_ERROR;
}
location += fieldLength;
offset += fieldLength;
fFieldList.AddItem(field);
HashInsert(field);
}
// set the buffer to the actual size
fFlatBuffer.SetSize(offset);
return B_OK;
}
status_t
BMessageBody::AddData(const char *name, type_code type, const void *item,
ssize_t length, bool fixedSize)
{
status_t error = B_ERROR;
BMessageField *field = AddData(name, type, error);
if (!field)
return error;
if (fixedSize) {
error = field->SetFixedSize(length);
if (error != B_OK)
return error;
}
field->AddItem(item, length);
return B_OK;
}
status_t
BMessageBody::AddData(const char *name, type_code type, void **buffer,
ssize_t length)
{
status_t error = B_ERROR;
BMessageField *field = AddData(name, type, error);
if (!field)
return error;
*buffer = field->AddItem(length);
return B_OK;
}
BMessageField *
BMessageBody::AddData(const char *name, type_code type, status_t &error)
{
if (type == B_ANY_TYPE) {
error = B_BAD_VALUE;
return NULL;
}
BMessageField *foundField = FindData(name, type, error);
if (error < B_OK) {
if (error == B_NAME_NOT_FOUND) {
// reset the error - we will create the field
error = B_OK;
} else {
// looking for B_BAD_TYPE here in particular, which would indicate
// that we tried to add data of type X when we already had data of
// type Y with the same name
return NULL;
}
}
if (foundField)
return foundField;
// add a new field if it's not yet present
BMessageField *newField = new BMessageField(this,
fFlatBuffer.BufferLength(), name, type);
fFieldList.AddItem(newField);
HashInsert(newField);
return newField;
}
status_t
BMessageBody::ReplaceData(const char *name, type_code type, int32 index,
const void *item, ssize_t length)
{
if (type == B_ANY_TYPE)
return B_BAD_VALUE;
status_t error = B_ERROR;
BMessageField *field = FindData(name, type, error);
if (!field)
return error;
if (field->FixedSize()) {
ssize_t itemSize = 0;
void *item = field->ItemAt(0, &itemSize);
if (item && itemSize != length)
return B_BAD_VALUE;
}
field->ReplaceItem(index, item, length);
return B_OK;
}
status_t
BMessageBody::ReplaceData(const char *name, type_code type, int32 index,
void **buffer, ssize_t length)
{
if (type == B_ANY_TYPE)
return B_BAD_VALUE;
status_t error = B_ERROR;
BMessageField *field = FindData(name, type, error);
if (!field)
return error;
*buffer = field->ReplaceItem(index, length);
return B_OK;
}
status_t
BMessageBody::RemoveData(const char *name, int32 index)
{
if (index < 0)
return B_BAD_VALUE;
status_t error = B_ERROR;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (field) {
if (index < field->CountItems()) {
if (field->CountItems() == 1)
RemoveName(name);
else
field->RemoveItem(index);
} else
error = B_BAD_INDEX;
}
return error;
}
status_t
BMessageBody::RemoveName(const char *name)
{
status_t error = B_ERROR;
BMessageField *field = FindData(name, B_ANY_TYPE, error);
if (!field)
return error;
fFieldList.RemoveItem(field);
HashRemove(name);
field->MakeEmpty();
field->RemoveSelf();
delete field;
return B_OK;
}
status_t
BMessageBody::MakeEmpty()
{
for (int32 index = 0; index < fFieldList.CountItems(); index++) {
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index);
field->MakeEmpty();
delete field;
}
fFieldList.MakeEmpty();
fFlatBuffer.SetSize(0);
HashClear();
return B_OK;
}
bool
BMessageBody::HasData(const char *name, type_code type, int32 index) const
{
if (!name || index < 0)
return false;
status_t error = B_ERROR;
BMessageField *field = FindData(name, type, error);
if (!field)
return false;
if (index >= field->CountItems())
return false;
return true;
}
status_t
BMessageBody::FindData(const char *name, type_code type, int32 index,
const void **data, ssize_t *numBytes) const
{
if (!data)
return B_BAD_VALUE;
status_t error = B_ERROR;
*data = NULL;
BMessageField *field = FindData(name, type, error);
if (error >= B_OK) {
if (index >= field->CountItems())
return B_BAD_INDEX;
*data = field->ItemAt(index, numBytes);
}
return error;
}
BMessageField *
BMessageBody::FindData(const char *name, type_code type, status_t &error) const
{
if (!name) {
error = B_BAD_VALUE;
return NULL;
}
BMessageField *field = HashLookup(name);
if (field) {
if (type != B_ANY_TYPE && field->Type() != type) {
error = B_BAD_TYPE;
return NULL;
}
error = B_OK;
return field;
}
error = B_NAME_NOT_FOUND;
return NULL;
}
uint8 *
BMessageBody::FlatInsert(int32 offset, ssize_t oldLength, ssize_t newLength)
{
if (oldLength == newLength)
return FlatBuffer() + offset;
ssize_t change = newLength - oldLength;
ssize_t bufferLength = fFlatBuffer.BufferLength();
if (change > 0) {
fFlatBuffer.SetSize(bufferLength + change);
// usual case for adds
if (offset == bufferLength)
return FlatBuffer() + offset;
}
ssize_t length = bufferLength - offset - oldLength;
if (length > 0) {
uint8 *location = FlatBuffer() + offset;
memmove(location + newLength, location + oldLength, length);
}
if (change < 0)
fFlatBuffer.SetSize(bufferLength + change);
for (int32 index = fFieldList.CountItems() - 1; index >= 0; index--) {
BMessageField *field = (BMessageField *)fFieldList.ItemAt(index);
if (field->Offset() <= offset)
break;
field->SetOffset(field->Offset() + change);
}
return FlatBuffer() + offset;
}
void
BMessageBody::HashInsert(BMessageField *field)
{
uint32 index = HashString(field->Name()) % fFieldTableSize;
field->SetNext(fFieldTable[index]);
fFieldTable[index] = field;
}
BMessageField *
BMessageBody::HashLookup(const char *name) const
{
uint32 index = HashString(name) % fFieldTableSize;
BMessageField *result = fFieldTable[index];
while (result) {
if (strcmp(result->Name(), name) == 0)
return result;
result = result->Next();
}
return NULL;
}
BMessageField *
BMessageBody::HashRemove(const char *name)
{
uint32 index = HashString(name) % fFieldTableSize;
BMessageField *result = fFieldTable[index];
BMessageField *last = NULL;
while (result) {
if (strcmp(result->Name(), name) == 0) {
if (last)
last->SetNext(result->Next());
else
fFieldTable[index] = result->Next();
return result;
}
last = result;
result = result->Next();
}
return NULL;
}
void
BMessageBody::HashClear()
{
memset(fFieldTable, 0, fFieldTableSize * sizeof(BMessageField *));
}
uint32
BMessageBody::HashString(const char *string) const
{
char ch;
uint32 result = 0;
while ((ch = *string++) != 0) {
result = (result << 7) ^ (result >> 24);
result ^= ch;
}
result ^= result << 12;
return result;
}
} // namespace BPrivate

View File

@ -0,0 +1,273 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include <stdio.h>
#include <DataIO.h>
#include <MessageUtils.h>
#include "MessageBody3.h"
#include "MessageField3.h"
namespace BPrivate {
#define DATA_OFFSET (fOffset + sizeof(FieldHeader) + fHeader->nameLength)
inline int32
round_to_8(int32 length)
{
// already includes the + 4 for size_t length field
return (length + 11) & ~7;
}
BMessageField::BMessageField(BMessageBody *parent, int32 offset,
const char *name, type_code type)
: fParent(parent),
fOffset(offset),
fItemSize(0)
{
// insert space needed for the header
fParent->FlatInsert(fOffset, 0, sizeof(FieldHeader));
// create and fill header
fHeader = (FieldHeader *)(fParent->FlatBuffer() + fOffset);
fHeader->type = type;
fHeader->flags = MSG_FLAG_VALID;
fHeader->count = 0;
fHeader->dataSize = 0;
fHeader->nameLength = 0;
SetName(name);
}
BMessageField::BMessageField(BMessageBody *parent)
: fParent(parent),
fOffset(0),
fHeader(NULL),
fItemSize(0)
{
}
BMessageField::~BMessageField()
{
}
int32
BMessageField::Unflatten(int32 _offset)
{
fOffset = _offset;
// field is already present, just tap into it
fHeader = (FieldHeader *)(fParent->FlatBuffer() + fOffset);
if (fHeader->flags & MSG_FLAG_FIXED_SIZE) {
if (fHeader->count > 0)
fItemSize = fHeader->dataSize / fHeader->count;
return sizeof(FieldHeader) + fHeader->nameLength + fHeader->count * fItemSize;
}
// create the item info list
int32 offset = 0;
uint8 *location = fParent->FlatBuffer() + DATA_OFFSET;
for (int32 index = 0; index < fHeader->count; index++) {
ItemInfo *info = new ItemInfo(offset);
info->length = *(size_t *)location;
info->paddedLength = round_to_8(info->length);
fItemInfos.AddItem(info);
offset += info->paddedLength;
location += info->paddedLength;
}
return sizeof(FieldHeader) + fHeader->nameLength + offset;
}
void
BMessageField::SetOffset(int32 offset)
{
fOffset = offset;
fHeader = (FieldHeader *)(fParent->FlatBuffer() + fOffset);
}
void
BMessageField::SetName(const char *newName)
{
int32 newLength = min_c(strlen(newName), 254) + 1;
char *buffer = (char *)fParent->FlatInsert(fOffset + sizeof(FieldHeader), fHeader->nameLength, newLength);
strcpy(buffer, newName);
fHeader->nameLength = newLength;
}
const char *
BMessageField::Name() const
{
return (const char *)(fParent->FlatBuffer() + fOffset + sizeof(FieldHeader));
}
status_t
BMessageField::SetFixedSize(int32 itemSize)
{
if ((fItemSize > 0 && fItemSize != itemSize)
|| fItemInfos.CountItems() > 0)
return B_BAD_VALUE;
fItemSize = itemSize;
fHeader->flags |= MSG_FLAG_FIXED_SIZE;
return B_OK;
}
void
BMessageField::AddItem(const void *item, ssize_t length)
{
memcpy(AddItem(length), item, length);
}
uint8 *
BMessageField::AddItem(ssize_t length)
{
if (fHeader->flags & MSG_FLAG_FIXED_SIZE) {
int32 offset = DATA_OFFSET + (fHeader->count * fItemSize);
fHeader->dataSize += fItemSize;
fHeader->count++;
return fParent->FlatInsert(offset, 0, fItemSize);
}
int32 newOffset = 0;
if (fHeader->count > 0) {
ItemInfo *info = (ItemInfo *)fItemInfos.ItemAt(fHeader->count - 1);
newOffset = info->offset + info->paddedLength;
}
ItemInfo *newInfo = new ItemInfo(newOffset, length);
newInfo->paddedLength = round_to_8(length);
fItemInfos.AddItem(newInfo);
fHeader->dataSize += newInfo->paddedLength;
fHeader->count++;
uint8 *result = fParent->FlatInsert(DATA_OFFSET + newInfo->offset, 0, newInfo->paddedLength);
*(int32 *)result = length;
return result + sizeof(int32);
}
void
BMessageField::ReplaceItem(int32 index, const void *newItem, ssize_t length)
{
memcpy(ReplaceItem(index, length), newItem, length);
}
uint8 *
BMessageField::ReplaceItem(int32 index, ssize_t length)
{
if (fHeader->flags & MSG_FLAG_FIXED_SIZE)
return fParent->FlatBuffer() + DATA_OFFSET + (index * fItemSize);
ItemInfo *info = (ItemInfo *)fItemInfos.ItemAt(index);
int32 newLength = round_to_8(length);
if (info->paddedLength == newLength) {
uint8 *result = fParent->FlatBuffer() + DATA_OFFSET + info->offset;
info->length = length;
*(int32 *)result = length;
return result + sizeof(int32);
}
int32 change = newLength - info->paddedLength;
for (int32 i = index + 1; i < fHeader->count; i++)
((ItemInfo *)fItemInfos.ItemAt(i))->offset += change;
fHeader->dataSize += change;
int32 oldLength = info->paddedLength;
info->length = length;
info->paddedLength = newLength;
uint8 *result = fParent->FlatInsert(DATA_OFFSET + info->offset, oldLength, newLength);
*(int32 *)result = length;
return result + sizeof(int32);
}
void *
BMessageField::ItemAt(int32 index, ssize_t *size)
{
if (fHeader->flags & MSG_FLAG_FIXED_SIZE) {
if (size)
*size = fItemSize;
return fParent->FlatBuffer() + DATA_OFFSET + (index * fItemSize);
}
ItemInfo *info = (ItemInfo *)fItemInfos.ItemAt(index);
if (size)
*size = info->length;
return fParent->FlatBuffer() + DATA_OFFSET + info->offset + sizeof(int32);
}
void
BMessageField::RemoveItem(int32 index)
{
if (fHeader->flags & MSG_FLAG_FIXED_SIZE) {
fParent->FlatInsert(DATA_OFFSET + (index * fItemSize), fItemSize, 0);
fHeader->dataSize -= fItemSize;
fHeader->count--;
return;
}
ItemInfo *info = (ItemInfo *)fItemInfos.RemoveItem(index);
for (int32 i = index; i < fHeader->count; i++)
((ItemInfo *)fItemInfos.ItemAt(i))->offset -= info->paddedLength;
fParent->FlatInsert(DATA_OFFSET + info->offset, info->paddedLength, 0);
fHeader->dataSize -= info->paddedLength;
fHeader->count--;
delete info;
}
void
BMessageField::PrintToStream() const
{
printf("\tname: \"%s\"; items: %ld; dataSize: %ld; flags: %02x;", Name(), fHeader->count, fHeader->dataSize, fHeader->flags);
// ToDo: implement for real
}
void
BMessageField::MakeEmpty()
{
for (int32 index = 0; index < fItemInfos.CountItems(); index++)
delete (ItemInfo *)fItemInfos.ItemAt(index);
fItemInfos.MakeEmpty();
}
void
BMessageField::RemoveSelf()
{
// remove ourselfs from the flat buffer
fParent->FlatInsert(fOffset, sizeof(FieldHeader) + fHeader->nameLength + fHeader->dataSize, 0);
fOffset = 0;
fHeader = NULL;
}
} // namespace BPrivate