LCOV - code coverage report
Current view: top level - acl/common - json_parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 233 251 92.8 %
Date: 2026-08-27 13:24:42 Functions: 13 13 100.0 %

          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

Generated by: LCOV version 1.14