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