1/*
2* Copyright (c) 2023 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 JSON_UTILS_H
17#define JSON_UTILS_H
18
19#include <algorithm>
20#include <functional>
21#include <string>
22
23#include "nlohmann/json.hpp"
24
25#include "update_define.h"
26
27namespace OHOS::UpdateEngine {
28enum class JsonParseError {
29    ERR_OK = 0,
30    COMMOM_ERROR,
31    MISSING_PROP,
32    TYPE_ERROR
33};
34
35// 开发人员请使用该工具类封装的安全函数来获取json对象/数组,以及从json对象获取Value
36// 当前获取json对象/数组的封装使用的parse方法参数:string输入、无解析回调、解析失败不报异常
37class JsonUtils {
38public:
39    template <typename T>
40    static int32_t GetValueAndSetTo(const nlohmann::json &jsonObject, const std::string &key, T &value)
41    {
42        if (jsonObject.find(key) == jsonObject.end()) {
43            return CAST_INT(JsonParseError::MISSING_PROP);
44        }
45        if (!CheckType(jsonObject.at(key), value)) {
46            return CAST_INT(JsonParseError::TYPE_ERROR);
47        }
48        GetValue(jsonObject, key, value);
49        return CAST_INT(JsonParseError::ERR_OK);
50    }
51
52    static bool ParseAndGetJsonObject(const std::string &jsonStr, nlohmann::json &root)
53    {
54        root = nlohmann::json::parse(jsonStr, nullptr, false);
55        if (root.is_discarded() || !root.is_object()) {
56            return false;
57        }
58        return true;
59    }
60
61    static bool ParseAndGetJsonArray(const std::string &jsonStr, nlohmann::json &root)
62    {
63        root = nlohmann::json::parse(jsonStr, nullptr, false);
64        if (root.is_discarded() || !root.is_array()) {
65            return false;
66        }
67        return true;
68    }
69
70    static int32_t GetValueAndSetToArray(const nlohmann::json &jsonObject, const std::string &key,
71        nlohmann::json &value)
72    {
73        if (jsonObject.find(key) == jsonObject.end()) {
74            return CAST_INT(JsonParseError::MISSING_PROP);
75        }
76        if (!jsonObject.at(key).is_array()) {
77            return CAST_INT(JsonParseError::TYPE_ERROR);
78        }
79        jsonObject.at(key).get_to(value);
80        return CAST_INT(JsonParseError::ERR_OK);
81    }
82
83    static void SetJsonToVector(nlohmann::json &jsonObject, std::vector<std::string> &vector)
84    {
85        if (jsonObject.is_array()) {
86            for (nlohmann::json::iterator it = jsonObject.begin(); it != jsonObject.end(); ++it) {
87                if (!it.value().is_string()) {
88                    continue;
89                }
90                vector.push_back(static_cast<std::string>(it.value()));
91            }
92        }
93    }
94
95    static void SetJsonToVector(const nlohmann::json &jsonObject, const std::string &key,
96        std::vector<std::string> &vector)
97    {
98        if (!IsArray(jsonObject, key)) {
99            return;
100        }
101        nlohmann::json jsonArray = jsonObject.at(key);
102        SetJsonToVector(jsonArray, vector);
103    }
104
105    static bool IsArray(const nlohmann::json &jsonObject, const std::string &key)
106    {
107        if (jsonObject.find(key) == jsonObject.end()) {
108            return false;
109        }
110        return jsonObject.at(key).is_array();
111    }
112
113    template <typename T> static std::string StructToJsonStr(const T &value)
114    {
115        nlohmann::json jsonObj(value);
116        return jsonObj.dump();
117    }
118
119    template <typename T> static int32_t JsonStrToStruct(const std::string &jsonStr, T &value)
120    {
121        if (jsonStr.empty()) {
122            return CAST_INT(JsonParseError::COMMOM_ERROR);
123        }
124        nlohmann::json jsonObj = nlohmann::json::parse(jsonStr, nullptr, false);
125        if (!jsonObj.is_discarded() && CheckType(jsonObj, value)) {
126            value = jsonObj.get<T>();
127            return CAST_INT(JsonParseError::ERR_OK);
128        }
129        return CAST_INT(JsonParseError::TYPE_ERROR);
130    }
131
132private:
133    static bool CheckType(const nlohmann::json &jsonObject, std::string &value)
134    {
135        return jsonObject.is_string();
136    }
137
138    static bool CheckType(const nlohmann::json &jsonObject, int32_t &value)
139    {
140        return jsonObject.is_number();
141    }
142
143    static bool CheckType(const nlohmann::json &jsonObject, uint32_t &value)
144    {
145        return jsonObject.is_number();
146    }
147
148    static bool CheckType(const nlohmann::json &jsonObject, uint64_t &value)
149    {
150        return jsonObject.is_number();
151    }
152
153    static bool CheckType(const nlohmann::json &jsonObject, int64_t &value)
154    {
155        return jsonObject.is_number();
156    }
157
158    static bool CheckType(const nlohmann::json &jsonObject, double &value)
159    {
160        return jsonObject.is_number();
161    }
162
163    static bool CheckType(const nlohmann::json &jsonObject, bool &value)
164    {
165        return jsonObject.is_boolean();
166    }
167
168    template <typename T> static bool CheckType(const nlohmann::json &jsonObject, T &value)
169    {
170        return jsonObject.is_object();
171    }
172
173    template <typename T> static bool CheckType(const nlohmann::json &jsonObject, std::vector<T> &value)
174    {
175        return jsonObject.is_array();
176    }
177
178    template <typename T> static void GetValue(const nlohmann::json &jsonObject, const std::string &key, T &value)
179    {
180        jsonObject.at(key).get_to(value);
181    }
182
183    static void GetValue(const nlohmann::json &jsonObject, const std::string &key, std::vector<std::string> &value)
184    {
185        if (!IsArray(jsonObject, key)) {
186            return;
187        }
188        nlohmann::json jsonArray = jsonObject.at(key);
189        for (nlohmann::json::iterator it = jsonArray.begin(); it != jsonArray.end(); ++it) {
190            if (!it.value().is_string()) {
191                continue;
192            }
193            value.push_back(static_cast<std::string>(it.value()));
194        }
195    }
196};
197} // namespace OHOS::UpdateEngine
198#endif // JSON_UTILS_H