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