1 /*
2 * Copyright (c) 2022 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 #ifndef LOADER_JSON_UTIL_H
17 #define LOADER_JSON_UTIL_H
18
19 #include <cerrno>
20 #include <cstdlib>
21
22 #include <base/containers/array_view.h>
23 #include <base/containers/fixed_string.h>
24 #include <base/containers/string.h>
25 #include <base/containers/string_view.h>
26 #include <base/containers/vector.h>
27 #include <base/math/mathf.h>
28 #include <base/math/vector.h>
29 #include <base/util/uid.h>
30 #include <base/util/uid_util.h>
31 #include <core/json/json.h>
32 #include <core/namespace.h>
33
34 #include "util/json_util.h"
35 #include "util/log.h"
36 #include "util/string_util.h"
37
38 RENDER_BEGIN_NAMESPACE()
39 #define RENDER_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
40 template<typename BasicJsonType> \
41 inline bool FromJson(const BasicJsonType& j, ENUM_TYPE& e) \
42 { \
43 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
44 using StorageType = std::underlying_type_t<ENUM_TYPE>; \
45 struct Pair { \
46 constexpr Pair(StorageType v, const char* c) : value(v), name(c) \
47 {} \
48 constexpr Pair(ENUM_TYPE v, const char* c) : value(StorageType(v)), name(c) \
49 {} \
50 StorageType value; \
51 BASE_NS::string_view name; \
52 }; \
53 static constexpr Pair m[] = __VA_ARGS__; \
54 if (j.is_string()) { \
55 auto it = std::find_if(std::begin(m), std::end(m), \
56 [name = j.string_](const Pair& ej_pair) -> bool { return ej_pair.name == name; }); \
57 e = static_cast<ENUM_TYPE>(((it != std::end(m)) ? it : std::begin(m))->value); \
58 return true; \
59 } \
60 return false; \
61 }
62
63 template<class T>
64 struct JsonContext {
65 T data;
66 BASE_NS::string error;
67 };
68
ParseHex(BASE_NS::string_view str,uint32_t & val)69 inline bool ParseHex(BASE_NS::string_view str, uint32_t& val)
70 {
71 if (!str.empty()) {
72 errno = 0;
73 char* end;
74 constexpr const int hexadecimalBase = 16;
75 const unsigned long result = std::strtoul(str.data(), &end, hexadecimalBase);
76 if ((result <= UINT32_MAX) && (end == str.end().ptr()) && (errno == 0)) {
77 val = result;
78 return true;
79 }
80 }
81 val = 0U;
82 return false;
83 }
84
85 template<class JsonType, class T, BASE_NS::enable_if_t<BASE_NS::is_arithmetic_v<T>, bool> = true>
SafeGetJsonValue(const JsonType & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,T & output)86 bool SafeGetJsonValue(const JsonType& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
87 {
88 if (auto const pos = jsonData.find(element); pos) {
89 if (!FromJson(*pos, output)) {
90 error += element + ": expected number.\n";
91 return false;
92 }
93 }
94 return true;
95 }
96
97 template<class JsonType, class T, BASE_NS::enable_if_t<BASE_NS::is_convertible_v<T, BASE_NS::string_view>, bool> = true>
SafeGetJsonValue(const JsonType & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,T & output)98 bool SafeGetJsonValue(const JsonType& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
99 {
100 if (auto const pos = jsonData.find(element); pos) {
101 if (!FromJson(*pos, output)) {
102 error += element + ": expected string.\n";
103 return false;
104 }
105 }
106 return true;
107 }
108
109 template<class JsonType, class T>
SafeGetJsonEnum(const JsonType & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,T & output)110 bool SafeGetJsonEnum(const JsonType& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, T& output)
111 {
112 if (auto const pos = jsonData.find(element); pos) {
113 if (!FromJson(*pos, output)) {
114 error += Detail::INVALID_DATATYPE + element + " (" + CORE_NS::json::to_string(*pos) + ")\n";
115 return false;
116 }
117 }
118 return true;
119 }
120
121 template<class T, class JsonType>
SafeGetJsonBitfield(const JsonType & jData,const BASE_NS::string_view element,BASE_NS::string & error,uint32_t & output)122 bool SafeGetJsonBitfield(
123 const JsonType& jData, const BASE_NS::string_view element, BASE_NS::string& error, uint32_t& output)
124 {
125 if (auto const pos = jData.find(element); pos) {
126 output = 0;
127
128 if (pos->is_string()) {
129 for (const auto& field : StringUtil::Split(pos->string_, BASE_NS::string_view("|"))) {
130 if (const T value = Detail::Convert<T>(field); value != static_cast<T>(0x7FFFFFFF)) {
131 output |= value;
132 } else {
133 PLUGIN_LOG_W("Unknown bit value in \'%s\' \'%s\'", element.data(), BASE_NS::string(field).data());
134 }
135 }
136 } else {
137 error += Detail::INVALID_DATATYPE + element + " (" + CORE_NS::json::to_string(*pos) + ")\n";
138 return false;
139 }
140 }
141 return true;
142 }
143
144 template<class JsonType>
SafeGetJsonUidValue(const JsonType & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,BASE_NS::Uid & output)145 bool SafeGetJsonUidValue(
146 const JsonType& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, BASE_NS::Uid& output)
147 {
148 if (auto const pos = jsonData.find(element); pos) {
149 output = {};
150 if (pos->is_string()) {
151 constexpr size_t uidLength { to_string(BASE_NS::Uid {}).size() }; // default uid length
152 if (pos->string_.size() == uidLength) {
153 output = StringToUid(pos->string_);
154 return true;
155 } else {
156 error += element + ": size does not match uid.\n";
157 }
158 } else {
159 error += element + ": expected string as uid.\n";
160 }
161 }
162 return false;
163 }
164
165 template<class ArrayType, class JsonType, class ResultType>
ParseArray(JsonType const & jData,const char * element,BASE_NS::vector<ArrayType> & out,ResultType & res)166 void ParseArray(JsonType const& jData, const char* element, BASE_NS::vector<ArrayType>& out, ResultType& res)
167 {
168 if (auto const array = jData.find(element); array && array->is_array()) {
169 out.reserve(out.size() + array->array_.size());
170 Detail::Transform(array->array_, std::back_inserter(out), [&res](const JsonType& value) {
171 JsonContext<ArrayType> result;
172 FromJson(value, result);
173 if (!result.error.empty()) {
174 res.error += result.error;
175 }
176 return result.data;
177 });
178 }
179 }
180
181 template<class JsonType>
SafeGetJsonMask(const JsonType & jsonData,const BASE_NS::string_view element,BASE_NS::string & error,uint32_t & output)182 void SafeGetJsonMask(
183 const JsonType& jsonData, const BASE_NS::string_view element, BASE_NS::string& error, uint32_t& output)
184 {
185 if (const auto mask = jsonData.find(element); mask) {
186 if (mask->is_string() && ParseHex(mask->string_, output)) {
187 } else if (mask->is_number()) {
188 output = mask->template as_number<uint32_t>();
189 } else {
190 error += "Failed to read value: " + element + " (" + CORE_NS::json::to_string(*mask) + ')';
191 }
192 }
193 }
194 RENDER_END_NAMESPACE()
195
196 #endif // LOADER_JSON_UTIL_H
197