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