1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ref_uri_util.h"
17 
18 #include <meta/api/util.h>
19 #include <meta/base/ref_uri.h>
20 #include <meta/ext/resolve_helper.h>
21 #include <meta/interface/intf_containable.h>
22 #include <meta/interface/intf_container.h>
23 #include <meta/interface/intf_metadata.h>
24 #include <meta/interface/property/intf_property.h>
25 
META_BEGIN_NAMESPACE()26 META_BEGIN_NAMESPACE()
27 
28 static IObjectInstance::ConstPtr FindParentObject(const IObjectInstance::ConstPtr& obj)
29 {
30     auto containee = interface_cast<IContainable>(obj);
31     return containee ? interface_pointer_cast<IObjectInstance>(containee->GetParent()) : nullptr;
32 }
33 
FindRootObject(IObjectInstance::ConstPtr obj)34 static IObjectInstance::ConstPtr FindRootObject(IObjectInstance::ConstPtr obj)
35 {
36     auto prev = obj;
37     while ((obj = FindParentObject(obj))) {
38         prev = obj;
39     }
40     return prev;
41 }
42 
FindChildObject(const IObjectInstance::ConstPtr & obj,BASE_NS::string_view name)43 static IObjectInstance::ConstPtr FindChildObject(const IObjectInstance::ConstPtr& obj, BASE_NS::string_view name)
44 {
45     auto cont = interface_cast<IContainer>(obj);
46     return cont ? interface_pointer_cast<IObjectInstance>(cont->FindByName(name)) : nullptr;
47 }
48 
ResolvePropertySegment(BASE_NS::string_view propName,const IObjectInstance::Ptr & base,const RefUri & ref)49 static IObject::Ptr ResolvePropertySegment(
50     BASE_NS::string_view propName, const IObjectInstance::Ptr& base, const RefUri& ref)
51 {
52     // get the property and see if it contains object to continue the resolve
53     IMetadata* meta = interface_cast<IMetadata>(base);
54     if (!meta) {
55         return nullptr;
56     }
57 
58     auto prop = meta->GetPropertyByName(propName);
59     if (prop) {
60         if (ref.GetAbsoluteInterpretation() && ref.IsEmpty()) {
61             return interface_pointer_cast<IObject>(prop);
62         }
63         if (auto obj = GetPointer<IObjectInstance>(prop)) {
64             return obj->Resolve(ref);
65         }
66     }
67     return nullptr;
68 }
69 
ResolveSegment(const IObjectInstance::Ptr & base,RefUri ref)70 static IObject::Ptr ResolveSegment(const IObjectInstance::Ptr& base, RefUri ref)
71 {
72     auto node = ref.TakeFirstNode();
73     if (node.type == RefUri::Node::OBJECT) {
74         IObjectInstance::ConstPtr obj = (node.name == "..") ? FindParentObject(base) : FindChildObject(base, node.name);
75         return obj ? obj->Resolve(ref) : nullptr;
76     }
77 
78     if (node.type == RefUri::Node::SPECIAL) {
79         if (node.name != "@Context") {
80             return nullptr;
81         }
82         // ask the object to resolve the special segment
83         auto obj = base->Resolve<IObjectInstance>(RefUri::ContextUri());
84         return obj ? obj->Resolve(ref) : nullptr;
85     }
86 
87     return ResolvePropertySegment(node.name, base, ref);
88 }
89 
DefaultResolveObject(const IObjectInstance::Ptr & base,const RefUri & uri)90 IObject::Ptr DefaultResolveObject(const IObjectInstance::Ptr& base, const RefUri& uri)
91 {
92     if (!CheckValidResolve(base, uri)) {
93         return nullptr;
94     }
95 
96     RefUri ref { uri.RelativeUri() };
97     if (ref.IsEmpty()) {
98         return base;
99     }
100 
101     if (ref.StartsFromRoot()) {
102         ref.SetStartsFromRoot(false);
103         auto obj = FindRootObject(base);
104         return obj ? obj->Resolve(BASE_NS::move(ref)) : nullptr;
105     }
106 
107     return ResolveSegment(base, BASE_NS::move(ref));
108 }
109 
110 META_END_NAMESPACE()
111