/*
 * Copyright 2005-2011, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Michael Lotz <mmlr@mlotz.ch>
 */
 
 
#include <Message.h>
#include <MessageAdapter.h>
#include <MessagePrivate.h>
#include <MessageUtils.h>
 
#include <MessengerPrivate.h>
#include <TokenSpace.h>
 
#include <Application.h>
#include <AppMisc.h>
#include <BlockCache.h>
#include <Entry.h>
#include <MessageQueue.h>
#include <Messenger.h>
#include <Path.h>
#include <Point.h>
#include <Rect.h>
#include <String.h>
#include <StringList.h>
 
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "tracing_config.h"
	// kernel tracing configuration
 
//#define VERBOSE_DEBUG_OUTPUT
#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	/* nothing */
#define DEBUG_FUNCTION_ENTER2	/* nothing */
#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";
 
extern "C" {
	// private os function to set the owning team of an area
	status_t _kern_transfer_area(area_id area, void **_address,
		uint32 addressSpec, team_id target);
}
 
 
BBlockCache *BMessage::sMsgCache = NULL;
 
 
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);
}
 
 
//	#pragma mark -
 
 
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;
	_InitCommon(true);
	fHeader->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;
 
	memcpy(fHeader, other.fHeader, sizeof(message_header));
 
	// Clear some header flags inherited from the original message that don't
	// apply to the clone.
	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
		| MESSAGE_FLAG_PASS_BY_AREA);
	// Note, that BeOS R5 seems to keep the reply info.
 
	if (fHeader->field_count > 0) {
		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
		fFields = (field_header *)malloc(fieldsSize);
		if (fFields == NULL) {
			fHeader->field_count = 0;
			fHeader->data_size = 0;
		} else
			memcpy(fFields, other.fFields, fieldsSize);
	}
 
	if (fHeader->data_size > 0) {
		fData = (uint8 *)malloc(fHeader->data_size);
		if (fData == NULL) {
			fHeader->field_count = 0;
			free(fFields);
			fFields = NULL;
		} else
			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;
	if (!sMsgCache)
		sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE);
	void *pointer = sMsgCache->Get(size);
	return pointer;
}
 
 
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;
	sMsgCache->Save(pointer, size);
}
 
 
bool
BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
	bool deep) const
{
	if (this == &other)
		return true;
 
	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;
 
	if (initHeader)
		return _InitHeader();
 
	fHeader = NULL;
	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;
 
	// initializing the hash table to -1 because 0 is a valid index
	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) {
		free(fHeader);
		fHeader = NULL;
	}
 
	free(fFields);
	fFields = NULL;
	free(fData);
	fData = 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 (index < 0 || (uint32)index >= fHeader->field_count)
		return B_BAD_INDEX;
 
	if (typeRequested == B_ANY_TYPE) {
		if (nameFound)
			*nameFound = (char *)fData + fFields[index].offset;
		if (typeFound)
			*typeFound = fFields[index].type;
		if (countFound)
			*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)
				*nameFound = (char *)fData + field->offset;
			if (typeFound)
				*typeFound = field->type;
			if (countFound)
				*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)
		*countFound = 0;
 
	field_header *field = NULL;
	status_t result = _FindField(name, B_ANY_TYPE, &field);
	if (result < B_OK || field == NULL)
		return result;
 
	if (typeFound)
		*typeFound = field->type;
	if (countFound)
		*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 || field == NULL)
		return result;
 
	if (typeFound)
		*typeFound = field->type;
	if (fixedSize)
		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
 
	return B_OK;
}
 
 
int32
BMessage::CountNames(type_code type) const
{
	DEBUG_FUNCTION_ENTER;
	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->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);
 
	// The BeBook says:
	//		... we've adopted a strict convention for assigning values to all
	//		Be-defined constants.  The value assigned will always be formed by
	//		combining four characters into a multicharacter constant, with the
	//		characters limited to uppercase letters and the underbar
	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
		return true;
 
	return false;
}
 
 
bool
BMessage::IsReply() const
{
	DEBUG_FUNCTION_ENTER;
	return (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);
			}
 
			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:
				{
					size = *(uint32 *)pointer;
					pointer += sizeof(uint32);
					printf("string(\"%s\", %ld bytes)\n", (char *)pointer,
						(long)size);
					break;
				}
 
				case B_INT8_TYPE:
					print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
					break;
 
				case B_UINT8_TYPE:
					print_type<uint8>("uint8(0x%hx or %u or '%.1s')\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 %Ld)\n", pointer);
					break;
 
				case B_UINT64_TYPE:
					print_type<uint64>("uint64(0x%Lx or %Ld\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:
				{
					size = *(uint32 *)pointer;
					pointer += sizeof(uint32);
					entry_ref ref;
					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
 
					printf("entry_ref(device=%d, directory=%lld"
						", name=\"%s\", ", (int)ref.device,
						(long long)ref.directory, ref.name);
 
					BPath path(&ref);
					printf("path=\"%s\")\n", path.Path());
					break;
				}
 
				case B_MESSAGE_TYPE:
				{
					char buffer[1024];
					sprintf(buffer, "%s        ", indent);
 
					BMessage message;
					size = *(uint32 *)pointer;
					pointer += sizeof(uint32);
					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;
				}
 
				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;
 
	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) {
			// nextField points to the field for oldEntry, save it and unlink
			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;
			status_t 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->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
}
 
 
bool
BMessage::IsSourceWaiting() const
{
	DEBUG_FUNCTION_ENTER;
	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
}
 
 
BMessenger
BMessage::ReturnAddress() const
{
	DEBUG_FUNCTION_ENTER;
	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
		BMessenger messenger;
		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
			fHeader->reply_port, fHeader->reply_target);
		return messenger;
	}
 
	return BMessenger();
}
 
 
const BMessage *
BMessage::Previous() const
{
	DEBUG_FUNCTION_ENTER;
	/* ToDo: test if the "_previous_" field is used in R5 */
	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->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
}
 
 
BPoint
BMessage::DropPoint(BPoint *offset) const
{
	DEBUG_FUNCTION_ENTER;
	if (offset)
		*offset = FindPoint("_drop_offset_");
 
	return FindPoint("_drop_point_");
}
 
 
ssize_t
BMessage::FlattenedSize() const
{
	DEBUG_FUNCTION_ENTER;
	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;
 
	/* we have to sync the what code as it is a public member */
	fHeader->what = what;
 
	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
	buffer += sizeof(message_header);
	size -= sizeof(message_header);
 
	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
	memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
	buffer += fieldsSize;
	size -= fieldsSize;
 
	memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
	if ((size_t)size < fHeader->data_size)
		return B_BUFFER_OVERFLOW;
 
	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;
 
	/* we have to sync the what code as it is a public member */
	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::_ValidateMessage()
{
	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)) {
			// the message is corrupt
			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);
 
	// native message unflattening
 
	_Clear();
 
	fHeader = (message_header *)malloc(sizeof(message_header));
	if (fHeader == NULL)
		return B_NO_MEMORY;
 
	memcpy(fHeader, flatBuffer, sizeof(message_header));
	flatBuffer += sizeof(message_header);
 
	if (fHeader->format != MESSAGE_FORMAT_HAIKU
		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
		_InitHeader();
		return 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)
//			return result;
	} else {
		fHeader->message_area = -1;
 
		if (fHeader->field_count > 0) {
			size_t fieldsSize = fHeader->field_count * sizeof(field_header);
			fFields = (field_header *)malloc(fieldsSize);
			if (fFields == NULL) {
				_InitHeader();
				return B_NO_MEMORY;
			}
 
			memcpy(fFields, flatBuffer, fieldsSize);
			flatBuffer += fieldsSize;
		}
 
		if (fHeader->data_size > 0) {
			fData = (uint8 *)malloc(fHeader->data_size);
			if (fData == NULL) {
				free(fFields);
				fFields = NULL;
				_InitHeader();
				return B_NO_MEMORY;
			}
 
			memcpy(fData, flatBuffer, fHeader->data_size);
		}
	}
 
	return _ValidateMessage();
}
 
 
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);
 
	// native message unflattening
 
	_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;
 
	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)
			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 (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->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
}
 
 
status_t
BMessage::PopSpecifier()
{
	DEBUG_FUNCTION_ENTER;
	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;
}
 
 
status_t
BMessage::_ResizeData(uint32 offset, int32 change)
{
	if (change == 0)
		return B_OK;
 
	/* optimize for the most usual case: appending data */
	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;
		}
	}
 
	if (change > 0) {
		if (fDataAvailable >= (uint32)change) {
			if (offset < fHeader->data_size) {
				memmove(fData + offset + change, fData + offset,
					fHeader->data_size - offset);
			}
 
			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);
 
		// change is negative
		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) {
				// this is strange, but not really fatal
				return B_OK;
			}
 
			fData = newData;
			fDataAvailable = available;
		}
	}
 
	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 || 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_ERROR;
 
	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) {
			// this is strange, but not really fatal
			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)
{
	// Note that the "count" argument is only a hint at how many items
	// the caller expects to add to this field. Since we do no item pre-
	// allocation, we ignore this argument.
	DEBUG_FUNCTION_ENTER;
	if (numBytes <= 0 || data == NULL)
		return B_BAD_VALUE;
 
	field_header *field = NULL;
	status_t 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;
 
	field_header *field = NULL;
	status_t result = _FindField(name, B_ANY_TYPE, &field);
 
	if (result < B_OK)
		return result;
 
	if (field == NULL)
		return B_ERROR;
 
	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;
	field_header *field = NULL;
	status_t result = _FindField(name, B_ANY_TYPE, &field);
 
	if (result < B_OK)
		return result;
 
	if (field == NULL)
		return B_ERROR;
 
	return _RemoveField(field);
}
 
 
status_t
BMessage::MakeEmpty()
{
	DEBUG_FUNCTION_ENTER;
	_Clear();
	_InitHeader();
	return B_OK;
}
 
 
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 (field == NULL)
		return B_ERROR;
 
	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;
 
	field_header *field = NULL;
	status_t result = _FindField(name, type, &field);
 
	if (result < B_OK)
		return result;
 
	if (field == NULL)
		return B_ERROR;
 
	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 (field == NULL)
		return false;
 
	if (index < 0 || (uint32)index >= field->count)
		return false;
 
	return true;
}
 
 
void BMessage::_ReservedMessage1(void) {};
void BMessage::_ReservedMessage2(void) {};
void BMessage::_ReservedMessage3(void) {};
 
 
/* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
 
#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					\
{																			\
	void *ptr = NULL;														\
	ssize_t bytes = 0;														\
	status_t error = B_OK;													\
																			\
	*p = type();															\
	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
																			\
	if (error == B_OK)														\
		memcpy(p, ptr, sizeof(type));										\
																			\
	return error;															\
}																			\
																			\
status_t																	\
BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
{																			\
	void *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(p, ptr, sizeof(type));										\
																			\
	return error;															\
}																			\
																			\
status_t																	\
BMessage::Replace##typeName(const char *name, type val)						\
{																			\
	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
}																			\
																			\
status_t																	\
BMessage::Replace##typeName(const char *name, int32 index, type val)		\
{																			\
	return ReplaceData(name, typeCode, index, &val, 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(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);
 
#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(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(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
 
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::AddMessage(const char *name, const BMessage *message)
{
	if (message == NULL)
		return B_BAD_VALUE;
 
	// TODO: This and the following functions waste time by allocating and
	// copying an extra buffer. Functions can be added that return a direct
	// pointer into the message.
 
	char stackBuffer[16384];
	ssize_t size = message->FlattenedSize();
 
	char* buffer;
	if (size > (ssize_t)sizeof(stackBuffer)) {
		buffer = (char *)malloc(size);
		if (buffer == NULL)
			return B_NO_MEMORY;
	} else
		buffer = stackBuffer;
 
	status_t error = message->Flatten(buffer, size);
 
	if (error >= B_OK)
		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
 
	if (buffer != stackBuffer)
		free(buffer);
 
	return error;
}
 
 
status_t
BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
{
	if (object == NULL)
		return B_BAD_VALUE;
 
	char stackBuffer[16384];
	ssize_t size = object->FlattenedSize();
 
	char* buffer;
	if (size > (ssize_t)sizeof(stackBuffer)) {
		buffer = (char *)malloc(size);
		if (buffer == NULL)
			return B_NO_MEMORY;
	} else
		buffer = stackBuffer;
 
	status_t error = object->Flatten(buffer, size);
 
	if (error >= B_OK)
		error = AddData(name, object->TypeCode(), buffer, size, false);
 
	if (buffer != stackBuffer)
		free(buffer);
 
	return error;
}
 
 
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 *cstr;
	status_t error = FindString(name, index, &cstr);
	if (error < B_OK)
		return error;
 
	*string = cstr;
	return B_OK;
}
 
 
status_t
BMessage::FindStrings(const char *name, BStringList *list) const
{
	if (list == NULL)
		return B_BAD_VALUE;
 
	list->MakeEmpty();
 
	// get the number of items
	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;
 
	void *data = NULL;
	ssize_t size = 0;
	status_t error = FindData(name, B_MESSENGER_TYPE, index,
		(const void **)&data, &size);
 
	if (error == B_OK)
		memcpy(messenger, data, sizeof(BMessenger));
	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::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::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::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();
	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();
	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);
}

V512 A call of the 'memset' function will lead to underflow of the buffer 'fHeader'.

V781 The value of the 'field->count' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 1396, 1403.

V781 The value of the 'size' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 1207, 1208.