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#include "json_utils.h"
17
18#include <climits>
19#include <fcntl.h>
20#include <fstream>
21#include <sstream>
22#include <unistd.h>
23#include <vector>
24
25#include "standby_service_log.h"
26
27namespace OHOS {
28namespace DevStandbyMgr {
29namespace {
30    constexpr uint32_t JSON_FORMAT = 4;
31}
32
33bool JsonUtils::LoadJsonValueFromContent(nlohmann::json& jsonValue, const std::string& content)
34{
35    if (content.empty()) {
36        STANDBYSERVICE_LOGE("content is empty");
37        return false;
38    }
39    jsonValue = nlohmann::json::parse(content, nullptr, false);
40    if (jsonValue.is_discarded()) {
41        STANDBYSERVICE_LOGE("failed to parse content");
42        return false;
43    }
44    if (!jsonValue.is_object()) {
45        STANDBYSERVICE_LOGE("the content is not an object");
46        return false;
47    }
48    return true;
49}
50
51bool JsonUtils::LoadJsonValueFromFile(nlohmann::json& jsonValue, const std::string& filePath)
52{
53    std::string content;
54    if (!GetFileContent(filePath, content)) {
55        STANDBYSERVICE_LOGE("failed to load content from %{public}s", filePath.c_str());
56        return false;
57    }
58    if (content.empty()) {
59        STANDBYSERVICE_LOGE("content of %{public}s is empty", filePath.c_str());
60        return false;
61    }
62    jsonValue = nlohmann::json::parse(content, nullptr, false);
63    if (jsonValue.is_discarded()) {
64        STANDBYSERVICE_LOGE("failed to parse content from %{public}s", filePath.c_str());
65        return false;
66    }
67    if (!jsonValue.is_object()) {
68        STANDBYSERVICE_LOGE("the content of %{public}s is not an object ", filePath.c_str());
69        return false;
70    }
71    return true;
72}
73
74bool JsonUtils::DumpJsonValueToFile(const nlohmann::json& jsonValue, const std::string& filePath)
75{
76    if (!CreateNodeFile(filePath)) {
77        STANDBYSERVICE_LOGE("create file failed.");
78        return false;
79    }
80    std::ofstream fout;
81    std::string realPath;
82    if (!GetRealPath(filePath, realPath)) {
83        STANDBYSERVICE_LOGE("get real file path: %{public}s failed", filePath.c_str());
84        return false;
85    }
86    fout.open(realPath, std::ios::out);
87    if (!fout.is_open()) {
88        STANDBYSERVICE_LOGE("open file: %{public}s failed.", filePath.c_str());
89        return false;
90    }
91    fout << jsonValue.dump(JSON_FORMAT).c_str() << std::endl;
92    fout.close();
93    return true;
94}
95
96bool JsonUtils::CreateNodeFile(const std::string &filePath)
97{
98    if (access(filePath.c_str(), F_OK) == ERR_OK) {
99        STANDBYSERVICE_LOGD("the standby service config file: %{public}s already exists.", filePath.c_str());
100        return true;
101    }
102    std::string fullpath {""};
103    if (!GetRealPath(filePath, fullpath)) {
104        STANDBYSERVICE_LOGD("the standby service config file: %{public}s not exists.", filePath.c_str());
105        fullpath = filePath;
106    }
107    int32_t fd = open(fullpath.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
108    if (fd < ERR_OK) {
109        STANDBYSERVICE_LOGE("Fail to open file: %{public}s", fullpath.c_str());
110        return false;
111    }
112    close(fd);
113    return true;
114}
115
116bool JsonUtils::GetInt32FromJsonValue(const nlohmann::json& jsonValue, const std::string& key, int32_t& value)
117{
118    if (jsonValue.empty() || key.empty()) {
119        return false;
120    }
121    if (jsonValue.contains(key) == 0 || !jsonValue.at(key).is_number_integer()) {
122        return false;
123    }
124    value =  jsonValue.at(key).get<int32_t>();
125    return true;
126}
127
128bool JsonUtils::GetBoolFromJsonValue(const nlohmann::json& jsonValue, const std::string& key, bool& value)
129{
130    if (jsonValue.empty() || key.empty()) {
131        return false;
132    }
133    if (jsonValue.contains(key) == 0 || !jsonValue.at(key).is_boolean()) {
134        return false;
135    }
136    value =  jsonValue.at(key).get<bool>();
137    return true;
138}
139
140bool JsonUtils::GetStringFromJsonValue(const nlohmann::json& jsonValue, const std::string& key, std::string& value)
141{
142    if (jsonValue.empty() || key.empty()) {
143        return false;
144    }
145    if (jsonValue.contains(key) == 0 || !jsonValue.at(key).is_string()) {
146        return false;
147    }
148    value =  jsonValue.at(key).get<std::string>();
149    return true;
150}
151
152bool JsonUtils::GetObjFromJsonValue(const nlohmann::json& jsonValue, const std::string& key, nlohmann::json& value)
153{
154    if (jsonValue.empty() || key.empty()) {
155        return false;
156    }
157    if (jsonValue.contains(key) == 0 || !jsonValue.at(key).is_object()) {
158        return false;
159    }
160    value =  jsonValue.at(key);
161    return true;
162}
163
164bool JsonUtils::GetArrayFromJsonValue(const nlohmann::json& jsonValue, const std::string& key, nlohmann::json& value)
165{
166    if (jsonValue.empty() || key.empty()) {
167        return false;
168    }
169    if (jsonValue.contains(key) == 0 || !jsonValue.at(key).is_array()) {
170        return false;
171    }
172    value =  jsonValue.at(key);
173    return true;
174}
175
176bool JsonUtils::GetStrArrFromJsonValue(const nlohmann::json& jsonValue, const std::string& key,
177    std::vector<std::string>& strArray)
178{
179    nlohmann::json strArrayValue;
180    if (!JsonUtils::GetArrayFromJsonValue(jsonValue, key, strArrayValue)) {
181        return false;
182    }
183    strArray.clear();
184    for (const auto &strItem : strArrayValue) {
185        if (!strItem.is_string()) {
186            return false;
187        }
188        strArray.emplace_back(strItem.get<std::string>());
189    }
190    return true;
191}
192
193bool JsonUtils::GetFileContent(const std::string& filePath, std::string& content)
194{
195    std::string fullPath;
196    if (!GetRealPath(filePath, fullPath)) {
197        return false;
198    }
199    STANDBYSERVICE_LOGD("full path of standby service config file is: %{public}s ", fullPath.c_str());
200    std::ifstream fin(fullPath);
201    if (!fin.is_open()) {
202        return false;
203    }
204    std::ostringstream ss;
205    ss << fin.rdbuf();
206    content = ss.str();
207    return true;
208}
209
210bool JsonUtils::GetRealPath(const std::string& partialPath, std::string& fullPath)
211{
212    char tmpPath[PATH_MAX] = {0};
213    if (partialPath.size() > PATH_MAX || !realpath(partialPath.c_str(), tmpPath)) {
214        return false;
215    }
216    fullPath = tmpPath;
217    return true;
218}
219
220std::vector<std::string> JsonUtils::SplitVersion(const std::string& versionStr, char versionDelim)
221{
222    std::vector<std::string> tokens;
223    std::stringstream ss(versionStr);
224    std::string token;
225    while (std::getline(ss, token, versionDelim)) {
226        if (!token.empty()) {
227            tokens.push_back(token);
228        }
229    }
230    return tokens;
231}
232}  // namespace DevStandbyMgr
233}  // namespace OHOS