• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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