xref: /haiku/src/kits/debugger/value/value_nodes/BMessageValueNode.cpp (revision 6a2d53e7237764eab0c7b6d121772f26d636fb60)
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 
26 static const int64 kMaxStringSize = 64;
27 
28 
29 // #pragma mark - BMessageWhatNodeChild
30 
31 
32 class BMessageWhatNodeChild : public ValueNodeChild {
33 public:
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 
97 private:
98 	DataMember*			fMember;
99 	BString				fName;
100 	BMessageValueNode*	fParent;
101 	Type*				fType;
102 };
103 
104 
105 // #pragma mark - BMessageValueNode
106 
107 
108 BMessageValueNode::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 
122 BMessageValueNode::~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 
134 Type*
135 BMessageValueNode::GetType() const
136 {
137 	return fType;
138 }
139 
140 
141 status_t
142 BMessageValueNode::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 
326 status_t
327 BMessageValueNode::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 
379 int32
380 BMessageValueNode::CountChildren() const
381 {
382 	return fChildren.CountItems();
383 }
384 
385 
386 ValueNodeChild*
387 BMessageValueNode::ChildAt(int32 index) const
388 {
389 	return fChildren.ItemAt(index);
390 }
391 
392 
393 status_t
394 BMessageValueNode::_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 
522 status_t
523 BMessageValueNode::_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 
559 uint32
560 BMessageValueNode::_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 
575 status_t
576 BMessageValueNode::_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 
617 BMessageValueNode::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 
633 BMessageValueNode::BMessageFieldNode::~BMessageFieldNode()
634 {
635 	fParent->ReleaseReference();
636 	fType->ReleaseReference();
637 }
638 
639 
640 Type*
641 BMessageValueNode::BMessageFieldNode::GetType() const
642 {
643 	return fType;
644 }
645 
646 
647 status_t
648 BMessageValueNode::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 
679 int32
680 BMessageValueNode::BMessageFieldNode::CountChildren() const
681 {
682 	return fChildren.CountItems();
683 }
684 
685 ValueNodeChild*
686 BMessageValueNode::BMessageFieldNode::ChildAt(int32 index) const
687 {
688 	return fChildren.ItemAt(index);
689 }
690 
691 
692 status_t
693 BMessageValueNode::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 
706 BMessageValueNode::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 
727 BMessageValueNode::BMessageFieldNodeChild::~BMessageFieldNodeChild()
728 {
729 	fParent->ReleaseReference();
730 	fType->ReleaseReference();
731 }
732 
733 
734 const BString&
735 BMessageValueNode::BMessageFieldNodeChild::Name() const
736 {
737 	return fPresentationName;
738 }
739 
740 
741 Type*
742 BMessageValueNode::BMessageFieldNodeChild::GetType() const
743 {
744 	return fType;
745 }
746 
747 
748 ValueNode*
749 BMessageValueNode::BMessageFieldNodeChild::Parent() const
750 {
751 	return fParent;
752 }
753 
754 
755 bool
756 BMessageValueNode::BMessageFieldNodeChild::IsInternal() const
757 {
758 	return fFieldCount > 1 && fFieldIndex == -1;
759 }
760 
761 
762 status_t
763 BMessageValueNode::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 
776 status_t
777 BMessageValueNode::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