18d79c7dbSAxel Dörfler/*
2f31ab90aSIngo Weinhold * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3395fb089SIngo Weinhold * Distributed under the terms of the MIT License.
4c3a3ddf2SIngo Weinhold */
5c3a3ddf2SIngo Weinhold
6395fb089SIngo Weinhold
774c0424aSAxel Dörfler#include <util/KMessage.h>
8dad63129SIngo Weinhold
9c3a3ddf2SIngo Weinhold#include <stdlib.h>
10c3a3ddf2SIngo Weinhold#include <string.h>
11c3a3ddf2SIngo Weinhold
12a1209343SAxel Dörfler#include <ByteOrder.h>
13c3a3ddf2SIngo Weinhold#include <Debug.h>
14c3a3ddf2SIngo Weinhold#include <KernelExport.h>
15c3a3ddf2SIngo Weinhold#include <TypeConstants.h>
16c3a3ddf2SIngo Weinhold
17395fb089SIngo Weinhold
1874c0424aSAxel Dörfler#if defined(_BOOT_MODE) || defined(_LOADER_MODE)
19dad63129SIngo Weinhold#	include <util/kernel_cpp.h>
20dad63129SIngo Weinhold#else
21dad63129SIngo Weinhold#	include <new>
22dad63129SIngo Weinhold#endif
23dad63129SIngo Weinhold
24c3a3ddf2SIngo Weinhold
25c3a3ddf2SIngo Weinhold// TODO: Add a field index using a hash map, so that lookup improves to O(1)
26c3a3ddf2SIngo Weinhold// (is now O(n)).
27c3a3ddf2SIngo Weinhold
28395fb089SIngo Weinhold
29c3a3ddf2SIngo Weinhold// define the PANIC macro
30c3a3ddf2SIngo Weinhold#ifndef PANIC
31d35f0da7SIngo Weinhold#	ifdef _KERNEL_MODE
32c3a3ddf2SIngo Weinhold#		define PANIC(str)	panic(str)
33d35f0da7SIngo Weinhold#	else
34d35f0da7SIngo Weinhold#		define PANIC(str)	debugger(str)
35c3a3ddf2SIngo Weinhold#	endif
36c3a3ddf2SIngo Weinhold#endif
37c3a3ddf2SIngo Weinhold
38395fb089SIngo Weinhold
3944c3f5c1SMichael Lotz#if !defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(_BOOT_MODE) \
4044c3f5c1SMichael Lotz	|| defined(_LOADER_MODE)
4144c3f5c1SMichael Lotz#	define MEMALIGN(alignment, size)	malloc(size)
4244c3f5c1SMichael Lotz	// Built as part of a build tool or the boot or runtime loader.
4344c3f5c1SMichael Lotz#else
4444c3f5c1SMichael Lotz#	include <malloc.h>
4544c3f5c1SMichael Lotz#	define MEMALIGN(alignment, size)	memalign(alignment, size)
4644c3f5c1SMichael Lotz	// Built as part of the kernel or userland. Using memalign allows use of
4744c3f5c1SMichael Lotz	// special heap implementations that might otherwise return unaligned
4844c3f5c1SMichael Lotz	// buffers for debugging purposes.
4944c3f5c1SMichael Lotz#endif
5044c3f5c1SMichael Lotz
5144c3f5c1SMichael Lotz
52c3a3ddf2SIngo Weinholdstatic const int32 kMessageReallocChunkSize = 64;
53d0aa0748SMichael Lotzstatic const size_t kMessageBufferAlignment = 4;
54c3a3ddf2SIngo Weinhold
55ea69d9d3SIngo Weinholdconst uint32 KMessage::kMessageHeaderMagic = 'kMsG';
56ea69d9d3SIngo Weinhold
57395fb089SIngo Weinhold
58395fb089SIngo Weinhold// #pragma mark - Helper Functions
59395fb089SIngo Weinhold
60395fb089SIngo Weinholdstatic inline int32
61c3a3ddf2SIngo Weinhold_Align(int32 offset)
62c3a3ddf2SIngo Weinhold{
63d0aa0748SMichael Lotz	return (offset + kMessageBufferAlignment - 1)
64d0aa0748SMichael Lotz		& ~(kMessageBufferAlignment - 1);
65c3a3ddf2SIngo Weinhold}
66c3a3ddf2SIngo Weinhold
67395fb089SIngo Weinhold
68395fb089SIngo Weinholdstatic inline void*
69395fb089SIngo Weinhold_Align(void* address, int32 offset = 0)
70c3a3ddf2SIngo Weinhold{
71d0aa0748SMichael Lotz	return (void*)(((addr_t)address + offset + kMessageBufferAlignment - 1)
72d0aa0748SMichael Lotz		& ~(kMessageBufferAlignment - 1));
73c3a3ddf2SIngo Weinhold}
74c3a3ddf2SIngo Weinhold
75395fb089SIngo Weinhold
76395fb089SIngo Weinhold// #pragma mark - FieldValueHeader
77395fb089SIngo Weinhold
78395fb089SIngo Weinhold
79c3a3ddf2SIngo Weinholdstruct KMessage::FieldValueHeader {
80c3a3ddf2SIngo Weinhold	int32		size;
81c3a3ddf2SIngo Weinhold
82395fb089SIngo Weinhold	void* Data()
83c3a3ddf2SIngo Weinhold	{
84c3a3ddf2SIngo Weinhold		return _Align(this, sizeof(FieldValueHeader));
85c3a3ddf2SIngo Weinhold	}
86c3a3ddf2SIngo Weinhold
87395fb089SIngo Weinhold	FieldValueHeader* NextFieldValueHeader()
88c3a3ddf2SIngo Weinhold	{
89c3a3ddf2SIngo Weinhold		return (FieldValueHeader*)_Align(Data(), size);
90c3a3ddf2SIngo Weinhold	}
91c3a3ddf2SIngo Weinhold};
92c3a3ddf2SIngo Weinhold
93395fb089SIngo Weinhold
94395fb089SIngo Weinhold// #pragma mark - FieldHeader
95395fb089SIngo Weinhold
96395fb089SIngo Weinhold
97c3a3ddf2SIngo Weinholdstruct KMessage::FieldHeader {
98c3a3ddf2SIngo Weinhold	type_code	type;
99c3a3ddf2SIngo Weinhold	int32		elementSize;	// if < 0: non-fixed size
100c3a3ddf2SIngo Weinhold	int32		elementCount;
101c3a3ddf2SIngo Weinhold	int32		fieldSize;
102c3a3ddf2SIngo Weinhold	int16		headerSize;
103c3a3ddf2SIngo Weinhold	char		name[1];
104c3a3ddf2SIngo Weinhold
105395fb089SIngo Weinhold	void* Data()
106c3a3ddf2SIngo Weinhold	{
107c3a3ddf2SIngo Weinhold		return (uint8*)this + headerSize;
108c3a3ddf2SIngo Weinhold	}
109c3a3ddf2SIngo Weinhold
110395fb089SIngo Weinhold	bool HasFixedElementSize()
111395fb089SIngo Weinhold	{
112395fb089SIngo Weinhold		return elementSize >= 0;
113395fb089SIngo Weinhold	}
114c3a3ddf2SIngo Weinhold
115395fb089SIngo Weinhold	void* ElementAt(int32 index, int32* size)
116c3a3ddf2SIngo Weinhold	{
117c3a3ddf2SIngo Weinhold		if (index < 0 || index >= elementCount)
118c3a3ddf2SIngo Weinhold			return NULL;
119395fb089SIngo Weinhold		uint8* data = (uint8*)this + headerSize;
120c3a3ddf2SIngo Weinhold		if (HasFixedElementSize()) {
121c3a3ddf2SIngo Weinhold			*size = elementSize;
122c3a3ddf2SIngo Weinhold			return data + elementSize * index;
123c3a3ddf2SIngo Weinhold		}
124c3a3ddf2SIngo Weinhold		// non-fixed element size: we need to iterate
125395fb089SIngo Weinhold		FieldValueHeader* valueHeader = (FieldValueHeader*)data;
126c3a3ddf2SIngo Weinhold		for (int i = 0; i < index; i++)
127c3a3ddf2SIngo Weinhold			valueHeader = valueHeader->NextFieldValueHeader();
128c3a3ddf2SIngo Weinhold		*size = valueHeader->size;
129c3a3ddf2SIngo Weinhold		return valueHeader->Data();
130c3a3ddf2SIngo Weinhold	}
131c3a3ddf2SIngo Weinhold
132395fb089SIngo Weinhold	FieldHeader* NextFieldHeader()
133c3a3ddf2SIngo Weinhold	{
134c3a3ddf2SIngo Weinhold		return (FieldHeader*)_Align(this, fieldSize);
135c3a3ddf2SIngo Weinhold	}
136c3a3ddf2SIngo Weinhold};
137c3a3ddf2SIngo Weinhold
138395fb089SIngo Weinhold
139395fb089SIngo Weinhold// #pragma mark - KMessage
140395fb089SIngo Weinhold
141395fb089SIngo Weinhold
142c3a3ddf2SIngo WeinholdKMessage::KMessage()
143395fb089SIngo Weinhold	:
144395fb089SIngo Weinhold	fBuffer(NULL),
145395fb089SIngo Weinhold	fBufferCapacity(0),
146395fb089SIngo Weinhold	fFlags(0),
147395fb089SIngo Weinhold	fLastFieldOffset(0)
148c3a3ddf2SIngo Weinhold{
149c3a3ddf2SIngo Weinhold	Unset();
150c3a3ddf2SIngo Weinhold}
151c3a3ddf2SIngo Weinhold
152395fb089SIngo Weinhold
153c3a3ddf2SIngo WeinholdKMessage::KMessage(uint32 what)
154395fb089SIngo Weinhold	:
155395fb089SIngo Weinhold	fBuffer(NULL),
156395fb089SIngo Weinhold	fBufferCapacity(0),
157395fb089SIngo Weinhold	fFlags(0),
158395fb089SIngo Weinhold	fLastFieldOffset(0)
159c3a3ddf2SIngo Weinhold{
160c3a3ddf2SIngo Weinhold	Unset();
161c3a3ddf2SIngo Weinhold	SetWhat(what);
162c3a3ddf2SIngo Weinhold}
163c3a3ddf2SIngo Weinhold
164395fb089SIngo Weinhold
165c3a3ddf2SIngo WeinholdKMessage::~KMessage()
166c3a3ddf2SIngo Weinhold{
167c3a3ddf2SIngo Weinhold	Unset();
168c3a3ddf2SIngo Weinhold}
169c3a3ddf2SIngo Weinhold
170395fb089SIngo Weinhold
171c3a3ddf2SIngo Weinholdstatus_t
172c3a3ddf2SIngo WeinholdKMessage::SetTo(uint32 what, uint32 flags)
173c3a3ddf2SIngo Weinhold{
174c3a3ddf2SIngo Weinhold	// There are no flags interesting in this case at the moment.
175c3a3ddf2SIngo Weinhold	Unset();
176c3a3ddf2SIngo Weinhold	SetWhat(what);
177c3a3ddf2SIngo Weinhold	return B_OK;
178c3a3ddf2SIngo Weinhold}
179c3a3ddf2SIngo Weinhold
180395fb089SIngo Weinhold
181c3a3ddf2SIngo Weinholdstatus_t
182395fb089SIngo WeinholdKMessage::SetTo(void* buffer, int32 bufferSize, uint32 what, uint32 flags)
183c3a3ddf2SIngo Weinhold{
184c3a3ddf2SIngo Weinhold	Unset();
185dad63129SIngo Weinhold
186dad63129SIngo Weinhold	if (!buffer)
187c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
188dad63129SIngo Weinhold
189dad63129SIngo Weinhold	if (bufferSize < 0) {
190dad63129SIngo Weinhold		if (!(flags & KMESSAGE_INIT_FROM_BUFFER))
191dad63129SIngo Weinhold			return B_BAD_VALUE;
192dad63129SIngo Weinhold	} else if (bufferSize < (int)sizeof(Header))
193dad63129SIngo Weinhold		return B_BAD_VALUE;
194dad63129SIngo Weinhold
195c3a3ddf2SIngo Weinhold	// if read-only, we need to init from the buffer, too
1960d1fab52SIngo Weinhold	if ((flags & KMESSAGE_READ_ONLY) != 0
1970d1fab52SIngo Weinhold		&& (flags & KMESSAGE_INIT_FROM_BUFFER) == 0) {
198c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
1990d1fab52SIngo Weinhold	}
2000d1fab52SIngo Weinhold
2010d1fab52SIngo Weinhold	// if not initializing from the given buffer, cloning it doesn't make sense
2020d1fab52SIngo Weinhold	if ((flags & KMESSAGE_INIT_FROM_BUFFER) == 0
2030d1fab52SIngo Weinhold		&& (flags & KMESSAGE_CLONE_BUFFER) != 0) {
2040d1fab52SIngo Weinhold		return B_BAD_VALUE;
2050d1fab52SIngo Weinhold	}
206dad63129SIngo Weinhold
207c3a3ddf2SIngo Weinhold	fBuffer = buffer;
208c3a3ddf2SIngo Weinhold	fBufferCapacity = bufferSize;
209c3a3ddf2SIngo Weinhold	fFlags = flags;
210dad63129SIngo Weinhold
211c3a3ddf2SIngo Weinhold	status_t error = B_OK;
212c3a3ddf2SIngo Weinhold	if (flags & KMESSAGE_INIT_FROM_BUFFER)
213dad63129SIngo Weinhold		error = _InitFromBuffer(bufferSize < 0);
214c3a3ddf2SIngo Weinhold	else
215c3a3ddf2SIngo Weinhold		_InitBuffer(what);
216dad63129SIngo Weinhold
217c3a3ddf2SIngo Weinhold	if (error != B_OK)
218c3a3ddf2SIngo Weinhold		Unset();
219dad63129SIngo Weinhold
220c3a3ddf2SIngo Weinhold	return error;
221c3a3ddf2SIngo Weinhold}
222c3a3ddf2SIngo Weinhold
223395fb089SIngo Weinhold
224c3a3ddf2SIngo Weinholdstatus_t
2250d1fab52SIngo WeinholdKMessage::SetTo(const void* buffer, int32 bufferSize, uint32 flags)
226c3a3ddf2SIngo Weinhold{
227c3a3ddf2SIngo Weinhold	return SetTo(const_cast<void*>(buffer), bufferSize, 0,
2280d1fab52SIngo Weinhold		KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY | flags);
229c3a3ddf2SIngo Weinhold}
230c3a3ddf2SIngo Weinhold
231395fb089SIngo Weinhold
232c3a3ddf2SIngo Weinholdvoid
233c3a3ddf2SIngo WeinholdKMessage::Unset()
234c3a3ddf2SIngo Weinhold{
235c3a3ddf2SIngo Weinhold	// free buffer
236c3a3ddf2SIngo Weinhold	if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER))
237c3a3ddf2SIngo Weinhold		free(fBuffer);
238c3a3ddf2SIngo Weinhold	fBuffer = &fHeader;
239c3a3ddf2SIngo Weinhold	fBufferCapacity = sizeof(Header);
240c3a3ddf2SIngo Weinhold	_InitBuffer(0);
241c3a3ddf2SIngo Weinhold}
242c3a3ddf2SIngo Weinhold
243395fb089SIngo Weinhold
244c3a3ddf2SIngo Weinholdvoid
245c3a3ddf2SIngo WeinholdKMessage::SetWhat(uint32 what)
246c3a3ddf2SIngo Weinhold{
247c3a3ddf2SIngo Weinhold	_Header()->what = what;
248c3a3ddf2SIngo Weinhold}
249c3a3ddf2SIngo Weinhold
250395fb089SIngo Weinhold
251c3a3ddf2SIngo Weinholduint32
252c3a3ddf2SIngo WeinholdKMessage::What() const
253c3a3ddf2SIngo Weinhold{
254c3a3ddf2SIngo Weinhold	return _Header()->what;
255c3a3ddf2SIngo Weinhold}
256c3a3ddf2SIngo Weinhold
257395fb089SIngo Weinhold
258395fb089SIngo Weinholdconst void*
259c3a3ddf2SIngo WeinholdKMessage::Buffer() const
260c3a3ddf2SIngo Weinhold{
261c3a3ddf2SIngo Weinhold	return fBuffer;
262c3a3ddf2SIngo Weinhold}
263c3a3ddf2SIngo Weinhold
264395fb089SIngo Weinhold
265c3a3ddf2SIngo Weinholdint32
266c3a3ddf2SIngo WeinholdKMessage::BufferCapacity() const
267c3a3ddf2SIngo Weinhold{
268c3a3ddf2SIngo Weinhold	return fBufferCapacity;
269c3a3ddf2SIngo Weinhold}
270c3a3ddf2SIngo Weinhold
271395fb089SIngo Weinhold
272c3a3ddf2SIngo Weinholdint32
273c3a3ddf2SIngo WeinholdKMessage::ContentSize() const
274c3a3ddf2SIngo Weinhold{
275c3a3ddf2SIngo Weinhold	return _Header()->size;
276c3a3ddf2SIngo Weinhold}
277c3a3ddf2SIngo Weinhold
278395fb089SIngo Weinhold
279c3a3ddf2SIngo Weinholdstatus_t
280395fb089SIngo WeinholdKMessage::AddField(const char* name, type_code type, int32 elementSize,
281c3a3ddf2SIngo Weinhold	KMessageField* field)
282c3a3ddf2SIngo Weinhold{
283c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE)
284c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
285c3a3ddf2SIngo Weinhold	KMessageField existingField;
286c3a3ddf2SIngo Weinhold	if (FindField(name, &existingField) == B_OK)
287c3a3ddf2SIngo Weinhold		return B_NAME_IN_USE;
288c3a3ddf2SIngo Weinhold	return _AddField(name, type, elementSize, field);
289c3a3ddf2SIngo Weinhold}
290c3a3ddf2SIngo Weinhold
291395fb089SIngo Weinhold
292c3a3ddf2SIngo Weinholdstatus_t
293395fb089SIngo WeinholdKMessage::FindField(const char* name, KMessageField* field) const
294c3a3ddf2SIngo Weinhold{
295c3a3ddf2SIngo Weinhold	return FindField(name, B_ANY_TYPE, field);
296c3a3ddf2SIngo Weinhold}
297c3a3ddf2SIngo Weinhold
298395fb089SIngo Weinhold
299c3a3ddf2SIngo Weinholdstatus_t
300395fb089SIngo WeinholdKMessage::FindField(const char* name, type_code type,
301395fb089SIngo Weinhold	KMessageField* field) const
302c3a3ddf2SIngo Weinhold{
303c3a3ddf2SIngo Weinhold	if (!name)
304c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
305c3a3ddf2SIngo Weinhold	KMessageField stackField;
306c3a3ddf2SIngo Weinhold	if (field)
307c3a3ddf2SIngo Weinhold		field->Unset();
308c3a3ddf2SIngo Weinhold	else
309c3a3ddf2SIngo Weinhold		field = &stackField;
310c3a3ddf2SIngo Weinhold	while (GetNextField(field) == B_OK) {
311c3a3ddf2SIngo Weinhold		if ((type == B_ANY_TYPE || field->TypeCode() == type)
312c3a3ddf2SIngo Weinhold			&& strcmp(name, field->Name()) == 0) {
313c3a3ddf2SIngo Weinhold			return B_OK;
314c3a3ddf2SIngo Weinhold		}
315c3a3ddf2SIngo Weinhold	}
316c3a3ddf2SIngo Weinhold	return B_NAME_NOT_FOUND;
317c3a3ddf2SIngo Weinhold}
318c3a3ddf2SIngo Weinhold
319395fb089SIngo Weinhold
320c3a3ddf2SIngo Weinholdstatus_t
321395fb089SIngo WeinholdKMessage::GetNextField(KMessageField* field) const
322c3a3ddf2SIngo Weinhold{
323c3a3ddf2SIngo Weinhold	if (!field || (field->Message() != NULL && field->Message() != this))
324c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
325395fb089SIngo Weinhold	FieldHeader* fieldHeader = field->_Header();
326c3a3ddf2SIngo Weinhold	FieldHeader* lastField = _LastFieldHeader();
327c3a3ddf2SIngo Weinhold	if (!lastField)
328c3a3ddf2SIngo Weinhold		return B_NAME_NOT_FOUND;
329c3a3ddf2SIngo Weinhold	if (fieldHeader == NULL) {
330c3a3ddf2SIngo Weinhold		fieldHeader = _FirstFieldHeader();
331c3a3ddf2SIngo Weinhold	} else {
332c3a3ddf2SIngo Weinhold		if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader()
333c3a3ddf2SIngo Weinhold			|| (uint8*)fieldHeader > (uint8*)lastField) {
334c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
335c3a3ddf2SIngo Weinhold		}
336c3a3ddf2SIngo Weinhold		if (fieldHeader == lastField)
337c3a3ddf2SIngo Weinhold			return B_NAME_NOT_FOUND;
338c3a3ddf2SIngo Weinhold		fieldHeader = fieldHeader->NextFieldHeader();
339c3a3ddf2SIngo Weinhold	}
340c3a3ddf2SIngo Weinhold	field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader));
341c3a3ddf2SIngo Weinhold	return B_OK;
342c3a3ddf2SIngo Weinhold}
343c3a3ddf2SIngo Weinhold
344a1209343SAxel Dörfler
345a1209343SAxel Dörflerbool
346a1209343SAxel DörflerKMessage::IsEmpty() const
347a1209343SAxel Dörfler{
348a1209343SAxel Dörfler	return _LastFieldHeader() == NULL;
349a1209343SAxel Dörfler}
350a1209343SAxel Dörfler
351a1209343SAxel Dörfler
352c3a3ddf2SIngo Weinholdstatus_t
353395fb089SIngo WeinholdKMessage::AddData(const char* name, type_code type, const void* data,
354c3a3ddf2SIngo Weinhold	int32 numBytes, bool isFixedSize)
355c3a3ddf2SIngo Weinhold{
356c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE || !data || numBytes < 0)
357c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
358c3a3ddf2SIngo Weinhold	KMessageField field;
359c3a3ddf2SIngo Weinhold	if (FindField(name, &field) == B_OK) {
360c3a3ddf2SIngo Weinhold		// field with that name already exists: check its type
361c3a3ddf2SIngo Weinhold		if (field.TypeCode() != type)
362c3a3ddf2SIngo Weinhold			return B_BAD_TYPE;
363c3a3ddf2SIngo Weinhold	} else {
364c3a3ddf2SIngo Weinhold		// no such field yet: add it
365c3a3ddf2SIngo Weinhold		status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1),
366c3a3ddf2SIngo Weinhold			&field);
367c3a3ddf2SIngo Weinhold		if (error != B_OK)
368c3a3ddf2SIngo Weinhold			return error;
369c3a3ddf2SIngo Weinhold	}
370c3a3ddf2SIngo Weinhold	return _AddFieldData(&field, data, numBytes, 1);
371c3a3ddf2SIngo Weinhold}
372c3a3ddf2SIngo Weinhold
373395fb089SIngo Weinhold
374c3a3ddf2SIngo Weinholdstatus_t
375395fb089SIngo WeinholdKMessage::AddArray(const char* name, type_code type, const void* data,
376c3a3ddf2SIngo Weinhold	int32 elementSize, int32 elementCount)
377c3a3ddf2SIngo Weinhold{
378c3a3ddf2SIngo Weinhold	if (!name || type == B_ANY_TYPE || !data || elementSize < 0
379c3a3ddf2SIngo Weinhold		|| elementCount < 0) {
380c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
381c3a3ddf2SIngo Weinhold	}
382c3a3ddf2SIngo Weinhold	KMessageField field;
383c3a3ddf2SIngo Weinhold	if (FindField(name, &field) == B_OK) {
384c3a3ddf2SIngo Weinhold		// field with that name already exists: check its type
385c3a3ddf2SIngo Weinhold		if (field.TypeCode() != type)
386c3a3ddf2SIngo Weinhold			return B_BAD_TYPE;
387c3a3ddf2SIngo Weinhold	} else {
388c3a3ddf2SIngo Weinhold		// no such field yet: add it
389c3a3ddf2SIngo Weinhold		status_t error = _AddField(name, type, elementSize, &field);
390c3a3ddf2SIngo Weinhold		if (error != B_OK)
391c3a3ddf2SIngo Weinhold			return error;
392c3a3ddf2SIngo Weinhold	}
393c3a3ddf2SIngo Weinhold	return _AddFieldData(&field, data, elementSize, elementCount);
394c3a3ddf2SIngo Weinhold}
395c3a3ddf2SIngo Weinhold
396dad63129SIngo Weinhold
397dad63129SIngo Weinholdstatus_t
398dad63129SIngo WeinholdKMessage::SetData(const char* name, type_code type, const void* data,
399dad63129SIngo Weinhold	int32 numBytes)
400dad63129SIngo Weinhold{
401dad63129SIngo Weinhold	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
402dad63129SIngo Weinhold		return B_NOT_ALLOWED;
403dad63129SIngo Weinhold
404dad63129SIngo Weinhold	KMessageField field;
405dad63129SIngo Weinhold
406dad63129SIngo Weinhold	if (FindField(name, &field) == B_OK) {
407dad63129SIngo Weinhold		// field already known
408dad63129SIngo Weinhold		if (field.TypeCode() != type || !field.HasFixedElementSize()
409dad63129SIngo Weinhold			|| field.ElementSize() != numBytes) {
410dad63129SIngo Weinhold			return B_BAD_VALUE;
411dad63129SIngo Weinhold		}
412dad63129SIngo Weinhold
413dad63129SIngo Weinhold		// if it has an element, just replace its value
414dad63129SIngo Weinhold		if (field.CountElements() > 0) {
415dad63129SIngo Weinhold			const void* element = field.ElementAt(0);
416dad63129SIngo Weinhold			memcpy(const_cast<void*>(element), data, numBytes);
417dad63129SIngo Weinhold			return B_OK;
418dad63129SIngo Weinhold		}
419dad63129SIngo Weinhold	} else {
420dad63129SIngo Weinhold		// no such field yet -- add it
421dad63129SIngo Weinhold		status_t error = _AddField(name, type, numBytes, &field);
422dad63129SIngo Weinhold		if (error != B_OK)
423dad63129SIngo Weinhold			return error;
424dad63129SIngo Weinhold	}
425dad63129SIngo Weinhold
426dad63129SIngo Weinhold	// we've got an empty field -- add the element
427dad63129SIngo Weinhold	return _AddFieldData(&field, data, numBytes, 1);
428dad63129SIngo Weinhold}
429dad63129SIngo Weinhold
430dad63129SIngo Weinhold
431c3a3ddf2SIngo Weinholdstatus_t
432395fb089SIngo WeinholdKMessage::FindData(const char* name, type_code type, const void** data,
433395fb089SIngo Weinhold	int32* numBytes) const
434c3a3ddf2SIngo Weinhold{
435c3a3ddf2SIngo Weinhold	return FindData(name, type, 0, data, numBytes);
436c3a3ddf2SIngo Weinhold}
437c3a3ddf2SIngo Weinhold
438395fb089SIngo Weinhold
439c3a3ddf2SIngo Weinholdstatus_t
440395fb089SIngo WeinholdKMessage::FindData(const char* name, type_code type, int32 index,
441395fb089SIngo Weinhold	const void** data, int32* numBytes) const
442c3a3ddf2SIngo Weinhold{
443c3a3ddf2SIngo Weinhold	if (!name || !data || !numBytes)
444c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
445c3a3ddf2SIngo Weinhold	KMessageField field;
446c3a3ddf2SIngo Weinhold	status_t error = FindField(name, type, &field);
447c3a3ddf2SIngo Weinhold	if (error != B_OK)
448c3a3ddf2SIngo Weinhold		return error;
449395fb089SIngo Weinhold	const void* foundData = field.ElementAt(index, numBytes);
450c3a3ddf2SIngo Weinhold	if (!foundData)
451c3a3ddf2SIngo Weinhold		return B_BAD_INDEX;
452c3a3ddf2SIngo Weinhold	if (data)
453c3a3ddf2SIngo Weinhold		*data = foundData;
454c3a3ddf2SIngo Weinhold	return B_OK;
455c3a3ddf2SIngo Weinhold}
456c3a3ddf2SIngo Weinhold
457395fb089SIngo Weinhold
458c3a3ddf2SIngo Weinholdteam_id
459c3a3ddf2SIngo WeinholdKMessage::Sender() const
460c3a3ddf2SIngo Weinhold{
461c3a3ddf2SIngo Weinhold	return _Header()->sender;
462c3a3ddf2SIngo Weinhold}
463c3a3ddf2SIngo Weinhold
464395fb089SIngo Weinhold
465c3a3ddf2SIngo Weinholdint32
466c3a3ddf2SIngo WeinholdKMessage::TargetToken() const
467c3a3ddf2SIngo Weinhold{
468c3a3ddf2SIngo Weinhold	return _Header()->targetToken;
469c3a3ddf2SIngo Weinhold}
470c3a3ddf2SIngo Weinhold
471395fb089SIngo Weinhold
472c3a3ddf2SIngo Weinholdport_id
473c3a3ddf2SIngo WeinholdKMessage::ReplyPort() const
474c3a3ddf2SIngo Weinhold{
475c3a3ddf2SIngo Weinhold	return _Header()->replyPort;
476c3a3ddf2SIngo Weinhold}
477c3a3ddf2SIngo Weinhold
478395fb089SIngo Weinhold
479c3a3ddf2SIngo Weinholdint32
480c3a3ddf2SIngo WeinholdKMessage::ReplyToken() const
481c3a3ddf2SIngo Weinhold{
482c3a3ddf2SIngo Weinhold	return _Header()->replyToken;
483c3a3ddf2SIngo Weinhold}
484c3a3ddf2SIngo Weinhold
485395fb089SIngo Weinhold
4864bef3723SAxel Dörflervoid
4874bef3723SAxel DörflerKMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
4884bef3723SAxel Dörfler	int32 replyToken, team_id senderTeam)
4894bef3723SAxel Dörfler{
4904bef3723SAxel Dörfler	Header* header = _Header();
4914bef3723SAxel Dörfler	header->sender = senderTeam;
4924bef3723SAxel Dörfler	header->targetToken = targetToken;
4934bef3723SAxel Dörfler	header->replyPort = replyPort;
4944bef3723SAxel Dörfler	header->replyToken = replyToken;
4954bef3723SAxel Dörfler	header->sender = senderTeam;
4964bef3723SAxel Dörfler}
497dad63129SIngo Weinhold
498395fb089SIngo Weinhold
499dad63129SIngo Weinhold#ifndef KMESSAGE_CONTAINER_ONLY
500dad63129SIngo Weinhold
501395fb089SIngo Weinhold
502c3a3ddf2SIngo Weinholdstatus_t
503c3a3ddf2SIngo WeinholdKMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
504c3a3ddf2SIngo Weinhold	int32 replyToken, bigtime_t timeout, team_id senderTeam)
505c3a3ddf2SIngo Weinhold{
506c3a3ddf2SIngo Weinhold	// get the sender team
5074bef3723SAxel Dörfler	if (senderTeam < 0) {
508c3a3ddf2SIngo Weinhold		thread_info info;
509c3a3ddf2SIngo Weinhold		status_t error = get_thread_info(find_thread(NULL), &info);
510c3a3ddf2SIngo Weinhold		if (error != B_OK)
511c3a3ddf2SIngo Weinhold			return error;
5124bef3723SAxel Dörfler
5134bef3723SAxel Dörfler		senderTeam = info.team;
514c3a3ddf2SIngo Weinhold	}
5154bef3723SAxel Dörfler
5164bef3723SAxel Dörfler	SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
5174bef3723SAxel Dörfler
518c3a3ddf2SIngo Weinhold	// send the message
519c3a3ddf2SIngo Weinhold	if (timeout < 0)
520c3a3ddf2SIngo Weinhold		return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
5214bef3723SAxel Dörfler
522c3a3ddf2SIngo Weinhold	return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
523c3a3ddf2SIngo Weinhold		B_RELATIVE_TIMEOUT, timeout);
524c3a3ddf2SIngo Weinhold}
525c3a3ddf2SIngo Weinhold
526395fb089SIngo Weinhold
527c3a3ddf2SIngo Weinholdstatus_t
528c3a3ddf2SIngo WeinholdKMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
529c3a3ddf2SIngo Weinhold	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
530c3a3ddf2SIngo Weinhold{
531c3a3ddf2SIngo Weinhold	// get the team the target port belongs to
532c3a3ddf2SIngo Weinhold	port_info portInfo;
533c3a3ddf2SIngo Weinhold	status_t error = get_port_info(targetPort, &portInfo);
534c3a3ddf2SIngo Weinhold	if (error != B_OK)
535c3a3ddf2SIngo Weinhold		return error;
536c3a3ddf2SIngo Weinhold	team_id targetTeam = portInfo.team;
537c3a3ddf2SIngo Weinhold	// allocate a reply port, if a reply is desired
538c3a3ddf2SIngo Weinhold	port_id replyPort = -1;
539c3a3ddf2SIngo Weinhold	if (reply) {
540c3a3ddf2SIngo Weinhold		// get our team
541c3a3ddf2SIngo Weinhold		team_id ourTeam = B_SYSTEM_TEAM;
542685645f9SPhilippe Houdoin		#ifndef _KERNEL_MODE
543c3a3ddf2SIngo Weinhold			if (targetTeam != B_SYSTEM_TEAM) {
544c3a3ddf2SIngo Weinhold				thread_info threadInfo;
545c3a3ddf2SIngo Weinhold				error = get_thread_info(find_thread(NULL), &threadInfo);
546c3a3ddf2SIngo Weinhold				if (error != B_OK)
547c3a3ddf2SIngo Weinhold					return error;
548c3a3ddf2SIngo Weinhold				ourTeam = threadInfo.team;
549c3a3ddf2SIngo Weinhold			}
550c3a3ddf2SIngo Weinhold		#endif
551c3a3ddf2SIngo Weinhold		// create the port
552c3a3ddf2SIngo Weinhold		replyPort = create_port(1, "KMessage reply port");
553c3a3ddf2SIngo Weinhold		if (replyPort < 0)
554c3a3ddf2SIngo Weinhold			return replyPort;
555c3a3ddf2SIngo Weinhold		// If the target team is not our team and not the kernel team either,
556c3a3ddf2SIngo Weinhold		// we transfer the ownership of the port to it, so we will not block
557c3a3ddf2SIngo Weinhold		if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM)
558c3a3ddf2SIngo Weinhold			set_port_owner(replyPort, targetTeam);
559c3a3ddf2SIngo Weinhold	}
560c3a3ddf2SIngo Weinhold	struct PortDeleter {
561c3a3ddf2SIngo Weinhold		PortDeleter(port_id port) : port(port) {}
562c3a3ddf2SIngo Weinhold		~PortDeleter()
563c3a3ddf2SIngo Weinhold		{
564c3a3ddf2SIngo Weinhold			if (port >= 0)
565c3a3ddf2SIngo Weinhold				delete_port(port);
566c3a3ddf2SIngo Weinhold		}
567c3a3ddf2SIngo Weinhold
568c3a3ddf2SIngo Weinhold		port_id	port;
569c3a3ddf2SIngo Weinhold	} replyPortDeleter(replyPort);
570c3a3ddf2SIngo Weinhold	// send the message
571c3a3ddf2SIngo Weinhold	error = SendTo(targetPort, targetToken, replyPort, 0,
572c3a3ddf2SIngo Weinhold		deliveryTimeout, senderTeam);
573c3a3ddf2SIngo Weinhold	if (error != B_OK)
574c3a3ddf2SIngo Weinhold		return error;
575c3a3ddf2SIngo Weinhold	// get the reply
576c3a3ddf2SIngo Weinhold	if (reply)
577c3a3ddf2SIngo Weinhold		return reply->ReceiveFrom(replyPort, replyTimeout);
578c3a3ddf2SIngo Weinhold	return B_OK;
579c3a3ddf2SIngo Weinhold}
580c3a3ddf2SIngo Weinhold
581395fb089SIngo Weinhold
582c3a3ddf2SIngo Weinholdstatus_t
583c3a3ddf2SIngo WeinholdKMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
584c3a3ddf2SIngo Weinhold	bigtime_t timeout, team_id senderTeam)
585c3a3ddf2SIngo Weinhold{
586c3a3ddf2SIngo Weinhold	if (!message)
587c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
588c3a3ddf2SIngo Weinhold	return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
589c3a3ddf2SIngo Weinhold		timeout, senderTeam);
590c3a3ddf2SIngo Weinhold}
591c3a3ddf2SIngo Weinhold
592395fb089SIngo Weinhold
593c3a3ddf2SIngo Weinholdstatus_t
594c3a3ddf2SIngo WeinholdKMessage::SendReply(KMessage* message, KMessage* reply,
595c3a3ddf2SIngo Weinhold	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
596c3a3ddf2SIngo Weinhold{
597c3a3ddf2SIngo Weinhold	if (!message)
598c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
599c3a3ddf2SIngo Weinhold	return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
600c3a3ddf2SIngo Weinhold		replyTimeout, senderTeam);
601c3a3ddf2SIngo Weinhold}
602c3a3ddf2SIngo Weinhold
6032d9a4022SIngo Weinhold
604c3a3ddf2SIngo Weinholdstatus_t
6052d9a4022SIngo WeinholdKMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
6062d9a4022SIngo Weinhold	port_message_info* messageInfo)
607c3a3ddf2SIngo Weinhold{
6082d9a4022SIngo Weinhold	port_message_info _messageInfo;
6092d9a4022SIngo Weinhold	if (messageInfo == NULL)
6102d9a4022SIngo Weinhold		messageInfo = &_messageInfo;
6112d9a4022SIngo Weinhold
612c3a3ddf2SIngo Weinhold	// get the port buffer size
6132d9a4022SIngo Weinhold	status_t error;
6142d9a4022SIngo Weinhold	if (timeout < 0) {
6152d9a4022SIngo Weinhold		error = get_port_message_info_etc(fromPort, messageInfo, 0, 0);
6162d9a4022SIngo Weinhold	} else {
6172d9a4022SIngo Weinhold		error = get_port_message_info_etc(fromPort, messageInfo,
6182d9a4022SIngo Weinhold			B_RELATIVE_TIMEOUT, timeout);
6192d9a4022SIngo Weinhold	}
6202d9a4022SIngo Weinhold	if (error != B_OK)
6212d9a4022SIngo Weinhold		return error;
6222d9a4022SIngo Weinhold
623c3a3ddf2SIngo Weinhold	// allocate a buffer
62444c3f5c1SMichael Lotz	uint8* buffer = (uint8*)MEMALIGN(kMessageBufferAlignment,
62544c3f5c1SMichael Lotz		messageInfo->size);
626c3a3ddf2SIngo Weinhold	if (!buffer)
627c3a3ddf2SIngo Weinhold		return B_NO_MEMORY;
6282d9a4022SIngo Weinhold
629c3a3ddf2SIngo Weinhold	// read the message
630c3a3ddf2SIngo Weinhold	int32 what;
6312d9a4022SIngo Weinhold	ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size,
632c3a3ddf2SIngo Weinhold		B_RELATIVE_TIMEOUT, 0);
6335839058aSIngo Weinhold	if (realSize < 0) {
6345839058aSIngo Weinhold		free(buffer);
635c3a3ddf2SIngo Weinhold		return realSize;
6365839058aSIngo Weinhold	}
6375839058aSIngo Weinhold	if (messageInfo->size != (size_t)realSize) {
6385839058aSIngo Weinhold		free(buffer);
639c3a3ddf2SIngo Weinhold		return B_ERROR;
6405839058aSIngo Weinhold	}
6412d9a4022SIngo Weinhold
642c3a3ddf2SIngo Weinhold	// init the message
6432d9a4022SIngo Weinhold	return SetTo(buffer, messageInfo->size, 0,
644c3a3ddf2SIngo Weinhold		KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
645c3a3ddf2SIngo Weinhold}
646c3a3ddf2SIngo Weinhold
647395fb089SIngo Weinhold
648dad63129SIngo Weinhold#endif	// !KMESSAGE_CONTAINER_ONLY
649dad63129SIngo Weinhold
650dad63129SIngo Weinhold
651e09769a9SIngo Weinholdvoid
652a1209343SAxel DörflerKMessage::Dump(void (*printFunc)(const char*, ...)) const
653e09769a9SIngo Weinhold{
654e09769a9SIngo Weinhold	Header* header = _Header();
655f31ab90aSIngo Weinhold	printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: %#"
656f31ab90aSIngo Weinhold		B_PRIx32 "\n", fBuffer, header->size, fBufferCapacity, fFlags);
657e09769a9SIngo Weinhold
658e09769a9SIngo Weinhold	KMessageField field;
659e09769a9SIngo Weinhold	while (GetNextField(&field) == B_OK) {
660e09769a9SIngo Weinhold		type_code type = field.TypeCode();
661a1209343SAxel Dörfler		uint32 bigEndianType = B_HOST_TO_BENDIAN_INT32(type);
662a1209343SAxel Dörfler		int nameSpacing = 17 - strlen(field.Name());
663a1209343SAxel Dörfler		if (nameSpacing < 0)
664a1209343SAxel Dörfler			nameSpacing = 0;
665a1209343SAxel Dörfler
666a1209343SAxel Dörfler		printFunc("  field: \"%s\"%*s (%.4s): ", field.Name(), nameSpacing, "",
667a1209343SAxel Dörfler			(char*)&bigEndianType);
668a1209343SAxel Dörfler
669a1209343SAxel Dörfler		if (field.CountElements() != 1)
670a1209343SAxel Dörfler			printFunc("\n");
671a1209343SAxel Dörfler
672dd84bf1dSRyan Leavengood		int32 size;
673a1209343SAxel Dörfler		for (int i = 0; const void* data = field.ElementAt(i, &size); i++) {
674a1209343SAxel Dörfler			if (field.CountElements() != 1)
675a1209343SAxel Dörfler				printFunc("    [%2d] ", i);
676a1209343SAxel Dörfler
677a1209343SAxel Dörfler			bool isIntType = false;
678a1209343SAxel Dörfler			int64 intData = 0;
679a1209343SAxel Dörfler			switch (type) {
680a1209343SAxel Dörfler				case B_BOOL_TYPE:
681a1209343SAxel Dörfler					printFunc("%s\n", (*(bool*)data ? "true" : "false"));
682a1209343SAxel Dörfler					break;
683a1209343SAxel Dörfler				case B_INT8_TYPE:
684a1209343SAxel Dörfler					isIntType = true;
685a1209343SAxel Dörfler					intData = *(int8*)data;
686a1209343SAxel Dörfler					break;
687a1209343SAxel Dörfler				case B_INT16_TYPE:
688a1209343SAxel Dörfler					isIntType = true;
689a1209343SAxel Dörfler					intData = *(int16*)data;
690a1209343SAxel Dörfler					break;
691a1209343SAxel Dörfler				case B_INT32_TYPE:
692a1209343SAxel Dörfler					isIntType = true;
693a1209343SAxel Dörfler					intData = *(int32*)data;
694a1209343SAxel Dörfler					break;
695a1209343SAxel Dörfler				case B_INT64_TYPE:
696a1209343SAxel Dörfler					isIntType = true;
697a1209343SAxel Dörfler					intData = *(int64*)data;
698a1209343SAxel Dörfler					break;
699a1209343SAxel Dörfler				case B_STRING_TYPE:
700a1209343SAxel Dörfler					printFunc("\"%s\"\n", (char*)data);
701a1209343SAxel Dörfler					break;
702a1209343SAxel Dörfler				default:
703a1209343SAxel Dörfler					printFunc("data at %p, %ld bytes\n", (char*)data, size);
704a1209343SAxel Dörfler					break;
705a1209343SAxel Dörfler			}
706a1209343SAxel Dörfler			if (isIntType)
707a1209343SAxel Dörfler				printFunc("%lld (0x%llx)\n", intData, intData);
708a1209343SAxel Dörfler		}
709e09769a9SIngo Weinhold	}
710e09769a9SIngo Weinhold}
711e09769a9SIngo Weinhold
712e09769a9SIngo Weinhold
713395fb089SIngo WeinholdKMessage::Header*
714c3a3ddf2SIngo WeinholdKMessage::_Header() const
715c3a3ddf2SIngo Weinhold{
716c3a3ddf2SIngo Weinhold	return (Header*)fBuffer;
717c3a3ddf2SIngo Weinhold}
718c3a3ddf2SIngo Weinhold
719395fb089SIngo Weinhold
720c3a3ddf2SIngo Weinholdint32
721c3a3ddf2SIngo WeinholdKMessage::_BufferOffsetFor(const void* data) const
722c3a3ddf2SIngo Weinhold{
723c3a3ddf2SIngo Weinhold	if (!data)
724c3a3ddf2SIngo Weinhold		return -1;
725395fb089SIngo Weinhold	return (uint8*)data - (uint8*)fBuffer;
726c3a3ddf2SIngo Weinhold}
727c3a3ddf2SIngo Weinhold
728395fb089SIngo Weinhold
729395fb089SIngo WeinholdKMessage::FieldHeader*
730c3a3ddf2SIngo WeinholdKMessage::_FirstFieldHeader() const
731c3a3ddf2SIngo Weinhold{
732c3a3ddf2SIngo Weinhold	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
733c3a3ddf2SIngo Weinhold}
734c3a3ddf2SIngo Weinhold
735395fb089SIngo Weinhold
736395fb089SIngo WeinholdKMessage::FieldHeader*
737c3a3ddf2SIngo WeinholdKMessage::_LastFieldHeader() const
738c3a3ddf2SIngo Weinhold{
739c3a3ddf2SIngo Weinhold	return _FieldHeaderForOffset(fLastFieldOffset);
740c3a3ddf2SIngo Weinhold}
741c3a3ddf2SIngo Weinhold
742395fb089SIngo Weinhold
743395fb089SIngo WeinholdKMessage::FieldHeader*
744c3a3ddf2SIngo WeinholdKMessage::_FieldHeaderForOffset(int32 offset) const
745c3a3ddf2SIngo Weinhold{
746c3a3ddf2SIngo Weinhold	if (offset <= 0 || offset >= _Header()->size)
747c3a3ddf2SIngo Weinhold		return NULL;
748c3a3ddf2SIngo Weinhold	return (FieldHeader*)((uint8*)fBuffer + offset);
749c3a3ddf2SIngo Weinhold}
750c3a3ddf2SIngo Weinhold
751395fb089SIngo Weinhold
752c3a3ddf2SIngo Weinholdstatus_t
753395fb089SIngo WeinholdKMessage::_AddField(const char* name, type_code type, int32 elementSize,
754395fb089SIngo Weinhold	KMessageField* field)
755c3a3ddf2SIngo Weinhold{
756395fb089SIngo Weinhold	FieldHeader* fieldHeader;
757c3a3ddf2SIngo Weinhold	int32 alignedSize;
758c3a3ddf2SIngo Weinhold	status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
759c3a3ddf2SIngo Weinhold		true, (void**)&fieldHeader, &alignedSize);
760c3a3ddf2SIngo Weinhold	if (error != B_OK)
761c3a3ddf2SIngo Weinhold		return error;
762c3a3ddf2SIngo Weinhold	fieldHeader->type = type;
763c3a3ddf2SIngo Weinhold	fieldHeader->elementSize = elementSize;
764c3a3ddf2SIngo Weinhold	fieldHeader->elementCount = 0;
765c3a3ddf2SIngo Weinhold	fieldHeader->fieldSize = alignedSize;
766c3a3ddf2SIngo Weinhold	fieldHeader->headerSize = alignedSize;
767c3a3ddf2SIngo Weinhold	strcpy(fieldHeader->name, name);
768c3a3ddf2SIngo Weinhold	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
769c3a3ddf2SIngo Weinhold	if (field)
770c3a3ddf2SIngo Weinhold		field->SetTo(this, _BufferOffsetFor(fieldHeader));
771c3a3ddf2SIngo Weinhold	return B_OK;
772c3a3ddf2SIngo Weinhold}
773c3a3ddf2SIngo Weinhold
774395fb089SIngo Weinhold
775c3a3ddf2SIngo Weinholdstatus_t
776395fb089SIngo WeinholdKMessage::_AddFieldData(KMessageField* field, const void* data,
777c3a3ddf2SIngo Weinhold	int32 elementSize, int32 elementCount)
778c3a3ddf2SIngo Weinhold{
779c3a3ddf2SIngo Weinhold	if (!field)
780c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
781395fb089SIngo Weinhold	FieldHeader* fieldHeader = field->_Header();
782c3a3ddf2SIngo Weinhold	FieldHeader* lastField = _LastFieldHeader();
783c3a3ddf2SIngo Weinhold	if (!fieldHeader || fieldHeader != lastField || !data
784c3a3ddf2SIngo Weinhold		|| elementSize < 0 || elementCount < 0) {
785c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
786c3a3ddf2SIngo Weinhold	}
787c3a3ddf2SIngo Weinhold	if (elementCount == 0)
788c3a3ddf2SIngo Weinhold		return B_OK;
789c3a3ddf2SIngo Weinhold	// fixed size values
790c3a3ddf2SIngo Weinhold	if (fieldHeader->HasFixedElementSize()) {
791c3a3ddf2SIngo Weinhold		if (elementSize != fieldHeader->elementSize)
792c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
793395fb089SIngo Weinhold		void* address;
794c3a3ddf2SIngo Weinhold		int32 alignedSize;
795c3a3ddf2SIngo Weinhold		status_t error = _AllocateSpace(elementSize * elementCount,
796c3a3ddf2SIngo Weinhold			(fieldHeader->elementCount == 0), false, &address, &alignedSize);
797c3a3ddf2SIngo Weinhold		if (error != B_OK)
798c3a3ddf2SIngo Weinhold			return error;
799c3a3ddf2SIngo Weinhold		fieldHeader = field->_Header();	// might have been relocated
800c3a3ddf2SIngo Weinhold		memcpy(address, data, elementSize * elementCount);
801c3a3ddf2SIngo Weinhold		fieldHeader->elementCount += elementCount;
802c3a3ddf2SIngo Weinhold		fieldHeader->fieldSize = (uint8*)address + alignedSize
803c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader;
804c3a3ddf2SIngo Weinhold		return B_OK;
805c3a3ddf2SIngo Weinhold	}
806c3a3ddf2SIngo Weinhold	// non-fixed size values
807c3a3ddf2SIngo Weinhold	// add the elements individually (TODO: Optimize!)
808c3a3ddf2SIngo Weinhold	int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
809c3a3ddf2SIngo Weinhold	int32 entrySize = valueHeaderSize + elementSize;
810c3a3ddf2SIngo Weinhold	for (int32 i = 0; i < elementCount; i++) {
811395fb089SIngo Weinhold		void* address;
812c3a3ddf2SIngo Weinhold		int32 alignedSize;
813c3a3ddf2SIngo Weinhold		status_t error = _AllocateSpace(entrySize, true, false, &address,
814c3a3ddf2SIngo Weinhold			&alignedSize);
815c3a3ddf2SIngo Weinhold		if (error != B_OK)
816c3a3ddf2SIngo Weinhold			return error;
817c3a3ddf2SIngo Weinhold		fieldHeader = field->_Header();	// might have been relocated
818395fb089SIngo Weinhold		FieldValueHeader* valueHeader = (FieldValueHeader*)address;
819c3a3ddf2SIngo Weinhold		valueHeader->size = elementSize;
820c3a3ddf2SIngo Weinhold		memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
821c3a3ddf2SIngo Weinhold			elementSize);
822c3a3ddf2SIngo Weinhold		fieldHeader->elementCount++;
823c3a3ddf2SIngo Weinhold		fieldHeader->fieldSize = (uint8*)address + alignedSize
824c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader;
825c3a3ddf2SIngo Weinhold	}
826c3a3ddf2SIngo Weinhold	return B_OK;
827c3a3ddf2SIngo Weinhold}
828c3a3ddf2SIngo Weinhold
829395fb089SIngo Weinhold
830c3a3ddf2SIngo Weinholdstatus_t
831dad63129SIngo WeinholdKMessage::_InitFromBuffer(bool sizeFromBuffer)
832c3a3ddf2SIngo Weinhold{
8330d1fab52SIngo Weinhold	if (fBuffer == NULL)
8340d1fab52SIngo Weinhold		return B_BAD_DATA;
8350d1fab52SIngo Weinhold
8360d1fab52SIngo Weinhold	// clone the buffer, if requested
837d0aa0748SMichael Lotz	if ((fFlags & KMESSAGE_CLONE_BUFFER) != 0 || _Align(fBuffer) != fBuffer) {
8380d1fab52SIngo Weinhold		if (sizeFromBuffer) {
8390d1fab52SIngo Weinhold			int32 size = fBufferCapacity;
8400d1fab52SIngo Weinhold			memcpy(&size, &_Header()->size, 4);
8410d1fab52SIngo Weinhold			fBufferCapacity = size;
8420d1fab52SIngo Weinhold		}
8430d1fab52SIngo Weinhold
84444c3f5c1SMichael Lotz		void* buffer = MEMALIGN(kMessageBufferAlignment, fBufferCapacity);
8450d1fab52SIngo Weinhold		if (buffer == NULL)
8460d1fab52SIngo Weinhold			return B_NO_MEMORY;
8470d1fab52SIngo Weinhold
8480d1fab52SIngo Weinhold		memcpy(buffer, fBuffer, fBufferCapacity);
849d0aa0748SMichael Lotz
8509a876461SMichael Lotz		if ((fFlags & KMESSAGE_OWNS_BUFFER) != 0)
851d0aa0748SMichael Lotz			free(fBuffer);
852d0aa0748SMichael Lotz
8530d1fab52SIngo Weinhold		fBuffer = buffer;
8540d1fab52SIngo Weinhold		fFlags &= ~(uint32)(KMESSAGE_READ_ONLY | KMESSAGE_CLONE_BUFFER);
8559a876461SMichael Lotz		fFlags |= KMESSAGE_OWNS_BUFFER;
8560d1fab52SIngo Weinhold	}
8570d1fab52SIngo Weinhold
8580d1fab52SIngo Weinhold	if (_Align(fBuffer) != fBuffer)
859c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
860d0aa0748SMichael Lotz
861395fb089SIngo Weinhold	Header* header = _Header();
862dad63129SIngo Weinhold
863dad63129SIngo Weinhold	if (sizeFromBuffer)
864dad63129SIngo Weinhold		fBufferCapacity = header->size;
865dad63129SIngo Weinhold
866dad63129SIngo Weinhold	if (fBufferCapacity < (int)sizeof(Header))
867dad63129SIngo Weinhold		return B_BAD_DATA;
868dad63129SIngo Weinhold
869dad63129SIngo Weinhold	// check header
870c3a3ddf2SIngo Weinhold	if (header->magic != kMessageHeaderMagic)
871c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
872c3a3ddf2SIngo Weinhold	if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
873c3a3ddf2SIngo Weinhold		return B_BAD_DATA;
874dad63129SIngo Weinhold
875c3a3ddf2SIngo Weinhold	// check the fields
876395fb089SIngo Weinhold	FieldHeader* fieldHeader = NULL;
877395fb089SIngo Weinhold	uint8* data = (uint8*)_FirstFieldHeader();
878c3a3ddf2SIngo Weinhold	int32 remainingBytes = (uint8*)fBuffer + header->size - data;
879c3a3ddf2SIngo Weinhold	while (remainingBytes > 0) {
880c3a3ddf2SIngo Weinhold		if (remainingBytes < (int)sizeof(FieldHeader))
881c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
882c3a3ddf2SIngo Weinhold		fieldHeader = (FieldHeader*)data;
883c3a3ddf2SIngo Weinhold		// check field header
884c3a3ddf2SIngo Weinhold		if (fieldHeader->type == B_ANY_TYPE)
885c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
886c3a3ddf2SIngo Weinhold		if (fieldHeader->elementCount < 0)
887c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
888c3a3ddf2SIngo Weinhold		if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
889c3a3ddf2SIngo Weinhold			|| fieldHeader->fieldSize > remainingBytes) {
890c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
891c3a3ddf2SIngo Weinhold		}
892c3a3ddf2SIngo Weinhold		if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
893c3a3ddf2SIngo Weinhold			|| fieldHeader->headerSize > fieldHeader->fieldSize) {
894c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
895c3a3ddf2SIngo Weinhold		}
896c3a3ddf2SIngo Weinhold		int32 maxNameLen = data + fieldHeader->headerSize
897c3a3ddf2SIngo Weinhold			- (uint8*)fieldHeader->name;
898c3a3ddf2SIngo Weinhold		int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
899c3a3ddf2SIngo Weinhold		if (nameLen == maxNameLen || nameLen == 0)
900c3a3ddf2SIngo Weinhold			return B_BAD_DATA;
901c3a3ddf2SIngo Weinhold		int32 fieldSize =  fieldHeader->headerSize;
902c3a3ddf2SIngo Weinhold		if (fieldHeader->HasFixedElementSize()) {
903c3a3ddf2SIngo Weinhold			// fixed element size
904c3a3ddf2SIngo Weinhold			int32 dataSize = fieldHeader->elementSize
905c3a3ddf2SIngo Weinhold				* fieldHeader->elementCount;
906c3a3ddf2SIngo Weinhold			fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
907c3a3ddf2SIngo Weinhold		} else {
908c3a3ddf2SIngo Weinhold			// non-fixed element size
909395fb089SIngo Weinhold			FieldValueHeader* valueHeader
910395fb089SIngo Weinhold				= (FieldValueHeader*)fieldHeader->Data();
911c3a3ddf2SIngo Weinhold			for (int32 i = 0; i < fieldHeader->elementCount; i++) {
912c3a3ddf2SIngo Weinhold				remainingBytes = (uint8*)fBuffer + header->size
913c3a3ddf2SIngo Weinhold					- (uint8*)valueHeader;
914c3a3ddf2SIngo Weinhold				if (remainingBytes < (int)sizeof(FieldValueHeader))
915c3a3ddf2SIngo Weinhold					return B_BAD_DATA;
916395fb089SIngo Weinhold				uint8* value = (uint8*)valueHeader->Data();
917c3a3ddf2SIngo Weinhold				remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
918c3a3ddf2SIngo Weinhold				if (remainingBytes < valueHeader->size)
919c3a3ddf2SIngo Weinhold					return B_BAD_DATA;
920c3a3ddf2SIngo Weinhold				fieldSize = value + valueHeader->size - data;
921c3a3ddf2SIngo Weinhold				valueHeader = valueHeader->NextFieldValueHeader();
922c3a3ddf2SIngo Weinhold			}
923c3a3ddf2SIngo Weinhold			if (fieldSize > fieldHeader->fieldSize)
924c3a3ddf2SIngo Weinhold				return B_BAD_DATA;
925c3a3ddf2SIngo Weinhold		}
926c3a3ddf2SIngo Weinhold		data = (uint8*)fieldHeader->NextFieldHeader();
927c3a3ddf2SIngo Weinhold		remainingBytes = (uint8*)fBuffer + header->size - data;
928c3a3ddf2SIngo Weinhold	}
929c3a3ddf2SIngo Weinhold	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
930c3a3ddf2SIngo Weinhold	return B_OK;
931c3a3ddf2SIngo Weinhold}
932c3a3ddf2SIngo Weinhold
933395fb089SIngo Weinhold
934c3a3ddf2SIngo Weinholdvoid
935c3a3ddf2SIngo WeinholdKMessage::_InitBuffer(uint32 what)
936c3a3ddf2SIngo Weinhold{
937395fb089SIngo Weinhold	Header* header = _Header();
938c3a3ddf2SIngo Weinhold	header->magic = kMessageHeaderMagic;
939c3a3ddf2SIngo Weinhold	header->size = sizeof(Header);
940c3a3ddf2SIngo Weinhold	header->what = what;
941c3a3ddf2SIngo Weinhold	header->sender = -1;
942c3a3ddf2SIngo Weinhold	header->targetToken = -1;
943c3a3ddf2SIngo Weinhold	header->replyPort = -1;
944c3a3ddf2SIngo Weinhold	header->replyToken = -1;
945c3a3ddf2SIngo Weinhold	fLastFieldOffset = 0;
946c3a3ddf2SIngo Weinhold}
947c3a3ddf2SIngo Weinhold
948395fb089SIngo Weinhold
949c3a3ddf2SIngo Weinholdvoid
950c3a3ddf2SIngo WeinholdKMessage::_CheckBuffer()
951c3a3ddf2SIngo Weinhold{
952c3a3ddf2SIngo Weinhold	int32 lastFieldOffset = fLastFieldOffset;
953dad63129SIngo Weinhold	if (_InitFromBuffer(false) != B_OK) {
954c3a3ddf2SIngo Weinhold		PANIC("internal data mangled");
955c3a3ddf2SIngo Weinhold	}
956c3a3ddf2SIngo Weinhold	if (fLastFieldOffset != lastFieldOffset) {
957c3a3ddf2SIngo Weinhold		PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
958c3a3ddf2SIngo Weinhold	}
959c3a3ddf2SIngo Weinhold}
960c3a3ddf2SIngo Weinhold
961395fb089SIngo Weinhold
962c3a3ddf2SIngo Weinholdstatus_t
963c3a3ddf2SIngo WeinholdKMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
964395fb089SIngo Weinhold	void** address, int32* alignedSize)
965c3a3ddf2SIngo Weinhold{
966c3a3ddf2SIngo Weinhold	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
967c3a3ddf2SIngo Weinhold		return B_NOT_ALLOWED;
96874c0424aSAxel Dörfler
969c3a3ddf2SIngo Weinhold	int32 offset = ContentSize();
970c3a3ddf2SIngo Weinhold	if (alignAddress)
971c3a3ddf2SIngo Weinhold		offset = _Align(offset);
972c3a3ddf2SIngo Weinhold	int32 newSize = offset + size;
973c3a3ddf2SIngo Weinhold	if (alignSize)
974c3a3ddf2SIngo Weinhold		newSize = _Align(newSize);
975c3a3ddf2SIngo Weinhold	// reallocate if necessary
976c3a3ddf2SIngo Weinhold	if (fBuffer == &fHeader) {
977c3a3ddf2SIngo Weinhold		int32 newCapacity = _CapacityFor(newSize);
97844c3f5c1SMichael Lotz		void* newBuffer = MEMALIGN(kMessageBufferAlignment, newCapacity);
979c3a3ddf2SIngo Weinhold		if (!newBuffer)
980c3a3ddf2SIngo Weinhold			return B_NO_MEMORY;
981c3a3ddf2SIngo Weinhold		fBuffer = newBuffer;
982c3a3ddf2SIngo Weinhold		fBufferCapacity = newCapacity;
983c3a3ddf2SIngo Weinhold		fFlags |= KMESSAGE_OWNS_BUFFER;
984c3a3ddf2SIngo Weinhold		memcpy(fBuffer, &fHeader, sizeof(fHeader));
985c3a3ddf2SIngo Weinhold	} else {
986c3a3ddf2SIngo Weinhold		if (newSize > fBufferCapacity) {
987c3a3ddf2SIngo Weinhold			// if we don't own the buffer, we can't resize it
98840287cbaSIngo Weinhold			if (!(fFlags & KMESSAGE_OWNS_BUFFER)) {
989ee87d51dSIngo Weinhold#if defined(_KERNEL_MODE) && 0
99040287cbaSIngo Weinhold				// optional debugging to find insufficiently sized KMessage
99140287cbaSIngo Weinhold				// buffers (e.g. for in-kernel notifications)
99240287cbaSIngo Weinhold				panic("KMessage: out of space: available: %" B_PRId32
99340287cbaSIngo Weinhold					", needed: %" B_PRId32 "\n", fBufferCapacity, newSize);
99440287cbaSIngo Weinhold#endif
995c3a3ddf2SIngo Weinhold				return B_BUFFER_OVERFLOW;
99640287cbaSIngo Weinhold			}
99740287cbaSIngo Weinhold
998c3a3ddf2SIngo Weinhold			int32 newCapacity = _CapacityFor(newSize);
999395fb089SIngo Weinhold			void* newBuffer = realloc(fBuffer, newCapacity);
1000c3a3ddf2SIngo Weinhold			if (!newBuffer)
1001c3a3ddf2SIngo Weinhold				return B_NO_MEMORY;
1002c3a3ddf2SIngo Weinhold			fBuffer = newBuffer;
1003c3a3ddf2SIngo Weinhold			fBufferCapacity = newCapacity;
1004c3a3ddf2SIngo Weinhold		}
1005c3a3ddf2SIngo Weinhold	}
1006c3a3ddf2SIngo Weinhold	_Header()->size = newSize;
1007c3a3ddf2SIngo Weinhold	*address = (char*)fBuffer + offset;
1008c3a3ddf2SIngo Weinhold	*alignedSize = newSize - offset;
1009c3a3ddf2SIngo Weinhold	return B_OK;
1010c3a3ddf2SIngo Weinhold}
1011c3a3ddf2SIngo Weinhold
1012395fb089SIngo Weinhold
1013c3a3ddf2SIngo Weinholdint32
1014c3a3ddf2SIngo WeinholdKMessage::_CapacityFor(int32 size)
1015c3a3ddf2SIngo Weinhold{
1016c3a3ddf2SIngo Weinhold	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
1017c3a3ddf2SIngo Weinhold		* kMessageReallocChunkSize;
1018c3a3ddf2SIngo Weinhold}
1019c3a3ddf2SIngo Weinhold
1020c3a3ddf2SIngo Weinhold
1021395fb089SIngo Weinhold// #pragma mark - KMessageField
1022395fb089SIngo Weinhold
1023c3a3ddf2SIngo Weinhold
1024c3a3ddf2SIngo WeinholdKMessageField::KMessageField()
1025395fb089SIngo Weinhold	:
1026395fb089SIngo Weinhold	fMessage(NULL),
1027395fb089SIngo Weinhold	fHeaderOffset(0)
1028c3a3ddf2SIngo Weinhold{
1029c3a3ddf2SIngo Weinhold}
1030c3a3ddf2SIngo Weinhold
1031395fb089SIngo Weinhold
1032c3a3ddf2SIngo Weinholdvoid
1033c3a3ddf2SIngo WeinholdKMessageField::Unset()
1034c3a3ddf2SIngo Weinhold{
1035c3a3ddf2SIngo Weinhold	fMessage = NULL;
1036c3a3ddf2SIngo Weinhold	fHeaderOffset = 0;
1037c3a3ddf2SIngo Weinhold}
1038c3a3ddf2SIngo Weinhold
1039395fb089SIngo Weinhold
1040395fb089SIngo WeinholdKMessage*
1041c3a3ddf2SIngo WeinholdKMessageField::Message() const
1042c3a3ddf2SIngo Weinhold{
1043c3a3ddf2SIngo Weinhold	return fMessage;
1044c3a3ddf2SIngo Weinhold}
1045c3a3ddf2SIngo Weinhold
1046395fb089SIngo Weinhold
1047395fb089SIngo Weinholdconst char*
1048c3a3ddf2SIngo WeinholdKMessageField::Name() const
1049c3a3ddf2SIngo Weinhold{
1050c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1051395fb089SIngo Weinhold	return header ? header->name : NULL;
1052c3a3ddf2SIngo Weinhold}
1053c3a3ddf2SIngo Weinhold
1054395fb089SIngo Weinhold
1055c3a3ddf2SIngo Weinholdtype_code
1056c3a3ddf2SIngo WeinholdKMessageField::TypeCode() const
1057c3a3ddf2SIngo Weinhold{
1058c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1059395fb089SIngo Weinhold	return header ? header->type : 0;
1060c3a3ddf2SIngo Weinhold}
1061c3a3ddf2SIngo Weinhold
1062395fb089SIngo Weinhold
1063c3a3ddf2SIngo Weinholdbool
1064c3a3ddf2SIngo WeinholdKMessageField::HasFixedElementSize() const
1065c3a3ddf2SIngo Weinhold{
1066c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1067395fb089SIngo Weinhold	return header ? header->HasFixedElementSize() : false;
1068c3a3ddf2SIngo Weinhold}
1069c3a3ddf2SIngo Weinhold
1070395fb089SIngo Weinhold
1071c3a3ddf2SIngo Weinholdint32
1072c3a3ddf2SIngo WeinholdKMessageField::ElementSize() const
1073c3a3ddf2SIngo Weinhold{
1074c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1075395fb089SIngo Weinhold	return header ? header->elementSize : -1;
1076c3a3ddf2SIngo Weinhold}
1077c3a3ddf2SIngo Weinhold
1078395fb089SIngo Weinhold
1079c3a3ddf2SIngo Weinholdstatus_t
1080395fb089SIngo WeinholdKMessageField::AddElement(const void* data, int32 size)
1081c3a3ddf2SIngo Weinhold{
1082c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1083c3a3ddf2SIngo Weinhold	if (!header || !data)
1084c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
1085c3a3ddf2SIngo Weinhold	if (size < 0) {
1086c3a3ddf2SIngo Weinhold		size = ElementSize();
1087c3a3ddf2SIngo Weinhold		if (size < 0)
1088c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
1089c3a3ddf2SIngo Weinhold	}
1090c3a3ddf2SIngo Weinhold	return fMessage->_AddFieldData(this, data, size, 1);
1091c3a3ddf2SIngo Weinhold}
1092c3a3ddf2SIngo Weinhold
1093395fb089SIngo Weinhold
1094c3a3ddf2SIngo Weinholdstatus_t
1095395fb089SIngo WeinholdKMessageField::AddElements(const void* data, int32 count, int32 elementSize)
1096c3a3ddf2SIngo Weinhold{
1097c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1098c3a3ddf2SIngo Weinhold	if (!header || !data || count < 0)
1099c3a3ddf2SIngo Weinhold		return B_BAD_VALUE;
1100c3a3ddf2SIngo Weinhold	if (elementSize < 0) {
1101c3a3ddf2SIngo Weinhold		elementSize = ElementSize();
1102c3a3ddf2SIngo Weinhold		if (elementSize < 0)
1103c3a3ddf2SIngo Weinhold			return B_BAD_VALUE;
1104c3a3ddf2SIngo Weinhold	}
1105c3a3ddf2SIngo Weinhold	return fMessage->_AddFieldData(this, data, elementSize, count);
1106c3a3ddf2SIngo Weinhold}
1107c3a3ddf2SIngo Weinhold
1108395fb089SIngo Weinhold
1109395fb089SIngo Weinholdconst void*
1110395fb089SIngo WeinholdKMessageField::ElementAt(int32 index, int32* size) const
1111c3a3ddf2SIngo Weinhold{
1112c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1113395fb089SIngo Weinhold	return header ? header->ElementAt(index, size) : NULL;
1114c3a3ddf2SIngo Weinhold}
1115c3a3ddf2SIngo Weinhold
1116395fb089SIngo Weinhold
1117c3a3ddf2SIngo Weinholdint32
1118c3a3ddf2SIngo WeinholdKMessageField::CountElements() const
1119c3a3ddf2SIngo Weinhold{
1120c3a3ddf2SIngo Weinhold	KMessage::FieldHeader* header = _Header();
1121395fb089SIngo Weinhold	return header ? header->elementCount : 0;
1122c3a3ddf2SIngo Weinhold}
1123c3a3ddf2SIngo Weinhold
1124395fb089SIngo Weinhold
1125c3a3ddf2SIngo Weinholdvoid
1126395fb089SIngo WeinholdKMessageField::SetTo(KMessage* message, int32 headerOffset)
1127c3a3ddf2SIngo Weinhold{
1128c3a3ddf2SIngo Weinhold	fMessage = message;
1129c3a3ddf2SIngo Weinhold	fHeaderOffset = headerOffset;
1130c3a3ddf2SIngo Weinhold}
1131c3a3ddf2SIngo Weinhold
1132395fb089SIngo Weinhold
1133c3a3ddf2SIngo WeinholdKMessage::FieldHeader*
1134c3a3ddf2SIngo WeinholdKMessageField::_Header() const
1135c3a3ddf2SIngo Weinhold{
1136395fb089SIngo Weinhold	return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL;
1137c3a3ddf2SIngo Weinhold}
1138