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