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