Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "json_parser.h"
12 :
13 : #include <fstream>
14 : #include <sstream>
15 : #include <regex>
16 : #include <sys/stat.h>
17 : #include "mmpa/mmpa_api.h"
18 :
19 : namespace {
20 : const std::string ACL_JSON_DEFAULT_DEVICE = "defaultDevice";
21 : const std::string ACL_JSON_DEFAULT_DEVICE_ID = "default_device";
22 : constexpr int32_t DECIMAL = 10;
23 :
24 26135 : void CountDepth(const char_t ch, size_t &objDepth, size_t &maxObjDepth, size_t &arrayDepth, size_t &maxArrayDepth)
25 : {
26 26135 : switch (ch) {
27 454 : case '{': {
28 454 : ++objDepth;
29 454 : if (objDepth > maxObjDepth) {
30 441 : maxObjDepth = objDepth;
31 : }
32 454 : break;
33 : }
34 452 : case '}': {
35 452 : if (objDepth > 0) {
36 452 : --objDepth;
37 : }
38 452 : break;
39 : }
40 56 : case '[': {
41 56 : ++arrayDepth;
42 56 : if (arrayDepth > maxArrayDepth) {
43 55 : maxArrayDepth = arrayDepth;
44 : }
45 56 : break;
46 : }
47 56 : case ']': {
48 56 : if (arrayDepth > 0) {
49 56 : --arrayDepth;
50 : }
51 56 : break;
52 : }
53 25117 : default: {
54 25117 : return;
55 : }
56 : }
57 : }
58 : } // namespace
59 : namespace acl {
60 : // 配置文件最大字节数目10MBytes
61 : constexpr int64_t MAX_CONFIG_FILE_BYTE = 10 * 1024 * 1024;
62 : // 配置文件最大递归深度
63 : constexpr size_t MAX_CONFIG_OBJ_DEPTH = 10U;
64 : // 配置文件最大数组个数
65 : constexpr size_t MAX_CONFIG_ARRAY_DEPTH = 10U;
66 :
67 241 : void JsonParser::GetMaxNestedLayers(const char_t *const fileName, const size_t length,
68 : size_t &maxObjDepth, size_t &maxArrayDepth)
69 : {
70 241 : if (length <= 0) {
71 1 : ACL_LOG_INNER_ERROR("[Check][Length]the length of file %s must be larger than 0.", fileName);
72 1 : return;
73 : }
74 :
75 240 : char_t *pBuffer = new(std::nothrow) char_t[length];
76 240 : ACL_REQUIRES_NOT_NULL_RET_VOID(pBuffer);
77 480 : const std::shared_ptr<char_t> buffer(pBuffer, [](char_t *const deletePtr) { delete[] deletePtr; });
78 :
79 240 : std::ifstream fin(fileName);
80 240 : if (!fin.is_open()) {
81 1 : ACL_LOG_INNER_ERROR("[Open][File]read file %s failed.", fileName);
82 1 : return;
83 : }
84 239 : (void)fin.seekg(0, fin.beg);
85 239 : (void)fin.read(buffer.get(), static_cast<int64_t>(length));
86 :
87 239 : size_t arrayDepth = 0U;
88 239 : size_t objDepth = 0U;
89 26374 : for (size_t i = 0U; i < length; ++i) {
90 26136 : const char_t v = buffer.get()[i];
91 26136 : if (v == '\0') {
92 1 : fin.close();
93 1 : return;
94 : }
95 26135 : CountDepth(v, objDepth, maxObjDepth, arrayDepth, maxArrayDepth);
96 : }
97 238 : fin.close();
98 : }
99 :
100 251 : bool JsonParser::IsValidFileName(const char_t *const fileName)
101 : {
102 251 : char_t trustedPath[MMPA_MAX_PATH] = {};
103 251 : int32_t ret = mmRealPath(fileName, trustedPath, MMPA_MAX_PATH);
104 251 : if (ret != EN_OK) {
105 3 : const auto formatErrMsg = acl::AclGetErrorFormatMessage(mmGetErrorCode());
106 3 : ACL_LOG_INNER_ERROR("[Trans][RealPath]the file path %s is not like a real path, mmRealPath return %d, "
107 : "errMessage is %s", fileName, ret, formatErrMsg.c_str());
108 3 : return false;
109 : }
110 :
111 248 : mmStat_t pathStat;
112 248 : ret = mmStatGet(trustedPath, &pathStat);
113 248 : if (ret != EN_OK) {
114 0 : ACL_LOG_INNER_ERROR("[Get][FileStatus]cannot get config file status, which path is %s, "
115 : "maybe does not exist, return %d, errcode %d", trustedPath, ret, mmGetErrorCode());
116 0 : return false;
117 : }
118 248 : if ((pathStat.st_mode & S_IFMT) != S_IFREG) {
119 0 : ACL_LOG_INNER_ERROR("[Config][ConfigFile]config file is not a common file, which path is %s, "
120 : "mode is %u", trustedPath, pathStat.st_mode);
121 0 : return false;
122 : }
123 248 : if (pathStat.st_size > MAX_CONFIG_FILE_BYTE) {
124 0 : ACL_LOG_INNER_ERROR("[Check][FileSize]config file %s size[%ld] is larger than "
125 : "max config file Bytes[%ld]", trustedPath, pathStat.st_size, MAX_CONFIG_FILE_BYTE);
126 0 : return false;
127 : }
128 248 : return true;
129 : }
130 :
131 215 : aclError JsonParser::ParseJson(const char_t* const fileName, const char_t *const configStr, nlohmann::json &js)
132 : {
133 215 : if (strlen(configStr) == 0UL) {
134 11 : ACL_LOG_DEBUG("buffer is empty, no need parse json.");
135 11 : return ACL_SUCCESS;
136 : }
137 : try {
138 229 : js = nlohmann::json::parse(std::string(configStr));
139 5 : } catch (const nlohmann::json::exception &e) {
140 5 : ACL_LOG_INNER_ERROR("[Check][JsonFile]invalid json buffer, exception:%s.", e.what());
141 15 : acl::AclErrorLogManager::ReportInputError(
142 10 : acl::INVALID_FILE_MSG, std::vector<const char*>({"path", "reason"}),
143 10 : std::vector<const char*>({fileName, ("Parse exception: " + std::string(e.what())).c_str()}));
144 5 : return ACL_ERROR_PARSE_FILE;
145 : }
146 199 : ACL_LOG_DEBUG("parse json from buffer successfully.");
147 199 : return ACL_SUCCESS;
148 : }
149 :
150 252 : aclError JsonParser::GetConfigStrFromFile(const char_t *const fileName, std::string &configStr)
151 : {
152 252 : if (fileName == nullptr) {
153 1 : ACL_LOG_DEBUG("filename is nullptr, no need to parse json");
154 1 : return ACL_SUCCESS;
155 : }
156 251 : ACL_LOG_DEBUG("before GetConfigStrFromFile in ParseJsonFromFile");
157 251 : if (!IsValidFileName(fileName)) {
158 3 : ACL_LOG_INNER_ERROR("[Check][File]invalid config file[%s]", fileName);
159 3 : return ACL_ERROR_INVALID_FILE;
160 : }
161 496 : std::ifstream fin(fileName, std::ios::binary);
162 248 : if (!fin.is_open()) {
163 0 : ACL_LOG_INNER_ERROR("[Read][File]read file %s failed cause it cannnot be read.", fileName);
164 0 : return ACL_ERROR_INVALID_FILE;
165 : }
166 248 : (void)fin.seekg(0, std::ios::end);
167 248 : const std::streampos fp = fin.tellg();
168 248 : if (static_cast<int32_t>(fp) == 0) {
169 11 : ACL_LOG_DEBUG("parse file is null");
170 11 : fin.close();
171 11 : return ACL_SUCCESS;
172 : }
173 : // checking the depth of file
174 237 : size_t maxObjDepth = 0U;
175 237 : size_t maxArrayDepth = 0U;
176 237 : GetMaxNestedLayers(fileName, static_cast<size_t>(fp), maxObjDepth, maxArrayDepth);
177 237 : if ((maxObjDepth > MAX_CONFIG_OBJ_DEPTH) || (maxArrayDepth > MAX_CONFIG_ARRAY_DEPTH)) {
178 0 : ACL_LOG_INNER_ERROR("[Check][MaxArrayDepth]invalid json file, the object's depth[%zu] is larger than %zu, "
179 : "or the array's depth[%zu] is larger than %zu.",
180 : maxObjDepth, MAX_CONFIG_OBJ_DEPTH, maxArrayDepth, MAX_CONFIG_ARRAY_DEPTH);
181 0 : fin.close();
182 0 : return ACL_ERROR_PARSE_FILE;
183 : }
184 237 : ACL_LOG_DEBUG("json file's obj's depth is %zu, array's depth is %zu", maxObjDepth, maxArrayDepth);
185 237 : std::stringstream buffer;
186 237 : fin.seekg(0, std::ios::beg);
187 237 : buffer << fin.rdbuf();
188 237 : configStr = buffer.str();
189 237 : fin.close();
190 237 : return ACL_SUCCESS;
191 : }
192 :
193 218 : aclError JsonParser::ParseJsonFromFile(const char_t *const fileName, nlohmann::json &js)
194 : {
195 436 : std::string configStr;
196 218 : auto ret = GetConfigStrFromFile(fileName, configStr);
197 218 : if (ret != ACL_SUCCESS) {
198 3 : ACL_LOG_INNER_ERROR("[Parse][File]Get Buffer from file[%s] failed.", fileName);
199 3 : return ret;
200 : }
201 :
202 215 : ret= ParseJson(fileName, configStr.c_str(), js);
203 215 : if (ret != ACL_SUCCESS) {
204 5 : ACL_LOG_INNER_ERROR("[Parse][File]parse config file[%s] to json failed.", fileName);
205 5 : return ACL_ERROR_PARSE_FILE;
206 : }
207 :
208 210 : ACL_LOG_DEBUG("parse json from file[%s] successfully.", fileName);
209 210 : return ACL_SUCCESS;
210 : }
211 :
212 73 : aclError JsonParser::GetJsonCtxByKey(const char_t *const fileName,
213 : std::string &strJsonCtx, const std::string &subStrKey, bool &found) {
214 73 : found = false;
215 146 : nlohmann::json js;
216 73 : aclError ret = acl::JsonParser::ParseJsonFromFile(fileName, js);
217 73 : if (ret != ACL_SUCCESS) {
218 2 : ACL_LOG_INNER_ERROR("parse json from file falied, errorCode = %d", ret);
219 2 : return ret;
220 : }
221 71 : const auto configIter = js.find(subStrKey);
222 71 : if (configIter != js.end()) {
223 10 : strJsonCtx = configIter->dump();
224 10 : found = true;
225 : }
226 71 : return ACL_SUCCESS;
227 : }
228 :
229 6 : aclError JsonParser::GetAttrConfigFromFile(
230 : const char_t *const fileName, std::map<aclCannAttr, CannInfo> &cannInfoMap)
231 : {
232 12 : nlohmann::json js;
233 6 : aclError ret = JsonParser::ParseJsonFromFile(fileName, js);
234 6 : if (ret != ACL_SUCCESS) {
235 1 : ACL_LOG_INNER_ERROR("parse swFeatureList.json from file[%s] failed, ret = %d", fileName, ret);
236 1 : return ret;
237 : }
238 : try {
239 20 : for (auto &item : cannInfoMap) {
240 15 : auto &cannInfo = item.second;
241 15 : const auto config = js.find(cannInfo.readableAttrName);
242 15 : if (config != js.end()) {
243 13 : const auto runtimeIter = config->find(SW_CONFIG_RUNTIME);
244 13 : if (runtimeIter != config->end()) {
245 13 : ACL_REQUIRES_OK(CannInfoUtils::ParseVersionValue(
246 : runtimeIter->get<std::string>(), &cannInfo.minimumRuntimeVersion));
247 : }
248 : }
249 : }
250 0 : } catch (const nlohmann::json::exception &e) {
251 0 : ACL_LOG_INNER_ERROR("invalid config file [%s], exception: %s", fileName, e.what());
252 0 : return ACL_ERROR_INTERNAL_ERROR;
253 : }
254 5 : ACL_LOG_INFO("Finish parsing swFeatureList.json");
255 5 : return ACL_SUCCESS;
256 : }
257 :
258 30 : aclError JsonParser::GetDefaultDeviceIdFromFile(const char_t *const fileName, int32_t& devId)
259 : {
260 30 : ACL_LOG_DEBUG("start to execute GetDefaultDeviceIdFromFile.");
261 60 : nlohmann::json js;
262 60 : std::string enableFlagStr, defaultDeviceIdStr;
263 30 : aclError ret = acl::JsonParser::ParseJsonFromFile(fileName, js);
264 30 : if (ret != ACL_SUCCESS) {
265 0 : ACL_LOG_INNER_ERROR("[Parse][JsonFromFile]parse default config from file[%s] failed, errorCode = %d", fileName, ret);
266 0 : return ret;
267 : }
268 :
269 : try {
270 30 : if (!JsonParser::ContainKey(js, ACL_JSON_DEFAULT_DEVICE)) {
271 21 : ACL_LOG_WARN("no defaultDevice item!");
272 21 : return ACL_SUCCESS;
273 : }
274 9 : const nlohmann::json &jsDefaultDeviceConfig = JsonParser::GetCfgJsonByKey(js, ACL_JSON_DEFAULT_DEVICE);
275 9 : if (!JsonParser::ContainKey(jsDefaultDeviceConfig, ACL_JSON_DEFAULT_DEVICE_ID)) {
276 1 : ACL_LOG_WARN("no default_device in acl.json!");
277 1 : return ACL_SUCCESS;
278 : }
279 :
280 8 : defaultDeviceIdStr = JsonParser::GetCfgStrByKey(jsDefaultDeviceConfig, ACL_JSON_DEFAULT_DEVICE_ID);
281 1 : } catch (const nlohmann::json::exception &e) {
282 1 : ACL_LOG_INNER_ERROR("parse config file [%s], exception: %s", fileName, e.what());
283 1 : return ACL_ERROR_INTERNAL_ERROR;
284 : }
285 :
286 14 : std::regex reg("0|[1-9]\\d*");
287 7 : if (!std::regex_match(defaultDeviceIdStr, reg)) {
288 3 : ACL_LOG_ERROR("default_device %s in acl.json is neither zero nor positive integer.",
289 : defaultDeviceIdStr.c_str());
290 3 : return ACL_ERROR_INVALID_PARAM;
291 : }
292 4 : devId = static_cast<int32_t>(std::strtol(defaultDeviceIdStr.c_str(), nullptr, DECIMAL));
293 4 : ACL_LOG_DEBUG("successfully parse defaultDevice, devId:%d", devId);
294 4 : return ACL_SUCCESS;
295 : }
296 :
297 15 : aclError JsonParser::GetEventModeFromFile(const char_t *const fileName, uint8_t &event_mode, bool &found)
298 : {
299 30 : nlohmann::json js;
300 30 : std::string eventModeStr;
301 15 : aclError ret = acl::JsonParser::ParseJsonFromFile(fileName, js);
302 15 : if (ret != ACL_SUCCESS) {
303 1 : ACL_LOG_INNER_ERROR("[Parse][JsonFromFile]parse json from file[%s] failed, errorCode = %d", fileName, ret);
304 1 : return ret;
305 : }
306 42 : const std::string ACL_GRAPH_CONFIG_NAME = "acl_graph";
307 42 : const std::string ACL_EVENT_MODE_CONFIG_NAME = "event_mode";
308 :
309 14 : if (!JsonParser::ContainKey(js, ACL_GRAPH_CONFIG_NAME)) {
310 10 : ACL_LOG_INFO("No acl_graph in json file!");
311 10 : return ACL_SUCCESS;
312 : }
313 4 : const nlohmann::json &jsAclGraphConfig = JsonParser::GetCfgJsonByKey(js, ACL_GRAPH_CONFIG_NAME);
314 4 : if (!JsonParser::ContainKey(jsAclGraphConfig, ACL_EVENT_MODE_CONFIG_NAME)) {
315 1 : ACL_LOG_INFO("No event_mode under acl_graph in json file!");
316 1 : return ACL_SUCCESS;
317 : }
318 3 : eventModeStr = JsonParser::GetCfgStrByKey(jsAclGraphConfig, ACL_EVENT_MODE_CONFIG_NAME);
319 :
320 : // 校验 event_mode 是否为合法整数,只允许 0 或 1
321 6 : std::regex reg("0|1");
322 3 : if (!std::regex_match(eventModeStr, reg)) {
323 1 : ACL_LOG_ERROR("event_mode value [%s] in json is not a valid integer.", eventModeStr.c_str());
324 1 : const char_t *argList[] = {"param", "value", "reason"};
325 1 : const char_t *argVal[] = {"event_mode", eventModeStr.c_str(), "only support [0,1]"};
326 1 : acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_PARAM_MSG,
327 : argList, argVal, 3U);
328 1 : return ACL_ERROR_INVALID_PARAM;
329 : }
330 :
331 2 : event_mode = static_cast<uint8_t>(std::strtol(eventModeStr.c_str(), nullptr, DECIMAL));
332 2 : found = true;
333 2 : ACL_LOG_INFO("Successfully parse event_mode: %d, event_mode_str: %s", event_mode, eventModeStr.c_str());
334 2 : return ACL_SUCCESS;
335 : }
336 :
337 90 : aclError JsonParser::GetStackSizeByType(
338 : const char_t* const fileName, const std::string& typeName, size_t& outSize, bool& outExist)
339 : {
340 90 : ACL_LOG_DEBUG("start to execute GetStackSizeByType, typeName = %s.", typeName.c_str());
341 90 : outExist = false;
342 90 : outSize = 0U;
343 180 : nlohmann::json js;
344 90 : aclError ret = acl::JsonParser::ParseJsonFromFile(fileName, js);
345 90 : if (ret != ACL_SUCCESS) {
346 2 : ACL_LOG_ERROR(
347 : "[Parse][JsonFromFile]parse default config from file[%s] failed, errorCode = %d", fileName, ret);
348 6 : acl::AclErrorLogManager::ReportInputError(
349 4 : acl::INVALID_FILE_MSG, std::vector<const char*>({"path", "reason"}),
350 4 : std::vector<const char*>({fileName, "Parse config file failed"}));
351 2 : return ret;
352 : }
353 :
354 : try {
355 : // 检查 "StackSize" 键是否存在
356 88 : if (js.find("StackSize") == js.end()) {
357 66 : ACL_LOG_DEBUG("StackSize key not found in config file [%s]", fileName);
358 66 : outExist = false; // 明确设置 outExist 为 false
359 66 : return ACL_SUCCESS;
360 : }
361 :
362 22 : const nlohmann::json& stackSizeJs = js["StackSize"];
363 22 : if (stackSizeJs.find(typeName.c_str()) != stackSizeJs.end()) {
364 19 : size_t rawSize = stackSizeJs.at(typeName.c_str()).get<size_t>();
365 18 : outSize = rawSize;
366 18 : outExist = true;
367 18 : ACL_LOG_INFO("successfully parse %s, size is %zu", typeName.c_str(), outSize);
368 : }
369 1 : } catch (const nlohmann::json::exception& e) {
370 1 : ACL_LOG_ERROR("parse config file [%s], exception: %s", fileName, e.what());
371 3 : acl::AclErrorLogManager::ReportInputError(
372 2 : acl::INVALID_FILE_MSG, std::vector<const char*>({"path", "reason"}),
373 2 : std::vector<const char*>({fileName, ("Parse exception: " + std::string(e.what())).c_str()}));
374 1 : return ACL_ERROR_INTERNAL_ERROR;
375 : }
376 :
377 21 : ACL_LOG_DEBUG("successfully parse StackSize by type");
378 21 : return ACL_SUCCESS;
379 : }
380 :
381 31 : aclError JsonParser::GetPrintFifoSizeByType(
382 : const char_t* const fileName, const std::string& typeName, size_t& fifoSize, bool& found)
383 : {
384 31 : ACL_LOG_DEBUG("start to execute GetPrintFifoSizeByType, typeName = %s.", typeName.c_str());
385 62 : std::string fifoSizeStr;
386 31 : found = false;
387 :
388 31 : auto ret = acl::JsonParser::GetJsonCtxByKey(fileName, fifoSizeStr, typeName, found);
389 31 : if (ret != ACL_SUCCESS) {
390 0 : ACL_LOG_INNER_ERROR("can not parse config from file[%s], config[%s], errorCode = %d", fileName, typeName.c_str(), ret);
391 0 : return ret;
392 : }
393 31 : if (!found) {
394 26 : return ACL_SUCCESS;
395 : }
396 :
397 10 : std::regex reg("[1-9]\\d*");
398 5 : if (!std::regex_match(fifoSizeStr, reg)) {
399 2 : ACL_LOG_ERROR("fifoSize %s in acl.json is not a positive integer.", fifoSizeStr.c_str());
400 2 : return ACL_ERROR_INVALID_PARAM;
401 : }
402 :
403 3 : fifoSize = static_cast<size_t>(std::strtol(fifoSizeStr.c_str(), nullptr, DECIMAL));
404 3 : ACL_LOG_DEBUG("successfully parse print fifo size by type");
405 3 : return ACL_SUCCESS;
406 : }
407 : } // namespace acl
|