1338b8dc3SIngo Weinhold/*
24cc4f7bbSIngo Weinhold * Copyright 2005-2011, Haiku Inc. All rights reserved.
3338b8dc3SIngo Weinhold * Distributed under the terms of the MIT License.
4338b8dc3SIngo Weinhold *
5338b8dc3SIngo Weinhold * Authors:
6da0f338eSMichael Lotz *		Michael Lotz <mmlr@mlotz.ch>
7338b8dc3SIngo Weinhold */
8a3e1fc11SAxel Dörfler
97870a9ffSIngo Weinhold
10da0f338eSMichael Lotz#include <Message.h>
117870a9ffSIngo Weinhold#include <MessageAdapter.h>
127870a9ffSIngo Weinhold#include <MessagePrivate.h>
137870a9ffSIngo Weinhold#include <MessageUtils.h>
14338b8dc3SIngo Weinhold
157870a9ffSIngo Weinhold#include <MessengerPrivate.h>
167870a9ffSIngo Weinhold#include <TokenSpace.h>
17338b8dc3SIngo Weinhold
18338b8dc3SIngo Weinhold#include <Application.h>
197870a9ffSIngo Weinhold#include <AppMisc.h>
20338b8dc3SIngo Weinhold#include <BlockCache.h>
21da0f338eSMichael Lotz#include <Entry.h>
22da0f338eSMichael Lotz#include <MessageQueue.h>
23338b8dc3SIngo Weinhold#include <Messenger.h>
24da0f338eSMichael Lotz#include <Path.h>
25da0f338eSMichael Lotz#include <Point.h>
26da0f338eSMichael Lotz#include <Rect.h>
27338b8dc3SIngo Weinhold#include <String.h>
2874233e2cSOliver Tappe#include <StringList.h>
29338b8dc3SIngo Weinhold
307870a9ffSIngo Weinhold#include <assert.h>
317870a9ffSIngo Weinhold#include <ctype.h>
327870a9ffSIngo Weinhold#include <stdio.h>
337870a9ffSIngo Weinhold#include <stdlib.h>
347870a9ffSIngo Weinhold#include <string.h>
357870a9ffSIngo Weinhold
367870a9ffSIngo Weinhold#include "tracing_config.h"
377870a9ffSIngo Weinhold	// kernel tracing configuration
387870a9ffSIngo Weinhold
397870a9ffSIngo Weinhold//#define VERBOSE_DEBUG_OUTPUT
407870a9ffSIngo Weinhold#ifdef VERBOSE_DEBUG_OUTPUT
417870a9ffSIngo Weinhold#define DEBUG_FUNCTION_ENTER	\
427870a9ffSIngo Weinhold	debug_printf("msg thread: %ld; this: %p; header: %p; fields: %p;" \
437870a9ffSIngo Weinhold		" data: %p; what: 0x%08lx '%.4s'; line: %d; func: %s\n", \
447870a9ffSIngo Weinhold		find_thread(NULL), this, fHeader, fFields, fData, what, (char *)&what, \
457870a9ffSIngo Weinhold		__LINE__, __PRETTY_FUNCTION__);
467870a9ffSIngo Weinhold
477870a9ffSIngo Weinhold#define DEBUG_FUNCTION_ENTER2	\
487870a9ffSIngo Weinhold	debug_printf("msg thread: %ld; line: %d: func: %s\n", find_thread(NULL), \
497870a9ffSIngo Weinhold		__LINE__, __PRETTY_FUNCTION__);
507870a9ffSIngo Weinhold#else
517870a9ffSIngo Weinhold#define DEBUG_FUNCTION_ENTER	/* nothing */
527870a9ffSIngo Weinhold#define DEBUG_FUNCTION_ENTER2	/* nothing */
537870a9ffSIngo Weinhold#endif
547870a9ffSIngo Weinhold
557870a9ffSIngo Weinhold#if BMESSAGE_TRACING
567870a9ffSIngo Weinhold#	define KTRACE(format...)	ktrace_printf(format)
577870a9ffSIngo Weinhold#else
587870a9ffSIngo Weinhold#	define KTRACE(format...)
597870a9ffSIngo Weinhold#endif
60338b8dc3SIngo Weinhold
61338b8dc3SIngo Weinhold
62da0f338eSMichael Lotzconst char *B_SPECIFIER_ENTRY = "specifiers";
63da0f338eSMichael Lotzconst char *B_PROPERTY_ENTRY = "property";
64da0f338eSMichael Lotzconst char *B_PROPERTY_NAME_ENTRY = "name";
65338b8dc3SIngo Weinhold
667870a9ffSIngo Weinholdextern "C" {
677870a9ffSIngo Weinhold	// private os function to set the owning team of an area
687870a9ffSIngo Weinhold	status_t _kern_transfer_area(area_id area, void **_address,
697870a9ffSIngo Weinhold		uint32 addressSpec, team_id target);
707870a9ffSIngo Weinhold}
717870a9ffSIngo Weinhold
72338b8dc3SIngo Weinhold
73da0f338eSMichael LotzBBlockCache *BMessage::sMsgCache = NULL;
74338b8dc3SIngo Weinhold
75338b8dc3SIngo Weinhold
767870a9ffSIngo Weinholdtemplate<typename Type>
777870a9ffSIngo Weinholdstatic void
787870a9ffSIngo Weinholdprint_to_stream_type(uint8 *pointer)
797870a9ffSIngo Weinhold{
807870a9ffSIngo Weinhold	Type *item = (Type *)pointer;
817870a9ffSIngo Weinhold	item->PrintToStream();
827870a9ffSIngo Weinhold}
837870a9ffSIngo Weinhold
847870a9ffSIngo Weinhold
857870a9ffSIngo Weinholdtemplate<typename Type>
867870a9ffSIngo Weinholdstatic void
877870a9ffSIngo Weinholdprint_type(const char *format, uint8 *pointer)
887870a9ffSIngo Weinhold{
897870a9ffSIngo Weinhold	Type *item = (Type *)pointer;
907870a9ffSIngo Weinhold	printf(format, *item, *item);
917870a9ffSIngo Weinhold}
927870a9ffSIngo Weinhold
937870a9ffSIngo Weinhold
947870a9ffSIngo Weinhold//	#pragma mark -
957870a9ffSIngo Weinhold
967870a9ffSIngo Weinhold
97da0f338eSMichael LotzBMessage::BMessage()
98da0f338eSMichael Lotz{
997870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
1007870a9ffSIngo Weinhold	_InitCommon(true);
101da0f338eSMichael Lotz}
102338b8dc3SIngo Weinhold
103338b8dc3SIngo Weinhold
104da0f338eSMichael LotzBMessage::BMessage(BMessage *other)
105da0f338eSMichael Lotz{
1067870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
1077870a9ffSIngo Weinhold	_InitCommon(false);
108da0f338eSMichael Lotz	*this = *other;
109da0f338eSMichael Lotz}
110338b8dc3SIngo Weinhold
111338b8dc3SIngo Weinhold
112da0f338eSMichael LotzBMessage::BMessage(uint32 _what)
113da0f338eSMichael Lotz{
1147870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
1157870a9ffSIngo Weinhold	_InitCommon(true);
116da0f338eSMichael Lotz	fHeader->what = what = _what;
117da0f338eSMichael Lotz}
118338b8dc3SIngo Weinhold
119338b8dc3SIngo Weinhold
120da0f338eSMichael LotzBMessage::BMessage(const BMessage &other)
121da0f338eSMichael Lotz{
1227870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
1237870a9ffSIngo Weinhold	_InitCommon(false);
124da0f338eSMichael Lotz	*this = other;
125da0f338eSMichael Lotz}
126338b8dc3SIngo Weinhold
127338b8dc3SIngo Weinhold
128da0f338eSMichael LotzBMessage::~BMessage()
129da0f338eSMichael Lotz{
1307870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
131da0f338eSMichael Lotz	_Clear();
132da0f338eSMichael Lotz}
133338b8dc3SIngo Weinhold
134338b8dc3SIngo Weinhold
135da0f338eSMichael LotzBMessage &
136da0f338eSMichael LotzBMessage::operator=(const BMessage &other)
137da0f338eSMichael Lotz{
1387870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
1397870a9ffSIngo Weinhold
14028fb504bSFrançois Revol	if (this == &other)
14128fb504bSFrançois Revol		return *this;
1427870a9ffSIngo Weinhold
143da0f338eSMichael Lotz	_Clear();
144338b8dc3SIngo Weinhold
145da0f338eSMichael Lotz	fHeader = (message_header *)malloc(sizeof(message_header));
1467870a9ffSIngo Weinhold	if (fHeader == NULL)
1477870a9ffSIngo Weinhold		return *this;
1487870a9ffSIngo Weinhold
149da0f338eSMichael Lotz	memcpy(fHeader, other.fHeader, sizeof(message_header));
150338b8dc3SIngo Weinhold
151da0f338eSMichael Lotz	// Clear some header flags inherited from the original message that don't
152da0f338eSMichael Lotz	// apply to the clone.
153da0f338eSMichael Lotz	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
154da0f338eSMichael Lotz		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
1557870a9ffSIngo Weinhold		| MESSAGE_FLAG_PASS_BY_AREA);
156da0f338eSMichael Lotz	// Note, that BeOS R5 seems to keep the reply info.
157338b8dc3SIngo Weinhold
1587870a9ffSIngo Weinhold	if (fHeader->field_count > 0) {
1597870a9ffSIngo Weinhold		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1607870a9ffSIngo Weinhold		fFields = (field_header *)malloc(fieldsSize);
1617870a9ffSIngo Weinhold		if (fFields == NULL) {
1627870a9ffSIngo Weinhold			fHeader->field_count = 0;
1637870a9ffSIngo Weinhold			fHeader->data_size = 0;
1647870a9ffSIngo Weinhold		} else
1657870a9ffSIngo Weinhold			memcpy(fFields, other.fFields, fieldsSize);
166da0f338eSMichael Lotz	}
167338b8dc3SIngo Weinhold
168da0f338eSMichael Lotz	if (fHeader->data_size > 0) {
169da0f338eSMichael Lotz		fData = (uint8 *)malloc(fHeader->data_size);
1707870a9ffSIngo Weinhold		if (fData == NULL) {
1717870a9ffSIngo Weinhold			fHeader->field_count = 0;
1727870a9ffSIngo Weinhold			free(fFields);
1737870a9ffSIngo Weinhold			fFields = NULL;
1747870a9ffSIngo Weinhold		} else
1757870a9ffSIngo Weinhold			memcpy(fData, other.fData, fHeader->data_size);
176da0f338eSMichael Lotz	}
177338b8dc3SIngo Weinhold
178da0f338eSMichael Lotz	fHeader->what = what = other.what;
1797870a9ffSIngo Weinhold	fHeader->message_area = -1;
1807870a9ffSIngo Weinhold	fFieldsAvailable = 0;
1817870a9ffSIngo Weinhold	fDataAvailable = 0;
182338b8dc3SIngo Weinhold
183da0f338eSMichael Lotz	return *this;
184da0f338eSMichael Lotz}
185338b8dc3SIngo Weinhold
186338b8dc3SIngo Weinhold
187da0f338eSMichael Lotzvoid *
188da0f338eSMichael LotzBMessage::operator new(size_t size)
189338b8dc3SIngo Weinhold{
1907870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER2;
191da0f338eSMichael Lotz	if (!sMsgCache)
192da0f338eSMichael Lotz		sMsgCache = new BBlockCache(10, sizeof(BMessage), B_OBJECT_CACHE);
1937870a9ffSIngo Weinhold	void *pointer = sMsgCache->Get(size);
1947870a9ffSIngo Weinhold	return pointer;
195338b8dc3SIngo Weinhold}
196338b8dc3SIngo Weinhold
197338b8dc3SIngo Weinhold
198da0f338eSMichael Lotzvoid *
199da0f338eSMichael LotzBMessage::operator new(size_t, void *pointer)
200338b8dc3SIngo Weinhold{
2017870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER2;
202da0f338eSMichael Lotz	return pointer;
203da0f338eSMichael Lotz}
204338b8dc3SIngo Weinhold
205338b8dc3SIngo Weinhold
206da0f338eSMichael Lotzvoid
207da0f338eSMichael LotzBMessage::operator delete(void *pointer, size_t size)
208da0f338eSMichael Lotz{
2097870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER2;
210da0f338eSMichael Lotz	sMsgCache->Save(pointer, size);
211da0f338eSMichael Lotz}
212338b8dc3SIngo Weinhold
213338b8dc3SIngo Weinhold
2147870a9ffSIngo Weinholdbool
2157870a9ffSIngo WeinholdBMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
2167870a9ffSIngo Weinhold	bool deep) const
2177870a9ffSIngo Weinhold{
2187870a9ffSIngo Weinhold	if (this == &other)
2197870a9ffSIngo Weinhold		return true;
2207870a9ffSIngo Weinhold
2217870a9ffSIngo Weinhold	if (fHeader->field_count != other.fHeader->field_count)
2227870a9ffSIngo Weinhold		return false;
2237870a9ffSIngo Weinhold
2247870a9ffSIngo Weinhold	for (uint32 i = 0; i < fHeader->field_count; i++) {
2257870a9ffSIngo Weinhold		field_header *field = &fFields[i];
2267870a9ffSIngo Weinhold		field_header *otherField = NULL;
2277870a9ffSIngo Weinhold
2287870a9ffSIngo Weinhold		const char *name = (const char *)fData + field->offset;
2297870a9ffSIngo Weinhold		if (ignoreFieldOrder) {
2307870a9ffSIngo Weinhold			if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
2317870a9ffSIngo Weinhold				return false;
2327870a9ffSIngo Weinhold		} else {
2337870a9ffSIngo Weinhold			otherField = &other.fFields[i];
2347870a9ffSIngo Weinhold			if (otherField->name_length != field->name_length)
2357870a9ffSIngo Weinhold				return false;
2367870a9ffSIngo Weinhold
2377870a9ffSIngo Weinhold			const char *otherName = (const char *)other.fData
2387870a9ffSIngo Weinhold				+ otherField->offset;
2397870a9ffSIngo Weinhold			if (strncmp(name, otherName, field->name_length) != 0)
2407870a9ffSIngo Weinhold				return false;
2417870a9ffSIngo Weinhold		}
2427870a9ffSIngo Weinhold
2437870a9ffSIngo Weinhold		if (otherField->type != field->type || otherField->count != field->count)
2447870a9ffSIngo Weinhold			return false;
2457870a9ffSIngo Weinhold
2467870a9ffSIngo Weinhold		uint8 *data = fData + field->offset + field->name_length;
2477870a9ffSIngo Weinhold		uint8 *otherData = other.fData + otherField->offset
2487870a9ffSIngo Weinhold			+ otherField->name_length;
2497870a9ffSIngo Weinhold
2507870a9ffSIngo Weinhold		bool needsMemCompare = true;
2517870a9ffSIngo Weinhold		if (deep && field->type == B_MESSAGE_TYPE) {
2527870a9ffSIngo Weinhold			BMessage message, otherMessage;
2537870a9ffSIngo Weinhold			if (message.Unflatten((const char *)data) == B_OK
2547870a9ffSIngo Weinhold				&& otherMessage.Unflatten((const char *)otherData) == B_OK) {
2557870a9ffSIngo Weinhold				if (!message.HasSameData(ignoreFieldOrder, deep))
2567870a9ffSIngo Weinhold					return false;
2577870a9ffSIngo Weinhold				needsMemCompare = false;
2587870a9ffSIngo Weinhold			}
2597870a9ffSIngo Weinhold		}
2607870a9ffSIngo Weinhold
2617870a9ffSIngo Weinhold		if (needsMemCompare) {
2627870a9ffSIngo Weinhold			if (otherField->data_size != field->data_size)
2637870a9ffSIngo Weinhold				return false;
2647870a9ffSIngo Weinhold			if (memcmp(data, otherData, field->data_size) != 0)
2657870a9ffSIngo Weinhold				return false;
2667870a9ffSIngo Weinhold		}
2677870a9ffSIngo Weinhold	}
2687870a9ffSIngo Weinhold
2697870a9ffSIngo Weinhold	return true;
2707870a9ffSIngo Weinhold}
2717870a9ffSIngo Weinhold
2727870a9ffSIngo Weinhold
273da0f338eSMichael Lotzstatus_t
2747870a9ffSIngo WeinholdBMessage::_InitCommon(bool initHeader)
275da0f338eSMichael Lotz{
2767870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
277da0f338eSMichael Lotz	what = 0;
278338b8dc3SIngo Weinhold
279da0f338eSMichael Lotz	fHeader = NULL;
280da0f338eSMichael Lotz	fFields = NULL;
281da0f338eSMichael Lotz	fData = NULL;
282338b8dc3SIngo Weinhold
2837870a9ffSIngo Weinhold	fFieldsAvailable = 0;
2847870a9ffSIngo Weinhold	fDataAvailable = 0;
2857870a9ffSIngo Weinhold
286da0f338eSMichael Lotz	fOriginal = NULL;
287da0f338eSMichael Lotz	fQueueLink = NULL;
288338b8dc3SIngo Weinhold
2897870a9ffSIngo Weinhold	if (initHeader)
2907870a9ffSIngo Weinhold		return _InitHeader();
2917870a9ffSIngo Weinhold
2927870a9ffSIngo Weinhold	fHeader = NULL;
2937870a9ffSIngo Weinhold	return B_OK;
294338b8dc3SIngo Weinhold}
295338b8dc3SIngo Weinhold
296338b8dc3SIngo Weinhold
297da0f338eSMichael Lotzstatus_t
298da0f338eSMichael LotzBMessage::_InitHeader()
299da0f338eSMichael Lotz{
3007870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
3017870a9ffSIngo Weinhold	if (fHeader == NULL) {
3027870a9ffSIngo Weinhold		fHeader = (message_header *)malloc(sizeof(message_header));
3037870a9ffSIngo Weinhold		if (fHeader == NULL)
3047870a9ffSIngo Weinhold			return B_NO_MEMORY;
3057870a9ffSIngo Weinhold	}
3067870a9ffSIngo Weinhold
307da0f338eSMichael Lotz	memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
308338b8dc3SIngo Weinhold
309da0f338eSMichael Lotz	fHeader->format = MESSAGE_FORMAT_HAIKU;
310da0f338eSMichael Lotz	fHeader->flags = MESSAGE_FLAG_VALID;
311da0f338eSMichael Lotz	fHeader->what = what;
312da0f338eSMichael Lotz	fHeader->current_specifier = -1;
3137870a9ffSIngo Weinhold	fHeader->message_area = -1;
314338b8dc3SIngo Weinhold
315da0f338eSMichael Lotz	fHeader->target = B_NULL_TOKEN;
316da0f338eSMichael Lotz	fHeader->reply_target = B_NULL_TOKEN;
317da0f338eSMichael Lotz	fHeader->reply_port = -1;
318da0f338eSMichael Lotz	fHeader->reply_team = -1;
319338b8dc3SIngo Weinhold
320da0f338eSMichael Lotz	// initializing the hash table to -1 because 0 is a valid index
321da0f338eSMichael Lotz	fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
322da0f338eSMichael Lotz	memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
323da0f338eSMichael Lotz	return B_OK;
324338b8dc3SIngo Weinhold}
325338b8dc3SIngo Weinhold
326da0f338eSMichael Lotz
327da0f338eSMichael Lotzstatus_t
328da0f338eSMichael LotzBMessage::_Clear()
329338b8dc3SIngo Weinhold{
3307870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
3317870a9ffSIngo Weinhold	if (fHeader != NULL) {
3327870a9ffSIngo Weinhold		free(fHeader);
3337870a9ffSIngo Weinhold		fHeader = NULL;
3347870a9ffSIngo Weinhold	}
3357870a9ffSIngo Weinhold
336da0f338eSMichael Lotz	free(fFields);
337da0f338eSMichael Lotz	fFields = NULL;
338da0f338eSMichael Lotz	free(fData);
339da0f338eSMichael Lotz	fData = NULL;
340338b8dc3SIngo Weinhold
3417870a9ffSIngo Weinhold	fFieldsAvailable = 0;
3427870a9ffSIngo Weinhold	fDataAvailable = 0;
3437870a9ffSIngo Weinhold
344da0f338eSMichael Lotz	delete fOriginal;
345da0f338eSMichael Lotz	fOriginal = NULL;
346da0f338eSMichael Lotz
347da0f338eSMichael Lotz	return B_OK;
348da0f338eSMichael Lotz}
349338b8dc3SIngo Weinhold
350338b8dc3SIngo Weinhold
351da0f338eSMichael Lotzstatus_t
352da0f338eSMichael LotzBMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound,
353da0f338eSMichael Lotz	type_code *typeFound, int32 *countFound) const
354da0f338eSMichael Lotz{
3557870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
3567870a9ffSIngo Weinhold	if (index < 0 || (uint32)index >= fHeader->field_count)
3577870a9ffSIngo Weinhold		return B_BAD_INDEX;
358da0f338eSMichael Lotz
3597870a9ffSIngo Weinhold	if (typeRequested == B_ANY_TYPE) {
360da0f338eSMichael Lotz		if (nameFound)
361da0f338eSMichael Lotz			*nameFound = (char *)fData + fFields[index].offset;
362da0f338eSMichael Lotz		if (typeFound)
363da0f338eSMichael Lotz			*typeFound = fFields[index].type;
364da0f338eSMichael Lotz		if (countFound)
365da0f338eSMichael Lotz			*countFound = fFields[index].count;
366da0f338eSMichael Lotz		return B_OK;
367338b8dc3SIngo Weinhold	}
368338b8dc3SIngo Weinhold
369da0f338eSMichael Lotz	int32 counter = -1;
370da0f338eSMichael Lotz	field_header *field = fFields;
3717870a9ffSIngo Weinhold	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
372da0f338eSMichael Lotz		if (field->type == typeRequested)
373da0f338eSMichael Lotz			counter++;
374da0f338eSMichael Lotz
375da0f338eSMichael Lotz		if (counter == index) {
376da0f338eSMichael Lotz			if (nameFound)
377da0f338eSMichael Lotz				*nameFound = (char *)fData + field->offset;
378da0f338eSMichael Lotz			if (typeFound)
379da0f338eSMichael Lotz				*typeFound = field->type;
380da0f338eSMichael Lotz			if (countFound)
381da0f338eSMichael Lotz				*countFound = field->count;
382da0f338eSMichael Lotz			return B_OK;
383da0f338eSMichael Lotz		}
384da0f338eSMichael Lotz	}
385338b8dc3SIngo Weinhold
386da0f338eSMichael Lotz	if (counter == -1)
387da0f338eSMichael Lotz		return B_BAD_TYPE;
388338b8dc3SIngo Weinhold
389da0f338eSMichael Lotz	return B_BAD_INDEX;
390338b8dc3SIngo Weinhold}
391338b8dc3SIngo Weinhold
392338b8dc3SIngo Weinhold
393da0f338eSMichael Lotzstatus_t
394da0f338eSMichael LotzBMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound)
395da0f338eSMichael Lotz	const
396338b8dc3SIngo Weinhold{
3977870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
398da0f338eSMichael Lotz	if (countFound)
399da0f338eSMichael Lotz		*countFound = 0;
400338b8dc3SIngo Weinhold
401da0f338eSMichael Lotz	field_header *field = NULL;
402da0f338eSMichael Lotz	status_t result = _FindField(name, B_ANY_TYPE, &field);
4037870a9ffSIngo Weinhold	if (result < B_OK || field == NULL)
404da0f338eSMichael Lotz		return result;
405338b8dc3SIngo Weinhold
406da0f338eSMichael Lotz	if (typeFound)
407da0f338eSMichael Lotz		*typeFound = field->type;
408da0f338eSMichael Lotz	if (countFound)
409da0f338eSMichael Lotz		*countFound = field->count;
410338b8dc3SIngo Weinhold
411da0f338eSMichael Lotz	return B_OK;
412338b8dc3SIngo Weinhold}
413338b8dc3SIngo Weinhold
414338b8dc3SIngo Weinhold
415da0f338eSMichael Lotzstatus_t
416da0f338eSMichael LotzBMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize)
417da0f338eSMichael Lotz	const
418338b8dc3SIngo Weinhold{
4197870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
420da0f338eSMichael Lotz	field_header *field = NULL;
421da0f338eSMichael Lotz	status_t result = _FindField(name, B_ANY_TYPE, &field);
4227870a9ffSIngo Weinhold	if (result < B_OK || field == NULL)
423da0f338eSMichael Lotz		return result;
424338b8dc3SIngo Weinhold
425da0f338eSMichael Lotz	if (typeFound)
426da0f338eSMichael Lotz		*typeFound = field->type;
427da0f338eSMichael Lotz	if (fixedSize)
4287870a9ffSIngo Weinhold		*fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;
429338b8dc3SIngo Weinhold
430da0f338eSMichael Lotz	return B_OK;
431da0f338eSMichael Lotz}
432338b8dc3SIngo Weinhold
433338b8dc3SIngo Weinhold
434da0f338eSMichael Lotzint32
435da0f338eSMichael LotzBMessage::CountNames(type_code type) const
436338b8dc3SIngo Weinhold{
4377870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
438da0f338eSMichael Lotz	if (type == B_ANY_TYPE)
439da0f338eSMichael Lotz		return fHeader->field_count;
440338b8dc3SIngo Weinhold
441da0f338eSMichael Lotz	int32 count = 0;
442da0f338eSMichael Lotz	field_header *field = fFields;
4437870a9ffSIngo Weinhold	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
444da0f338eSMichael Lotz		if (field->type == type)
445da0f338eSMichael Lotz			count++;
446338b8dc3SIngo Weinhold	}
447da0f338eSMichael Lotz
448da0f338eSMichael Lotz	return count;
449338b8dc3SIngo Weinhold}
450da0f338eSMichael Lotz
451da0f338eSMichael Lotz
452da0f338eSMichael Lotzbool
453da0f338eSMichael LotzBMessage::IsEmpty() const
454338b8dc3SIngo Weinhold{
4557870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
456da0f338eSMichael Lotz	return fHeader->field_count == 0;
457338b8dc3SIngo Weinhold}
458da0f338eSMichael Lotz
459da0f338eSMichael Lotz
460da0f338eSMichael Lotzbool
461da0f338eSMichael LotzBMessage::IsSystem() const
462338b8dc3SIngo Weinhold{
4637870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
464338b8dc3SIngo Weinhold	char a = char(what >> 24);
465338b8dc3SIngo Weinhold	char b = char(what >> 16);
466338b8dc3SIngo Weinhold	char c = char(what >> 8);
467338b8dc3SIngo Weinhold	char d = char(what);
468338b8dc3SIngo Weinhold
469338b8dc3SIngo Weinhold	// The BeBook says:
470338b8dc3SIngo Weinhold	//		... we've adopted a strict convention for assigning values to all
471338b8dc3SIngo Weinhold	//		Be-defined constants.  The value assigned will always be formed by
472338b8dc3SIngo Weinhold	//		combining four characters into a multicharacter constant, with the
473338b8dc3SIngo Weinhold	//		characters limited to uppercase letters and the underbar
474338b8dc3SIngo Weinhold	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
475338b8dc3SIngo Weinhold	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
476338b8dc3SIngo Weinhold		return true;
477338b8dc3SIngo Weinhold
478338b8dc3SIngo Weinhold	return false;
479338b8dc3SIngo Weinhold}
480da0f338eSMichael Lotz
481da0f338eSMichael Lotz
482da0f338eSMichael Lotzbool
483da0f338eSMichael LotzBMessage::IsReply() const
484338b8dc3SIngo Weinhold{
4857870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
4867870a9ffSIngo Weinhold	return (fHeader->flags & MESSAGE_FLAG_IS_REPLY) != 0;
487338b8dc3SIngo Weinhold}
488da0f338eSMichael Lotz
489da0f338eSMichael Lotz
490da0f338eSMichael Lotzvoid
491da0f338eSMichael LotzBMessage::PrintToStream() const
492338b8dc3SIngo Weinhold{
493da0f338eSMichael Lotz	_PrintToStream("");
494da0f338eSMichael Lotz	printf("}\n");
495338b8dc3SIngo Weinhold}
496da0f338eSMichael Lotz
497da0f338eSMichael Lotz
498da0f338eSMichael Lotzvoid
499da0f338eSMichael LotzBMessage::_PrintToStream(const char* indent) const
500338b8dc3SIngo Weinhold{
5017870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
5027870a9ffSIngo Weinhold
503da0f338eSMichael Lotz	int32 value = B_BENDIAN_TO_HOST_INT32(what);
504da0f338eSMichael Lotz	printf("BMessage(");
5057870a9ffSIngo Weinhold	if (isprint(*(char *)&value))
506da0f338eSMichael Lotz		printf("'%.4s'", (char *)&value);
5077870a9ffSIngo Weinhold	else
50841975f20SIngo Weinhold		printf("0x%" B_PRIx32, what);
509da0f338eSMichael Lotz	printf(") {\n");
510da0f338eSMichael Lotz
5117870a9ffSIngo Weinhold	if (fHeader == NULL || fFields == NULL || fData == NULL)
5127870a9ffSIngo Weinhold		return;
5137870a9ffSIngo Weinhold
514da0f338eSMichael Lotz	field_header *field = fFields;
5157870a9ffSIngo Weinhold	for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
516da0f338eSMichael Lotz		value = B_BENDIAN_TO_HOST_INT32(field->type);
517da0f338eSMichael Lotz		ssize_t size = 0;
5187870a9ffSIngo Weinhold		if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0 && field->count > 0)
519da0f338eSMichael Lotz			size = field->data_size / field->count;
520da0f338eSMichael Lotz
521da0f338eSMichael Lotz		uint8 *pointer = fData + field->offset + field->name_length;
5227870a9ffSIngo Weinhold		for (uint32 j = 0; j < field->count; j++) {
523da0f338eSMichael Lotz			if (field->count == 1) {
524da0f338eSMichael Lotz				printf("%s        %s = ", indent,
525da0f338eSMichael Lotz					(char *)(fData + field->offset));
526da0f338eSMichael Lotz			} else {
52741975f20SIngo Weinhold				printf("%s        %s[%" B_PRIu32 "] = ", indent,
528da0f338eSMichael Lotz					(char *)(fData + field->offset), j);
529da0f338eSMichael Lotz			}
530da0f338eSMichael Lotz
531da0f338eSMichael Lotz			switch (field->type) {
532da0f338eSMichael Lotz				case B_RECT_TYPE:
5337870a9ffSIngo Weinhold					print_to_stream_type<BRect>(pointer);
534da0f338eSMichael Lotz					break;
535da0f338eSMichael Lotz
536da0f338eSMichael Lotz				case B_POINT_TYPE:
5377870a9ffSIngo Weinhold					print_to_stream_type<BPoint>(pointer);
538da0f338eSMichael Lotz					break;
539da0f338eSMichael Lotz
5407870a9ffSIngo Weinhold				case B_STRING_TYPE:
5417870a9ffSIngo Weinhold				{
5427870a9ffSIngo Weinhold					size = *(uint32 *)pointer;
5437870a9ffSIngo Weinhold					pointer += sizeof(uint32);
544a3e1fc11SAxel Dörfler					printf("string(\"%s\", %ld bytes)\n", (char *)pointer,
54541975f20SIngo Weinhold						(long)size);
546da0f338eSMichael Lotz					break;
547da0f338eSMichael Lotz				}
548da0f338eSMichael Lotz
549da0f338eSMichael Lotz				case B_INT8_TYPE:
5507870a9ffSIngo Weinhold					print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
5517870a9ffSIngo Weinhold					break;
5527870a9ffSIngo Weinhold
5537870a9ffSIngo Weinhold				case B_UINT8_TYPE:
5547870a9ffSIngo Weinhold					print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n",
5557870a9ffSIngo Weinhold						pointer);
556da0f338eSMichael Lotz					break;
557da0f338eSMichael Lotz
558da0f338eSMichael Lotz				case B_INT16_TYPE:
5597870a9ffSIngo Weinhold					print_type<int16>("int16(0x%x or %d)\n", pointer);
5607870a9ffSIngo Weinhold					break;
5617870a9ffSIngo Weinhold
5627870a9ffSIngo Weinhold				case B_UINT16_TYPE:
5637870a9ffSIngo Weinhold					print_type<uint16>("uint16(0x%x or %u\n", pointer);
564da0f338eSMichael Lotz					break;
565da0f338eSMichael Lotz
566da0f338eSMichael Lotz				case B_INT32_TYPE:
5677870a9ffSIngo Weinhold					print_type<int32>("int32(0x%lx or %ld)\n", pointer);
5687870a9ffSIngo Weinhold					break;
5697870a9ffSIngo Weinhold
5707870a9ffSIngo Weinhold				case B_UINT32_TYPE:
5717870a9ffSIngo Weinhold					print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
572da0f338eSMichael Lotz					break;
573da0f338eSMichael Lotz
574da0f338eSMichael Lotz				case B_INT64_TYPE:
5757870a9ffSIngo Weinhold					print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
5767870a9ffSIngo Weinhold					break;
5777870a9ffSIngo Weinhold
5787870a9ffSIngo Weinhold				case B_UINT64_TYPE:
5797870a9ffSIngo Weinhold					print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
580da0f338eSMichael Lotz					break;
581da0f338eSMichael Lotz
582da0f338eSMichael Lotz				case B_BOOL_TYPE:
5837870a9ffSIngo Weinhold					printf("bool(%s)\n", *((bool *)pointer) != 0
5847870a9ffSIngo Weinhold						? "true" : "false");
585da0f338eSMichael Lotz					break;
586da0f338eSMichael Lotz
587da0f338eSMichael Lotz				case B_FLOAT_TYPE:
5887870a9ffSIngo Weinhold					print_type<float>("float(%.4f)\n", pointer);
589da0f338eSMichael Lotz					break;
590da0f338eSMichael Lotz
591da0f338eSMichael Lotz				case B_DOUBLE_TYPE:
5927870a9ffSIngo Weinhold					print_type<double>("double(%.8f)\n", pointer);
593da0f338eSMichael Lotz					break;
594da0f338eSMichael Lotz
5957870a9ffSIngo Weinhold				case B_REF_TYPE:
5967870a9ffSIngo Weinhold				{
5977870a9ffSIngo Weinhold					size = *(uint32 *)pointer;
5987870a9ffSIngo Weinhold					pointer += sizeof(uint32);
599da0f338eSMichael Lotz					entry_ref ref;
600da0f338eSMichael Lotz					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
601da0f338eSMichael Lotz
6024cc4f7bbSIngo Weinhold					printf("entry_ref(device=%d, directory=%lld"
6034cc4f7bbSIngo Weinhold						", name=\"%s\", ", (int)ref.device,
6044cc4f7bbSIngo Weinhold						(long long)ref.directory, ref.name);
605da0f338eSMichael Lotz
606da0f338eSMichael Lotz					BPath path(&ref);
607da0f338eSMichael Lotz					printf("path=\"%s\")\n", path.Path());
608da0f338eSMichael Lotz					break;
609da0f338eSMichael Lotz				}
610da0f338eSMichael Lotz
611da0f338eSMichael Lotz				case B_MESSAGE_TYPE:
612da0f338eSMichael Lotz				{
613da0f338eSMichael Lotz					char buffer[1024];
614da0f338eSMichael Lotz					sprintf(buffer, "%s        ", indent);
615da0f338eSMichael Lotz
616da0f338eSMichael Lotz					BMessage message;
6177870a9ffSIngo Weinhold					size = *(uint32 *)pointer;
6187870a9ffSIngo Weinhold					pointer += sizeof(uint32);
6197870a9ffSIngo Weinhold					status_t result = message.Unflatten((const char *)pointer);
6207870a9ffSIngo Weinhold					if (result != B_OK) {
6217870a9ffSIngo Weinhold						printf("failed unflatten: %s\n", strerror(result));
622da0f338eSMichael Lotz						break;
623da0f338eSMichael Lotz					}
6247870a9ffSIngo Weinhold
625da0f338eSMichael Lotz					message._PrintToStream(buffer);
626da0f338eSMichael Lotz					printf("%s        }\n", indent);
627da0f338eSMichael Lotz					break;
628da0f338eSMichael Lotz				}
629da0f338eSMichael Lotz
630a3e1fc11SAxel Dörfler				default:
6317870a9ffSIngo Weinhold				{
632a3e1fc11SAxel Dörfler					printf("(type = '%.4s')(size = %ld)\n", (char *)&value,
63341975f20SIngo Weinhold						(long)size);
634a3e1fc11SAxel Dörfler					break;
6357870a9ffSIngo Weinhold				}
636da0f338eSMichael Lotz			}
6377870a9ffSIngo Weinhold
6387870a9ffSIngo Weinhold			pointer += size;
639da0f338eSMichael Lotz		}
640da0f338eSMichael Lotz	}
641338b8dc3SIngo Weinhold}
642da0f338eSMichael Lotz
643da0f338eSMichael Lotz
644da0f338eSMichael Lotzstatus_t
645da0f338eSMichael LotzBMessage::Rename(const char *oldEntry, const char *newEntry)
646338b8dc3SIngo Weinhold{
6477870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
6487870a9ffSIngo Weinhold	if (oldEntry == NULL || newEntry == NULL)
649da0f338eSMichael Lotz		return B_BAD_VALUE;
650da0f338eSMichael Lotz
651da0f338eSMichael Lotz	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
652da0f338eSMichael Lotz	int32 *nextField = &fHeader->hash_table[hash];
653da0f338eSMichael Lotz
654da0f338eSMichael Lotz	while (*nextField >= 0) {
655da0f338eSMichael Lotz		field_header *field = &fFields[*nextField];
656da0f338eSMichael Lotz
657da0f338eSMichael Lotz		if (strncmp((const char *)(fData + field->offset), oldEntry,
658da0f338eSMichael Lotz			field->name_length) == 0) {
659da0f338eSMichael Lotz			// nextField points to the field for oldEntry, save it and unlink
660da0f338eSMichael Lotz			int32 index = *nextField;
661da0f338eSMichael Lotz			*nextField = field->next_field;
662da0f338eSMichael Lotz			field->next_field = -1;
663da0f338eSMichael Lotz
664da0f338eSMichael Lotz			hash = _HashName(newEntry) % fHeader->hash_table_size;
665da0f338eSMichael Lotz			nextField = &fHeader->hash_table[hash];
666da0f338eSMichael Lotz			while (*nextField >= 0)
667da0f338eSMichael Lotz				nextField = &fFields[*nextField].next_field;
668da0f338eSMichael Lotz			*nextField = index;
669da0f338eSMichael Lotz
670b7a5b10aSMichael Lotz			int32 newLength = strlen(newEntry) + 1;
671b7a5b10aSMichael Lotz			status_t result = _ResizeData(field->offset + 1,
672b7a5b10aSMichael Lotz				newLength - field->name_length);
673b7a5b10aSMichael Lotz			if (result < B_OK)
674b7a5b10aSMichael Lotz				return result;
675b7a5b10aSMichael Lotz
676b7a5b10aSMichael Lotz			memcpy(fData + field->offset, newEntry, newLength);
677b7a5b10aSMichael Lotz			field->name_length = newLength;
678da0f338eSMichael Lotz			return B_OK;
679da0f338eSMichael Lotz		}
680da0f338eSMichael Lotz
681da0f338eSMichael Lotz		nextField = &field->next_field;
682338b8dc3SIngo Weinhold	}
683338b8dc3SIngo Weinhold
684da0f338eSMichael Lotz	return B_NAME_NOT_FOUND;
685da0f338eSMichael Lotz}
686da0f338eSMichael Lotz
687da0f338eSMichael Lotz
688da0f338eSMichael Lotzbool
689da0f338eSMichael LotzBMessage::WasDelivered() const
690da0f338eSMichael Lotz{
6917870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
6927870a9ffSIngo Weinhold	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
693da0f338eSMichael Lotz}
694da0f338eSMichael Lotz
695da0f338eSMichael Lotz
696da0f338eSMichael Lotzbool
697da0f338eSMichael LotzBMessage::IsSourceWaiting() const
698da0f338eSMichael Lotz{
6997870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
7007870a9ffSIngo Weinhold	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
7017870a9ffSIngo Weinhold		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
702da0f338eSMichael Lotz}
703da0f338eSMichael Lotz
704da0f338eSMichael Lotz
705da0f338eSMichael LotzBMessenger
706da0f338eSMichael LotzBMessage::ReturnAddress() const
707da0f338eSMichael Lotz{
7087870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
7097870a9ffSIngo Weinhold	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
7107870a9ffSIngo Weinhold		BMessenger messenger;
7117870a9ffSIngo Weinhold		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
7127870a9ffSIngo Weinhold			fHeader->reply_port, fHeader->reply_target);
7137870a9ffSIngo Weinhold		return messenger;
7147870a9ffSIngo Weinhold	}
7157870a9ffSIngo Weinhold
716338b8dc3SIngo Weinhold	return BMessenger();
717338b8dc3SIngo Weinhold}
718da0f338eSMichael Lotz
719da0f338eSMichael Lotz
720da0f338eSMichael Lotzconst BMessage *
721da0f338eSMichael LotzBMessage::Previous() const
722338b8dc3SIngo Weinhold{
7237870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
724da0f338eSMichael Lotz	/* ToDo: test if the "_previous_" field is used in R5 */
7257870a9ffSIngo Weinhold	if (fOriginal == NULL) {
726da0f338eSMichael Lotz		fOriginal = new BMessage();
727da0f338eSMichael Lotz
728da0f338eSMichael Lotz		if (FindMessage("_previous_", fOriginal) != B_OK) {
729338b8dc3SIngo Weinhold			delete fOriginal;
730338b8dc3SIngo Weinhold			fOriginal = NULL;
731338b8dc3SIngo Weinhold		}
732338b8dc3SIngo Weinhold	}
733338b8dc3SIngo Weinhold
734338b8dc3SIngo Weinhold	return fOriginal;
735338b8dc3SIngo Weinhold}
736da0f338eSMichael Lotz
737da0f338eSMichael Lotz
738da0f338eSMichael Lotzbool
739da0f338eSMichael LotzBMessage::WasDropped() const
740338b8dc3SIngo Weinhold{
7417870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
7427870a9ffSIngo Weinhold	return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
743338b8dc3SIngo Weinhold}
744da0f338eSMichael Lotz
745da0f338eSMichael Lotz
746da0f338eSMichael LotzBPoint
747da0f338eSMichael LotzBMessage::DropPoint(BPoint *offset) const
748338b8dc3SIngo Weinhold{
7497870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
750338b8dc3SIngo Weinhold	if (offset)
751338b8dc3SIngo Weinhold		*offset = FindPoint("_drop_offset_");
752da0f338eSMichael Lotz
753338b8dc3SIngo Weinhold	return FindPoint("_drop_point_");
754338b8dc3SIngo Weinhold}
755338b8dc3SIngo Weinhold
756da0f338eSMichael Lotz
757da0f338eSMichael Lotzssize_t
758da0f338eSMichael LotzBMessage::FlattenedSize() const
759338b8dc3SIngo Weinhold{
7607870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
7617870a9ffSIngo Weinhold	return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
7627870a9ffSIngo Weinhold		+ fHeader->data_size;
763338b8dc3SIngo Weinhold}
764338b8dc3SIngo Weinhold
765da0f338eSMichael Lotz
766da0f338eSMichael Lotzstatus_t
767da0f338eSMichael LotzBMessage::Flatten(char *buffer, ssize_t size) const
768338b8dc3SIngo Weinhold{
7697870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
7707870a9ffSIngo Weinhold	if (buffer == NULL || size < 0)
771da0f338eSMichael Lotz		return B_BAD_VALUE;
772da0f338eSMichael Lotz
7737870a9ffSIngo Weinhold	if (fHeader == NULL)
774da0f338eSMichael Lotz		return B_NO_INIT;
775da0f338eSMichael Lotz
776da0f338eSMichael Lotz	/* we have to sync the what code as it is a public member */
777da0f338eSMichael Lotz	fHeader->what = what;
778da0f338eSMichael Lotz
779da0f338eSMichael Lotz	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
780da0f338eSMichael Lotz	buffer += sizeof(message_header);
781da0f338eSMichael Lotz	size -= sizeof(message_header);
782da0f338eSMichael Lotz
7837870a9ffSIngo Weinhold	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
7847870a9ffSIngo Weinhold	memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
7857870a9ffSIngo Weinhold	buffer += fieldsSize;
7867870a9ffSIngo Weinhold	size -= fieldsSize;
787da0f338eSMichael Lotz
7887870a9ffSIngo Weinhold	memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
7897870a9ffSIngo Weinhold	if ((size_t)size < fHeader->data_size)
7907870a9ffSIngo Weinhold		return B_BUFFER_OVERFLOW;
791da0f338eSMichael Lotz
7927870a9ffSIngo Weinhold	return B_OK;
793338b8dc3SIngo Weinhold}
794da0f338eSMichael Lotz
795da0f338eSMichael Lotz
796da0f338eSMichael Lotzstatus_t
7977870a9ffSIngo WeinholdBMessage::Flatten(BDataIO *stream, ssize_t *size) const
798338b8dc3SIngo Weinhold{
7997870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
8007870a9ffSIngo Weinhold	if (stream == NULL)
801da0f338eSMichael Lotz		return B_BAD_VALUE;
802338b8dc3SIngo Weinhold
8037870a9ffSIngo Weinhold	if (fHeader == NULL)
804da0f338eSMichael Lotz		return B_NO_INIT;
805da0f338eSMichael Lotz
806da0f338eSMichael Lotz	/* we have to sync the what code as it is a public member */
807da0f338eSMichael Lotz	fHeader->what = what;
808da0f338eSMichael Lotz
809da0f338eSMichael Lotz	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
810da0f338eSMichael Lotz	if (result1 != sizeof(message_header))
8117870a9ffSIngo Weinhold		return result1 < 0 ? result1 : B_ERROR;
812da0f338eSMichael Lotz
813da0f338eSMichael Lotz	ssize_t result2 = 0;
8147870a9ffSIngo Weinhold	if (fHeader->field_count > 0) {
8157870a9ffSIngo Weinhold		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
8167870a9ffSIngo Weinhold		result2 = stream->Write(fFields, fieldsSize);
8177870a9ffSIngo Weinhold		if (result2 != fieldsSize)
8187870a9ffSIngo Weinhold			return result2 < 0 ? result2 : B_ERROR;
819338b8dc3SIngo Weinhold	}
820da0f338eSMichael Lotz
821da0f338eSMichael Lotz	ssize_t result3 = 0;
822da0f338eSMichael Lotz	if (fHeader->data_size > 0) {
823da0f338eSMichael Lotz		result3 = stream->Write(fData, fHeader->data_size);
8247870a9ffSIngo Weinhold		if (result3 != (ssize_t)fHeader->data_size)
8257870a9ffSIngo Weinhold			return result3 < 0 ? result3 : B_ERROR;
826338b8dc3SIngo Weinhold	}
827338b8dc3SIngo Weinhold
828da0f338eSMichael Lotz	if (size)
829da0f338eSMichael Lotz		*size = result1 + result2 + result3;
830da0f338eSMichael Lotz
831da0f338eSMichael Lotz	return B_OK;
832338b8dc3SIngo Weinhold}
833338b8dc3SIngo Weinhold
834338b8dc3SIngo Weinhold
8357870a9ffSIngo Weinholdstatus_t
8367870a9ffSIngo WeinholdBMessage::_ValidateMessage()
8377870a9ffSIngo Weinhold{
8387870a9ffSIngo Weinhold	if (fHeader->field_count == 0)
8397870a9ffSIngo Weinhold		return B_OK;
8407870a9ffSIngo Weinhold
8417870a9ffSIngo Weinhold	if (fFields == NULL)
8427870a9ffSIngo Weinhold		return B_NO_INIT;
8437870a9ffSIngo Weinhold
8447870a9ffSIngo Weinhold	for (uint32 i = 0; i < fHeader->field_count; i++) {
8457870a9ffSIngo Weinhold		field_header *field = &fFields[i];
8467870a9ffSIngo Weinhold		if ((field->next_field >= 0
8477870a9ffSIngo Weinhold				&& (uint32)field->next_field > fHeader->field_count)
8487870a9ffSIngo Weinhold			|| (field->offset + field->name_length + field->data_size
8497870a9ffSIngo Weinhold				> fHeader->data_size)) {
8507870a9ffSIngo Weinhold			// the message is corrupt
8517870a9ffSIngo Weinhold			MakeEmpty();
8527870a9ffSIngo Weinhold			return B_BAD_VALUE;
8537870a9ffSIngo Weinhold		}
8547870a9ffSIngo Weinhold	}
8557870a9ffSIngo Weinhold
8567870a9ffSIngo Weinhold	return B_OK;
8577870a9ffSIngo Weinhold}
8587870a9ffSIngo Weinhold
8597870a9ffSIngo Weinhold
860338b8dc3SIngo Weinholdstatus_t
861da0f338eSMichael LotzBMessage::Unflatten(const char *flatBuffer)
862338b8dc3SIngo Weinhold{
8637870a9ffSIngo Weinhold	DEBUG_FUNCTION_ENTER;
8647870a9ffSIngo Weinhold	if (flatBuffer == NULL)
865338b8dc3SIngo Weinhold		return B_BAD_VALUE;
866338b8dc3SIngo Weinhold
867da0f338eSMichael Lotz	uint32 format = *(uint32 *)flatBuffer;
868da0f338eSMichael Lotz	if (format != MESSAGE_FORMAT_HAIKU)
869da0f338eSMichael Lotz		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
870da0f338eSMichael Lotz
871da0f338eSMichael Lotz	// native message unflattening
872da0f338eSMichael Lotz
873da0f338eSMichael Lotz	_Clear();
874da0f338eSMichael Lotz
875da0f338eSMichael Lotz	fHeader = (message_header *)malloc(sizeof(message_header));
8767870a9ffSIngo Weinhold	if (fHeader == NULL)
877da0f338eSMichael Lotz		return B_NO_MEMORY;
878338b8dc3SIngo Weinhold
879da0f338eSMichael Lotz	memcpy(fHeader, flatBuffer, sizeof(message_header));
880da0f338eSMichael Lotz	flatBuffer += sizeof(message_header);
881338b8dc3SIngo Weinhold
882da0f338eSMichael Lotz	if (fHeader->format != MESSAGE_FORMAT_HAIKU
8837870a9ffSIngo Weinhold		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
884da0f338eSMichael Lotz		_InitHeader();
885da0f338eSMichael Lotz		return B_BAD_VALUE;
886338b8dc3S