1/*
2 * Copyright 2012, Rene Gollent, rene@gollent.com
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "BListValueNode.h"
8
9#include <new>
10
11#include <AutoDeleter.h>
12
13#include "AddressValueNode.h"
14#include "Architecture.h"
15#include "StringValue.h"
16#include "Tracing.h"
17#include "Type.h"
18#include "TypeLookupConstraints.h"
19#include "ValueLoader.h"
20#include "ValueLocation.h"
21#include "ValueNodeContainer.h"
22
23
24// maximum number of array elements to show by default
25static const int64 kMaxArrayElementCount = 20;
26
27
28//#pragma mark - BListValueNode::BListElementNodeChild
29
30
31class BListValueNode::BListElementNodeChild : public ValueNodeChild {
32public:
33								BListElementNodeChild(BListValueNode* parent,
34									int64 elementIndex, Type* type);
35	virtual						~BListElementNodeChild();
36
37	virtual	const BString&		Name() const { return fName; };
38	virtual	Type*				GetType() const { return fType; };
39	virtual	ValueNode*			Parent() const { return fParent; };
40
41	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
42									ValueLocation*& _location);
43
44private:
45	Type*						fType;
46	BListValueNode*				fParent;
47	int64						fElementIndex;
48	BString						fName;
49};
50
51
52BListValueNode::BListElementNodeChild::BListElementNodeChild(
53	BListValueNode* parent, int64 elementIndex, Type* type)
54	:
55	ValueNodeChild(),
56	fType(type),
57	fParent(parent),
58	fElementIndex(elementIndex),
59	fName()
60{
61	fType->AcquireReference();
62	fParent->AcquireReference();
63	fName.SetToFormat("[%" B_PRId64 "]", fElementIndex);
64}
65
66
67BListValueNode::BListElementNodeChild::~BListElementNodeChild()
68{
69	fType->ReleaseReference();
70	fParent->ReleaseReference();
71}
72
73
74status_t
75BListValueNode::BListElementNodeChild::ResolveLocation(
76	ValueLoader* valueLoader, ValueLocation*& _location)
77{
78	uint8 addressSize = valueLoader->GetArchitecture()->AddressSize();
79	ValueLocation* location = new(std::nothrow) ValueLocation();
80	if (location == NULL)
81		return B_NO_MEMORY;
82
83
84	uint64 listAddress = fParent->fDataLocation.ToUInt64();
85	listAddress += fElementIndex * addressSize;
86
87	ValuePieceLocation piece;
88	piece.SetToMemory(listAddress);
89	piece.SetSize(addressSize);
90	location->AddPiece(piece);
91
92	_location = location;
93	return B_OK;
94}
95
96
97//#pragma mark - BListItemCountNodeChild
98
99class BListValueNode::BListItemCountNodeChild : public ValueNodeChild {
100public:
101								BListItemCountNodeChild(BVariant location,
102									BListValueNode* parent, Type* type);
103	virtual						~BListItemCountNodeChild();
104
105	virtual	const BString&		Name() const { return fName; };
106	virtual	Type*				GetType() const { return fType; };
107	virtual	ValueNode*			Parent() const { return fParent; };
108
109	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
110									ValueLocation*& _location);
111
112private:
113	Type*						fType;
114	BListValueNode*				fParent;
115	BVariant					fLocation;
116	BString						fName;
117};
118
119
120BListValueNode::BListItemCountNodeChild::BListItemCountNodeChild(
121	BVariant location, BListValueNode* parent, Type* type)
122	:
123	ValueNodeChild(),
124	fType(type),
125	fParent(parent),
126	fLocation(location),
127	fName("Capacity")
128{
129	fType->AcquireReference();
130	fParent->AcquireReference();
131}
132
133
134BListValueNode::BListItemCountNodeChild::~BListItemCountNodeChild()
135{
136	fType->ReleaseReference();
137	fParent->ReleaseReference();
138}
139
140
141status_t
142BListValueNode::BListItemCountNodeChild::ResolveLocation(
143	ValueLoader* valueLoader, ValueLocation*& _location)
144{
145	ValueLocation* location = new(std::nothrow) ValueLocation();
146	if (location == NULL)
147		return B_NO_MEMORY;
148
149	ValuePieceLocation piece;
150	piece.SetToMemory(fLocation.ToUInt64());
151	piece.SetSize(sizeof(int32));
152	location->AddPiece(piece);
153
154	_location = location;
155	return B_OK;
156}
157
158
159//#pragma mark - BListValueNode
160
161BListValueNode::BListValueNode(ValueNodeChild* nodeChild,
162	Type* type)
163	:
164	ValueNode(nodeChild),
165	fType(type),
166	fLoader(NULL),
167	fItemCountType(NULL),
168	fItemCount(0)
169{
170	fType->AcquireReference();
171}
172
173
174BListValueNode::~BListValueNode()
175{
176	fType->ReleaseReference();
177	for (int32 i = 0; i < fChildren.CountItems(); i++)
178		fChildren.ItemAt(i)->ReleaseReference();
179
180	if (fItemCountType != NULL)
181		fItemCountType->ReleaseReference();
182
183	delete fLoader;
184}
185
186
187Type*
188BListValueNode::GetType() const
189{
190	return fType;
191}
192
193
194status_t
195BListValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
196	ValueLocation*& _location, Value*& _value)
197{
198	// get the location
199	ValueLocation* location = NodeChild()->Location();
200	if (location == NULL)
201		return B_BAD_VALUE;
202
203
204	// get the value type
205	type_code valueType;
206	if (valueLoader->GetArchitecture()->AddressSize() == 4) {
207		valueType = B_UINT32_TYPE;
208		TRACE_LOCALS("    -> 32 bit\n");
209	} else {
210		valueType = B_UINT64_TYPE;
211		TRACE_LOCALS("    -> 64 bit\n");
212	}
213
214	// load the value data
215
216	status_t error = B_OK;
217	_location = location;
218	_value = NULL;
219
220	ValueLocation* memberLocation = NULL;
221	CompoundType* baseType = dynamic_cast<CompoundType*>(fType);
222
223	if (baseType->CountTemplateParameters() != 0) {
224		// for BObjectList we need to walk up
225		// the hierarchy: BObjectList -> _PointerList_ -> BList
226		if (baseType->CountBaseTypes() == 0)
227			return B_BAD_DATA;
228
229		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
230			->GetType());
231		if (baseType == NULL || baseType->Name() != "_PointerList_")
232			return B_BAD_DATA;
233
234		if (baseType->CountBaseTypes() == 0)
235			return B_BAD_DATA;
236
237		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
238			->GetType());
239		if (baseType == NULL || baseType->Name() != "BList")
240			return B_BAD_DATA;
241
242	}
243
244	for (int32 i = 0; i < baseType->CountDataMembers(); i++) {
245		DataMember* member = baseType->DataMemberAt(i);
246		if (strcmp(member->Name(), "fObjectList") == 0) {
247			error = baseType->ResolveDataMemberLocation(member,
248				*location, memberLocation);
249			BReference<ValueLocation> locationRef(memberLocation, true);
250			if (error != B_OK) {
251				TRACE_LOCALS(
252					"BListValueNode::ResolvedLocationAndValue(): "
253					"failed to resolve location of header member: %s\n",
254					strerror(error));
255				return error;
256			}
257
258			error = valueLoader->LoadValue(memberLocation, valueType,
259				false, fDataLocation);
260			if (error != B_OK)
261				return error;
262		} else if (strcmp(member->Name(), "fItemCount") == 0) {
263			error = baseType->ResolveDataMemberLocation(member,
264				*location, memberLocation);
265			BReference<ValueLocation> locationRef(memberLocation, true);
266			if (error != B_OK) {
267				TRACE_LOCALS(
268					"BListValueNode::ResolvedLocationAndValue(): "
269					"failed to resolve location of header member: %s\n",
270					strerror(error));
271				return error;
272			}
273
274			fItemCountType = member->GetType();
275			fItemCountType->AcquireReference();
276
277			fItemCountLocation = memberLocation->PieceAt(0).address;
278
279			BVariant listSize;
280			error = valueLoader->LoadValue(memberLocation, valueType,
281				false, listSize);
282			if (error != B_OK)
283				return error;
284
285			fItemCount = listSize.ToInt32();
286			TRACE_LOCALS(
287				"BListValueNode::ResolvedLocationAndValue(): "
288				"detected list size %" B_PRId32 "\n",
289				fItemCount);
290		}
291		memberLocation = NULL;
292	}
293
294	if (fLoader == NULL) {
295		fLoader = new(std::nothrow)ValueLoader(*valueLoader);
296		if (fLoader == NULL)
297			return B_NO_MEMORY;
298	}
299
300	return B_OK;
301}
302
303
304status_t
305BListValueNode::CreateChildren()
306{
307	if (fChildrenCreated)
308		return B_OK;
309
310	if (fLocationResolutionState != B_OK)
311		return fLocationResolutionState;
312
313	if (fItemCountType != NULL) {
314		BListItemCountNodeChild* countChild = new(std::nothrow)
315			BListItemCountNodeChild(fItemCountLocation, this, fItemCountType);
316
317		if (countChild == NULL)
318			return B_NO_MEMORY;
319
320		countChild->SetContainer(fContainer);
321		fChildren.AddItem(countChild);
322	}
323
324	BReference<Type> addressTypeRef;
325	Type* type = NULL;
326	CompoundType* objectType = dynamic_cast<CompoundType*>(fType);
327	if (objectType->CountTemplateParameters() != 0) {
328		AddressType* addressType = NULL;
329		status_t result = objectType->TemplateParameterAt(0)->GetType()
330			->CreateDerivedAddressType(DERIVED_TYPE_POINTER, addressType);
331		if (result != B_OK)
332			return result;
333
334		type = addressType;
335		addressTypeRef.SetTo(type, true);
336	} else {
337		BString typeName;
338		TypeLookupConstraints constraints;
339		constraints.SetTypeKind(TYPE_ADDRESS);
340		constraints.SetBaseTypeName("void");
341		status_t result = fLoader->LookupTypeByName(typeName, constraints, type);
342		if (result != B_OK)
343			return result;
344	}
345
346	for (int32 i = 0; i < fItemCount && i < kMaxArrayElementCount; i++)
347	{
348		BListElementNodeChild* child =
349			new(std::nothrow) BListElementNodeChild(this, i, type);
350		if (child == NULL)
351			return B_NO_MEMORY;
352		child->SetContainer(fContainer);
353		fChildren.AddItem(child);
354	}
355
356	fChildrenCreated = true;
357
358	if (fContainer != NULL)
359		fContainer->NotifyValueNodeChildrenCreated(this);
360
361	return B_OK;
362}
363
364
365int32
366BListValueNode::CountChildren() const
367{
368	return fChildren.CountItems();
369}
370
371
372ValueNodeChild*
373BListValueNode::ChildAt(int32 index) const
374{
375	return fChildren.ItemAt(index);
376}
377