• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include "json_input.h"
18 
19 #include <base/containers/vector.h>
20 #include <base/util/uid_util.h>
21 
22 #include <meta/base/namespace.h>
23 #include <meta/base/plugin.h>
24 #include <meta/base/ref_uri.h>
25 #include <meta/ext/minimal_object.h>
26 
27 #include "../ser_nodes.h"
28 
29 META_BEGIN_NAMESPACE()
30 
31 namespace Serialization {
32 
33 constexpr Version CURRENT_JSON_VERSION(2, 0);
34 constexpr int UID_SIZE = 36;
35 
ImportRef(const json::value & ref)36 ISerNode::Ptr JsonInput::ImportRef(const json::value& ref)
37 {
38     if (ref.is_string()) {
39         RefUri uri;
40         // check for backward compatibility
41         if (ref.string_.substr(0, 4) == "ref:") {
42             uri = RefUri(CORE_NS::json::unescape(ref.string_));
43         } else {
44             uri.SetBaseObjectUid(BASE_NS::StringToUid(CORE_NS::json::unescape(ref.string_)));
45         }
46         if (uri.IsValid()) {
47             return ISerNode::Ptr(new RefNode(BASE_NS::move(uri)));
48         }
49     }
50     return nullptr;
51 }
52 
ReadString(BASE_NS::string_view name,const json::value & value)53 BASE_NS::string ReadString(BASE_NS::string_view name, const json::value& value)
54 {
55     BASE_NS::string str;
56     if (const auto& v = value.find(name)) {
57         if (v->is_string()) {
58             str = CORE_NS::json::unescape(v->string_);
59         }
60     }
61     return str;
62 }
63 
ReadUid(BASE_NS::string_view name,const json::value & value)64 BASE_NS::Uid ReadUid(BASE_NS::string_view name, const json::value& value)
65 {
66     BASE_NS::Uid uid;
67     if (const auto& id = value.find(name)) {
68         if (id->is_string() && id->string_.size() == UID_SIZE) {
69             uid = BASE_NS::StringToUid(id->string_);
70         }
71     }
72     return uid;
73 }
74 
IsValidName(const BASE_NS::string_view & name)75 static bool IsValidName(const BASE_NS::string_view& name)
76 {
77     return !name.empty() && name[0] != '$';
78 }
79 
ImportObject(const json::value & value)80 ISerNode::Ptr JsonInput::ImportObject(const json::value& value)
81 {
82     BASE_NS::string className = ReadString(ClassNameName, value);
83     BASE_NS::string name = ReadString(NameName, value);
84     ObjectId oid = ReadUid(ObjectIdName, value);
85     InstanceId iid = ReadUid(InstanceIdName, value);
86 
87     BASE_NS::vector<NamedNode> members;
88     for (auto&& p : value.object_) {
89         auto key = RewriteReservedName(p.key);
90         if (!IsValidName(key)) {
91             // Skip empty keys and keys starting with $
92             continue;
93         }
94         auto n = Import(p.value);
95         if (!n) {
96             return nullptr;
97         }
98         members.push_back(NamedNode { key, BASE_NS::move(n) });
99     }
100     auto map = CreateShared<MapNode>(BASE_NS::move(members));
101     if (oid.IsValid()) {
102         return ISerNode::Ptr(
103             new ObjectNode(BASE_NS::move(className), BASE_NS::move(name), oid, iid, BASE_NS::move(map)));
104     }
105     return map;
106 }
107 
ImportArray(const json::value::array & arr)108 ISerNode::Ptr JsonInput::ImportArray(const json::value::array& arr)
109 {
110     BASE_NS::vector<ISerNode::Ptr> nodes;
111     nodes.reserve(arr.size());
112     for (auto&& value : arr) {
113         if (auto n = Import(value)) {
114             nodes.emplace_back(BASE_NS::move(n));
115         } else {
116             return nullptr;
117         }
118     }
119     return ISerNode::Ptr(new ArrayNode(BASE_NS::move(nodes)));
120 }
121 
Import(const json::value & value)122 ISerNode::Ptr JsonInput::Import(const json::value& value)
123 {
124     switch (value.type) {
125         case json::type::boolean:
126             return ISerNode::Ptr(new BoolNode(value.boolean_));
127         case json::type::floating_point:
128             return ISerNode::Ptr(new DoubleNode(value.float_));
129         case json::type::signed_int:
130             return ISerNode::Ptr(new IntNode(value.signed_));
131         case json::type::unsigned_int:
132             return ISerNode::Ptr(new UIntNode(value.unsigned_));
133         case json::type::string:
134             return ISerNode::Ptr(new StringNode(CORE_NS::json::unescape(value.string_)));
135         case json::type::object:
136             if (auto ref = value.find("$ref")) {
137                 return ImportRef(*ref);
138             }
139             return ImportObject(value);
140         case json::type::array:
141             return ImportArray(value.array_);
142         case json::type::null:
143             return ISerNode::Ptr(new NilNode);
144         default:
145             CORE_ASSERT_MSG(false, "Unhandled primitive type in Json input");
146             return nullptr;
147     }
148 }
149 
ReadMetadata(const json::value & value)150 bool JsonInput::ReadMetadata(const json::value& value)
151 {
152     if (auto v = value.find("version")) {
153         if (v->is_string()) {
154             auto ver = Version(CORE_NS::json::unescape(v->string_));
155             if (ver == Version()) {
156                 CORE_LOG_E(
157                     "Invalid file version: %s != %s", ver.ToString().c_str(), CURRENT_JSON_VERSION.ToString().c_str());
158                 return false;
159             }
160             version_ = ver;
161         }
162     }
163     if (auto v = value.find("exporter-version")) {
164         if (v->is_string()) {
165             exporterVersion_ = Version(CORE_NS::json::unescape(v->string_));
166         }
167     }
168     return true;
169 }
170 
ImportRootObject(const json::value & value)171 ISerNode::Ptr JsonInput::ImportRootObject(const json::value& value)
172 {
173     // see if we have meta data
174     if (auto v = value.find("$meta")) {
175         if (v->is_object() && !ReadMetadata(*v)) {
176             return nullptr;
177         }
178     }
179 
180     json::value root;
181 
182     // is it legacy version?
183     if (version_ == Version {}) {
184         version_ = Version { 1, 0 };
185         root = value;
186     } else if (auto v = value.find("$root")) {
187         if (v->is_object()) {
188             root = *v;
189         }
190     }
191     if (version_ < Version(2, 0)) {
192         SetMetaV1Compatibility();
193     }
194 
195     auto obj = Import(root);
196     return obj ? ISerNode::Ptr(new RootNode(obj, version_, exporterVersion_)) : nullptr;
197 }
198 
Process(BASE_NS::string_view data)199 ISerNode::Ptr JsonInput::Process(BASE_NS::string_view data)
200 {
201     ISerNode::Ptr res;
202     auto json = CORE_NS::json::parse(data.data());
203     if (json.is_object()) {
204         res = ImportRootObject(json);
205     }
206     return res;
207 }
208 
SetMetaV1Compatibility()209 void JsonInput::SetMetaV1Compatibility()
210 {
211     CORE_LOG_I("Enabling Meta Object Version 1 compatibility");
212     ClassNameName = "$name";
213     NameName = "";
214     RewriteReservedName = [](auto name) {
215         if (name == "$properties") {
216             return BASE_NS::string("__properties");
217         }
218         if (name == "$flags") {
219             return BASE_NS::string("__flags");
220         }
221         return BASE_NS::string(name);
222     };
223 }
224 
225 } // namespace Serialization
226 
227 META_END_NAMESPACE()
228