1/*
2 * Copyright 2011, Rene Gollent, rene@gollent.com
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "BMessageValueNode.h"
8
9#include <new>
10
11#include <AutoDeleter.h>
12#include <MessageAdapter.h>
13#include <MessagePrivate.h>
14
15#include "Architecture.h"
16#include "StringValue.h"
17#include "Tracing.h"
18#include "Type.h"
19#include "TypeLookupConstraints.h"
20#include "ValueLoader.h"
21#include "ValueLocation.h"
22#include "ValueNodeContainer.h"
23
24
25// #pragma mark - BMessageWhatNodeChild
26
27
28class BMessageWhatNodeChild : public ValueNodeChild {
29public:
30	BMessageWhatNodeChild(BMessageValueNode* parent, DataMember* member,
31		Type* type)
32		:
33		ValueNodeChild(),
34		fMember(member),
35		fName("what"),
36		fParent(parent),
37		fType(type)
38	{
39		fParent->AcquireReference();
40		fType->AcquireReference();
41	}
42
43	virtual ~BMessageWhatNodeChild()
44	{
45		fParent->ReleaseReference();
46		fType->ReleaseReference();
47	}
48
49	virtual const BString& Name() const
50	{
51		return fName;
52	}
53
54	virtual Type* GetType() const
55	{
56		return fType;
57	}
58
59	virtual ValueNode* Parent() const
60	{
61		return fParent;
62	}
63
64	virtual status_t ResolveLocation(ValueLoader* valueLoader,
65		ValueLocation*& _location)
66	{
67		ValueLocation* parentLocation = fParent->Location();
68		ValueLocation* location;
69		CompoundType* type = dynamic_cast<CompoundType*>(fParent->GetType());
70		status_t error = B_OK;
71		if (fParent->fIsFlatMessage) {
72			location = new ValueLocation();
73			if (location == NULL)
74				return B_NO_MEMORY;
75
76			ValuePieceLocation piece;
77			piece.SetToMemory(parentLocation->PieceAt(0).address
78				+ sizeof(uint32));
79			piece.SetSize(sizeof(uint32));
80			location->AddPiece(piece);
81		} else {
82			error = type->ResolveDataMemberLocation(fMember,
83				*parentLocation, location);
84		}
85
86		if (error != B_OK)
87			return error;
88
89		_location = location;
90		return B_OK;
91	}
92
93private:
94	DataMember*			fMember;
95	BString				fName;
96	BMessageValueNode*	fParent;
97	Type*				fType;
98};
99
100
101// #pragma mark - BMessageValueNode
102
103
104BMessageValueNode::BMessageValueNode(ValueNodeChild* nodeChild,
105	Type* type)
106	:
107	ValueNode(nodeChild),
108	fType(type),
109	fLoader(NULL),
110	fHeader(NULL),
111	fFields(NULL),
112	fData(NULL),
113	fIsFlatMessage(false)
114{
115	fType->AcquireReference();
116}
117
118
119BMessageValueNode::~BMessageValueNode()
120{
121	fType->ReleaseReference();
122	for (int32 i = 0; i < fChildren.CountItems(); i++)
123		fChildren.ItemAt(i)->ReleaseReference();
124
125	delete fLoader;
126	delete fHeader;
127	delete[] fFields;
128	delete[] fData;
129}
130
131
132Type*
133BMessageValueNode::GetType() const
134{
135	return fType;
136}
137
138
139status_t
140BMessageValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
141	ValueLocation*& _location, Value*& _value)
142{
143	fIsFlatMessage = dynamic_cast<BMessageFieldNodeChild*>(NodeChild())
144		!= NULL;
145
146	// get the location
147	ValueLocation* location = NodeChild()->Location();
148	if (location == NULL)
149		return B_BAD_VALUE;
150
151
152	// get the value type
153	type_code valueType;
154	if (valueLoader->GetArchitecture()->AddressSize() == 4) {
155		valueType = B_UINT32_TYPE;
156		TRACE_LOCALS("    -> 32 bit\n");
157	} else {
158		valueType = B_UINT64_TYPE;
159		TRACE_LOCALS("    -> 64 bit\n");
160	}
161
162	// load the value data
163
164	status_t error = B_OK;
165	_location = location;
166	_value = NULL;
167
168	ValueLocation* memberLocation = NULL;
169
170	BVariant headerAddress;
171	BVariant fieldAddress;
172	BVariant what;
173
174	CompoundType* baseType = dynamic_cast<CompoundType*>(fType);
175
176	if (fIsFlatMessage) {
177		headerAddress.SetTo(location->PieceAt(0).address);
178		fieldAddress.SetTo(headerAddress.ToUInt64()
179			+ sizeof(BMessage::message_header));
180	} else {
181		for (int32 i = 0; i < baseType->CountDataMembers(); i++) {
182			DataMember* member = baseType->DataMemberAt(i);
183			if (strcmp(member->Name(), "fHeader") == 0) {
184				error = baseType->ResolveDataMemberLocation(member,
185					*location, memberLocation);
186				BReference<ValueLocation> locationRef(memberLocation, true);
187				if (error != B_OK) {
188					TRACE_LOCALS(
189						"BMessageValueNode::ResolvedLocationAndValue(): "
190						"failed to resolve location of header member: %s\n",
191						strerror(error));
192					return error;
193				}
194
195				error = valueLoader->LoadValue(memberLocation, valueType,
196					false, headerAddress);
197				if (error != B_OK)
198					return error;
199			} else if (strcmp(member->Name(), "what") == 0) {
200				error = baseType->ResolveDataMemberLocation(member,
201					*location, memberLocation);
202				BReference<ValueLocation> locationRef(memberLocation, true);
203				if (error != B_OK) {
204					TRACE_LOCALS(
205						"BMessageValueNode::ResolvedLocationAndValue(): "
206						"failed to resolve location of header member: %s\n",
207							strerror(error));
208					return error;
209				}
210				error = valueLoader->LoadValue(memberLocation, valueType,
211					false, what);
212				if (error != B_OK)
213					return error;
214			} else if (strcmp(member->Name(), "fFields") == 0) {
215				error = baseType->ResolveDataMemberLocation(member,
216					*location, memberLocation);
217				BReference<ValueLocation> locationRef(memberLocation, true);
218				if (error != B_OK) {
219					TRACE_LOCALS(
220						"BMessageValueNode::ResolvedLocationAndValue(): "
221						"failed to resolve location of field member: %s\n",
222							strerror(error));
223					return error;
224				}
225				error = valueLoader->LoadValue(memberLocation, valueType,
226					false, fieldAddress);
227				if (error != B_OK)
228					return error;
229			} else if (strcmp(member->Name(), "fData") == 0) {
230				error = baseType->ResolveDataMemberLocation(member,
231					*location, memberLocation);
232				BReference<ValueLocation> locationRef(memberLocation, true);
233				if (error != B_OK) {
234					TRACE_LOCALS(
235						"BMessageValueNode::ResolvedLocationAndValue(): "
236						"failed to resolve location of data member: %s\n",
237							strerror(error));
238					return error;
239				}
240				error = valueLoader->LoadValue(memberLocation, valueType,
241					false, fDataLocation);
242				if (error != B_OK)
243					return error;
244			}
245			memberLocation = NULL;
246		}
247	}
248
249	fHeader = new(std::nothrow) BMessage::message_header();
250	if (fHeader == NULL)
251		return B_NO_MEMORY;
252	error = valueLoader->LoadRawValue(headerAddress, sizeof(
253		BMessage::message_header), fHeader);
254	TRACE_LOCALS("BMessage: Header Address: 0x%" B_PRIx64 ", result: %s\n",
255		headerAddress.ToUInt64(), strerror(error));
256	if (error != B_OK)
257		return error;
258
259	if (fHeader->format != MESSAGE_FORMAT_HAIKU
260		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0)
261		return B_NOT_A_MESSAGE;
262
263	if (fIsFlatMessage)
264		what.SetTo(fHeader->what);
265	else
266		fHeader->what = what.ToUInt32();
267
268	TRACE_LOCALS("BMessage: what: 0x%" B_PRIx32 ", result: %s\n",
269		what.ToUInt32(), strerror(error));
270
271	size_t fieldsSize = fHeader->field_count * sizeof(
272		BMessage::field_header);
273	if (fIsFlatMessage)
274		fDataLocation.SetTo(fieldAddress.ToUInt64() + fieldsSize);
275
276	size_t totalSize = sizeof(BMessage::message_header) + fieldsSize
277		+ fHeader->data_size;
278	uint8* messageBuffer = new(std::nothrow) uint8[totalSize];
279	if (messageBuffer == NULL)
280		return B_NO_MEMORY;
281
282	ArrayDeleter<uint8> deleter(messageBuffer);
283
284	memset(messageBuffer, 0, totalSize);
285	memcpy(messageBuffer, fHeader, sizeof(BMessage::message_header));
286	uint8* tempBuffer = messageBuffer + sizeof(BMessage::message_header);
287	if (fieldsSize > 0) {
288		fFields = new(std::nothrow)
289			BMessage::field_header[fHeader->field_count];
290		if (fFields == NULL)
291			return B_NO_MEMORY;
292
293		error = valueLoader->LoadRawValue(fieldAddress, fieldsSize,
294			fFields);
295		TRACE_LOCALS("BMessage: Field Header Address: 0x%" B_PRIx64
296			", result: %s\n",	headerAddress.ToUInt64(), strerror(error));
297		if (error != B_OK)
298			return error;
299
300		fData = new(std::nothrow) uint8[fHeader->data_size];
301		if (fData == NULL)
302			return B_NO_MEMORY;
303
304		error = valueLoader->LoadRawValue(fDataLocation, fHeader->data_size,
305			fData);
306		TRACE_LOCALS("BMessage: Data Address: 0x%" B_PRIx64
307			", result: %s\n",	fDataLocation.ToUInt64(), strerror(error));
308		if (error != B_OK)
309			return error;
310		memcpy(tempBuffer, fFields, fieldsSize);
311		tempBuffer += fieldsSize;
312		memcpy(tempBuffer, fData, fHeader->data_size);
313	}
314
315	error = fMessage.Unflatten((const char*)messageBuffer);
316	if (error != B_OK)
317		return error;
318
319	if (fLoader == NULL) {
320		fLoader = new(std::nothrow)ValueLoader(*valueLoader);
321		if (fLoader == NULL)
322			return B_NO_MEMORY;
323	}
324
325	return B_OK;
326}
327
328
329status_t
330BMessageValueNode::CreateChildren()
331{
332	DataMember* member = NULL;
333	CompoundType* messageType = dynamic_cast<CompoundType*>(fType);
334	for (int32 i = 0; i < messageType->CountDataMembers(); i++) {
335		member = messageType->DataMemberAt(i);
336		if (strcmp(member->Name(), "what") == 0) {
337			ValueNodeChild* whatNode
338				= new(std::nothrow) BMessageWhatNodeChild(this, member,
339					member->GetType());
340			if (whatNode == NULL)
341				return B_NO_MEMORY;
342
343			whatNode->SetContainer(fContainer);
344			fChildren.AddItem(whatNode);
345			break;
346		}
347	}
348
349	char* name;
350	type_code type;
351	int32 count;
352	Type* fieldType = NULL;
353	BReference<Type> typeRef;
354	for (int32 i = 0; fMessage.GetInfo(B_ANY_TYPE, i, &name, &type,
355		&count) == B_OK; i++) {
356		fieldType = NULL;
357
358		_GetTypeForTypeCode(type, fieldType);
359		if (fieldType != NULL)
360			typeRef.SetTo(fieldType, true);
361
362		BMessageFieldNodeChild* node = new(std::nothrow)
363			BMessageFieldNodeChild(this,
364				fieldType != NULL ? fieldType : fType, name, type,
365				count);
366		if (node == NULL)
367			return B_NO_MEMORY;
368
369		node->SetContainer(fContainer);
370		fChildren.AddItem(node);
371	}
372
373	fChildrenCreated = true;
374
375	if (fContainer != NULL)
376		fContainer->NotifyValueNodeChildrenCreated(this);
377
378	return B_OK;
379}
380
381
382int32
383BMessageValueNode::CountChildren() const
384{
385	return fChildren.CountItems();
386}
387
388
389ValueNodeChild*
390BMessageValueNode::ChildAt(int32 index) const
391{
392	return fChildren.ItemAt(index);
393}
394
395
396status_t
397BMessageValueNode::_GetTypeForTypeCode(type_code type,
398	Type*& _type)
399{
400	BString typeName;
401	TypeLookupConstraints constraints;
402
403	switch(type) {
404		case B_BOOL_TYPE:
405			typeName = "bool";
406			constraints.SetTypeKind(TYPE_PRIMITIVE);
407			break;
408
409		case B_INT8_TYPE:
410			typeName = "int8";
411			constraints.SetTypeKind(TYPE_TYPEDEF);
412			break;
413
414		case B_UINT8_TYPE:
415			typeName = "uint8";
416			constraints.SetTypeKind(TYPE_TYPEDEF);
417			break;
418
419		case B_INT16_TYPE:
420			typeName = "int16";
421			constraints.SetTypeKind(TYPE_TYPEDEF);
422			break;
423
424		case B_UINT16_TYPE:
425			typeName = "uint16";
426			constraints.SetTypeKind(TYPE_TYPEDEF);
427			break;
428
429		case B_INT32_TYPE:
430			typeName = "int32";
431			constraints.SetTypeKind(TYPE_TYPEDEF);
432			break;
433
434		case B_UINT32_TYPE:
435			typeName = "uint32";
436			constraints.SetTypeKind(TYPE_TYPEDEF);
437			break;
438
439		case B_INT64_TYPE:
440			typeName = "int64";
441			constraints.SetTypeKind(TYPE_TYPEDEF);
442			break;
443
444		case B_UINT64_TYPE:
445			typeName = "uint64";
446			constraints.SetTypeKind(TYPE_TYPEDEF);
447			break;
448
449		case B_FLOAT_TYPE:
450			typeName = "float";
451			constraints.SetTypeKind(TYPE_PRIMITIVE);
452			break;
453
454		case B_DOUBLE_TYPE:
455			typeName = "double";
456			constraints.SetTypeKind(TYPE_PRIMITIVE);
457			break;
458
459		case B_MESSAGE_TYPE:
460			typeName = "BMessage";
461			constraints.SetTypeKind(TYPE_COMPOUND);
462			break;
463
464		case B_MESSENGER_TYPE:
465			typeName = "BMessenger";
466			constraints.SetTypeKind(TYPE_COMPOUND);
467			break;
468
469		case B_POINT_TYPE:
470			typeName = "BPoint";
471			constraints.SetTypeKind(TYPE_COMPOUND);
472			break;
473
474		case B_POINTER_TYPE:
475			typeName = "";
476			constraints.SetTypeKind(TYPE_ADDRESS);
477			constraints.SetBaseTypeName("void");
478			break;
479
480		case B_RECT_TYPE:
481			typeName = "BRect";
482			constraints.SetTypeKind(TYPE_COMPOUND);
483			break;
484
485		case B_REF_TYPE:
486			typeName = "entry_ref";
487			constraints.SetTypeKind(TYPE_COMPOUND);
488			break;
489
490		case B_RGB_COLOR_TYPE:
491			typeName = "rgb_color";
492			constraints.SetTypeKind(TYPE_COMPOUND);
493			break;
494
495		case B_STRING_TYPE:
496			typeName = "";
497			constraints.SetTypeKind(TYPE_ARRAY);
498			constraints.SetBaseTypeName("char");
499			break;
500
501		default:
502			return B_BAD_VALUE;
503			break;
504	}
505
506	return fLoader->LookupTypeByName(typeName, constraints, _type);
507}
508
509
510status_t
511BMessageValueNode::_FindField(const char* name, type_code type,
512	BMessage::field_header** result) const
513{
514	if (name == NULL)
515		return B_BAD_VALUE;
516
517	if (fHeader == NULL)
518		return B_NO_INIT;
519
520	if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
521		return B_NAME_NOT_FOUND;
522
523	uint32 hash = _HashName(name) % fHeader->hash_table_size;
524	int32 nextField = fHeader->hash_table[hash];
525
526	while (nextField >= 0) {
527		BMessage::field_header* field = &fFields[nextField];
528		if ((field->flags & FIELD_FLAG_VALID) == 0)
529			break;
530
531		if (strncmp((const char*)(fData + field->offset), name,
532			field->name_length) == 0) {
533			if (type != B_ANY_TYPE && field->type != type)
534				return B_BAD_TYPE;
535
536			*result = field;
537			return B_OK;
538		}
539
540		nextField = field->next_field;
541	}
542
543	return B_NAME_NOT_FOUND;
544}
545
546
547uint32
548BMessageValueNode::_HashName(const char* name) const
549{
550	char ch;
551	uint32 result = 0;
552
553	while ((ch = *name++) != 0) {
554		result = (result << 7) ^ (result >> 24);
555		result ^= ch;
556	}
557
558	result ^= result << 12;
559	return result;
560}
561
562
563status_t
564BMessageValueNode::_FindDataLocation(const char* name, type_code type,
565	int32 index, ValueLocation& location) const
566{
567	BMessage::field_header* field = NULL;
568	int32 offset = 0;
569	int32 size = 0;
570	status_t result = _FindField(name, type, &field);
571	if (result != B_OK)
572		return result;
573
574	if (index < 0 || (uint32)index >= field->count)
575		return B_BAD_INDEX;
576
577	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
578		size = field->data_size / field->count;
579		offset = field->offset + field->name_length + index * size;
580	} else {
581		offset = field->offset + field->name_length;
582		uint8 *pointer = fData + field->offset + field->name_length;
583		for (int32 i = 0; i < index; i++) {
584			pointer += *(uint32*)pointer + sizeof(uint32);
585			offset += *(uint32*)pointer + sizeof(uint32);
586		}
587
588		size = *(uint32*)pointer;
589		offset += sizeof(uint32);
590	}
591
592	ValuePieceLocation piece;
593	piece.SetToMemory(fDataLocation.ToUInt64() + offset);
594	piece.SetSize(size);
595	location.Clear();
596	location.AddPiece(piece);
597
598	return B_OK;
599}
600
601
602// #pragma mark - BMessageValueNode::BMessageFieldNode
603
604
605BMessageValueNode::BMessageFieldNode::BMessageFieldNode(
606	BMessageFieldNodeChild *child, BMessageValueNode* parent,
607	const BString &name, type_code type, int32 count)
608	:
609	ValueNode(child),
610	fName(name),
611	fType(parent->GetType()),
612	fParent(parent),
613	fFieldType(type),
614	fFieldCount(count)
615{
616	fParent->AcquireReference();
617	fType->AcquireReference();
618}
619
620
621BMessageValueNode::BMessageFieldNode::~BMessageFieldNode()
622{
623	fParent->ReleaseReference();
624	fType->ReleaseReference();
625}
626
627
628Type*
629BMessageValueNode::BMessageFieldNode::GetType() const
630{
631	return fType;
632}
633
634
635status_t
636BMessageValueNode::BMessageFieldNode::CreateChildren()
637{
638	Type* type = NULL;
639	status_t error = fParent->_GetTypeForTypeCode(fFieldType, type);
640	if (error != B_OK)
641		return error;
642
643	BReference<Type> typeRef(type, true);
644	for (int32 i = 0; i < fFieldCount; i++) {
645		BMessageFieldNodeChild* child = new(std::nothrow)
646			BMessageFieldNodeChild(fParent, type, fName, fFieldType, fFieldCount, i);
647
648		if (child == NULL)
649			return B_NO_MEMORY;
650
651		if (fContainer != NULL)
652			child->SetContainer(fContainer);
653
654		fChildren.AddItem(child);
655	}
656
657	fChildrenCreated = true;
658
659	if (fContainer != NULL)
660		fContainer->NotifyValueNodeChildrenCreated(this);
661
662	return B_OK;
663}
664
665
666int32
667BMessageValueNode::BMessageFieldNode::CountChildren() const
668{
669	return fChildren.CountItems();
670}
671
672ValueNodeChild*
673BMessageValueNode::BMessageFieldNode::ChildAt(int32 index) const
674{
675	return fChildren.ItemAt(index);
676}
677
678
679status_t
680BMessageValueNode::BMessageFieldNode::ResolvedLocationAndValue(
681	ValueLoader* loader, ValueLocation *& _location, Value*& _value)
682{
683	_location = NULL;
684	_value = NULL;
685
686	return B_OK;
687}
688
689
690// #pragma mark - BMessageValueNode::BMessageFieldNodeChild
691
692
693BMessageValueNode::BMessageFieldNodeChild::BMessageFieldNodeChild(
694	BMessageValueNode* parent, Type* nodeType, const BString &name,
695	type_code type, int32 count, int32 index)
696	:
697	ValueNodeChild(),
698	fName(name),
699	fPresentationName(name),
700	fType(nodeType),
701	fParent(parent),
702	fFieldType(type),
703	fFieldCount(count),
704	fFieldIndex(index)
705{
706	fParent->AcquireReference();
707	fType->AcquireReference();
708
709	if (fFieldIndex >= 0)
710		fPresentationName.SetToFormat("[%" B_PRId32 "]", fFieldIndex);
711}
712
713
714BMessageValueNode::BMessageFieldNodeChild::~BMessageFieldNodeChild()
715{
716	fParent->ReleaseReference();
717	fType->ReleaseReference();
718}
719
720
721const BString&
722BMessageValueNode::BMessageFieldNodeChild::Name() const
723{
724	return fPresentationName;
725}
726
727
728Type*
729BMessageValueNode::BMessageFieldNodeChild::GetType() const
730{
731	return fType;
732}
733
734
735ValueNode*
736BMessageValueNode::BMessageFieldNodeChild::Parent() const
737{
738	return fParent;
739}
740
741
742bool
743BMessageValueNode::BMessageFieldNodeChild::IsInternal() const
744{
745	return fFieldCount > 1 && fFieldIndex == -1;
746}
747
748
749status_t
750BMessageValueNode::BMessageFieldNodeChild::CreateInternalNode(
751	ValueNode*& _node)
752{
753	BMessageFieldNode* node = new(std::nothrow)
754		BMessageFieldNode(this, fParent, fName, fFieldType, fFieldCount);
755	if (node == NULL)
756		return B_NO_MEMORY;
757
758	_node = node;
759	return B_OK;
760}
761
762
763status_t
764BMessageValueNode::BMessageFieldNodeChild::ResolveLocation(
765	ValueLoader* valueLoader, ValueLocation*& _location)
766{
767	_location = new(std::nothrow)ValueLocation();
768
769	if (_location == NULL)
770		return B_NO_MEMORY;
771
772	return fParent->_FindDataLocation(fName, fFieldType, fFieldIndex >= 0
773		? fFieldIndex : 0, *_location);
774}
775
776
777