#include <Message.h>
#include <MessageAdapter.h>
#include <MessagePrivate.h>
#include <MessageUtils.h>
#include <DirectMessageTarget.h>
#include <MessengerPrivate.h>
#include <TokenSpace.h>
#include <kernel/util/KMessage.h>
#include <Alignment.h>
#include <Application.h>
#include <AppMisc.h>
#include <BlockCache.h>
#include <GraphicsDefs.h>
#include <MessageQueue.h>
#include <Messenger.h>
#include <Path.h>
#include <Point.h>
#include <String.h>
#include <StringList.h>
#include <StackOrHeapArray.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tracing_config.h"
#ifdef VERBOSE_DEBUG_OUTPUT
#define DEBUG_FUNCTION_ENTER \
debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
" data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
find_thread(NULL), this, fHeader, fFields, fData, what, (char*)&what, \
__LINE__, __PRETTY_FUNCTION__);
#define DEBUG_FUNCTION_ENTER2 \
debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
__LINE__, __PRETTY_FUNCTION__);
#else
#define DEBUG_FUNCTION_ENTER
#define DEBUG_FUNCTION_ENTER2
#endif
#if BMESSAGE_TRACING
# define KTRACE(format...) ktrace_printf(format)
#else
# define KTRACE(format...) ;
#endif
const char* B_SPECIFIER_ENTRY = "specifiers";
const char* B_PROPERTY_ENTRY = "property";
const char* B_PROPERTY_NAME_ENTRY = "name";
static status_t handle_reply(port_id replyPort, int32* pCode,
bigtime_t timeout, BMessage* reply);
extern "C" {
status_t _kern_transfer_area(area_id area, void** _address,
uint32 addressSpec, team_id target);
}
BBlockCache* BMessage::sMsgCache = NULL;
port_id BMessage::sReplyPorts[sNumReplyPorts];
int32 BMessage::sReplyPortInUse[sNumReplyPorts];
template<typename Type>
static void
print_to_stream_type(uint8* pointer)
{
Type* item = (Type*)pointer;
item->PrintToStream();
}
template<typename Type>
static void
print_type(const char* format, uint8* pointer)
{
Type* item = (Type*)pointer;
printf(format,* item,* item);
}
template<typename Type>
static void
print_type3(const char* format, uint8* pointer)
{
Type* item = (Type*)pointer;
printf(format, *item, *item, *item);
}
static status_t
handle_reply(port_id replyPort, int32* _code, bigtime_t timeout,
BMessage* reply)
{
DEBUG_FUNCTION_ENTER2;
ssize_t size;
do {
size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
} while (size == B_INTERRUPTED);
if (size < 0)
return size;
BStackOrHeapArray<char, 4096> buffer(size);
if (!buffer.IsValid())
return B_NO_MEMORY;
status_t result;
do {
result = read_port(replyPort, _code, buffer, size);
} while (result == B_INTERRUPTED);
if (result < 0 || *_code != kPortMessageCode)
return result < 0 ? result : B_ERROR;
result = reply->Unflatten(buffer);
return result;
}
BMessage::BMessage()
{
DEBUG_FUNCTION_ENTER;
_InitCommon(true);
}
BMessage::BMessage(BMessage* other)
{
DEBUG_FUNCTION_ENTER;
_InitCommon(false);
*this = *other;
}
BMessage::BMessage(uint32 _what)
{
DEBUG_FUNCTION_ENTER;
if (_InitCommon(true))
fHeader->what = _what;
what = _what;
}
BMessage::BMessage(const BMessage& other)
{
DEBUG_FUNCTION_ENTER;
_InitCommon(false);
*this = other;
}
BMessage::~BMessage()
{
DEBUG_FUNCTION_ENTER;
_Clear();
}
BMessage&
BMessage::operator=(const BMessage& other)
{
DEBUG_FUNCTION_ENTER;
if (this == &other)
return *this;
_Clear();
fHeader = (message_header*)malloc(sizeof(message_header));
if (fHeader == NULL)
return *this;
if (other.fHeader == NULL)
return *this;
memcpy(fHeader, other.fHeader, sizeof(message_header));
fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
| MESSAGE_FLAG_PASS_BY_AREA);
if (fHeader->field_count > 0) {
size_t fieldsSize = fHeader->field_count * sizeof(field_header);
if (other.fFields != NULL)
fFields = (field_header*)malloc(fieldsSize);
if (fFields == NULL) {
fHeader->field_count = 0;
fHeader->data_size = 0;
} else if (other.fFields != NULL)
memcpy(fFields, other.fFields, fieldsSize);
}
if (fHeader->data_size > 0) {
if (other.fData != NULL)
fData = (uint8*)malloc(fHeader->data_size);
if (fData == NULL) {
fHeader->field_count = 0;
free(fFields);
fFields = NULL;
} else if (other.fData != NULL)
memcpy(fData, other.fData, fHeader->data_size);
}
fHeader->what = what = other.what;
fHeader->message_area = -1;
fFieldsAvailable = 0;
fDataAvailable = 0;
return *this;
}
void*
BMessage::operator new(size_t size)
{
DEBUG_FUNCTION_ENTER2;
return sMsgCache->Get(size);
}
void*
BMessage::operator new(size_t size, const std::nothrow_t& noThrow)
{
DEBUG_FUNCTION_ENTER2;
return sMsgCache->Get(size);
}
void*
BMessage::operator new(size_t, void* pointer)
{
DEBUG_FUNCTION_ENTER2;
return pointer;
}
void
BMessage::operator delete(void* pointer, size_t size)
{
DEBUG_FUNCTION_ENTER2;
if (pointer == NULL)
return;
sMsgCache->Save(pointer, size);
}
bool
BMessage::HasSameData(const BMessage& other, bool ignoreFieldOrder,
bool deep) const
{
if (this == &other)
return true;
if (fHeader == NULL)
return other.fHeader == NULL;
if (fHeader->field_count != other.fHeader->field_count)
return false;
for (uint32 i = 0; i < fHeader->field_count; i++) {
field_header* field = &fFields[i];
field_header* otherField = NULL;
const char* name = (const char*)fData + field->offset;
if (ignoreFieldOrder) {
if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
return false;
} else {
otherField = &other.fFields[i];
if (otherField->name_length != field->name_length)
return false;
const char* otherName = (const char*)other.fData
+ otherField->offset;
if (strncmp(name, otherName, field->name_length) != 0)
return false;
}
if (otherField->type != field->type
|| otherField->count != field->count) {
return false;
}
uint8* data = fData + field->offset + field->name_length;
uint8* otherData = other.fData + otherField->offset
+ otherField->name_length;
bool needsMemCompare = true;
if (deep && field->type == B_MESSAGE_TYPE) {
BMessage message, otherMessage;
if (message.Unflatten((const char*)data) == B_OK
&& otherMessage.Unflatten((const char*)otherData) == B_OK) {
if (!message.HasSameData(ignoreFieldOrder, deep))
return false;
needsMemCompare = false;
}
}
if (needsMemCompare) {
if (otherField->data_size != field->data_size)
return false;
if (memcmp(data, otherData, field->data_size) != 0)
return false;
}
}
return true;
}
status_t
BMessage::_InitCommon(bool initHeader)
{
DEBUG_FUNCTION_ENTER;
what = 0;
fHeader = NULL;
fFields = NULL;
fData = NULL;
fFieldsAvailable = 0;
fDataAvailable = 0;
fOriginal = NULL;
fQueueLink = NULL;
fArchivingPointer = NULL;
if (initHeader)
return _InitHeader();
return B_OK;
}
status_t
BMessage::_InitHeader()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL) {
fHeader = (message_header*)malloc(sizeof(message_header));
if (fHeader == NULL)
return B_NO_MEMORY;
}
memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
fHeader->format = MESSAGE_FORMAT_HAIKU;
fHeader->flags = MESSAGE_FLAG_VALID;
fHeader->what = what;
fHeader->current_specifier = -1;
fHeader->message_area = -1;
fHeader->target = B_NULL_TOKEN;
fHeader->reply_target = B_NULL_TOKEN;
fHeader->reply_port = -1;
fHeader->reply_team = -1;
fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
return B_OK;
}
status_t
BMessage::_Clear()
{
DEBUG_FUNCTION_ENTER;
if (fHeader != NULL) {
if (IsSourceWaiting())
SendReply(B_NO_REPLY);
if (fHeader->message_area >= 0)
_Dereference();
free(fHeader);
fHeader = NULL;
}
free(fFields);
fFields = NULL;
free(fData);
fData = NULL;
fArchivingPointer = NULL;
fFieldsAvailable = 0;
fDataAvailable = 0;
delete fOriginal;
fOriginal = NULL;
return B_OK;
}
status_t
BMessage::GetInfo(type_code typeRequested, int32 index, char** nameFound,
type_code* typeFound, int32* countFound) const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
if (index < 0 || (uint32)index >= fHeader->field_count)
return B_BAD_INDEX;
if (typeRequested == B_ANY_TYPE) {
if (nameFound != NULL)
*nameFound = (char*)fData + fFields[index].offset;
if (typeFound != NULL)
*typeFound = fFields[index].type;
if (countFound != NULL)
*countFound = fFields[index].count;
return B_OK;
}
int32 counter = -1;
field_header* field = fFields;
for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
if (field->type == typeRequested)
counter++;
if (counter == index) {
if (nameFound != NULL)
*nameFound = (char*)fData + field->offset;
if (typeFound != NULL)
*typeFound = field->type;
if (countFound != NULL)
*countFound = field->count;
return B_OK;
}
}
if (counter == -1)
return B_BAD_TYPE;
return B_BAD_INDEX;
}
status_t
BMessage::GetInfo(const char* name, type_code* typeFound,
int32* countFound) const
{
DEBUG_FUNCTION_ENTER;
if (countFound != NULL)
*countFound = 0;
field_header* field = NULL;
status_t result = _FindField(name, B_ANY_TYPE, &field);
if (result != B_OK)
return result;
if (typeFound != NULL)
*typeFound = field->type;
if (countFound != NULL)
*countFound = field->count;
return B_OK;
}
status_t
BMessage::GetInfo(const char* name, type_code* typeFound, bool* fixedSize)
const
{
DEBUG_FUNCTION_ENTER;
field_header* field = NULL;
status_t result = _FindField(name, B_ANY_TYPE, &field);
if (result != B_OK)
return result;
if (typeFound != NULL)
*typeFound = field->type;
if (fixedSize != NULL)
*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
return B_OK;
}
status_t
BMessage::GetInfo(const char* name, type_code* typeFound, int32* countFound,
bool* fixedSize) const
{
DEBUG_FUNCTION_ENTER;
field_header* field = NULL;
status_t result = _FindField(name, B_ANY_TYPE, &field);
if (result != B_OK)
return result;
if (typeFound != NULL)
*typeFound = field->type;
if (countFound != NULL)
*countFound = field->count;
if (fixedSize != NULL)
*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
return B_OK;
}
int32
BMessage::CountNames(type_code type) const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return 0;
if (type == B_ANY_TYPE)
return fHeader->field_count;
int32 count = 0;
field_header* field = fFields;
for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
if (field->type == type)
count++;
}
return count;
}
bool
BMessage::IsEmpty() const
{
DEBUG_FUNCTION_ENTER;
return fHeader == NULL || fHeader->field_count == 0;
}
bool
BMessage::IsSystem() const
{
DEBUG_FUNCTION_ENTER;
char a = char(what >> 24);
char b = char(what >> 16);
char c = char(what >> 8);
char d = char(what);
if (a == '_' && isupper(b) && isupper(c) && isupper(d))
return true;
return false;
}
bool
BMessage::IsReply() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL && (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
}
void
BMessage::PrintToStream() const
{
_PrintToStream("");
printf("}\n");
}
void
BMessage::_PrintToStream(const char* indent) const
{
DEBUG_FUNCTION_ENTER;
int32 value = B_BENDIAN_TO_HOST_INT32(what);
printf("BMessage(");
if (isprint(*(char*)&value))
printf("'%.4s'", (char*)&value);
else
printf("0x%" B_PRIx32, what);
printf(") {\n");
if (fHeader == NULL || fFields == NULL || fData == NULL)
return;
field_header* field = fFields;
for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
value = B_BENDIAN_TO_HOST_INT32(field->type);
ssize_t size = 0;
if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
size = field->data_size / field->count;
uint8* pointer = fData + field->offset + field->name_length;
for (uint32 j = 0; j < field->count; j++) {
if (field->count == 1) {
printf("%s %s = ", indent,
(char*)(fData + field->offset));
} else {
printf("%s %s[%" B_PRIu32 "] = ", indent,
(char*)(fData + field->offset), j);
}
if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) {
size = *(uint32*)pointer;
pointer += sizeof(uint32);
}
switch (field->type) {
case B_RECT_TYPE:
print_to_stream_type<BRect>(pointer);
break;
case B_POINT_TYPE:
print_to_stream_type<BPoint>(pointer);
break;
case B_STRING_TYPE:
printf("string(\"%.*s\", %ld bytes)\n", (int)size,
(char*)pointer, (long)size);
break;
case B_INT8_TYPE:
print_type3<int8>("int8(0x%hx or %d or '%c')\n",
pointer);
break;
case B_UINT8_TYPE:
print_type3<uint8>("uint8(0x%hx or %u or '%c')\n",
pointer);
break;
case B_INT16_TYPE:
print_type<int16>("int16(0x%x or %d)\n", pointer);
break;
case B_UINT16_TYPE:
print_type<uint16>("uint16(0x%x or %u)\n", pointer);
break;
case B_INT32_TYPE:
print_type<int32>("int32(0x%lx or %ld)\n", pointer);
break;
case B_UINT32_TYPE:
print_type<uint32>("uint32(0x%lx or %lu)\n", pointer);
break;
case B_INT64_TYPE:
print_type<int64>("int64(0x%Lx or %lld)\n", pointer);
break;
case B_UINT64_TYPE:
print_type<uint64>("uint64(0x%Lx or %lld)\n", pointer);
break;
case B_BOOL_TYPE:
printf("bool(%s)\n", *((bool*)pointer) != 0
? "true" : "false");
break;
case B_FLOAT_TYPE:
print_type<float>("float(%.4f)\n", pointer);
break;
case B_DOUBLE_TYPE:
print_type<double>("double(%.8f)\n", pointer);
break;
case B_REF_TYPE:
{
entry_ref ref;
BPrivate::entry_ref_unflatten(&ref, (char*)pointer, size);
printf("entry_ref(device=%d, directory=%" B_PRIdINO
", name=\"%s\", ", (int)ref.device, ref.directory,
ref.name);
BPath path(&ref);
printf("path=\"%s\")\n", path.Path());
break;
}
case B_NODE_REF_TYPE:
{
node_ref ref;
BPrivate::node_ref_unflatten(&ref, (char*)pointer, size);
printf("node_ref(device=%d, node=%" B_PRIdINO ", ",
(int)ref.device, ref.node);
break;
}
case B_MESSAGE_TYPE:
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "%s ", indent);
BMessage message;
status_t result = message.Unflatten((const char*)pointer);
if (result != B_OK) {
printf("failed unflatten: %s\n", strerror(result));
break;
}
message._PrintToStream(buffer);
printf("%s }\n", indent);
break;
}
case B_RGB_32_BIT_TYPE:
{
rgb_color* color = (rgb_color*)pointer;
printf("rgb_color(%u, %u, %u, %u)\n", color->red,
color->green, color->blue, color->alpha);
break;
}
default:
{
printf("(type = '%.4s')(size = %ld)\n", (char*)&value,
(long)size);
break;
}
}
pointer += size;
}
}
}
status_t
BMessage::Rename(const char* oldEntry, const char* newEntry)
{
DEBUG_FUNCTION_ENTER;
if (oldEntry == NULL || newEntry == NULL)
return B_BAD_VALUE;
if (fHeader == NULL)
return B_NO_INIT;
status_t result;
if (fHeader->message_area >= 0) {
result = _CopyForWrite();
if (result != B_OK)
return result;
}
uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
int32* nextField = &fHeader->hash_table[hash];
while (*nextField >= 0) {
field_header* field = &fFields[*nextField];
if (strncmp((const char*)(fData + field->offset), oldEntry,
field->name_length) == 0) {
int32 index = *nextField;
*nextField = field->next_field;
field->next_field = -1;
hash = _HashName(newEntry) % fHeader->hash_table_size;
nextField = &fHeader->hash_table[hash];
while (*nextField >= 0)
nextField = &fFields[*nextField].next_field;
*nextField = index;
int32 newLength = strlen(newEntry) + 1;
result = _ResizeData(field->offset + 1,
newLength - field->name_length);
if (result != B_OK)
return result;
memcpy(fData + field->offset, newEntry, newLength);
field->name_length = newLength;
return B_OK;
}
nextField = &field->next_field;
}
return B_NAME_NOT_FOUND;
}
bool
BMessage::WasDelivered() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL
&& (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
}
bool
BMessage::IsSourceWaiting() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL
&& (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
}
bool
BMessage::IsSourceRemote() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL
&& (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0
&& fHeader->reply_team != BPrivate::current_team();
}
BMessenger
BMessage::ReturnAddress() const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL || (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
return BMessenger();
BMessenger messenger;
BMessenger::Private(messenger).SetTo(fHeader->reply_team,
fHeader->reply_port, fHeader->reply_target);
return messenger;
}
const BMessage*
BMessage::Previous() const
{
DEBUG_FUNCTION_ENTER;
if (fOriginal == NULL) {
fOriginal = new BMessage();
if (FindMessage("_previous_", fOriginal) != B_OK) {
delete fOriginal;
fOriginal = NULL;
}
}
return fOriginal;
}
bool
BMessage::WasDropped() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL
&& (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
}
BPoint
BMessage::DropPoint(BPoint* offset) const
{
DEBUG_FUNCTION_ENTER;
if (offset != NULL)
*offset = FindPoint("_drop_offset_");
return FindPoint("_drop_point_");
}
status_t
BMessage::SendReply(uint32 command, BHandler* replyTo)
{
DEBUG_FUNCTION_ENTER;
BMessage message(command);
return SendReply(&message, replyTo);
}
status_t
BMessage::SendReply(BMessage* reply, BHandler* replyTo, bigtime_t timeout)
{
DEBUG_FUNCTION_ENTER;
BMessenger messenger(replyTo);
return SendReply(reply, messenger, timeout);
}
status_t
BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
BMessenger messenger;
BMessenger::Private messengerPrivate(messenger);
messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
fHeader->reply_target);
if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0)
reply->fHeader->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE;
if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
return B_DUPLICATE_REPLY;
fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
status_t result = messenger.SendMessage(reply, replyTo, timeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
if (result != B_OK && set_port_owner(messengerPrivate.Port(),
messengerPrivate.Team()) == B_BAD_TEAM_ID) {
delete_port(messengerPrivate.Port());
}
return result;
}
if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
return B_BAD_REPLY;
reply->AddMessage("_previous_", this);
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
status_t result = messenger.SendMessage(reply, replyTo, timeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
reply->RemoveName("_previous_");
return result;
}
status_t
BMessage::SendReply(uint32 command, BMessage* replyToReply)
{
DEBUG_FUNCTION_ENTER;
BMessage message(command);
return SendReply(&message, replyToReply);
}
status_t
BMessage::SendReply(BMessage* reply, BMessage* replyToReply,
bigtime_t sendTimeout, bigtime_t replyTimeout)
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
BMessenger messenger;
BMessenger::Private messengerPrivate(messenger);
messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
fHeader->reply_target);
if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
return B_DUPLICATE_REPLY;
fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
status_t result = messenger.SendMessage(reply, replyToReply,
sendTimeout, replyTimeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
if (result != B_OK) {
if (set_port_owner(messengerPrivate.Port(),
messengerPrivate.Team()) == B_BAD_TEAM_ID) {
delete_port(messengerPrivate.Port());
}
}
return result;
}
if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
return B_BAD_REPLY;
reply->AddMessage("_previous_", this);
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY
| (fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE);
status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
replyTimeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
reply->RemoveName("_previous_");
return result;
}
ssize_t
BMessage::FlattenedSize() const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
+ fHeader->data_size;
}
status_t
BMessage::Flatten(char* buffer, ssize_t size) const
{
DEBUG_FUNCTION_ENTER;
if (buffer == NULL || size < 0)
return B_BAD_VALUE;
if (fHeader == NULL)
return B_NO_INIT;
if (size < FlattenedSize())
return B_BUFFER_OVERFLOW;
fHeader->what = what;
memcpy(buffer, fHeader, sizeof(message_header));
buffer += sizeof(message_header);
size_t fieldsSize = fHeader->field_count * sizeof(field_header);
memcpy(buffer, fFields, fieldsSize);
buffer += fieldsSize;
memcpy(buffer, fData, fHeader->data_size);
return B_OK;
}
status_t
BMessage::Flatten(BDataIO* stream, ssize_t* size) const
{
DEBUG_FUNCTION_ENTER;
if (stream == NULL)
return B_BAD_VALUE;
if (fHeader == NULL)
return B_NO_INIT;
fHeader->what = what;
ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
if (result1 != sizeof(message_header))
return result1 < 0 ? result1 : B_ERROR;
ssize_t result2 = 0;
if (fHeader->field_count > 0) {
ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
result2 = stream->Write(fFields, fieldsSize);
if (result2 != fieldsSize)
return result2 < 0 ? result2 : B_ERROR;
}
ssize_t result3 = 0;
if (fHeader->data_size > 0) {
result3 = stream->Write(fData, fHeader->data_size);
if (result3 != (ssize_t)fHeader->data_size)
return result3 < 0 ? result3 : B_ERROR;
}
if (size)
*size = result1 + result2 + result3;
return B_OK;
}
status_t
BMessage::_FlattenToArea(message_header** _header) const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
message_header* header = (message_header*)malloc(sizeof(message_header));
if (header == NULL)
return B_NO_MEMORY;
memcpy(header, fHeader, sizeof(message_header));
header->what = what;
header->message_area = -1;
*_header = header;
if (header->field_count == 0 && header->data_size == 0)
return B_OK;
char* address = NULL;
size_t fieldsSize = header->field_count * sizeof(field_header);
size_t size = fieldsSize + header->data_size;
size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
area_id area = create_area("BMessage data", (void**)&address,
B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < 0) {
free(header);
*_header = NULL;
return area;
}
memcpy(address, fFields, fieldsSize);
memcpy(address + fieldsSize, fData, fHeader->data_size);
header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
header->message_area = area;
return B_OK;
}
status_t
BMessage::_Reference()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
if (fHeader->field_count == 0 && fHeader->data_size == 0)
return B_OK;
area_info areaInfo;
status_t result = get_area_info(fHeader->message_area, &areaInfo);
if (result != B_OK)
return result;
if (areaInfo.team != BPrivate::current_team())
return B_BAD_VALUE;
set_area_protection(fHeader->message_area, B_READ_AREA);
uint8* address = (uint8*)areaInfo.address;
fFields = (field_header*)address;
fData = address + fHeader->field_count * sizeof(field_header);
return B_OK;
}
status_t
BMessage::_Dereference()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
delete_area(fHeader->message_area);
fHeader->message_area = -1;
fFields = NULL;
fData = NULL;
return B_OK;
}
status_t
BMessage::_CopyForWrite()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
field_header* newFields = NULL;
uint8* newData = NULL;
if (fHeader->field_count > 0) {
size_t fieldsSize = fHeader->field_count * sizeof(field_header);
newFields = (field_header*)malloc(fieldsSize);
if (newFields == NULL)
return B_NO_MEMORY;
memcpy(newFields, fFields, fieldsSize);
}
if (fHeader->data_size > 0) {
newData = (uint8*)malloc(fHeader->data_size);
if (newData == NULL) {
free(newFields);
return B_NO_MEMORY;
}
memcpy(newData, fData, fHeader->data_size);
}
_Dereference();
fFieldsAvailable = 0;
fDataAvailable = 0;
fFields = newFields;
fData = newData;
return B_OK;
}
status_t
BMessage::_ValidateMessage()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
if (fHeader->field_count == 0)
return B_OK;
if (fFields == NULL)
return B_NO_INIT;
for (uint32 i = 0; i < fHeader->field_count; i++) {
field_header* field = &fFields[i];
if ((field->next_field >= 0
&& (uint32)field->next_field > fHeader->field_count)
|| (field->offset + field->name_length + field->data_size
> fHeader->data_size)) {
MakeEmpty();
return B_BAD_VALUE;
}
}
return B_OK;
}
status_t
BMessage::Unflatten(const char* flatBuffer)
{
DEBUG_FUNCTION_ENTER;
if (flatBuffer == NULL)
return B_BAD_VALUE;
uint32 format = *(uint32*)flatBuffer;
if (format != MESSAGE_FORMAT_HAIKU)
return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
BMemoryIO io(flatBuffer, SSIZE_MAX);
return Unflatten(&io);
}
status_t
BMessage::Unflatten(BDataIO* stream)
{
DEBUG_FUNCTION_ENTER;
if (stream == NULL)
return B_BAD_VALUE;
uint32 format = 0;
stream->Read(&format, sizeof(uint32));
if (format != MESSAGE_FORMAT_HAIKU)
return BPrivate::MessageAdapter::Unflatten(format, this, stream);
_Clear();
fHeader = (message_header*)malloc(sizeof(message_header));
if (fHeader == NULL)
return B_NO_MEMORY;
fHeader->format = format;
uint8* header = (uint8*)fHeader;
ssize_t result = stream->Read(header + sizeof(uint32),
sizeof(message_header) - sizeof(uint32));
if (result != sizeof(message_header) - sizeof(uint32)
|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
_InitHeader();
return result < 0 ? result : B_BAD_VALUE;
}
what = fHeader->what;
if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
&& fHeader->message_area >= 0) {
status_t result = _Reference();
if (result != B_OK) {
_InitHeader();
return result;
}
} else {
fHeader->message_area = -1;
if (fHeader->field_count > 0) {
ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
fFields = (field_header*)malloc(fieldsSize);
if (fFields == NULL) {
_InitHeader();
return B_NO_MEMORY;
}
result = stream->Read(fFields, fieldsSize);
if (result != fieldsSize)
return result < 0 ? result : B_BAD_VALUE;
}
if (fHeader->data_size > 0) {
fData = (uint8*)malloc(fHeader->data_size);
if (fData == NULL) {
free(fFields);
fFields = NULL;
_InitHeader();
return B_NO_MEMORY;
}
result = stream->Read(fData, fHeader->data_size);
if (result != (ssize_t)fHeader->data_size) {
free(fData);
fData = NULL;
free(fFields);
fFields = NULL;
_InitHeader();
return result < 0 ? result : B_BAD_VALUE;
}
}
}
return _ValidateMessage();
}
status_t
BMessage::AddSpecifier(const char* property)
{
DEBUG_FUNCTION_ENTER;
BMessage message(B_DIRECT_SPECIFIER);
status_t result = message.AddString(B_PROPERTY_ENTRY, property);
if (result != B_OK)
return result;
return AddSpecifier(&message);
}
status_t
BMessage::AddSpecifier(const char* property, int32 index)
{
DEBUG_FUNCTION_ENTER;
BMessage message(B_INDEX_SPECIFIER);
status_t result = message.AddString(B_PROPERTY_ENTRY, property);
if (result != B_OK)
return result;
result = message.AddInt32("index", index);
if (result != B_OK)
return result;
return AddSpecifier(&message);
}
status_t
BMessage::AddSpecifier(const char* property, int32 index, int32 range)
{
DEBUG_FUNCTION_ENTER;
if (range < 0)
return B_BAD_VALUE;
BMessage message(B_RANGE_SPECIFIER);
status_t result = message.AddString(B_PROPERTY_ENTRY, property);
if (result != B_OK)
return result;
result = message.AddInt32("index", index);
if (result != B_OK)
return result;
result = message.AddInt32("range", range);
if (result != B_OK)
return result;
return AddSpecifier(&message);
}
status_t
BMessage::AddSpecifier(const char* property, const char* name)
{
DEBUG_FUNCTION_ENTER;
BMessage message(B_NAME_SPECIFIER);
status_t result = message.AddString(B_PROPERTY_ENTRY, property);
if (result != B_OK)
return result;
result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
if (result != B_OK)
return result;
return AddSpecifier(&message);
}
status_t
BMessage::AddSpecifier(const BMessage* specifier)
{
DEBUG_FUNCTION_ENTER;
status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
if (result != B_OK)
return result;
fHeader->current_specifier++;
fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
return B_OK;
}
status_t
BMessage::SetCurrentSpecifier(int32 index)
{
DEBUG_FUNCTION_ENTER;
if (index < 0)
return B_BAD_INDEX;
type_code type;
int32 count;
status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
if (result != B_OK)
return result;
if (index >= count)
return B_BAD_INDEX;
fHeader->current_specifier = index;
return B_OK;
}
status_t
BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier, int32* _what,
const char** property) const
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
if (index != NULL)
*index = fHeader->current_specifier;
if (fHeader->current_specifier < 0
|| (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
return B_BAD_SCRIPT_SYNTAX;
if (specifier) {
if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
specifier) != B_OK)
return B_BAD_SCRIPT_SYNTAX;
if (_what != NULL)
*_what = specifier->what;
if (property) {
if (specifier->FindString(B_PROPERTY_ENTRY, property) != B_OK)
return B_BAD_SCRIPT_SYNTAX;
}
}
return B_OK;
}
bool
BMessage::HasSpecifiers() const
{
DEBUG_FUNCTION_ENTER;
return fHeader != NULL
&& (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
}
status_t
BMessage::PopSpecifier()
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
if (fHeader->current_specifier < 0 ||
(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
return B_BAD_VALUE;
if (fHeader->current_specifier >= 0)
fHeader->current_specifier--;
return B_OK;
}
void
BMessage::_UpdateOffsets(uint32 offset, int32 change)
{
if (offset < fHeader->data_size) {
field_header* field = fFields;
for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
if (field->offset >= offset)
field->offset += change;
}
}
}
status_t
BMessage::_ResizeData(uint32 offset, int32 change)
{
if (change == 0)
return B_OK;
if (change > 0) {
if (fDataAvailable >= (uint32)change) {
if (offset < fHeader->data_size) {
memmove(fData + offset + change, fData + offset,
fHeader->data_size - offset);
}
_UpdateOffsets(offset, change);
fDataAvailable -= change;
fHeader->data_size += change;
return B_OK;
}
size_t size = fHeader->data_size * 2;
size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
size = max_c(size, fHeader->data_size + change);
uint8* newData = (uint8*)realloc(fData, size);
if (size > 0 && newData == NULL)
return B_NO_MEMORY;
fData = newData;
if (offset < fHeader->data_size) {
memmove(fData + offset + change, fData + offset,
fHeader->data_size - offset);
}
fHeader->data_size += change;
fDataAvailable = size - fHeader->data_size;
} else {
ssize_t length = fHeader->data_size - offset + change;
if (length > 0)
memmove(fData + offset, fData + offset - change, length);
fHeader->data_size += change;
fDataAvailable -= change;
if (fDataAvailable > MAX_DATA_PREALLOCATION) {
ssize_t available = MAX_DATA_PREALLOCATION / 2;
ssize_t size = fHeader->data_size + available;
uint8* newData = (uint8*)realloc(fData, size);
if (size > 0 && newData == NULL) {
_UpdateOffsets(offset, change);
return B_OK;
}
fData = newData;
fDataAvailable = available;
}
}
_UpdateOffsets(offset, change);
return B_OK;
}
uint32
BMessage::_HashName(const char* name) const
{
char ch;
uint32 result = 0;
while ((ch = *name++) != 0) {
result = (result << 7) ^ (result >> 24);
result ^= ch;
}
result ^= result << 12;
return result;
}
status_t
BMessage::_FindField(const char* name, type_code type, field_header** result)
const
{
if (name == NULL)
return B_BAD_VALUE;
if (fHeader == NULL)
return B_NO_INIT;
if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
return B_NAME_NOT_FOUND;
uint32 hash = _HashName(name) % fHeader->hash_table_size;
int32 nextField = fHeader->hash_table[hash];
while (nextField >= 0) {
field_header* field = &fFields[nextField];
if ((field->flags & FIELD_FLAG_VALID) == 0)
break;
if (strncmp((const char*)(fData + field->offset), name,
field->name_length) == 0) {
if (type != B_ANY_TYPE && field->type != type)
return B_BAD_TYPE;
*result = field;
return B_OK;
}
nextField = field->next_field;
}
return B_NAME_NOT_FOUND;
}
status_t
BMessage::_AddField(const char* name, type_code type, bool isFixedSize,
field_header** result)
{
if (fHeader == NULL)
return B_NO_INIT;
if (fFieldsAvailable <= 0) {
uint32 count = fHeader->field_count * 2 + 1;
count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
field_header* newFields = (field_header*)realloc(fFields,
count * sizeof(field_header));
if (count > 0 && newFields == NULL)
return B_NO_MEMORY;
fFields = newFields;
fFieldsAvailable = count - fHeader->field_count;
}
uint32 hash = _HashName(name) % fHeader->hash_table_size;
int32* nextField = &fHeader->hash_table[hash];
while (*nextField >= 0)
nextField = &fFields[*nextField].next_field;
*nextField = fHeader->field_count;
field_header* field = &fFields[fHeader->field_count];
field->type = type;
field->count = 0;
field->data_size = 0;
field->next_field = -1;
field->offset = fHeader->data_size;
field->name_length = strlen(name) + 1;
status_t status = _ResizeData(field->offset, field->name_length);
if (status != B_OK)
return status;
memcpy(fData + field->offset, name, field->name_length);
field->flags = FIELD_FLAG_VALID;
if (isFixedSize)
field->flags |= FIELD_FLAG_FIXED_SIZE;
fFieldsAvailable--;
fHeader->field_count++;
*result = field;
return B_OK;
}
status_t
BMessage::_RemoveField(field_header* field)
{
status_t result = _ResizeData(field->offset, -(field->data_size
+ field->name_length));
if (result != B_OK)
return result;
int32 index = ((uint8*)field - (uint8*)fFields) / sizeof(field_header);
int32 nextField = field->next_field;
if (nextField > index)
nextField--;
int32* value = fHeader->hash_table;
for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
if (*value > index)
*value -= 1;
else if (*value == index)
*value = nextField;
}
field_header* other = fFields;
for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
if (other->next_field > index)
other->next_field--;
else if (other->next_field == index)
other->next_field = nextField;
}
size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
memmove(fFields + index, fFields + index + 1, size);
fHeader->field_count--;
fFieldsAvailable++;
if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
ssize_t available = MAX_FIELD_PREALLOCATION / 2;
size = (fHeader->field_count + available) * sizeof(field_header);
field_header* newFields = (field_header*)realloc(fFields, size);
if (size > 0 && newFields == NULL) {
return B_OK;
}
fFields = newFields;
fFieldsAvailable = available;
}
return B_OK;
}
status_t
BMessage::AddData(const char* name, type_code type, const void* data,
ssize_t numBytes, bool isFixedSize, int32 count)
{
DEBUG_FUNCTION_ENTER;
if (numBytes <= 0 || data == NULL)
return B_BAD_VALUE;
if (fHeader == NULL)
return B_NO_INIT;
status_t result;
if (fHeader->message_area >= 0) {
result = _CopyForWrite();
if (result != B_OK)
return result;
}
field_header* field = NULL;
result = _FindField(name, type, &field);
if (result == B_NAME_NOT_FOUND)
result = _AddField(name, type, isFixedSize, &field);
if (result != B_OK)
return result;
if (field == NULL)
return B_ERROR;
uint32 offset = field->offset + field->name_length + field->data_size;
if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
if (field->count) {
ssize_t size = field->data_size / field->count;
if (size != numBytes)
return B_BAD_VALUE;
}
result = _ResizeData(offset, numBytes);
if (result != B_OK) {
if (field->count == 0)
_RemoveField(field);
return result;
}
memcpy(fData + offset, data, numBytes);
field->data_size += numBytes;
} else {
int32 change = numBytes + sizeof(uint32);
result = _ResizeData(offset, change);
if (result != B_OK) {
if (field->count == 0)
_RemoveField(field);
return result;
}
uint32 size = (uint32)numBytes;
memcpy(fData + offset, &size, sizeof(uint32));
memcpy(fData + offset + sizeof(uint32), data, size);
field->data_size += change;
}
field->count++;
return B_OK;
}
status_t
BMessage::RemoveData(const char* name, int32 index)
{
DEBUG_FUNCTION_ENTER;
if (index < 0)
return B_BAD_INDEX;
if (fHeader == NULL)
return B_NO_INIT;
status_t result;
if (fHeader->message_area >= 0) {
result = _CopyForWrite();
if (result != B_OK)
return result;
}
field_header* field = NULL;
result = _FindField(name, B_ANY_TYPE, &field);
if (result != B_OK)
return result;
if ((uint32)index >= field->count)
return B_BAD_INDEX;
if (field->count == 1)
return _RemoveField(field);
uint32 offset = field->offset + field->name_length;
if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
ssize_t size = field->data_size / field->count;
result = _ResizeData(offset + index * size, -size);
if (result != B_OK)
return result;
field->data_size -= size;
} else {
uint8* pointer = fData + offset;
for (int32 i = 0; i < index; i++) {
offset += *(uint32*)pointer + sizeof(uint32);
pointer = fData + offset;
}
size_t currentSize = *(uint32*)pointer + sizeof(uint32);
result = _ResizeData(offset, -currentSize);
if (result != B_OK)
return result;
field->data_size -= currentSize;
}
field->count--;
return B_OK;
}
status_t
BMessage::RemoveName(const char* name)
{
DEBUG_FUNCTION_ENTER;
if (fHeader == NULL)
return B_NO_INIT;
status_t result;
if (fHeader->message_area >= 0) {
result = _CopyForWrite();
if (result != B_OK)
return result;
}
field_header* field = NULL;
result = _FindField(name, B_ANY_TYPE, &field);
if (result != B_OK)
return result;
return _RemoveField(field);
}
status_t
BMessage::MakeEmpty()
{
DEBUG_FUNCTION_ENTER;
_Clear();
return _InitHeader();
}
status_t
BMessage::FindData(const char* name, type_code type, int32 index,
const void** data, ssize_t* numBytes) const
{
DEBUG_FUNCTION_ENTER;
if (data == NULL)
return B_BAD_VALUE;
*data = NULL;
field_header* field = NULL;
status_t result = _FindField(name, type, &field);
if (result != B_OK)
return result;
if (index < 0 || (uint32)index >= field->count)
return B_BAD_INDEX;
if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
size_t bytes = field->data_size / field->count;
*data = fData + field->offset + field->name_length + index * bytes;
if (numBytes != NULL)
*numBytes = bytes;
} else {
uint8* pointer = fData + field->offset + field->name_length;
for (int32 i = 0; i < index; i++)
pointer += *(uint32*)pointer + sizeof(uint32);
*data = pointer + sizeof(uint32);
if (numBytes != NULL)
*numBytes = *(uint32*)pointer;
}
return B_OK;
}
status_t
BMessage::ReplaceData(const char* name, type_code type, int32 index,
const void* data, ssize_t numBytes)
{
DEBUG_FUNCTION_ENTER;
if (numBytes <= 0 || data == NULL)
return B_BAD_VALUE;
status_t result;
if (fHeader->message_area >= 0) {
result = _CopyForWrite();
if (result != B_OK)
return result;
}
field_header* field = NULL;
result = _FindField(name, type, &field);
if (result != B_OK)
return result;
if (index < 0 || (uint32)index >= field->count)
return B_BAD_INDEX;
if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
ssize_t size = field->data_size / field->count;
if (size != numBytes)
return B_BAD_VALUE;
memcpy(fData + field->offset + field->name_length + index * size, data,
size);
} else {
uint32 offset = field->offset + field->name_length;
uint8* pointer = fData + offset;
for (int32 i = 0; i < index; i++) {
offset += *(uint32*)pointer + sizeof(uint32);
pointer = fData + offset;
}
size_t currentSize = *(uint32*)pointer;
int32 change = numBytes - currentSize;
result = _ResizeData(offset, change);
if (result != B_OK)
return result;
uint32 newSize = (uint32)numBytes;
memcpy(fData + offset, &newSize, sizeof(uint32));
memcpy(fData + offset + sizeof(uint32), data, newSize);
field->data_size += change;
}
return B_OK;
}
bool
BMessage::HasData(const char* name, type_code type, int32 index) const
{
DEBUG_FUNCTION_ENTER;
field_header* field = NULL;
status_t result = _FindField(name, type, &field);
if (result != B_OK)
return false;
if (index < 0 || (uint32)index >= field->count)
return false;
return true;
}
void
BMessage::_StaticInit()
{
DEBUG_FUNCTION_ENTER2;
sReplyPorts[0] = create_port(1, "tmp_rport0");
sReplyPorts[1] = create_port(1, "tmp_rport1");
sReplyPorts[2] = create_port(1, "tmp_rport2");
sReplyPortInUse[0] = 0;
sReplyPortInUse[1] = 0;
sReplyPortInUse[2] = 0;
sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
}
void
BMessage::_StaticReInitForkedChild()
{
DEBUG_FUNCTION_ENTER2;
sReplyPorts[0] = create_port(1, "tmp_rport0");
sReplyPorts[1] = create_port(1, "tmp_rport1");
sReplyPorts[2] = create_port(1, "tmp_rport2");
sReplyPortInUse[0] = 0;
sReplyPortInUse[1] = 0;
sReplyPortInUse[2] = 0;
}
void
BMessage::_StaticCleanup()
{
DEBUG_FUNCTION_ENTER2;
delete_port(sReplyPorts[0]);
sReplyPorts[0] = -1;
delete_port(sReplyPorts[1]);
sReplyPorts[1] = -1;
delete_port(sReplyPorts[2]);
sReplyPorts[2] = -1;
}
void
BMessage::_StaticCacheCleanup()
{
DEBUG_FUNCTION_ENTER2;
delete sMsgCache;
sMsgCache = NULL;
}
int32
BMessage::_StaticGetCachedReplyPort()
{
DEBUG_FUNCTION_ENTER2;
int index = -1;
for (int32 i = 0; i < sNumReplyPorts; i++) {
int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
if (old == 0) {
index = i;
break;
} else {
atomic_add(&(sReplyPortInUse[i]), -1);
}
}
return index;
}
status_t
BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
bigtime_t timeout, bool replyRequired, BMessenger& replyTo) const
{
DEBUG_FUNCTION_ENTER;
ssize_t size = 0;
char stackBuffer[4096];
char* buffer = NULL;
message_header* header = NULL;
status_t result = B_OK;
BPrivate::BDirectMessageTarget* direct = NULL;
BMessage* copy = NULL;
if (portOwner == BPrivate::current_team())
BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
if (direct != NULL) {
copy = new BMessage(*this);
if (copy != NULL) {
header = copy->fHeader;
header->flags = fHeader->flags;
} else {
direct->Release();
return B_NO_MEMORY;
}
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
} else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) {
KMessage toMessage;
result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage);
if (result != B_OK)
return result;
return toMessage.SendTo(port, token);
} else if (fHeader->data_size > B_PAGE_SIZE * 10) {
result = _FlattenToArea(&header);
if (result != B_OK)
return result;
buffer = (char*)header;
size = sizeof(message_header);
if (header->message_area >= 0) {
team_id target = portOwner;
if (target < 0) {
port_info info;
result = get_port_info(port, &info);
if (result != B_OK) {
free(header);
return result;
}
target = info.team;
}
void* address = NULL;
area_id transfered = _kern_transfer_area(header->message_area,
&address, B_ANY_ADDRESS, target);
if (transfered < 0) {
delete_area(header->message_area);
free(header);
return transfered;
}
header->message_area = transfered;
}
#endif
} else {
size = FlattenedSize();
if (size > (ssize_t)sizeof(stackBuffer)) {
buffer = (char*)malloc(size);
if (buffer == NULL)
return B_NO_MEMORY;
} else
buffer = stackBuffer;
result = Flatten(buffer, size);
if (result != B_OK) {
if (buffer != stackBuffer)
free(buffer);
return result;
}
header = (message_header*)buffer;
}
if (!replyTo.IsValid()) {
BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
fHeader->reply_port, fHeader->reply_target);
if (!replyTo.IsValid())
replyTo = be_app_messenger;
}
BMessenger::Private replyToPrivate(replyTo);
if (replyRequired) {
header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
}
header->target = token;
header->reply_team = replyToPrivate.Team();
header->reply_port = replyToPrivate.Port();
header->reply_target = replyToPrivate.Token();
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
if (direct == NULL) {
KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
"message: '%c%c%c%c'", portOwner, port, token,
char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
do {
result = write_port_etc(port, kPortMessageCode, (void*)buffer,
size, B_RELATIVE_TIMEOUT, timeout);
} while (result == B_INTERRUPTED);
}
if (result == B_OK && IsSourceWaiting()) {
fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
}
if (direct != NULL) {
KTRACE("BMessage send direct: port: %ld, token: %ld, "
"message: '%c%c%c%c'", port, token,
char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
direct->AddMessage(copy);
if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
}
direct->Release();
}
if (buffer != stackBuffer)
free(buffer);
return result;
}
status_t
BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
BMessage* reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
{
if (IsSourceWaiting()) {
return B_ERROR;
}
DEBUG_FUNCTION_ENTER;
const int32 cachedReplyPort = _StaticGetCachedReplyPort();
port_id replyPort = B_BAD_PORT_ID;
status_t result = B_OK;
if (cachedReplyPort < 0) {
replyPort = create_port(1 , "tmp_reply_port");
if (replyPort < 0)
return replyPort;
} else {
assert(cachedReplyPort < sNumReplyPorts);
replyPort = sReplyPorts[cachedReplyPort];
}
bool recreateCachedPort = false;
team_id team = B_BAD_TEAM_ID;
if (be_app != NULL)
team = be_app->Team();
else {
port_info portInfo;
result = get_port_info(replyPort, &portInfo);
if (result != B_OK)
goto error;
team = portInfo.team;
}
result = set_port_owner(replyPort, portOwner);
if (result != B_OK)
goto error;
#if 0
port_info portInfo;
if (get_port_info(replyPort, &portInfo) == B_OK
&& portInfo.queue_count > 0) {
debugger("reply port not empty!");
printf(" reply port not empty! %ld message(s) in queue\n",
portInfo.queue_count);
for (int32 i = 0; i < portInfo.queue_count; i++) {
char buffer[1024];
int32 code;
ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
if (size < 0) {
printf("failed to read message from reply port\n");
continue;
}
if (size >= (ssize_t)sizeof(buffer)) {
printf("message from reply port too big\n");
continue;
}
BMemoryIO stream(buffer, size);
BMessage reply;
if (reply.Unflatten(&stream) != B_OK) {
printf("failed to unflatten message from reply port\n");
continue;
}
printf("message %ld from reply port:\n", i);
reply.PrintToStream();
}
}
#endif
{
BMessenger replyTarget;
BMessenger::Private(replyTarget).SetTo(team, replyPort,
B_PREFERRED_TOKEN);
result = _SendMessage(port, -1, token, sendTimeout, true,
replyTarget);
}
if (result != B_OK)
goto error;
int32 code;
result = handle_reply(replyPort, &code, replyTimeout, reply);
if (result != B_OK && cachedReplyPort >= 0) {
delete_port(replyPort);
recreateCachedPort = true;
}
error:
if (cachedReplyPort >= 0) {
if (!recreateCachedPort && set_port_owner(replyPort, team) == B_OK) {
atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
} else
sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
return result;
}
delete_port(replyPort);
return result;
}
status_t
BMessage::_SendFlattenedMessage(void* data, int32 size, port_id port,
int32 token, bigtime_t timeout)
{
DEBUG_FUNCTION_ENTER2;
if (data == NULL)
return B_BAD_VALUE;
uint32 magic = *(uint32*)data;
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 == MESSAGE_FORMAT_R5) {
uint8* header = (uint8*)data;
header += sizeof(uint32) + sizeof(uint32)
+ sizeof(ssize_t) + sizeof(int32)
+ sizeof(uint8) ;
*(int32*)header = token;
} else if (((KMessage::Header*)data)->magic
== KMessage::kMessageHeaderMagic) {
KMessage::Header* header = (KMessage::Header*)data;
header->targetToken = token;
} else {
return B_NOT_A_MESSAGE;
}
status_t result;
do {
result = write_port_etc(port, kPortMessageCode, data, size,
B_RELATIVE_TIMEOUT, timeout);
} while (result == B_INTERRUPTED);
return result;
}
void BMessage::_ReservedMessage1() {}
void BMessage::_ReservedMessage2() {}
void BMessage::_ReservedMessage3() {}
#define DEFINE_FUNCTIONS(type, typeName, typeCode) \
status_t \
BMessage::Add##typeName(const char* name, type val) \
{ \
return AddData(name, typeCode, &val, sizeof(type), true); \
} \
\
\
status_t \
BMessage::Find##typeName(const char* name, type* p) const \
{ \
return Find##typeName(name, 0, p); \
} \
\
\
status_t \
BMessage::Find##typeName(const char* name, int32 index, type* p) const \
{ \
type* ptr = NULL; \
ssize_t bytes = 0; \
status_t error = B_OK; \
\
*p = type(); \
error = FindData(name, typeCode, index, (const void**)&ptr, &bytes); \
\
if (error == B_OK) \
memcpy((void *)p, ptr, sizeof(type)); \
\
return error; \
} \
\
\
status_t \
BMessage::Replace##typeName(const char* name, type value) \
{ \
return ReplaceData(name, typeCode, 0, &value, sizeof(type)); \
} \
\
\
status_t \
BMessage::Replace##typeName(const char* name, int32 index, type value) \
{ \
return ReplaceData(name, typeCode, index, &value, sizeof(type)); \
} \
\
\
bool \
BMessage::Has##typeName(const char* name, int32 index) const \
{ \
return HasData(name, typeCode, index); \
}
DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
DEFINE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
DEFINE_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
#undef DEFINE_FUNCTIONS
#define DEFINE_HAS_FUNCTION(typeName, typeCode) \
bool \
BMessage::Has##typeName(const char* name, int32 index) const \
{ \
return HasData(name, typeCode, index); \
}
DEFINE_HAS_FUNCTION(Alignment, B_ALIGNMENT_TYPE);
DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
DEFINE_HAS_FUNCTION(NodeRef, B_NODE_REF_TYPE);
DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
#undef DEFINE_HAS_FUNCTION
#define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize) \
type \
BMessage::Find##typeName(const char* name, int32 index) const \
{ \
type val = initialize; \
Find##typeName(name, index, &val); \
return val; \
}
DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
DEFINE_LAZY_FIND_FUNCTION(const char*, String, NULL);
DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
#undef DEFINE_LAZY_FIND_FUNCTION
#define DEFINE_SET_GET_FUNCTIONS(type, typeName, typeCode) \
type \
BMessage::Get##typeName(const char* name, type defaultValue) const \
{ \
return Get##typeName(name, 0, defaultValue); \
} \
\
\
type \
BMessage::Get##typeName(const char* name, int32 index, \
type defaultValue) const \
{ \
type value; \
if (Find##typeName(name, index, &value) == B_OK) \
return value; \
\
return defaultValue; \
} \
\
\
status_t \
BMessage::Set##typeName(const char* name, type value) \
{ \
return SetData(name, typeCode, &value, sizeof(type)); \
} \
DEFINE_SET_GET_FUNCTIONS(int8, Int8, B_INT8_TYPE);
DEFINE_SET_GET_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
DEFINE_SET_GET_FUNCTIONS(int16, Int16, B_INT16_TYPE);
DEFINE_SET_GET_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
DEFINE_SET_GET_FUNCTIONS(int32, Int32, B_INT32_TYPE);
DEFINE_SET_GET_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
DEFINE_SET_GET_FUNCTIONS(int64, Int64, B_INT64_TYPE);
DEFINE_SET_GET_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
DEFINE_SET_GET_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
DEFINE_SET_GET_FUNCTIONS(float, Float, B_FLOAT_TYPE);
DEFINE_SET_GET_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
DEFINE_SET_GET_FUNCTIONS(rgb_color, Color, B_RGB_32_BIT_TYPE);
#undef DEFINE_SET_GET_FUNCTION
const void*
BMessage::GetPointer(const char* name, const void* defaultValue) const
{
return GetPointer(name, 0, defaultValue);
}
const void*
BMessage::GetPointer(const char* name, int32 index,
const void* defaultValue) const
{
void* value;
if (FindPointer(name, index, &value) == B_OK)
return value;
return defaultValue;
}
status_t
BMessage::SetPointer(const char* name, const void* value)
{
return SetData(name, B_POINTER_TYPE, &value, sizeof(void*));
}
#define DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(type, typeName, typeCode) \
type \
BMessage::Get##typeName(const char* name, const type& defaultValue) const \
{ \
return Get##typeName(name, 0, defaultValue); \
} \
\
\
type \
BMessage::Get##typeName(const char* name, int32 index, \
const type& defaultValue) const \
{ \
type value; \
if (Find##typeName(name, index, &value) == B_OK) \
return value; \
\
return defaultValue; \
} \
\
\
status_t \
BMessage::Set##typeName(const char* name, const type& value) \
{ \
return SetData(name, typeCode, &value, sizeof(type)); \
} \
DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BSize, Size, B_SIZE_TYPE);
DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS(BAlignment, Alignment, B_ALIGNMENT_TYPE);
#undef DEFINE_SET_GET_BY_REFERENCE_FUNCTIONS
status_t
BMessage::AddAlignment(const char* name, const BAlignment& alignment)
{
int32 data[2] = { alignment.horizontal, alignment.vertical };
return AddData(name, B_ALIGNMENT_TYPE, data, sizeof(data));
}
status_t
BMessage::AddString(const char* name, const char* string)
{
return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0,
false);
}
status_t
BMessage::AddString(const char* name, const BString& string)
{
return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1,
false);
}
status_t
BMessage::AddStrings(const char* name, const BStringList& list)
{
int32 count = list.CountStrings();
for (int32 i = 0; i < count; i++) {
status_t error = AddString(name, list.StringAt(i));
if (error != B_OK)
return error;
}
return B_OK;
}
status_t
BMessage::AddPointer(const char* name, const void* pointer)
{
return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
}
status_t
BMessage::AddMessenger(const char* name, BMessenger messenger)
{
return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
}
status_t
BMessage::AddRef(const char* name, const entry_ref* ref)
{
size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
char buffer[size];
status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
if (error >= B_OK)
error = AddData(name, B_REF_TYPE, buffer, size, false);
return error;
}
status_t
BMessage::AddNodeRef(const char* name, const node_ref* ref)
{
size_t size = sizeof(node_ref);
char buffer[size];
status_t error = BPrivate::node_ref_flatten(buffer, &size, ref);
if (error >= B_OK)
error = AddData(name, B_NODE_REF_TYPE, buffer, size, false);
return error;
}
status_t
BMessage::AddMessage(const char* name, const BMessage* message)
{
if (message == NULL)
return B_BAD_VALUE;
ssize_t size = message->FlattenedSize();
BStackOrHeapArray<char, 4096> buffer(size);
if (!buffer.IsValid())
return B_NO_MEMORY;
status_t error = message->Flatten(buffer, size);
if (error >= B_OK)
error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
return error;
}
status_t
BMessage::AddFlat(const char* name, BFlattenable* object, int32 count)
{
return AddFlat(name, (const BFlattenable*)object, count);
}
status_t
BMessage::AddFlat(const char* name, const BFlattenable* object, int32 count)
{
if (object == NULL)
return B_BAD_VALUE;
ssize_t size = object->FlattenedSize();
BStackOrHeapArray<char, 4096> buffer(size);
if (!buffer.IsValid())
return B_NO_MEMORY;
status_t error = object->Flatten(buffer, size);
if (error >= B_OK)
error = AddData(name, object->TypeCode(), buffer, size, false);
return error;
}
status_t
BMessage::Append(const BMessage& other)
{
field_header* field = other.fFields;
for (uint32 i = 0; i < other.fHeader->field_count; i++, field++) {
const char* name = (const char*)(other.fData + field->offset);
const void* data = (const void*)(other.fData + field->offset
+ field->name_length);
bool isFixed = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
size_t size = field->data_size / field->count;
for (uint32 j = 0; j < field->count; j++) {
if (!isFixed) {
size = *(uint32*)data;
data = (const void*)((const char*)data + sizeof(uint32));
}
status_t status = AddData(name, field->type, data, size,
isFixed, 1);
if (status != B_OK)
return status;
data = (const void*)((const char*)data + size);
}
}
return B_OK;
}
status_t
BMessage::FindAlignment(const char* name, BAlignment* alignment) const
{
return FindAlignment(name, 0, alignment);
}
status_t
BMessage::FindAlignment(const char* name, int32 index, BAlignment* alignment)
const
{
if (!alignment)
return B_BAD_VALUE;
int32* data;
ssize_t bytes;
status_t err = FindData(name, B_ALIGNMENT_TYPE, index,
(const void**)&data, &bytes);
if (err == B_OK) {
if (bytes != sizeof(int32[2]))
return B_ERROR;
alignment->horizontal = (enum alignment)(*data);
alignment->vertical = (vertical_alignment)*(data + 1);
}
return err;
}
status_t
BMessage::FindString(const char* name, const char** string) const
{
return FindString(name, 0, string);
}
status_t
BMessage::FindString(const char* name, int32 index, const char** string) const
{
ssize_t bytes;
return FindData(name, B_STRING_TYPE, index, (const void**)string, &bytes);
}
status_t
BMessage::FindString(const char* name, BString* string) const
{
return FindString(name, 0, string);
}
status_t
BMessage::FindString(const char* name, int32 index, BString* string) const
{
if (string == NULL)
return B_BAD_VALUE;
const char* value;
status_t error = FindString(name, index, &value);
string->SetTo(value);
return error;
}
status_t
BMessage::FindStrings(const char* name, BStringList* list) const
{
if (list == NULL)
return B_BAD_VALUE;
list->MakeEmpty();
type_code type;
int32 count;
if (GetInfo(name, &type, &count) != B_OK)
return B_NAME_NOT_FOUND;
if (type != B_STRING_TYPE)
return B_BAD_DATA;
for (int32 i = 0; i < count; i++) {
BString string;
status_t error = FindString(name, i, &string);
if (error != B_OK)
return error;
if (!list->Add(string))
return B_NO_MEMORY;
}
return B_OK;
}
status_t
BMessage::FindPointer(const char* name, void** pointer) const
{
return FindPointer(name, 0, pointer);
}
status_t
BMessage::FindPointer(const char* name, int32 index, void** pointer) const
{
if (pointer == NULL)
return B_BAD_VALUE;
void** data = NULL;
ssize_t size = 0;
status_t error = FindData(name, B_POINTER_TYPE, index,
(const void**)&data, &size);
if (error == B_OK)
*pointer = *data;
else
*pointer = NULL;
return error;
}
status_t
BMessage::FindMessenger(const char* name, BMessenger* messenger) const
{
return FindMessenger(name, 0, messenger);
}
status_t
BMessage::FindMessenger(const char* name, int32 index,
BMessenger* messenger) const
{
if (messenger == NULL)
return B_BAD_VALUE;
BMessenger* data = NULL;
ssize_t size = 0;
status_t error = FindData(name, B_MESSENGER_TYPE, index,
(const void**)&data, &size);
if (error == B_OK)
*messenger = *data;
else
*messenger = BMessenger();
return error;
}
status_t
BMessage::FindRef(const char* name, entry_ref* ref) const
{
return FindRef(name, 0, ref);
}
status_t
BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
{
if (ref == NULL)
return B_BAD_VALUE;
void* data = NULL;
ssize_t size = 0;
status_t error = FindData(name, B_REF_TYPE, index,
(const void**)&data, &size);
if (error == B_OK)
error = BPrivate::entry_ref_unflatten(ref, (char*)data, size);
else
*ref = entry_ref();
return error;
}
status_t
BMessage::FindNodeRef(const char* name, node_ref* ref) const
{
return FindNodeRef(name, 0, ref);
}
status_t
BMessage::FindNodeRef(const char* name, int32 index, node_ref* ref) const
{
if (ref == NULL)
return B_BAD_VALUE;
void* data = NULL;
ssize_t size = 0;
status_t error = FindData(name, B_NODE_REF_TYPE, index,
(const void**)&data, &size);
if (error == B_OK)
error = BPrivate::node_ref_unflatten(ref, (char*)data, size);
else
*ref = node_ref();
return error;
}
status_t
BMessage::FindMessage(const char* name, BMessage* message) const
{
return FindMessage(name, 0, message);
}
status_t
BMessage::FindMessage(const char* name, int32 index, BMessage* message) const
{
if (message == NULL)
return B_BAD_VALUE;
void* data = NULL;
ssize_t size = 0;
status_t error = FindData(name, B_MESSAGE_TYPE, index,
(const void**)&data, &size);
if (error == B_OK)
error = message->Unflatten((const char*)data);
else
*message = BMessage();
return error;
}
status_t
BMessage::FindFlat(const char* name, BFlattenable* object) const
{
return FindFlat(name, 0, object);
}
status_t
BMessage::FindFlat(const char* name, int32 index, BFlattenable* object) const
{
if (object == NULL)
return B_BAD_VALUE;
void* data = NULL;
ssize_t numBytes = 0;
status_t error = FindData(name, object->TypeCode(), index,
(const void**)&data, &numBytes);
if (error == B_OK)
error = object->Unflatten(object->TypeCode(), data, numBytes);
return error;
}
status_t
BMessage::FindData(const char* name, type_code type, const void** data,
ssize_t* numBytes) const
{
return FindData(name, type, 0, data, numBytes);
}
status_t
BMessage::ReplaceAlignment(const char* name, const BAlignment& alignment)
{
int32 data[2] = {alignment.horizontal, alignment.vertical};
return ReplaceData(name, B_ALIGNMENT_TYPE, 0, data, sizeof(data));
}
status_t
BMessage::ReplaceAlignment(const char* name, int32 index,
const BAlignment& alignment)
{
int32 data[2] = {alignment.horizontal, alignment.vertical};
return ReplaceData(name, B_ALIGNMENT_TYPE, index, data, sizeof(data));
}
status_t
BMessage::ReplaceString(const char* name, const char* string)
{
if (string == NULL)
return B_BAD_VALUE;
return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
}
status_t
BMessage::ReplaceString(const char* name, int32 index, const char* string)
{
if (string == NULL)
return B_BAD_VALUE;
return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
}
status_t
BMessage::ReplaceString(const char* name, const BString& string)
{
return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
string.Length() + 1);
}
status_t
BMessage::ReplaceString(const char* name, int32 index, const BString& string)
{
return ReplaceData(name, B_STRING_TYPE, index, string.String(),
string.Length() + 1);
}
status_t
BMessage::ReplacePointer(const char* name, const void* pointer)
{
return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
}
status_t
BMessage::ReplacePointer(const char* name, int32 index, const void* pointer)
{
return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
}
status_t
BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
{
return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
sizeof(BMessenger));
}
status_t
BMessage::ReplaceMessenger(const char* name, int32 index, BMessenger messenger)
{
return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
sizeof(BMessenger));
}
status_t
BMessage::ReplaceRef(const char* name, const entry_ref* ref)
{
return ReplaceRef(name, 0, ref);
}
status_t
BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
{
size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
char buffer[size];
status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
if (error >= B_OK)
error = ReplaceData(name, B_REF_TYPE, index, buffer, size);
return error;
}
status_t
BMessage::ReplaceNodeRef(const char* name, const node_ref* ref)
{
return ReplaceNodeRef(name, 0, ref);
}
status_t
BMessage::ReplaceNodeRef(const char* name, int32 index, const node_ref* ref)
{
size_t size = sizeof(node_ref) + B_PATH_NAME_LENGTH;
char buffer[size];
status_t error = BPrivate::node_ref_flatten(buffer, &size, ref);
if (error >= B_OK)
error = ReplaceData(name, B_NODE_REF_TYPE, index, buffer, size);
return error;
}
status_t
BMessage::ReplaceMessage(const char* name, const BMessage* message)
{
return ReplaceMessage(name, 0, message);
}
status_t
BMessage::ReplaceMessage(const char* name, int32 index, const BMessage* message)
{
if (message == NULL)
return B_BAD_VALUE;
ssize_t size = message->FlattenedSize();
if (size < 0)
return B_BAD_VALUE;
char buffer[size];
status_t error = message->Flatten(buffer, size);
if (error >= B_OK)
error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
return error;
}
status_t
BMessage::ReplaceFlat(const char* name, BFlattenable* object)
{
return ReplaceFlat(name, 0, object);
}
status_t
BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* object)
{
if (object == NULL)
return B_BAD_VALUE;
ssize_t size = object->FlattenedSize();
if (size < 0)
return B_BAD_VALUE;
char buffer[size];
status_t error = object->Flatten(buffer, size);
if (error >= B_OK)
error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
return error;
}
status_t
BMessage::ReplaceData(const char* name, type_code type, const void* data,
ssize_t numBytes)
{
return ReplaceData(name, type, 0, data, numBytes);
}
bool
BMessage::HasFlat(const char* name, const BFlattenable* object) const
{
return HasFlat(name, 0, object);
}
bool
BMessage::HasFlat(const char* name, int32 index, const BFlattenable* object)
const
{
return HasData(name, object->TypeCode(), index);
}
const char*
BMessage::GetString(const char* name, const char* defaultValue) const
{
return GetString(name, 0, defaultValue);
}
const char*
BMessage::GetString(const char* name, int32 index,
const char* defaultValue) const
{
const char* value;
if (FindString(name, index, &value) == B_OK)
return value;
return defaultValue;
}
status_t
BMessage::SetString(const char* name, const BString& value)
{
return SetData(name, B_STRING_TYPE, value.String(), value.Length() + 1,
false);
}
status_t
BMessage::SetString(const char* name, const char* value)
{
return SetData(name, B_STRING_TYPE, value, strlen(value) + 1, false);
}
status_t
BMessage::SetData(const char* name, type_code type, const void* data,
ssize_t numBytes, bool fixedSize, int count)
{
if (numBytes <= 0 || data == NULL)
return B_BAD_VALUE;
if (ReplaceData(name, type, data, numBytes) == B_OK)
return B_OK;
return AddData(name, type, data, numBytes, fixedSize, count);
}