KMessage.cpp revision 5839058a
1c3a3ddf2SIngo Weinhold/*
2dad63129SIngo Weinhold * Copyright 2005-2007, Ingo Weinhold,
3dad63129SIngo Weinhold * All rights reserved. Distributed under the terms of the MIT License.
4c3a3ddf2SIngo Weinhold */
5c3a3ddf2SIngo Weinhold
674c0424aSAxel Dörfler#include <util/KMessage.h>
7dad63129SIngo Weinhold
8c3a3ddf2SIngo Weinhold#include <stdlib.h>
9c3a3ddf2SIngo Weinhold#include <string.h>
10c3a3ddf2SIngo Weinhold
11c3a3ddf2SIngo Weinhold#include <Debug.h>
12c3a3ddf2SIngo Weinhold#include <KernelExport.h>
13c3a3ddf2SIngo Weinhold#include <TypeConstants.h>
14c3a3ddf2SIngo Weinhold
1574c0424aSAxel Dörfler#if defined(_BOOT_MODE) || defined(_LOADER_MODE)
16dad63129SIngo Weinhold#	include <util/kernel_cpp.h>
17dad63129SIngo Weinhold#else
18dad63129SIngo Weinhold#	include <new>
19dad63129SIngo Weinhold#endif
20dad63129SIngo Weinhold
21dad63129SIngo Weinholdusing std::nothrow;
22c3a3ddf2SIngo Weinhold
23c3a3ddf2SIngo Weinhold// TODO: Add a field index using a hash map, so that lookup improves to O(1)
24c3a3ddf2SIngo Weinhold// (is now O(n)).
25c3a3ddf2SIngo Weinhold
26c3a3ddf2SIngo Weinhold// define the PANIC macro
27c3a3ddf2SIngo Weinhold#ifndef PANIC
28d35f0da7SIngo Weinhold#	ifdef _KERNEL_MODE
29c3a3ddf2SIngo Weinhold#		define PANIC(str)	panic(str)
30d35f0da7SIngo Weinhold#	else
31d35f0da7SIngo Weinhold#		define PANIC(str)	debugger(str)
32c3a3ddf2SIngo Weinhold#	endif
33c3a3ddf2SIngo Weinhold#endif
34c3a3ddf2SIngo Weinhold
35c3a3ddf2SIngo Weinholdstatic const int32 kMessageReallocChunkSize = 64;
36c3a3ddf2SIngo Weinhold
37ea69d9d3SIngo Weinhold// kMessageHeaderMagic
38ea69d9d3SIngo Weinholdconst uint32 KMessage::kMessageHeaderMagic = 'kMsG';
39ea69d9d3SIngo Weinhold
40c3a3ddf2SIngo Weinhold// _Align
41c3a3ddf2SIngo Weinholdstatic inline
42c3a3ddf2SIngo Weinholdint32
43c3a3ddf2SIngo Weinhold_Align(int32 offset)
44c3a3ddf2SIngo Weinhold{
45c3a3ddf2SIngo Weinhold	return (offset + 3) & ~0x3;
46c3a3ddf2SIngo Weinhold}
47c3a3ddf2SIngo Weinhold
48c3a3ddf2SIngo Weinhold// _Align
49c3a3ddf2SIngo Weinholdstatic inline
50c3a3ddf2SIngo Weinholdvoid*
51c3a3ddf2SIngo Weinhold_Align(void *address, int32 offset = 0)
52c3a3ddf2SIngo Weinhold{
53c3a3ddf2SIngo Weinhold	return (void*)(((uint32)address + offset + 3) & ~0x3);
54c3a3ddf2SIngo Weinhold}
55c3a3ddf2SIngo Weinhold
56c3a3ddf2SIngo Weinhold// FieldValueHeader
57c3a3ddf2SIngo Weinholdstruct KMessage::FieldValueHeader {
58c3a3ddf2SIngo Weinhold	int32		size;
59c3a3ddf2SIngo Weinhold
60c3a3ddf2SIngo Weinhold	void *Data()
61c3a3ddf2SIngo Weinhold	{
62c3a3ddf2SIngo Weinhold		return _Align(this, sizeof(FieldValueHeader));
63c3a3ddf2SIngo Weinhold	}
64c3a3ddf2SIngo Weinhold
65c3a3ddf2SIngo Weinhold	FieldValueHeader *NextFieldValueHeader()
66c3a3ddf2SIngo Weinhold	{
67c3a3ddf2SIngo Weinhold		return (FieldValueHeader*)_Align(Data(), size);
68c3a3ddf2SIngo Weinhold	}
69c3a3ddf2SIngo Weinhold};
70c3a3ddf2SIngo Weinhold
71c3a3ddf2SIngo Weinhold// FieldHeader
72c3a3ddf2SIngo Weinholdstruct KMessage::FieldHeader {
73c3a3ddf2SIngo Weinhold	type_code	type;
74c3a3ddf2SIngo Weinhold	int32		elementSize;	// if < 0: non-fixed size
75c3a3ddf2SIngo Weinhold	int32		elementCount;
76c3a3ddf2SIngo Weinhold	int32		fieldSize;
77c3a3ddf2SIngo Weinhold	int16		headerSize;
78c3a3ddf2SIngo Weinhold	char		name[1];
79c3a3ddf2SIngo Weinhold
80c3a3ddf2SIngo Weinhold	void *Data()
81c3a3ddf2SIngo Weinhold	{
82c3a3ddf2SIngo Weinhold		return (uint8*)this + headerSize;
83c3a3ddf2SIngo Weinhold	}
84c3a3ddf2SIngo Weinhold
85c3a3ddf2SIngo Weinhold	bool HasFixedElementSize() { return (elementSize >= 0); }
86c3a3ddf2SIngo Weinhold
87c3a3ddf2SIngo Weinhold	void *ElementAt(int32 index, int32 *size)
88c3a3ddf2SIngo Weinhold	{
89c3a3ddf2SIngo Weinhold		if (index < 0 || index >= elementCount)
90c3a3ddf2SIngo Weinhold			return NULL;
91c3a3ddf2SIngo Weinhold		uint8 *data = (uint8*)this + headerSize;
92c3a3ddf2SIngo Weinhold		if (HasFixedElementSize()) {
93c3a3ddf2SIngo Weinhold			*size = elementSize;
94c3a3ddf2SIngo Weinhold			return data + elementSize * index;
95c3a3ddf2SIngo Weinhold		}
96c3a3ddf2SIngo Weinhold		// non-fixed element size: we need to iterate
97c3a3ddf2SIngo Weinhold		FieldValueHeader *valueHeader = (FieldValueHeader *)data;
98c3a3ddf2SIngo Weinhold		for (int i = 0; i < index; i++)
99c3a3ddf2SIngo Weinhold			valueHeader = valueHeader->NextFieldValueHeader();
100c3a3ddf2SIngo Weinhold		*size = valueHeader->size;
101c3a3ddf2SIngo Weinhold		return valueHeader->Data();
102c3a3ddf2SIngo Weinhold	}
103c3a3ddf2SIngo Weinhold
104c3a3ddf2SIngo Weinhold	FieldHeader *NextFieldHeader()
105c3a3ddf2SIngo Weinhold	{
106c3a3ddf2SIngo Weinhold		return (FieldHeader*)_Align(this, fieldSize);
107c3a3ddf2SIngo Weinhold	}
108c3a3ddf2SIngo Weinhold};
109c3a3ddf2SIngo Weinhold
110c3a3ddf2SIngo Weinhold// constructor
111c3a3ddf2SIngo WeinholdKMessage::KMessage()
112c3a3ddf2SIngo Weinhold	: fBuffer(NULL),
113c3a3ddf2SIngo Weinhold	  fBufferCapacity(0),
114c3a3ddf2SIngo Weinhold	  fFlags(0),
115c3a3ddf2SIngo Weinhold	  fLastFieldOffset(0)
116c3a3ddf2SIngo Weinhold{
117c3a3ddf2SIngo Weinhold	Unset();
118c3a3ddf2SIngo Weinhold}
119c3a3ddf2SIngo Weinhold
120c3a3ddf2SIngo Weinhold// constructor
121c3a3ddf2SIngo WeinholdKMessage::KMessage(uint32 what)
122c3a3ddf2SIngo Weinhold	: fBuffer(NULL),
123c3a3ddf2SIngo Weinhold	  fBufferCapacity(0),
124c3a3ddf2SIngo Weinhold	  fFlags(0),
125c3a3ddf2SIngo Weinhold	  fLastFieldOffset(0)
126c3a3ddf2SIngo Weinhold{
127c3a3ddf2SIngo Weinhold	Unset();
128c3a3ddf2SIngo Weinhold	SetWhat(what);
129c3a3ddf2SIngo Weinhold}
130c3a3ddf2SIngo Weinhold
131c3a3ddf2SIngo Weinhold// destructor
132c3a3ddf2SIngo WeinholdKMessage::~KMessage()
133c3a3ddf2SIngo Weinhold{
134c3a3ddf2SIngo Weinhold	Unset();
135c3a3ddf2SIngo Weinhold}
136c3a3ddf2SIngo Weinhold
137c3a3ddf2SIngo Weinhold// SetTo
138c3a3ddf2SIngo Weinholdstatus_t
139c3a3ddf2SIngo WeinholdKMessage::SetTo(uint32 what, uint32 flags)
140c3a3ddf2SIngo Weinhold{
141c3a3ddf2SIngo Weinhold	// There are no flags interesting in this case at the moment.
142c3a3ddf2SIngo Weinhold	Unset();
143c3a3ddf2SIngo Weinhold	SetWhat(what);
144c3a3ddf2SIngo Weinhold	return B_OK;
145c3a3ddf2SIngo Weinhold}
146c3a3ddf2SIngo Weinhold
147c3a3ddf2SIngo Weinhold// SetTo
148c3a3ddf2SIngo Weinholdstatus_t
149c3a3ddf2SIngo WeinholdKMessage::SetTo(void *buffer, int32 bufferSize, uint32 what, uint32 flags)
150c3a3ddf2SIngo Weinhold{
151c3a3ddf2SIngo Weinhold	Unset();
152dad63129SIngo Weinhold
153dad63129SIngo Weinhold	if (!buffer)
154c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
155dad63129SIngo Weinhold
156dad63129SIngo Weinhold	if (bufferSize < 0) {
157dad63129SIngo Weinhold		if (!(flags & KMESSAGE_INIT_FROM_BUFFER))
158dad63129SIngo Weinhold			return B_BAD_VALUE;
159dad63129SIngo Weinhold	} else if (bufferSize < (int)sizeof(Header))
160dad63129SIngo Weinhold		return B_BAD_VALUE;
161dad63129SIngo Weinhold
162c3a3ddf2SIngo Weinhold	// if read-only, we need to init from the buffer, too
163c3a3ddf2SIngo Weinhold	if (flags & KMESSAGE_READ_ONLY && !(flags & KMESSAGE_INIT_FROM_BUFFER))
164c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
165dad63129SIngo Weinhold
166c3a3ddf2SIngo Weinhold	fBuffer = buffer;
167c3a3ddf2SIngo Weinhold	fBufferCapacity = bufferSize;
168c3a3ddf2SIngo Weinhold	fFlags = flags;
169dad63129SIngo Weinhold
170c3a3ddf2SIngo Weinhold	status_t error = B_OK;
171c3a3ddf2SIngo Weinhold	if (flags & KMESSAGE_INIT_FROM_BUFFER)
172dad63129SIngo Weinhold		error = _InitFromBuffer(bufferSize < 0);
173c3a3ddf2SIngo Weinhold	else
174c3a3ddf2SIngo Weinhold		_InitBuffer(what);
175dad63129SIngo Weinhold
176c3a3ddf2SIngo Weinhold	if (error != B_OK)
177c3a3ddf2SIngo Weinhold		Unset();
178dad63129SIngo Weinhold
179c3a3ddf2SIngo Weinhold	return error;
180c3a3ddf2SIngo Weinhold}
181c3a3ddf2SIngo Weinhold
182c3a3ddf2SIngo Weinhold// SetTo
183c3a3ddf2SIngo Weinholdstatus_t
184c3a3ddf2SIngo WeinholdKMessage::SetTo(const void *buffer, int32 bufferSize)
185c3a3ddf2SIngo Weinhold{
186c3a3ddf2SIngo Weinhold	return SetTo(const_cast<void*>(buffer), bufferSize, 0,
188c3a3ddf2SIngo Weinhold}
189c3a3ddf2SIngo Weinhold
190c3a3ddf2SIngo Weinhold// Unset
191c3a3ddf2SIngo Weinholdvoid
192c3a3ddf2SIngo WeinholdKMessage::Unset()
193c3a3ddf2SIngo Weinhold{
194c3a3ddf2SIngo Weinhold	// free buffer
195c3a3ddf2SIngo Weinhold	if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER))
196c3a3ddf2SIngo Weinhold		free(fBuffer);
197c3a3ddf2SIngo Weinhold	fBuffer = &fHeader;
198c3a3ddf2SIngo Weinhold	fBufferCapacity = sizeof(Header);
199c3a3ddf2SIngo Weinhold	_InitBuffer(0);
200c3a3ddf2SIngo Weinhold}
201c3a3ddf2SIngo Weinhold
202c3a3ddf2SIngo Weinhold// SetWhat
203c3a3ddf2SIngo Weinholdvoid
204c3a3ddf2SIngo WeinholdKMessage::SetWhat(uint32 what)
205c3a3ddf2SIngo Weinhold{
206c3a3ddf2SIngo Weinhold	_Header()->what = what;
207c3a3ddf2SIngo Weinhold}
208c3a3ddf2SIngo Weinhold
209c3a3ddf2SIngo Weinhold// What
210c3a3ddf2SIngo Weinholduint32
211c3a3ddf2SIngo WeinholdKMessage::What() const
212c3a3ddf2SIngo Weinhold{
213c3a3ddf2SIngo Weinhold	return _Header()->what;
214c3a3ddf2SIngo Weinhold}
215c3a3ddf2SIngo Weinhold
216c3a3ddf2SIngo Weinhold// Buffer
217c3a3ddf2SIngo Weinholdconst void *
218c3a3ddf2SIngo WeinholdKMessage::Buffer() const
219c3a3ddf2SIngo Weinhold{
220c3a3ddf2SIngo Weinhold	return fBuffer;
221c3a3ddf2SIngo Weinhold}
222c3a3ddf2SIngo Weinhold
223c3a3ddf2SIngo Weinhold// BufferCapacity
224c3a3ddf2SIngo Weinholdint32
225c3a3ddf2SIngo WeinholdKMessage::BufferCapacity() const
226c3a3ddf2SIngo Weinhold{
227c3a3ddf2SIngo Weinhold	return fBufferCapacity;
228c3a3ddf2SIngo Weinhold}
229c3a3ddf2SIngo Weinhold
230c3a3ddf2SIngo Weinhold// ContentSize
231c3a3ddf2SIngo Weinholdint32
232c3a3ddf2SIngo WeinholdKMessage::ContentSize() const
233c3a3ddf2SIngo Weinhold{
234c3a3ddf2SIngo Weinhold	return _Header()->size;
235c3a3ddf2SIngo Weinhold}
236c3a3ddf2SIngo Weinhold
237c3a3ddf2SIngo Weinhold// AddField
238c3a3ddf2SIngo Weinholdstatus_t
239c3a3ddf2SIngo WeinholdKMessage::AddField(const char *name, type_code type, int32 elementSize,
240c3a3ddf2SIngo Weinhold	KMessageField* field)
241c3a3ddf2SIngo Weinhold{
242c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE)
243c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
244c3a3ddf2SIngo Weinhold	KMessageField existingField;
245c3a3ddf2SIngo Weinhold	if (FindField(name, &existingField) == B_OK)
246c3a3ddf2SIngo Weinhold		return B_NAME_IN_USE;
247c3a3ddf2SIngo Weinhold	return _AddField(name, type, elementSize, field);
248c3a3ddf2SIngo Weinhold}
249c3a3ddf2SIngo Weinhold
250c3a3ddf2SIngo Weinhold// FindField
251c3a3ddf2SIngo Weinholdstatus_t
252c3a3ddf2SIngo WeinholdKMessage::FindField(const char *name, KMessageField *field) const
253c3a3ddf2SIngo Weinhold{
254c3a3ddf2SIngo Weinhold	return FindField(name, B_ANY_TYPE, field);
255c3a3ddf2SIngo Weinhold}
256c3a3ddf2SIngo Weinhold
257c3a3ddf2SIngo Weinhold// FindField
258c3a3ddf2SIngo Weinholdstatus_t
259c3a3ddf2SIngo WeinholdKMessage::FindField(const char *name, type_code type,
260c3a3ddf2SIngo Weinhold	KMessageField *field) const
261c3a3ddf2SIngo Weinhold{
262c3a3ddf2SIngo Weinhold	if (!name)
263c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
264c3a3ddf2SIngo Weinhold	KMessageField stackField;
265c3a3ddf2SIngo Weinhold	if (field)
266c3a3ddf2SIngo Weinhold		field->Unset();
267c3a3ddf2SIngo Weinhold	else
268c3a3ddf2SIngo Weinhold		field = &stackField;
269c3a3ddf2SIngo Weinhold	while (GetNextField(field) == B_OK) {
270c3a3ddf2SIngo Weinhold		if ((type == B_ANY_TYPE || field->TypeCode() == type)
271c3a3ddf2SIngo Weinhold			&& strcmp(name, field->Name()) == 0) {
272c3a3ddf2SIngo Weinhold			return B_OK;
273c3a3ddf2SIngo Weinhold		}
274c3a3ddf2SIngo Weinhold	}
275c3a3ddf2SIngo Weinhold	return B_NAME_NOT_FOUND;
276c3a3ddf2SIngo Weinhold}
277c3a3ddf2SIngo Weinhold
278c3a3ddf2SIngo Weinhold// GetNextField
279c3a3ddf2SIngo Weinholdstatus_t
280c3a3ddf2SIngo WeinholdKMessage::GetNextField(KMessageField *field) const
281c3a3ddf2SIngo Weinhold{
282c3a3ddf2SIngo Weinhold	if (!field || (field->Message() != NULL && field->Message() != this))
283c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
284c3a3ddf2SIngo Weinhold	FieldHeader *fieldHeader = field->_Header();
285c3a3ddf2SIngo Weinhold	FieldHeader* lastField = _LastFieldHeader();
286c3a3ddf2SIngo Weinhold	if (!lastField)
287c3a3ddf2SIngo Weinhold		return B_NAME_NOT_FOUND;
288c3a3ddf2SIngo Weinhold	if (fieldHeader == NULL) {
289c3a3ddf2SIngo Weinhold		fieldHeader = _FirstFieldHeader();
290c3a3ddf2SIngo Weinhold	} else {
291c3a3ddf2SIngo Weinhold		if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader()
292c3a3ddf2SIngo Weinhold			|| (uint8*)fieldHeader > (uint8*)lastField) {
293c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
294c3a3ddf2SIngo Weinhold		}
295c3a3ddf2SIngo Weinhold		if (fieldHeader == lastField)
296c3a3ddf2SIngo Weinhold			return B_NAME_NOT_FOUND;
297c3a3ddf2SIngo Weinhold		fieldHeader = fieldHeader->NextFieldHeader();
298c3a3ddf2SIngo Weinhold	}
299c3a3ddf2SIngo Weinhold	field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader));
300c3a3ddf2SIngo Weinhold	return B_OK;
301c3a3ddf2SIngo Weinhold}
302c3a3ddf2SIngo Weinhold
303c3a3ddf2SIngo Weinhold// AddData
304c3a3ddf2SIngo Weinholdstatus_t
305c3a3ddf2SIngo WeinholdKMessage::AddData(const char *name, type_code type, const void *data,
306c3a3ddf2SIngo Weinhold	int32 numBytes, bool isFixedSize)
307c3a3ddf2SIngo Weinhold{
308c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE || !data || numBytes < 0)
309c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
310c3a3ddf2SIngo Weinhold	KMessageField field;
311c3a3ddf2SIngo Weinhold	if (FindField(name, &field) == B_OK) {
312c3a3ddf2SIngo Weinhold		// field with that name already exists: check its type
313c3a3ddf2SIngo Weinhold		if (field.TypeCode() != type)
314c3a3ddf2SIngo Weinhold			return B_BAD_TYPE;
315c3a3ddf2SIngo Weinhold	} else {
316c3a3ddf2SIngo Weinhold		// no such field yet: add it
317c3a3ddf2SIngo Weinhold		status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1),
318c3a3ddf2SIngo Weinhold			&field);
319c3a3ddf2SIngo Weinhold		if (error != B_OK)
320c3a3ddf2SIngo Weinhold			return error;
321c3a3ddf2SIngo Weinhold	}
322c3a3ddf2SIngo Weinhold	return _AddFieldData(&field, data, numBytes, 1);
323c3a3ddf2SIngo Weinhold}
324c3a3ddf2SIngo Weinhold
325c3a3ddf2SIngo Weinhold// AddArray
326c3a3ddf2SIngo Weinholdstatus_t
327c3a3ddf2SIngo WeinholdKMessage::AddArray(const char *name, type_code type, const void *data,
328c3a3ddf2SIngo Weinhold	int32 elementSize, int32 elementCount)
329c3a3ddf2SIngo Weinhold{
330c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE || !data || elementSize < 0
331c3a3ddf2SIngo Weinhold		|| elementCount < 0) {
332c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
333c3a3ddf2SIngo Weinhold	}
334c3a3ddf2SIngo Weinhold	KMessageField field;
335c3a3ddf2SIngo Weinhold	if (FindField(name, &field) == B_OK) {
336c3a3ddf2SIngo Weinhold		// field with that name already exists: check its type
337c3a3ddf2SIngo Weinhold		if (field.TypeCode() != type)
338c3a3ddf2SIngo Weinhold			return B_BAD_TYPE;
339c3a3ddf2SIngo Weinhold	} else {
340c3a3ddf2SIngo Weinhold		// no such field yet: add it
341c3a3ddf2SIngo Weinhold		status_t error = _AddField(name, type, elementSize, &field);
342c3a3ddf2SIngo Weinhold		if (error != B_OK)
343c3a3ddf2SIngo Weinhold			return error;
344c3a3ddf2SIngo Weinhold	}
345c3a3ddf2SIngo Weinhold	return _AddFieldData(&field, data, elementSize, elementCount);
346c3a3ddf2SIngo Weinhold}
347c3a3ddf2SIngo Weinhold
348dad63129SIngo Weinhold
349dad63129SIngo Weinhold// SetData
350dad63129SIngo Weinholdstatus_t
351dad63129SIngo WeinholdKMessage::SetData(const char* name, type_code type, const void* data,
352dad63129SIngo Weinhold	int32 numBytes)
353dad63129SIngo Weinhold{
354dad63129SIngo Weinhold	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
355dad63129SIngo Weinhold		return B_NOT_ALLOWED;
356dad63129SIngo Weinhold
357dad63129SIngo Weinhold	KMessageField field;
358dad63129SIngo Weinhold
359dad63129SIngo Weinhold	if (FindField(name, &field) == B_OK) {
360dad63129SIngo Weinhold		// field already known
361dad63129SIngo Weinhold		if (field.TypeCode() != type || !field.HasFixedElementSize()
362dad63129SIngo Weinhold			|| field.ElementSize() != numBytes) {
363dad63129SIngo Weinhold			return B_BAD_VALUE;
364dad63129SIngo Weinhold		}
365dad63129SIngo Weinhold
366dad63129SIngo Weinhold		// if it has an element, just replace its value
367dad63129SIngo Weinhold		if (field.CountElements() > 0) {
368dad63129SIngo Weinhold			const void* element = field.ElementAt(0);
369dad63129SIngo Weinhold			memcpy(const_cast<void*>(element), data, numBytes);
370dad63129SIngo Weinhold			return B_OK;
371dad63129SIngo Weinhold		}
372dad63129SIngo Weinhold	} else {
373dad63129SIngo Weinhold		// no such field yet -- add it
374dad63129SIngo Weinhold		status_t error = _AddField(name, type, numBytes, &field);
375dad63129SIngo Weinhold		if (error != B_OK)
376dad63129SIngo Weinhold			return error;
377dad63129SIngo Weinhold	}
378dad63129SIngo Weinhold
379dad63129SIngo Weinhold	// we've got an empty field -- add the element
380dad63129SIngo Weinhold	return _AddFieldData(&field, data, numBytes, 1);
381dad63129SIngo Weinhold}
382dad63129SIngo Weinhold
383dad63129SIngo Weinhold
384c3a3ddf2SIngo Weinhold// FindData
385c3a3ddf2SIngo Weinholdstatus_t
386c3a3ddf2SIngo WeinholdKMessage::FindData(const char *name, type_code type, const void **data,
387c3a3ddf2SIngo Weinhold	int32 *numBytes) const
388c3a3ddf2SIngo Weinhold{
389c3a3ddf2SIngo Weinhold	return FindData(name, type, 0, data, numBytes);
390c3a3ddf2SIngo Weinhold}
391c3a3ddf2SIngo Weinhold
392c3a3ddf2SIngo Weinhold// FindData
393c3a3ddf2SIngo Weinholdstatus_t
394c3a3ddf2SIngo WeinholdKMessage::FindData(const char *name, type_code type, int32 index,
395c3a3ddf2SIngo Weinhold	const void **data, int32 *numBytes) const
396c3a3ddf2SIngo Weinhold{
397c3a3ddf2SIngo Weinhold	if (!name || !data || !numBytes)
398c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
399c3a3ddf2SIngo Weinhold	KMessageField field;
400c3a3ddf2SIngo Weinhold	status_t error = FindField(name, type, &field);
401c3a3ddf2SIngo Weinhold	if (error != B_OK)
402c3a3ddf2SIngo Weinhold		return error;
403c3a3ddf2SIngo Weinhold	const void *foundData = field.ElementAt(index, numBytes);
404c3a3ddf2SIngo Weinhold	if (!foundData)
405c3a3ddf2SIngo Weinhold		return B_BAD_INDEX;
406c3a3ddf2SIngo Weinhold	if (data)
407c3a3ddf2SIngo Weinhold		*data = foundData;
408c3a3ddf2SIngo Weinhold	return B_OK;
409c3a3ddf2SIngo Weinhold}
410c3a3ddf2SIngo Weinhold
411c3a3ddf2SIngo Weinhold// Sender
412c3a3ddf2SIngo Weinholdteam_id
413c3a3ddf2SIngo WeinholdKMessage::Sender() const
414c3a3ddf2SIngo Weinhold{
415c3a3ddf2SIngo Weinhold	return _Header()->sender;
416c3a3ddf2SIngo Weinhold}
417c3a3ddf2SIngo Weinhold
418c3a3ddf2SIngo Weinhold// TargetToken
419c3a3ddf2SIngo Weinholdint32
420c3a3ddf2SIngo WeinholdKMessage::TargetToken() const
421c3a3ddf2SIngo Weinhold{
422c3a3ddf2SIngo Weinhold	return _Header()->targetToken;
423c3a3ddf2SIngo Weinhold}
424c3a3ddf2SIngo Weinhold
425c3a3ddf2SIngo Weinhold// ReplyPort
426c3a3ddf2SIngo Weinholdport_id
427c3a3ddf2SIngo WeinholdKMessage::ReplyPort() const
428c3a3ddf2SIngo Weinhold{
429c3a3ddf2SIngo Weinhold	return _Header()->replyPort;
430c3a3ddf2SIngo Weinhold}
431c3a3ddf2SIngo Weinhold
432c3a3ddf2SIngo Weinhold// ReplyToken
433c3a3ddf2SIngo Weinholdint32
434c3a3ddf2SIngo WeinholdKMessage::ReplyToken() const
435c3a3ddf2SIngo Weinhold{
436c3a3ddf2SIngo Weinhold	return _Header()->replyToken;
437c3a3ddf2SIngo Weinhold}
438c3a3ddf2SIngo Weinhold
4394bef3723SAxel Dörfler// SetDeliveryInfo
4404bef3723SAxel Dörflervoid
4414bef3723SAxel DörflerKMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
4424bef3723SAxel Dörfler	int32 replyToken, team_id senderTeam)
4434bef3723SAxel Dörfler{
4444bef3723SAxel Dörfler	Header* header = _Header();
4454bef3723SAxel Dörfler	header->sender = senderTeam;
4464bef3723SAxel Dörfler	header->targetToken = targetToken;
4474bef3723SAxel Dörfler	header->replyPort = replyPort;
4484bef3723SAxel Dörfler	header->replyToken = replyToken;
4494bef3723SAxel Dörfler	header->sender = senderTeam;
4504bef3723SAxel Dörfler}
451dad63129SIngo Weinhold
452dad63129SIngo Weinhold#ifndef KMESSAGE_CONTAINER_ONLY
453dad63129SIngo Weinhold
454c3a3ddf2SIngo Weinhold// SendTo
455c3a3ddf2SIngo Weinholdstatus_t
456c3a3ddf2SIngo WeinholdKMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
457c3a3ddf2SIngo Weinhold	int32 replyToken, bigtime_t timeout, team_id senderTeam)
458c3a3ddf2SIngo Weinhold{
459c3a3ddf2SIngo Weinhold	// get the sender team
4604bef3723SAxel Dörfler	if (senderTeam < 0) {
461c3a3ddf2SIngo Weinhold		thread_info info;
462c3a3ddf2SIngo Weinhold		status_t error = get_thread_info(find_thread(NULL), &info);
463c3a3ddf2SIngo Weinhold		if (error != B_OK)
464c3a3ddf2SIngo Weinhold			return error;
4654bef3723SAxel Dörfler
4664bef3723SAxel Dörfler		senderTeam =;
467c3a3ddf2SIngo Weinhold	}
4684bef3723SAxel Dörfler
4694bef3723SAxel Dörfler	SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
4704bef3723SAxel Dörfler
471c3a3ddf2SIngo Weinhold	// send the message
472c3a3ddf2SIngo Weinhold	if (timeout < 0)
473c3a3ddf2SIngo Weinhold		return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
4744bef3723SAxel Dörfler
475c3a3ddf2SIngo Weinhold	return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
476c3a3ddf2SIngo Weinhold		B_RELATIVE_TIMEOUT, timeout);
477c3a3ddf2SIngo Weinhold}
478c3a3ddf2SIngo Weinhold
479c3a3ddf2SIngo Weinhold// SendTo
480c3a3ddf2SIngo Weinholdstatus_t
481c3a3ddf2SIngo WeinholdKMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
482c3a3ddf2SIngo Weinhold	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
483c3a3ddf2SIngo Weinhold{
484c3a3ddf2SIngo Weinhold	// get the team the target port belongs to
485c3a3ddf2SIngo Weinhold	port_info portInfo;
486c3a3ddf2SIngo Weinhold	status_t error = get_port_info(targetPort, &portInfo);
487c3a3ddf2SIngo Weinhold	if (error != B_OK)
488c3a3ddf2SIngo Weinhold		return error;
489c3a3ddf2SIngo Weinhold	team_id targetTeam =;
490c3a3ddf2SIngo Weinhold	// allocate a reply port, if a reply is desired
491c3a3ddf2SIngo Weinhold	port_id replyPort = -1;
492c3a3ddf2SIngo Weinhold	if (reply) {
493c3a3ddf2SIngo Weinhold		// get our team
494c3a3ddf2SIngo Weinhold		team_id ourTeam = B_SYSTEM_TEAM;
495685645f9SPhilippe Houdoin		#ifndef _KERNEL_MODE
496c3a3ddf2SIngo Weinhold			if (targetTeam != B_SYSTEM_TEAM) {
497c3a3ddf2SIngo Weinhold				thread_info threadInfo;
498c3a3ddf2SIngo Weinhold				error = get_thread_info(find_thread(NULL), &threadInfo);
499c3a3ddf2SIngo Weinhold				if (error != B_OK)
500c3a3ddf2SIngo Weinhold					return error;
501c3a3ddf2SIngo Weinhold				ourTeam =;
502c3a3ddf2SIngo Weinhold			}
503c3a3ddf2SIngo Weinhold		#endif
504c3a3ddf2SIngo Weinhold		// create the port
505c3a3ddf2SIngo Weinhold		replyPort = create_port(1, "KMessage reply port");
506c3a3ddf2SIngo Weinhold		if (replyPort < 0)
507c3a3ddf2SIngo Weinhold			return replyPort;
508c3a3ddf2SIngo Weinhold		// If the target team is not our team and not the kernel team either,
509c3a3ddf2SIngo Weinhold		// we transfer the ownership of the port to it, so we will not block
510c3a3ddf2SIngo Weinhold		if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM)
511c3a3ddf2SIngo Weinhold			set_port_owner(replyPort, targetTeam);
512c3a3ddf2SIngo Weinhold	}
513c3a3ddf2SIngo Weinhold	struct PortDeleter {
514c3a3ddf2SIngo Weinhold		PortDeleter(port_id port) : port(port) {}
515c3a3ddf2SIngo Weinhold		~PortDeleter()
516c3a3ddf2SIngo Weinhold		{
517c3a3ddf2SIngo Weinhold			if (port >= 0)
518c3a3ddf2SIngo Weinhold				delete_port(port);
519c3a3ddf2SIngo Weinhold		}
520c3a3ddf2SIngo Weinhold
521c3a3ddf2SIngo Weinhold		port_id	port;
522c3a3ddf2SIngo Weinhold	} replyPortDeleter(replyPort);
523c3a3ddf2SIngo Weinhold	// send the message
524c3a3ddf2SIngo Weinhold	error = SendTo(targetPort, targetToken, replyPort, 0,
525c3a3ddf2SIngo Weinhold		deliveryTimeout, senderTeam);
526c3a3ddf2SIngo Weinhold	if (error != B_OK)
527c3a3ddf2SIngo Weinhold		return error;
528c3a3ddf2SIngo Weinhold	// get the reply
529c3a3ddf2SIngo Weinhold	if (reply)
530c3a3ddf2SIngo Weinhold		return reply->ReceiveFrom(replyPort, replyTimeout);
531c3a3ddf2SIngo Weinhold	return B_OK;
532c3a3ddf2SIngo Weinhold}
533c3a3ddf2SIngo Weinhold
534c3a3ddf2SIngo Weinhold// SendReply
535c3a3ddf2SIngo Weinholdstatus_t
536c3a3ddf2SIngo WeinholdKMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
537c3a3ddf2SIngo Weinhold	bigtime_t timeout, team_id senderTeam)
538c3a3ddf2SIngo Weinhold{
539c3a3ddf2SIngo Weinhold	if (!message)
540c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
541c3a3ddf2SIngo Weinhold	return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
542c3a3ddf2SIngo Weinhold		timeout, senderTeam);
543c3a3ddf2SIngo Weinhold}
544c3a3ddf2SIngo Weinhold
545c3a3ddf2SIngo Weinhold// SendReply
546c3a3ddf2SIngo Weinholdstatus_t
547c3a3ddf2SIngo WeinholdKMessage::SendReply(KMessage* message, KMessage* reply,
548c3a3ddf2SIngo Weinhold	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
549c3a3ddf2SIngo Weinhold{
550c3a3ddf2SIngo Weinhold	if (!message)
551c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
552c3a3ddf2SIngo Weinhold	return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
553c3a3ddf2SIngo Weinhold		replyTimeout, senderTeam);
554c3a3ddf2SIngo Weinhold}
555c3a3ddf2SIngo Weinhold
5562d9a4022SIngo Weinhold
557c3a3ddf2SIngo Weinhold// ReceiveFrom
558c3a3ddf2SIngo Weinholdstatus_t
5592d9a4022SIngo WeinholdKMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
5602d9a4022SIngo Weinhold	port_message_info* messageInfo)
561c3a3ddf2SIngo Weinhold{
5622d9a4022SIngo Weinhold	port_message_info _messageInfo;
5632d9a4022SIngo Weinhold	if (messageInfo == NULL)
5642d9a4022SIngo Weinhold		messageInfo = &_messageInfo;
5652d9a4022SIngo Weinhold
566c3a3ddf2SIngo Weinhold	// get the port buffer size
5672d9a4022SIngo Weinhold	status_t error;
5682d9a4022SIngo Weinhold	if (timeout < 0) {
5692d9a4022SIngo Weinhold		error = get_port_message_info_etc(fromPort, messageInfo, 0, 0);
5702d9a4022SIngo Weinhold	} else {
5712d9a4022SIngo Weinhold		error = get_port_message_info_etc(fromPort, messageInfo,
5722d9a4022SIngo Weinhold			B_RELATIVE_TIMEOUT, timeout);
5732d9a4022SIngo Weinhold	}
5742d9a4022SIngo Weinhold	if (error != B_OK)
5752d9a4022SIngo Weinhold		return error;
5762d9a4022SIngo Weinhold
577c3a3ddf2SIngo Weinhold	// allocate a buffer
5782d9a4022SIngo Weinhold	uint8* buffer = (uint8*)malloc(messageInfo->size);
579c3a3ddf2SIngo Weinhold	if (!buffer)
580c3a3ddf2SIngo Weinhold		return B_NO_MEMORY;
5812d9a4022SIngo Weinhold
582c3a3ddf2SIngo Weinhold	// read the message
583c3a3ddf2SIngo Weinhold	int32 what;
5842d9a4022SIngo Weinhold	ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size,
585c3a3ddf2SIngo Weinhold		B_RELATIVE_TIMEOUT, 0);
5865839058aSIngo Weinhold	if (realSize < 0) {
5875839058aSIngo Weinhold		free(buffer);
588c3a3ddf2SIngo Weinhold		return realSize;
5895839058aSIngo Weinhold	}
5905839058aSIngo Weinhold	if (messageInfo->size != (size_t)realSize) {
5915839058aSIngo Weinhold		free(buffer);
592c3a3ddf2SIngo Weinhold		return B_ERROR;
5935839058aSIngo Weinhold	}
5942d9a4022SIngo Weinhold
595c3a3ddf2SIngo Weinhold	// init the message
5962d9a4022SIngo Weinhold	return SetTo(buffer, messageInfo->size, 0,
598c3a3ddf2SIngo Weinhold}
599c3a3ddf2SIngo Weinhold
600dad63129SIngo Weinhold#endif	// !KMESSAGE_CONTAINER_ONLY
601dad63129SIngo Weinhold
602dad63129SIngo Weinhold
603e09769a9SIngo Weinholdvoid
604e09769a9SIngo WeinholdKMessage::Dump(void (*printFunc)(const char*,...))
605e09769a9SIngo Weinhold{
606e09769a9SIngo Weinhold	Header* header = _Header();
607e09769a9SIngo Weinhold	printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: 0x0lx\n",
608e09769a9SIngo Weinhold		fBuffer, header->size, fBufferCapacity, fFlags);
609e09769a9SIngo Weinhold
610e09769a9SIngo Weinhold	KMessageField field;
611e09769a9SIngo Weinhold	while (GetNextField(&field) == B_OK) {
612e09769a9SIngo Weinhold		type_code type = field.TypeCode();
613e09769a9SIngo Weinhold		int32 count = field.CountElements();
614e09769a9SIngo Weinhold		printFunc("  field: %-20s: type: 0x%lx ('%c%c%c%c'), %ld element%s\n",
615e09769a9SIngo Weinhold			field.Name(), type, (char)(type >> 24), (char)(type >> 16),
616e09769a9SIngo Weinhold			(char)(type >> 8), (char)type, count, count == 1 ? "" : "s");
617e09769a9SIngo Weinhold	}
618e09769a9SIngo Weinhold}
619e09769a9SIngo Weinhold
620e09769a9SIngo Weinhold
621c3a3ddf2SIngo Weinhold// _Header
622c3a3ddf2SIngo WeinholdKMessage::Header *
623c3a3ddf2SIngo WeinholdKMessage::_Header() const
624c3a3ddf2SIngo Weinhold{
625c3a3ddf2SIngo Weinhold	return (Header*)fBuffer;
626c3a3ddf2SIngo Weinhold}
627c3a3ddf2SIngo Weinhold
628c3a3ddf2SIngo Weinhold// _BufferOffsetFor
629c3a3ddf2SIngo Weinholdint32
630c3a3ddf2SIngo WeinholdKMessage::_BufferOffsetFor(const void* data) const
631c3a3ddf2SIngo Weinhold{
632c3a3ddf2SIngo Weinhold	if (!data)
633c3a3ddf2SIngo Weinhold		return -1;
634c3a3ddf2SIngo Weinhold	return ((uint8*)data - (uint8*)fBuffer);
635c3a3ddf2SIngo Weinhold}
636c3a3ddf2SIngo Weinhold
637c3a3ddf2SIngo Weinhold// _FirstFieldHeader
638c3a3ddf2SIngo WeinholdKMessage::FieldHeader *
639c3a3ddf2SIngo WeinholdKMessage::_FirstFieldHeader() const
640c3a3ddf2SIngo Weinhold{
641c3a3ddf2SIngo Weinhold	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
642c3a3ddf2SIngo Weinhold}
643c3a3ddf2SIngo Weinhold
644c3a3ddf2SIngo Weinhold// _LastFieldHeader
645c3a3ddf2SIngo WeinholdKMessage::FieldHeader *
646c3a3ddf2SIngo WeinholdKMessage::_LastFieldHeader() const
647c3a3ddf2SIngo Weinhold{
648c3a3ddf2SIngo Weinhold	return _FieldHeaderForOffset(fLastFieldOffset);
649c3a3ddf2SIngo Weinhold}
650c3a3ddf2SIngo Weinhold
651c3a3ddf2SIngo Weinhold// _FieldHeaderForOffset
652c3a3ddf2SIngo WeinholdKMessage::FieldHeader *
653c3a3ddf2SIngo WeinholdKMessage::_FieldHeaderForOffset(int32 offset) const
654c3a3ddf2SIngo Weinhold{
655c3a3ddf2SIngo Weinhold	if (offset <= 0 || offset >= _Header()->size)
656c3a3ddf2SIngo Weinhold		return NULL;
657c3a3ddf2SIngo Weinhold	return (FieldHeader*)((uint8*)fBuffer + offset);
658c3a3ddf2SIngo Weinhold}
659c3a3ddf2SIngo Weinhold
660c3a3ddf2SIngo Weinhold// _AddField
661c3a3ddf2SIngo Weinholdstatus_t
662c3a3ddf2SIngo WeinholdKMessage::_AddField(const char *name, type_code type, int32 elementSize,
663c3a3ddf2SIngo Weinhold	KMessageField *field)
664c3a3ddf2SIngo Weinhold{
665c3a3ddf2SIngo Weinhold	FieldHeader *fieldHeader;
666c3a3ddf2SIngo Weinhold	int32 alignedSize;
667c3a3ddf2SIngo Weinhold	status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
668c3a3ddf2SIngo Weinhold		true, (void**)&fieldHeader, &alignedSize);
669c3a3ddf2SIngo Weinhold	if (error != B_OK)
670c3a3ddf2SIngo Weinhold		return error;
671c3a3ddf2SIngo Weinhold	fieldHeader->type = type;
672c3a3ddf2SIngo Weinhold	fieldHeader->elementSize = elementSize;
673c3a3ddf2SIngo Weinhold	fieldHeader->elementCount = 0;
674c3a3ddf2SIngo Weinhold	fieldHeader->fieldSize = alignedSize;
675c3a3ddf2SIngo Weinhold	fieldHeader->headerSize = alignedSize;
676c3a3ddf2SIngo Weinhold	strcpy(fieldHeader->name, name);
677c3a3ddf2SIngo Weinhold	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
678c3a3ddf2SIngo Weinhold	if (field)
679c3a3ddf2SIngo Weinhold		field->SetTo(this, _BufferOffsetFor(fieldHeader));
680c3a3ddf2SIngo Weinhold	return B_OK;
681c3a3ddf2SIngo Weinhold}
682c3a3ddf2SIngo Weinhold
683c3a3ddf2SIngo Weinhold// _AddFieldData
684c3a3ddf2SIngo Weinholdstatus_t
685c3a3ddf2SIngo WeinholdKMessage::_AddFieldData(KMessageField *field, const void *data,
686c3a3ddf2SIngo Weinhold	int32 elementSize, int32 elementCount)
687c3a3ddf2SIngo Weinhold{
688c3a3ddf2SIngo Weinhold	if (!field)
689c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
690c3a3ddf2SIngo Weinhold	FieldHeader *fieldHeader = field->_Header();
691c3a3ddf2SIngo Weinhold	FieldHeader* lastField = _LastFieldHeader();
692c3a3ddf2SIngo Weinhold	if (!fieldHeader || fieldHeader != lastField || !data
693c3a3ddf2SIngo Weinhold		|| elementSize < 0 || elementCount < 0) {
694c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
695c3a3ddf2SIngo Weinhold	}
696c3a3ddf2SIngo Weinhold	if (elementCount == 0)
697c3a3ddf2SIngo Weinhold		return B_OK;
698c3a3ddf2SIngo Weinhold	// fixed size values
699c3a3ddf2SIngo Weinhold	if (fieldHeader->HasFixedElementSize()) {
700c3a3ddf2SIngo Weinhold		if (elementSize != fieldHeader->elementSize)
701c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
702c3a3ddf2SIngo Weinhold		void *address;
703c3a3ddf2SIngo Weinhold		int32 alignedSize;
704c3a3ddf2SIngo Weinhold		status_t error = _AllocateSpace(elementSize * elementCount,
705c3a3ddf2SIngo Weinhold			(fieldHeader->elementCount == 0), false, &address, &alignedSize);
706c3a3ddf2SIngo Weinhold		if (error != B_OK)
707c3a3ddf2SIngo Weinhold			return error;
708c3a3ddf2SIngo Weinhold		fieldHeader = field->_Header();	// might have been relocated
709c3a3ddf2SIngo Weinhold		memcpy(address, data, elementSize * elementCount);
710c3a3ddf2SIngo Weinhold		fieldHeader->elementCount += elementCount;
711c3a3ddf2SIngo Weinhold		fieldHeader->fieldSize = (uint8*)address + alignedSize
712c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader;
713c3a3ddf2SIngo Weinhold		return B_OK;
714c3a3ddf2SIngo Weinhold	}
715c3a3ddf2SIngo Weinhold	// non-fixed size values
716c3a3ddf2SIngo Weinhold	// add the elements individually (TODO: Optimize!)
717c3a3ddf2SIngo Weinhold	int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
718c3a3ddf2SIngo Weinhold	int32 entrySize = valueHeaderSize + elementSize;
719c3a3ddf2SIngo Weinhold	for (int32 i = 0; i < elementCount; i++) {
720c3a3ddf2SIngo Weinhold		void *address;
721c3a3ddf2SIngo Weinhold		int32 alignedSize;
722c3a3ddf2SIngo Weinhold		status_t error = _AllocateSpace(entrySize, true, false, &address,
723c3a3ddf2SIngo Weinhold			&alignedSize);
724c3a3ddf2SIngo Weinhold		if (error != B_OK)
725c3a3ddf2SIngo Weinhold			return error;
726c3a3ddf2SIngo Weinhold		fieldHeader = field->_Header();	// might have been relocated
727c3a3ddf2SIngo Weinhold		FieldValueHeader *valueHeader = (FieldValueHeader*)address;
728c3a3ddf2SIngo Weinhold		valueHeader->size = elementSize;
729c3a3ddf2SIngo Weinhold		memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
730c3a3ddf2SIngo Weinhold			elementSize);
731c3a3ddf2SIngo Weinhold		fieldHeader->elementCount++;
732c3a3ddf2SIngo Weinhold		fieldHeader->fieldSize = (uint8*)address + alignedSize
733c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader;
734c3a3ddf2SIngo Weinhold	}
735c3a3ddf2SIngo Weinhold	return B_OK;
736c3a3ddf2SIngo Weinhold}
737c3a3ddf2SIngo Weinhold
738c3a3ddf2SIngo Weinhold// _InitFromBuffer
739c3a3ddf2SIngo Weinholdstatus_t
740dad63129SIngo WeinholdKMessage::_InitFromBuffer(bool sizeFromBuffer)
741c3a3ddf2SIngo Weinhold{
742dad63129SIngo Weinhold	if (!fBuffer || _Align(fBuffer) != fBuffer)
743c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
744c3a3ddf2SIngo Weinhold	Header *header = _Header();
745dad63129SIngo Weinhold
746dad63129SIngo Weinhold	if (sizeFromBuffer)
747dad63129SIngo Weinhold		fBufferCapacity = header->size;
748dad63129SIngo Weinhold
749dad63129SIngo Weinhold	if (fBufferCapacity < (int)sizeof(Header))
750dad63129SIngo Weinhold		return B_BAD_DATA;
751dad63129SIngo Weinhold
752dad63129SIngo Weinhold	// check header
753c3a3ddf2SIngo Weinhold	if (header->magic != kMessageHeaderMagic)
754c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
755c3a3ddf2SIngo Weinhold	if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
756c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
757dad63129SIngo Weinhold
758c3a3ddf2SIngo Weinhold	// check the fields
759c3a3ddf2SIngo Weinhold	FieldHeader *fieldHeader = NULL;
760c3a3ddf2SIngo Weinhold	uint8 *data = (uint8*)_FirstFieldHeader();
761c3a3ddf2SIngo Weinhold	int32 remainingBytes = (uint8*)fBuffer + header->size - data;
762c3a3ddf2SIngo Weinhold	while (remainingBytes > 0) {
763c3a3ddf2SIngo Weinhold		if (remainingBytes < (int)sizeof(FieldHeader))
764c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
765c3a3ddf2SIngo Weinhold		fieldHeader = (FieldHeader*)data;
766c3a3ddf2SIngo Weinhold		// check field header
767c3a3ddf2SIngo Weinhold		if (fieldHeader->type == B_ANY_TYPE)
768c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
769c3a3ddf2SIngo Weinhold		if (fieldHeader->elementCount < 0)
770c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
771c3a3ddf2SIngo Weinhold		if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
772c3a3ddf2SIngo Weinhold			|| fieldHeader->fieldSize > remainingBytes) {
773c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
774c3a3ddf2SIngo Weinhold		}
775c3a3ddf2SIngo Weinhold		if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
776c3a3ddf2SIngo Weinhold			|| fieldHeader->headerSize > fieldHeader->fieldSize) {
777c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
778c3a3ddf2SIngo Weinhold		}
779c3a3ddf2SIngo Weinhold		int32 maxNameLen = data + fieldHeader->headerSize
780c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader->name;
781c3a3ddf2SIngo Weinhold		int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
782c3a3ddf2SIngo Weinhold		if (nameLen == maxNameLen || nameLen == 0)
783c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
784c3a3ddf2SIngo Weinhold		int32 fieldSize =  fieldHeader->headerSize;
785c3a3ddf2SIngo Weinhold		if (fieldHeader->HasFixedElementSize()) {
786c3a3ddf2SIngo Weinhold			// fixed element size
787c3a3ddf2SIngo Weinhold			int32 dataSize = fieldHeader->elementSize
788c3a3ddf2SIngo Weinhold				* fieldHeader->elementCount;
789c3a3ddf2SIngo Weinhold			fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
790c3a3ddf2SIngo Weinhold		} else {
791c3a3ddf2SIngo Weinhold			// non-fixed element size
792c3a3ddf2SIngo Weinhold			FieldValueHeader *valueHeader
793c3a3ddf2SIngo Weinhold				= (FieldValueHeader *)fieldHeader->Data();
794c3a3ddf2SIngo Weinhold			for (int32 i = 0; i < fieldHeader->elementCount; i++) {
795c3a3ddf2SIngo Weinhold				remainingBytes = (uint8*)fBuffer + header->size
796c3a3ddf2SIngo Weinhold					- (uint8*)valueHeader;
797c3a3ddf2SIngo Weinhold				if (remainingBytes < (int)sizeof(FieldValueHeader))
798c3a3ddf2SIngo Weinhold					return B_BAD_DATA;
799c3a3ddf2SIngo Weinhold				uint8 *value = (uint8*)valueHeader->Data();
800c3a3ddf2SIngo Weinhold				remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
801c3a3ddf2SIngo Weinhold				if (remainingBytes < valueHeader->size)
802c3a3ddf2SIngo Weinhold					return B_BAD_DATA;
803c3a3ddf2SIngo Weinhold				fieldSize = value + valueHeader->size - data;
804c3a3ddf2SIngo Weinhold				valueHeader = valueHeader->NextFieldValueHeader();
805c3a3ddf2SIngo Weinhold			}
806c3a3ddf2SIngo Weinhold			if (fieldSize > fieldHeader->fieldSize)
807c3a3ddf2SIngo Weinhold				return B_BAD_DATA;
808c3a3ddf2SIngo Weinhold		}
809c3a3ddf2SIngo Weinhold		data = (uint8*)fieldHeader->NextFieldHeader();
810c3a3ddf2SIngo Weinhold		remainingBytes = (uint8*)fBuffer + header->size - data;
811c3a3ddf2SIngo Weinhold	}
812c3a3ddf2SIngo Weinhold	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
813c3a3ddf2SIngo Weinhold	return B_OK;
814c3a3ddf2SIngo Weinhold}
815c3a3ddf2SIngo Weinhold
816c3a3ddf2SIngo Weinhold// _InitBuffer
817c3a3ddf2SIngo Weinholdvoid
818c3a3ddf2SIngo WeinholdKMessage::_InitBuffer(uint32 what)
819c3a3ddf2SIngo Weinhold{
820c3a3ddf2SIngo Weinhold	Header *header = _Header();
821c3a3ddf2SIngo Weinhold	header->magic = kMessageHeaderMagic;
822c3a3ddf2SIngo Weinhold	header->size = sizeof(Header);
823c3a3ddf2SIngo Weinhold	header->what = what;
824c3a3ddf2SIngo Weinhold	header->sender = -1;
825c3a3ddf2SIngo Weinhold	header->targetToken = -1;
826c3a3ddf2SIngo Weinhold	header->replyPort = -1;
827c3a3ddf2SIngo Weinhold	header->replyToken = -1;
828c3a3ddf2SIngo Weinhold	fLastFieldOffset = 0;
829c3a3ddf2SIngo Weinhold}
830c3a3ddf2SIngo Weinhold
831c3a3ddf2SIngo Weinhold// _CheckBuffer
832c3a3ddf2SIngo Weinholdvoid
833c3a3ddf2SIngo WeinholdKMessage::_CheckBuffer()
834c3a3ddf2SIngo Weinhold{
835c3a3ddf2SIngo Weinhold	int32 lastFieldOffset = fLastFieldOffset;
836dad63129SIngo Weinhold	if (_InitFromBuffer(false) != B_OK) {
837c3a3ddf2SIngo Weinhold		PANIC("internal data mangled");
838c3a3ddf2SIngo Weinhold	}
839c3a3ddf2SIngo Weinhold	if (fLastFieldOffset != lastFieldOffset) {
840c3a3ddf2SIngo Weinhold		PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
841c3a3ddf2SIngo Weinhold	}
842c3a3ddf2SIngo Weinhold}
843c3a3ddf2SIngo Weinhold
844c3a3ddf2SIngo Weinhold// _AllocateSpace
845c3a3ddf2SIngo Weinholdstatus_t
846c3a3ddf2SIngo WeinholdKMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
847c3a3ddf2SIngo Weinhold	void **address, int32 *alignedSize)
848c3a3ddf2SIngo Weinhold{
849c3a3ddf2SIngo Weinhold	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
850c3a3ddf2SIngo Weinhold		return B_NOT_ALLOWED;
85174c0424aSAxel Dörfler
852c3a3ddf2SIngo Weinhold	int32 offset = ContentSize();
853c3a3ddf2SIngo Weinhold	if (alignAddress)
854c3a3ddf2SIngo Weinhold		offset = _Align(offset);
855c3a3ddf2SIngo Weinhold	int32 newSize = offset + size;
856c3a3ddf2SIngo Weinhold	if (alignSize)
857c3a3ddf2SIngo Weinhold		newSize = _Align(newSize);
858c3a3ddf2SIngo Weinhold	// reallocate if necessary
859c3a3ddf2SIngo Weinhold	if (fBuffer == &fHeader) {
860c3a3ddf2SIngo Weinhold		int32 newCapacity = _CapacityFor(newSize);
861c3a3ddf2SIngo Weinhold		void *newBuffer = malloc(newCapacity);
862c3a3ddf2SIngo Weinhold		if (!newBuffer)
863c3a3ddf2SIngo Weinhold			return B_NO_MEMORY;
864c3a3ddf2SIngo Weinhold		fBuffer = newBuffer;
865c3a3ddf2SIngo Weinhold		fBufferCapacity = newCapacity;
866c3a3ddf2SIngo Weinhold		fFlags |= KMESSAGE_OWNS_BUFFER;
867c3a3ddf2SIngo Weinhold		memcpy(fBuffer, &fHeader, sizeof(fHeader));
868c3a3ddf2SIngo Weinhold	} else {
869c3a3ddf2SIngo Weinhold		if (newSize > fBufferCapacity) {
870c3a3ddf2SIngo Weinhold			// if we don't own the buffer, we can't resize it
871c3a3ddf2SIngo Weinhold			if (!(fFlags & KMESSAGE_OWNS_BUFFER))
872c3a3ddf2SIngo Weinhold				return B_BUFFER_OVERFLOW;
873c3a3ddf2SIngo Weinhold			int32 newCapacity = _CapacityFor(newSize);
874c3a3ddf2SIngo Weinhold			void *newBuffer = realloc(fBuffer, newCapacity);
875c3a3ddf2SIngo Weinhold			if (!newBuffer)
876c3a3ddf2SIngo Weinhold				return B_NO_MEMORY;
877c3a3ddf2SIngo Weinhold			fBuffer = newBuffer;
878c3a3ddf2SIngo Weinhold			fBufferCapacity = newCapacity;
879c3a3ddf2SIngo Weinhold		}
880c3a3ddf2SIngo Weinhold	}
881c3a3ddf2SIngo Weinhold	_Header()->size = newSize;
882c3a3ddf2SIngo Weinhold	*address = (char*)fBuffer + offset;
883c3a3ddf2SIngo Weinhold	*alignedSize = newSize - offset;
884c3a3ddf2SIngo Weinhold	return B_OK;
885c3a3ddf2SIngo Weinhold}
886c3a3ddf2SIngo Weinhold
887c3a3ddf2SIngo Weinhold// _CapacityFor
888c3a3ddf2SIngo Weinholdint32
889c3a3ddf2SIngo WeinholdKMessage::_CapacityFor(int32 size)
890c3a3ddf2SIngo Weinhold{
891c3a3ddf2SIngo Weinhold	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
892c3a3ddf2SIngo Weinhold		* kMessageReallocChunkSize;
893c3a3ddf2SIngo Weinhold}
894c3a3ddf2SIngo Weinhold
895c3a3ddf2SIngo Weinhold
896c3a3ddf2SIngo Weinhold// #pragma mark -
897c3a3ddf2SIngo Weinhold
898c3a3ddf2SIngo Weinhold// constructor
899c3a3ddf2SIngo WeinholdKMessageField::KMessageField()
900c3a3ddf2SIngo Weinhold	: fMessage(NULL),
901c3a3ddf2SIngo Weinhold	  fHeaderOffset(0)
902c3a3ddf2SIngo Weinhold{
903c3a3ddf2SIngo Weinhold}
904c3a3ddf2SIngo Weinhold
905c3a3ddf2SIngo Weinhold// Unset
906c3a3ddf2SIngo Weinholdvoid
907c3a3ddf2SIngo WeinholdKMessageField::Unset()
908c3a3ddf2SIngo Weinhold{
909c3a3ddf2SIngo Weinhold	fMessage = NULL;
910c3a3ddf2SIngo Weinhold	fHeaderOffset = 0;
911c3a3ddf2SIngo Weinhold}
912c3a3ddf2SIngo Weinhold
913c3a3ddf2SIngo Weinhold// Message
914c3a3ddf2SIngo WeinholdKMessage *
915c3a3ddf2SIngo WeinholdKMessageField::Message() const
916c3a3ddf2SIngo Weinhold{
917c3a3ddf2SIngo Weinhold	return fMessage;
918c3a3ddf2SIngo Weinhold}
919c3a3ddf2SIngo Weinhold
920c3a3ddf2SIngo Weinhold// Name
921c3a3ddf2SIngo Weinholdconst char *
922c3a3ddf2SIngo WeinholdKMessageField::Name() const
923c3a3ddf2SIngo Weinhold{
924c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
925c3a3ddf2SIngo Weinhold	return (header ? header->name : NULL);
926c3a3ddf2SIngo Weinhold}
927c3a3ddf2SIngo Weinhold
928c3a3ddf2SIngo Weinhold// TypeCode
929c3a3ddf2SIngo Weinholdtype_code
930c3a3ddf2SIngo WeinholdKMessageField::TypeCode() const
931c3a3ddf2SIngo Weinhold{
932c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
933c3a3ddf2SIngo Weinhold	return (header ? header->type : 0);
934c3a3ddf2SIngo Weinhold}
935c3a3ddf2SIngo Weinhold
936c3a3ddf2SIngo Weinhold// HasFixedElementSize
937c3a3ddf2SIngo Weinholdbool
938c3a3ddf2SIngo WeinholdKMessageField::HasFixedElementSize() const
939c3a3ddf2SIngo Weinhold{
940c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
941c3a3ddf2SIngo Weinhold	return (header ? header->HasFixedElementSize() : false);
942c3a3ddf2SIngo Weinhold}
943c3a3ddf2SIngo Weinhold
944c3a3ddf2SIngo Weinhold// ElementSize
945c3a3ddf2SIngo Weinholdint32
946c3a3ddf2SIngo WeinholdKMessageField::ElementSize() const
947c3a3ddf2SIngo Weinhold{
948c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
949c3a3ddf2SIngo Weinhold	return (header ? header->elementSize : -1);
950c3a3ddf2SIngo Weinhold}
951c3a3ddf2SIngo Weinhold
952c3a3ddf2SIngo Weinhold// AddElement
953c3a3ddf2SIngo Weinholdstatus_t
954c3a3ddf2SIngo WeinholdKMessageField::AddElement(const void *data, int32 size)
955c3a3ddf2SIngo Weinhold{
956c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
957c3a3ddf2SIngo Weinhold	if (!header || !data)
958c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
959c3a3ddf2SIngo Weinhold	if (size < 0) {
960c3a3ddf2SIngo Weinhold		size = ElementSize();
961c3a3ddf2SIngo Weinhold		if (size < 0)
962c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
963c3a3ddf2SIngo Weinhold	}
964c3a3ddf2SIngo Weinhold	return fMessage->_AddFieldData(this, data, size, 1);
965c3a3ddf2SIngo Weinhold}
966c3a3ddf2SIngo Weinhold
967c3a3ddf2SIngo Weinhold// AddElements
968c3a3ddf2SIngo Weinholdstatus_t
969c3a3ddf2SIngo WeinholdKMessageField::AddElements(const void *data, int32 count, int32 elementSize)
970c3a3ddf2SIngo Weinhold{
971c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
972c3a3ddf2SIngo Weinhold	if (!header || !data || count < 0)
973c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
974c3a3ddf2SIngo Weinhold	if (elementSize < 0) {
975c3a3ddf2SIngo Weinhold		elementSize = ElementSize();
976c3a3ddf2SIngo Weinhold		if (elementSize < 0)
977c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
978c3a3ddf2SIngo Weinhold	}
979c3a3ddf2SIngo Weinhold	return fMessage->_AddFieldData(this, data, elementSize, count);
980c3a3ddf2SIngo Weinhold}
981c3a3ddf2SIngo Weinhold
982c3a3ddf2SIngo Weinhold// ElementAt
983c3a3ddf2SIngo Weinholdconst void *
984c3a3ddf2SIngo WeinholdKMessageField::ElementAt(int32 index, int32 *size) const
985c3a3ddf2SIngo Weinhold{
986c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
987c3a3ddf2SIngo Weinhold	return (header ? header->ElementAt(index, size) : NULL);
988c3a3ddf2SIngo Weinhold}
989c3a3ddf2SIngo Weinhold
990c3a3ddf2SIngo Weinhold// CountElements
991c3a3ddf2SIngo Weinholdint32
992c3a3ddf2SIngo WeinholdKMessageField::CountElements() const
993c3a3ddf2SIngo Weinhold{
994c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
995c3a3ddf2SIngo Weinhold	return (header ? header->elementCount : 0);
996c3a3ddf2SIngo Weinhold}
997c3a3ddf2SIngo Weinhold
998c3a3ddf2SIngo Weinhold// SetTo
999c3a3ddf2SIngo Weinholdvoid
1000c3a3ddf2SIngo WeinholdKMessageField::SetTo(KMessage *message, int32 headerOffset)
1001c3a3ddf2SIngo Weinhold{
1002c3a3ddf2SIngo Weinhold	fMessage = message;
1003c3a3ddf2SIngo Weinhold	fHeaderOffset = headerOffset;
1004c3a3ddf2SIngo Weinhold}
1005c3a3ddf2SIngo Weinhold
1006c3a3ddf2SIngo Weinhold// _GetHeader
1007c3a3ddf2SIngo WeinholdKMessage::FieldHeader*
1008c3a3ddf2SIngo WeinholdKMessageField::_Header() const
1009c3a3ddf2SIngo Weinhold{
1010c3a3ddf2SIngo Weinhold	return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL);
1011c3a3ddf2SIngo Weinhold}
1012c3a3ddf2SIngo Weinhold