xref: /haiku/src/kits/debugger/value/value_nodes/BMessageValueNode.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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_RGB_COLOR_TYPE:
482 			typeName = "rgb_color";
483 			constraints.SetTypeKind(TYPE_COMPOUND);
484 			break;
485 
486 		case B_STRING_TYPE:
487 		{
488 			typeName = "char";
489 			constraints.SetTypeKind(TYPE_PRIMITIVE);
490 			Type* baseType = NULL;
491 			status_t result = info->LookupTypeByName(typeName, constraints,
492 				baseType);
493 			if (result != B_OK)
494 				return result;
495 			BReference<Type> typeReference(baseType, true);
496 			ArrayType* arrayType;
497 			result = baseType->CreateDerivedArrayType(0, kMaxStringSize, true,
498 				arrayType);
499 			if (result == B_OK)
500 				_type = arrayType;
501 
502 			return result;
503 			break;
504 		}
505 
506 		case B_POINTER_TYPE:
507 		default:
508 			typeName = "void*";
509 			constraints.SetTypeKind(TYPE_ADDRESS);
510 			break;
511 	}
512 
513 	return info->LookupTypeByName(typeName, constraints, _type);
514 }
515 
516 
517 status_t
518 BMessageValueNode::_FindField(const char* name, type_code type,
519 	BMessage::field_header** result) const
520 {
521 	if (name == NULL)
522 		return B_BAD_VALUE;
523 
524 	if (fHeader == NULL)
525 		return B_NO_INIT;
526 
527 	if (fHeader->field_count == 0 || fFields == NULL || fData == NULL)
528 		return B_NAME_NOT_FOUND;
529 
530 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
531 	int32 nextField = fHeader->hash_table[hash];
532 
533 	while (nextField >= 0) {
534 		BMessage::field_header* field = &fFields[nextField];
535 		if ((field->flags & FIELD_FLAG_VALID) == 0)
536 			break;
537 
538 		if (strncmp((const char*)(fData + field->offset), name,
539 			field->name_length) == 0) {
540 			if (type != B_ANY_TYPE && field->type != type)
541 				return B_BAD_TYPE;
542 
543 			*result = field;
544 			return B_OK;
545 		}
546 
547 		nextField = field->next_field;
548 	}
549 
550 	return B_NAME_NOT_FOUND;
551 }
552 
553 
554 uint32
555 BMessageValueNode::_HashName(const char* name) const
556 {
557 	char ch;
558 	uint32 result = 0;
559 
560 	while ((ch = *name++) != 0) {
561 		result = (result << 7) ^ (result >> 24);
562 		result ^= ch;
563 	}
564 
565 	result ^= result << 12;
566 	return result;
567 }
568 
569 
570 status_t
571 BMessageValueNode::_FindDataLocation(const char* name, type_code type,
572 	int32 index, ValueLocation& location) const
573 {
574 	BMessage::field_header* field = NULL;
575 	int32 offset = 0;
576 	int32 size = 0;
577 	status_t result = _FindField(name, type, &field);
578 	if (result != B_OK)
579 		return result;
580 
581 	if (index < 0 || (uint32)index >= field->count)
582 		return B_BAD_INDEX;
583 
584 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
585 		size = field->data_size / field->count;
586 		offset = field->offset + field->name_length + index * size;
587 	} else {
588 		offset = field->offset + field->name_length;
589 		uint8 *pointer = fData + field->offset + field->name_length;
590 		for (int32 i = 0; i < index; i++) {
591 			pointer += *(uint32*)pointer + sizeof(uint32);
592 			offset += *(uint32*)pointer + sizeof(uint32);
593 		}
594 
595 		size = *(uint32*)pointer;
596 		offset += sizeof(uint32);
597 	}
598 
599 	ValuePieceLocation piece;
600 	piece.SetToMemory(fDataLocation.ToUInt64() + offset);
601 	piece.SetSize(size);
602 	location.Clear();
603 	location.AddPiece(piece);
604 
605 	return B_OK;
606 }
607 
608 
609 // #pragma mark - BMessageValueNode::BMessageFieldNode
610 
611 
612 BMessageValueNode::BMessageFieldNode::BMessageFieldNode(
613 	BMessageFieldNodeChild *child, BMessageValueNode* parent,
614 	const BString &name, type_code type, int32 count)
615 	:
616 	ValueNode(child),
617 	fName(name),
618 	fType(parent->GetType()),
619 	fParent(parent),
620 	fFieldType(type),
621 	fFieldCount(count)
622 {
623 	fParent->AcquireReference();
624 	fType->AcquireReference();
625 }
626 
627 
628 BMessageValueNode::BMessageFieldNode::~BMessageFieldNode()
629 {
630 	fParent->ReleaseReference();
631 	fType->ReleaseReference();
632 }
633 
634 
635 Type*
636 BMessageValueNode::BMessageFieldNode::GetType() const
637 {
638 	return fType;
639 }
640 
641 
642 status_t
643 BMessageValueNode::BMessageFieldNode::CreateChildren(TeamTypeInformation* info)
644 {
645 	Type* type = NULL;
646 	status_t error = fParent->_GetTypeForTypeCode(info, fFieldType, type);
647 	if (error != B_OK)
648 		return error;
649 
650 	BReference<Type> typeRef(type, true);
651 	for (int32 i = 0; i < fFieldCount; i++) {
652 		BMessageFieldNodeChild* child = new(std::nothrow)
653 			BMessageFieldNodeChild(fParent, type, fName, fFieldType,
654 				fFieldCount, i);
655 
656 		if (child == NULL)
657 			return B_NO_MEMORY;
658 
659 		if (fContainer != NULL)
660 			child->SetContainer(fContainer);
661 
662 		fChildren.AddItem(child);
663 	}
664 
665 	fChildrenCreated = true;
666 
667 	if (fContainer != NULL)
668 		fContainer->NotifyValueNodeChildrenCreated(this);
669 
670 	return B_OK;
671 }
672 
673 
674 int32
675 BMessageValueNode::BMessageFieldNode::CountChildren() const
676 {
677 	return fChildren.CountItems();
678 }
679 
680 ValueNodeChild*
681 BMessageValueNode::BMessageFieldNode::ChildAt(int32 index) const
682 {
683 	return fChildren.ItemAt(index);
684 }
685 
686 
687 status_t
688 BMessageValueNode::BMessageFieldNode::ResolvedLocationAndValue(
689 	ValueLoader* loader, ValueLocation *& _location, Value*& _value)
690 {
691 	_location = NULL;
692 	_value = NULL;
693 
694 	return B_OK;
695 }
696 
697 
698 // #pragma mark - BMessageValueNode::BMessageFieldNodeChild
699 
700 
701 BMessageValueNode::BMessageFieldNodeChild::BMessageFieldNodeChild(
702 	BMessageValueNode* parent, Type* nodeType, const BString &name,
703 	type_code type, int32 count, int32 index)
704 	:
705 	ValueNodeChild(),
706 	fName(name),
707 	fPresentationName(name),
708 	fType(nodeType),
709 	fParent(parent),
710 	fFieldType(type),
711 	fFieldCount(count),
712 	fFieldIndex(index)
713 {
714 	fParent->AcquireReference();
715 	fType->AcquireReference();
716 
717 	if (fFieldIndex >= 0)
718 		fPresentationName.SetToFormat("[%" B_PRId32 "]", fFieldIndex);
719 }
720 
721 
722 BMessageValueNode::BMessageFieldNodeChild::~BMessageFieldNodeChild()
723 {
724 	fParent->ReleaseReference();
725 	fType->ReleaseReference();
726 }
727 
728 
729 const BString&
730 BMessageValueNode::BMessageFieldNodeChild::Name() const
731 {
732 	return fPresentationName;
733 }
734 
735 
736 Type*
737 BMessageValueNode::BMessageFieldNodeChild::GetType() const
738 {
739 	return fType;
740 }
741 
742 
743 ValueNode*
744 BMessageValueNode::BMessageFieldNodeChild::Parent() const
745 {
746 	return fParent;
747 }
748 
749 
750 bool
751 BMessageValueNode::BMessageFieldNodeChild::IsInternal() const
752 {
753 	return fFieldCount > 1 && fFieldIndex == -1;
754 }
755 
756 
757 status_t
758 BMessageValueNode::BMessageFieldNodeChild::CreateInternalNode(
759 	ValueNode*& _node)
760 {
761 	BMessageFieldNode* node = new(std::nothrow)
762 		BMessageFieldNode(this, fParent, fName, fFieldType, fFieldCount);
763 	if (node == NULL)
764 		return B_NO_MEMORY;
765 
766 	_node = node;
767 	return B_OK;
768 }
769 
770 
771 status_t
772 BMessageValueNode::BMessageFieldNodeChild::ResolveLocation(
773 	ValueLoader* valueLoader, ValueLocation*& _location)
774 {
775 	_location = new(std::nothrow)ValueLocation();
776 
777 	if (_location == NULL)
778 		return B_NO_MEMORY;
779 
780 	return fParent->_FindDataLocation(fName, fFieldType, fFieldIndex >= 0
781 		? fFieldIndex : 0, *_location);
782 }
783 
784 
785