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:
BMessageWhatNodeChild(BMessageValueNode * parent,DataMember * member,Type * type)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
~BMessageWhatNodeChild()47 virtual ~BMessageWhatNodeChild()
48 {
49 fParent->ReleaseReference();
50 fType->ReleaseReference();
51 }
52
Name() const53 virtual const BString& Name() const
54 {
55 return fName;
56 }
57
GetType() const58 virtual Type* GetType() const
59 {
60 return fType;
61 }
62
Parent() const63 virtual ValueNode* Parent() const
64 {
65 return fParent;
66 }
67
ResolveLocation(ValueLoader * valueLoader,ValueLocation * & _location)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
BMessageValueNode(ValueNodeChild * nodeChild,Type * type)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
~BMessageValueNode()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*
GetType() const135 BMessageValueNode::GetType() const
136 {
137 return fType;
138 }
139
140
141 status_t
ResolvedLocationAndValue(ValueLoader * valueLoader,ValueLocation * & _location,Value * & _value)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
CreateChildren(TeamTypeInformation * info)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
CountChildren() const380 BMessageValueNode::CountChildren() const
381 {
382 return fChildren.CountItems();
383 }
384
385
386 ValueNodeChild*
ChildAt(int32 index) const387 BMessageValueNode::ChildAt(int32 index) const
388 {
389 return fChildren.ItemAt(index);
390 }
391
392
393 status_t
_GetTypeForTypeCode(TeamTypeInformation * info,type_code type,Type * & _type)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
_FindField(const char * name,type_code type,BMessage::field_header ** result) const523 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
_HashName(const char * name) const560 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
_FindDataLocation(const char * name,type_code type,int32 index,ValueLocation & location) const576 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
BMessageFieldNode(BMessageFieldNodeChild * child,BMessageValueNode * parent,const BString & name,type_code type,int32 count)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
~BMessageFieldNode()633 BMessageValueNode::BMessageFieldNode::~BMessageFieldNode()
634 {
635 fParent->ReleaseReference();
636 fType->ReleaseReference();
637 }
638
639
640 Type*
GetType() const641 BMessageValueNode::BMessageFieldNode::GetType() const
642 {
643 return fType;
644 }
645
646
647 status_t
CreateChildren(TeamTypeInformation * info)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
CountChildren() const680 BMessageValueNode::BMessageFieldNode::CountChildren() const
681 {
682 return fChildren.CountItems();
683 }
684
685 ValueNodeChild*
ChildAt(int32 index) const686 BMessageValueNode::BMessageFieldNode::ChildAt(int32 index) const
687 {
688 return fChildren.ItemAt(index);
689 }
690
691
692 status_t
ResolvedLocationAndValue(ValueLoader * loader,ValueLocation * & _location,Value * & _value)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
BMessageFieldNodeChild(BMessageValueNode * parent,Type * nodeType,const BString & name,type_code type,int32 count,int32 index)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
~BMessageFieldNodeChild()727 BMessageValueNode::BMessageFieldNodeChild::~BMessageFieldNodeChild()
728 {
729 fParent->ReleaseReference();
730 fType->ReleaseReference();
731 }
732
733
734 const BString&
Name() const735 BMessageValueNode::BMessageFieldNodeChild::Name() const
736 {
737 return fPresentationName;
738 }
739
740
741 Type*
GetType() const742 BMessageValueNode::BMessageFieldNodeChild::GetType() const
743 {
744 return fType;
745 }
746
747
748 ValueNode*
Parent() const749 BMessageValueNode::BMessageFieldNodeChild::Parent() const
750 {
751 return fParent;
752 }
753
754
755 bool
IsInternal() const756 BMessageValueNode::BMessageFieldNodeChild::IsInternal() const
757 {
758 return fFieldCount > 1 && fFieldIndex == -1;
759 }
760
761
762 status_t
CreateInternalNode(ValueNode * & _node)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
ResolveLocation(ValueLoader * valueLoader,ValueLocation * & _location)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