13920e296Sopenharmony_ci/* 23920e296Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 33920e296Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43920e296Sopenharmony_ci * you may not use this file except in compliance with the License. 53920e296Sopenharmony_ci * You may obtain a copy of the License at 63920e296Sopenharmony_ci * 73920e296Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83920e296Sopenharmony_ci * 93920e296Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103920e296Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113920e296Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123920e296Sopenharmony_ci * See the License for the specific language governing permissions and 133920e296Sopenharmony_ci * limitations under the License. 143920e296Sopenharmony_ci */ 153920e296Sopenharmony_ci 163920e296Sopenharmony_ci#include "json_compiler.h" 173920e296Sopenharmony_ci#include <iostream> 183920e296Sopenharmony_ci#include <limits> 193920e296Sopenharmony_ci#include <regex> 203920e296Sopenharmony_ci#include "restool_errors.h" 213920e296Sopenharmony_ci#include "translatable_parser.h" 223920e296Sopenharmony_ci 233920e296Sopenharmony_cinamespace OHOS { 243920e296Sopenharmony_cinamespace Global { 253920e296Sopenharmony_cinamespace Restool { 263920e296Sopenharmony_ciusing namespace std; 273920e296Sopenharmony_ciconst string TAG_NAME = "name"; 283920e296Sopenharmony_ciconst string TAG_VALUE = "value"; 293920e296Sopenharmony_ciconst string TAG_PARENT = "parent"; 303920e296Sopenharmony_ciconst string TAG_QUANTITY = "quantity"; 313920e296Sopenharmony_ciconst vector<string> QUANTITY_ATTRS = { "zero", "one", "two", "few", "many", "other" }; 323920e296Sopenharmony_ciconst vector<string> TRANSLATION_TYPE = { "string", "strarray", "plural" }; 333920e296Sopenharmony_ci 343920e296Sopenharmony_ciJsonCompiler::JsonCompiler(ResType type, const string &output) 353920e296Sopenharmony_ci : IResourceCompiler(type, output), isBaseString_(false), root_(nullptr) 363920e296Sopenharmony_ci{ 373920e296Sopenharmony_ci InitParser(); 383920e296Sopenharmony_ci} 393920e296Sopenharmony_ci 403920e296Sopenharmony_ciJsonCompiler::~JsonCompiler() 413920e296Sopenharmony_ci{ 423920e296Sopenharmony_ci if (root_) { 433920e296Sopenharmony_ci cJSON_Delete(root_); 443920e296Sopenharmony_ci } 453920e296Sopenharmony_ci} 463920e296Sopenharmony_ci 473920e296Sopenharmony_ciuint32_t JsonCompiler::CompileSingleFile(const FileInfo &fileInfo) 483920e296Sopenharmony_ci{ 493920e296Sopenharmony_ci if (fileInfo.limitKey == "base" && 503920e296Sopenharmony_ci fileInfo.fileCluster == "element" && 513920e296Sopenharmony_ci fileInfo.filename == ID_DEFINED_FILE) { 523920e296Sopenharmony_ci return RESTOOL_SUCCESS; 533920e296Sopenharmony_ci } 543920e296Sopenharmony_ci 553920e296Sopenharmony_ci if (!ResourceUtil::OpenJsonFile(fileInfo.filePath, &root_)) { 563920e296Sopenharmony_ci return RESTOOL_ERROR; 573920e296Sopenharmony_ci } 583920e296Sopenharmony_ci if (!root_ || !cJSON_IsObject(root_)) { 593920e296Sopenharmony_ci cerr << "Error: JSON file parsing failed, please check the JSON file."; 603920e296Sopenharmony_ci cerr << NEW_LINE_PATH << fileInfo.filePath << endl; 613920e296Sopenharmony_ci return RESTOOL_ERROR; 623920e296Sopenharmony_ci } 633920e296Sopenharmony_ci cJSON *item = root_->child; 643920e296Sopenharmony_ci if (cJSON_GetArraySize(root_) != 1) { 653920e296Sopenharmony_ci cerr << "Error: node of a JSON file can only have one member, please check the JSON file."; 663920e296Sopenharmony_ci cerr << NEW_LINE_PATH << fileInfo.filePath << endl; 673920e296Sopenharmony_ci return RESTOOL_ERROR; 683920e296Sopenharmony_ci } 693920e296Sopenharmony_ci 703920e296Sopenharmony_ci string tag = item->string; 713920e296Sopenharmony_ci auto ret = g_contentClusterMap.find(tag); 723920e296Sopenharmony_ci if (ret == g_contentClusterMap.end()) { 733920e296Sopenharmony_ci cerr << "Error: invalid tag name '" << tag << "', please check the JSON file."; 743920e296Sopenharmony_ci cerr << NEW_LINE_PATH << fileInfo.filePath << endl; 753920e296Sopenharmony_ci return RESTOOL_ERROR; 763920e296Sopenharmony_ci } 773920e296Sopenharmony_ci isBaseString_ = (fileInfo.limitKey == "base" && 783920e296Sopenharmony_ci find(TRANSLATION_TYPE.begin(), TRANSLATION_TYPE.end(), tag) != TRANSLATION_TYPE.end()); 793920e296Sopenharmony_ci FileInfo copy = fileInfo; 803920e296Sopenharmony_ci copy.fileType = ret->second; 813920e296Sopenharmony_ci if (!ParseJsonArrayLevel(item, copy)) { 823920e296Sopenharmony_ci return RESTOOL_ERROR; 833920e296Sopenharmony_ci } 843920e296Sopenharmony_ci return RESTOOL_SUCCESS; 853920e296Sopenharmony_ci} 863920e296Sopenharmony_ci 873920e296Sopenharmony_ci// below private 883920e296Sopenharmony_civoid JsonCompiler::InitParser() 893920e296Sopenharmony_ci{ 903920e296Sopenharmony_ci using namespace placeholders; 913920e296Sopenharmony_ci handles_.emplace(ResType::STRING, bind(&JsonCompiler::HandleString, this, _1, _2)); 923920e296Sopenharmony_ci handles_.emplace(ResType::INTEGER, bind(&JsonCompiler::HandleInteger, this, _1, _2)); 933920e296Sopenharmony_ci handles_.emplace(ResType::BOOLEAN, bind(&JsonCompiler::HandleBoolean, this, _1, _2)); 943920e296Sopenharmony_ci handles_.emplace(ResType::COLOR, bind(&JsonCompiler::HandleColor, this, _1, _2)); 953920e296Sopenharmony_ci handles_.emplace(ResType::FLOAT, bind(&JsonCompiler::HandleFloat, this, _1, _2)); 963920e296Sopenharmony_ci handles_.emplace(ResType::STRARRAY, bind(&JsonCompiler::HandleStringArray, this, _1, _2)); 973920e296Sopenharmony_ci handles_.emplace(ResType::INTARRAY, bind(&JsonCompiler::HandleIntegerArray, this, _1, _2)); 983920e296Sopenharmony_ci handles_.emplace(ResType::THEME, bind(&JsonCompiler::HandleTheme, this, _1, _2)); 993920e296Sopenharmony_ci handles_.emplace(ResType::PATTERN, bind(&JsonCompiler::HandlePattern, this, _1, _2)); 1003920e296Sopenharmony_ci handles_.emplace(ResType::PLURAL, bind(&JsonCompiler::HandlePlural, this, _1, _2)); 1013920e296Sopenharmony_ci handles_.emplace(ResType::SYMBOL, bind(&JsonCompiler::HandleSymbol, this, _1, _2)); 1023920e296Sopenharmony_ci} 1033920e296Sopenharmony_ci 1043920e296Sopenharmony_cibool JsonCompiler::ParseJsonArrayLevel(const cJSON *arrayNode, const FileInfo &fileInfo) 1053920e296Sopenharmony_ci{ 1063920e296Sopenharmony_ci if (!arrayNode || !cJSON_IsArray(arrayNode)) { 1073920e296Sopenharmony_ci cerr << "Error: '" << ResourceUtil::ResTypeToString(fileInfo.fileType) << "' must be array."; 1083920e296Sopenharmony_ci cerr << NEW_LINE_PATH << fileInfo.filePath << endl; 1093920e296Sopenharmony_ci return false; 1103920e296Sopenharmony_ci } 1113920e296Sopenharmony_ci 1123920e296Sopenharmony_ci if (cJSON_GetArraySize(arrayNode) == 0) { 1133920e296Sopenharmony_ci cerr << "Error: '" << ResourceUtil::ResTypeToString(fileInfo.fileType) << "' empty."; 1143920e296Sopenharmony_ci cerr << NEW_LINE_PATH << fileInfo.filePath << endl; 1153920e296Sopenharmony_ci return false; 1163920e296Sopenharmony_ci } 1173920e296Sopenharmony_ci int32_t index = -1; 1183920e296Sopenharmony_ci for (cJSON *item = arrayNode->child; item; item = item->next) { 1193920e296Sopenharmony_ci index++; 1203920e296Sopenharmony_ci if (!item || !cJSON_IsObject(item)) { 1213920e296Sopenharmony_ci cerr << "Error: the seq=" << index << " item must be object." << NEW_LINE_PATH << fileInfo.filePath << endl; 1223920e296Sopenharmony_ci return false; 1233920e296Sopenharmony_ci } 1243920e296Sopenharmony_ci if (!ParseJsonObjectLevel(item, fileInfo)) { 1253920e296Sopenharmony_ci return false; 1263920e296Sopenharmony_ci } 1273920e296Sopenharmony_ci } 1283920e296Sopenharmony_ci return true; 1293920e296Sopenharmony_ci} 1303920e296Sopenharmony_ci 1313920e296Sopenharmony_cibool JsonCompiler::ParseJsonObjectLevel(cJSON *objectNode, const FileInfo &fileInfo) 1323920e296Sopenharmony_ci{ 1333920e296Sopenharmony_ci cJSON *nameNode = cJSON_GetObjectItem(objectNode, TAG_NAME.c_str()); 1343920e296Sopenharmony_ci if (!nameNode) { 1353920e296Sopenharmony_ci cerr << "Error: name empty." << NEW_LINE_PATH << fileInfo.filePath << endl; 1363920e296Sopenharmony_ci return false; 1373920e296Sopenharmony_ci } 1383920e296Sopenharmony_ci 1393920e296Sopenharmony_ci if (!cJSON_IsString(nameNode)) { 1403920e296Sopenharmony_ci cerr << "Error: name must string." << NEW_LINE_PATH << fileInfo.filePath << endl; 1413920e296Sopenharmony_ci return false; 1423920e296Sopenharmony_ci } 1433920e296Sopenharmony_ci 1443920e296Sopenharmony_ci if (isBaseString_ && !TranslatableParse::ParseTranslatable(objectNode, fileInfo, nameNode->valuestring)) { 1453920e296Sopenharmony_ci return false; 1463920e296Sopenharmony_ci } 1473920e296Sopenharmony_ci ResourceItem resourceItem(nameNode->valuestring, fileInfo.keyParams, fileInfo.fileType); 1483920e296Sopenharmony_ci resourceItem.SetFilePath(fileInfo.filePath); 1493920e296Sopenharmony_ci resourceItem.SetLimitKey(fileInfo.limitKey); 1503920e296Sopenharmony_ci auto ret = handles_.find(fileInfo.fileType); 1513920e296Sopenharmony_ci if (ret == handles_.end()) { 1523920e296Sopenharmony_ci cerr << "Error: json parser don't support " << ResourceUtil::ResTypeToString(fileInfo.fileType) << endl; 1533920e296Sopenharmony_ci return false; 1543920e296Sopenharmony_ci } 1553920e296Sopenharmony_ci 1563920e296Sopenharmony_ci if (!ret->second(objectNode, resourceItem)) { 1573920e296Sopenharmony_ci return false; 1583920e296Sopenharmony_ci } 1593920e296Sopenharmony_ci 1603920e296Sopenharmony_ci return MergeResourceItem(resourceItem); 1613920e296Sopenharmony_ci} 1623920e296Sopenharmony_ci 1633920e296Sopenharmony_cibool JsonCompiler::HandleString(const cJSON *objectNode, ResourceItem &resourceItem) const 1643920e296Sopenharmony_ci{ 1653920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str()); 1663920e296Sopenharmony_ci if (!CheckJsonStringValue(valueNode, resourceItem)) { 1673920e296Sopenharmony_ci return false; 1683920e296Sopenharmony_ci } 1693920e296Sopenharmony_ci return PushString(valueNode->valuestring, resourceItem); 1703920e296Sopenharmony_ci} 1713920e296Sopenharmony_ci 1723920e296Sopenharmony_cibool JsonCompiler::HandleInteger(const cJSON *objectNode, ResourceItem &resourceItem) const 1733920e296Sopenharmony_ci{ 1743920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str()); 1753920e296Sopenharmony_ci if (!CheckJsonIntegerValue(valueNode, resourceItem)) { 1763920e296Sopenharmony_ci return false; 1773920e296Sopenharmony_ci } 1783920e296Sopenharmony_ci if (cJSON_IsString(valueNode)) { 1793920e296Sopenharmony_ci return PushString(valueNode->valuestring, resourceItem); 1803920e296Sopenharmony_ci } else if (cJSON_IsNumber(valueNode)) { 1813920e296Sopenharmony_ci return PushString(to_string(valueNode->valueint), resourceItem); 1823920e296Sopenharmony_ci } else { 1833920e296Sopenharmony_ci return false; 1843920e296Sopenharmony_ci } 1853920e296Sopenharmony_ci} 1863920e296Sopenharmony_ci 1873920e296Sopenharmony_cibool JsonCompiler::HandleBoolean(const cJSON *objectNode, ResourceItem &resourceItem) const 1883920e296Sopenharmony_ci{ 1893920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str()); 1903920e296Sopenharmony_ci if (cJSON_IsString(valueNode)) { 1913920e296Sopenharmony_ci regex ref("^\\$(ohos:)?boolean:.*"); 1923920e296Sopenharmony_ci if (!regex_match(valueNode->valuestring, ref)) { 1933920e296Sopenharmony_ci cerr << "Error: '" << valueNode->valuestring << "' only refer '$boolean:xxx'."; 1943920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 1953920e296Sopenharmony_ci return false; 1963920e296Sopenharmony_ci } 1973920e296Sopenharmony_ci return PushString(valueNode->valuestring, resourceItem); 1983920e296Sopenharmony_ci } 1993920e296Sopenharmony_ci if (!cJSON_IsBool(valueNode)) { 2003920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value not boolean."; 2013920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 2023920e296Sopenharmony_ci return false; 2033920e296Sopenharmony_ci } 2043920e296Sopenharmony_ci return PushString(cJSON_IsTrue(valueNode) == 1 ? "true" : "false", resourceItem); 2053920e296Sopenharmony_ci} 2063920e296Sopenharmony_ci 2073920e296Sopenharmony_cibool JsonCompiler::HandleColor(const cJSON *objectNode, ResourceItem &resourceItem) const 2083920e296Sopenharmony_ci{ 2093920e296Sopenharmony_ci return HandleString(objectNode, resourceItem); 2103920e296Sopenharmony_ci} 2113920e296Sopenharmony_ci 2123920e296Sopenharmony_cibool JsonCompiler::HandleFloat(const cJSON *objectNode, ResourceItem &resourceItem) const 2133920e296Sopenharmony_ci{ 2143920e296Sopenharmony_ci return HandleString(objectNode, resourceItem); 2153920e296Sopenharmony_ci} 2163920e296Sopenharmony_ci 2173920e296Sopenharmony_cibool JsonCompiler::HandleStringArray(const cJSON *objectNode, ResourceItem &resourceItem) const 2183920e296Sopenharmony_ci{ 2193920e296Sopenharmony_ci vector<string> extra; 2203920e296Sopenharmony_ci return ParseValueArray(objectNode, resourceItem, extra, 2213920e296Sopenharmony_ci [this](const cJSON *arrayItem, const ResourceItem &resourceItem, vector<string> &values) -> bool { 2223920e296Sopenharmony_ci if (!cJSON_IsObject(arrayItem)) { 2233920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value array item not object."; 2243920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 2253920e296Sopenharmony_ci return false; 2263920e296Sopenharmony_ci } 2273920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(arrayItem, TAG_VALUE.c_str()); 2283920e296Sopenharmony_ci if (!CheckJsonStringValue(valueNode, resourceItem)) { 2293920e296Sopenharmony_ci return false; 2303920e296Sopenharmony_ci } 2313920e296Sopenharmony_ci values.push_back(valueNode->valuestring); 2323920e296Sopenharmony_ci return true; 2333920e296Sopenharmony_ci }); 2343920e296Sopenharmony_ci} 2353920e296Sopenharmony_ci 2363920e296Sopenharmony_cibool JsonCompiler::HandleIntegerArray(const cJSON *objectNode, ResourceItem &resourceItem) const 2373920e296Sopenharmony_ci{ 2383920e296Sopenharmony_ci vector<string> extra; 2393920e296Sopenharmony_ci return ParseValueArray(objectNode, resourceItem, extra, 2403920e296Sopenharmony_ci [this](const cJSON *arrayItem, const ResourceItem &resourceItem, vector<string> &values) -> bool { 2413920e296Sopenharmony_ci if (!CheckJsonIntegerValue(arrayItem, resourceItem)) { 2423920e296Sopenharmony_ci return false; 2433920e296Sopenharmony_ci } 2443920e296Sopenharmony_ci if (cJSON_IsString(arrayItem)) { 2453920e296Sopenharmony_ci values.push_back(arrayItem->valuestring); 2463920e296Sopenharmony_ci } else { 2473920e296Sopenharmony_ci values.push_back(to_string(arrayItem->valueint)); 2483920e296Sopenharmony_ci } 2493920e296Sopenharmony_ci return true; 2503920e296Sopenharmony_ci }); 2513920e296Sopenharmony_ci} 2523920e296Sopenharmony_ci 2533920e296Sopenharmony_cibool JsonCompiler::HandleTheme(const cJSON *objectNode, ResourceItem &resourceItem) const 2543920e296Sopenharmony_ci{ 2553920e296Sopenharmony_ci vector<string> extra; 2563920e296Sopenharmony_ci if (!ParseParent(objectNode, resourceItem, extra)) { 2573920e296Sopenharmony_ci return false; 2583920e296Sopenharmony_ci } 2593920e296Sopenharmony_ci return ParseValueArray(objectNode, resourceItem, extra, 2603920e296Sopenharmony_ci [this](const cJSON *arrayItem, const ResourceItem &resourceItem, vector<string> &values) { 2613920e296Sopenharmony_ci return ParseAttribute(arrayItem, resourceItem, values); 2623920e296Sopenharmony_ci }); 2633920e296Sopenharmony_ci} 2643920e296Sopenharmony_ci 2653920e296Sopenharmony_cibool JsonCompiler::HandlePattern(const cJSON *objectNode, ResourceItem &resourceItem) const 2663920e296Sopenharmony_ci{ 2673920e296Sopenharmony_ci return HandleTheme(objectNode, resourceItem); 2683920e296Sopenharmony_ci} 2693920e296Sopenharmony_ci 2703920e296Sopenharmony_cibool JsonCompiler::HandlePlural(const cJSON *objectNode, ResourceItem &resourceItem) const 2713920e296Sopenharmony_ci{ 2723920e296Sopenharmony_ci vector<string> extra; 2733920e296Sopenharmony_ci vector<string> attrs; 2743920e296Sopenharmony_ci bool result = ParseValueArray(objectNode, resourceItem, extra, 2753920e296Sopenharmony_ci [&attrs, this](const cJSON *arrayItem, const ResourceItem &resourceItem, vector<string> &values) { 2763920e296Sopenharmony_ci if (!CheckPluralValue(arrayItem, resourceItem)) { 2773920e296Sopenharmony_ci return false; 2783920e296Sopenharmony_ci } 2793920e296Sopenharmony_ci cJSON *quantityNode = cJSON_GetObjectItem(arrayItem, TAG_QUANTITY.c_str()); 2803920e296Sopenharmony_ci if (!quantityNode || !cJSON_IsString(quantityNode)) { 2813920e296Sopenharmony_ci return false; 2823920e296Sopenharmony_ci } 2833920e296Sopenharmony_ci string quantityValue = quantityNode->valuestring; 2843920e296Sopenharmony_ci if (find(attrs.begin(), attrs.end(), quantityValue) != attrs.end()) { 2853920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; 2863920e296Sopenharmony_ci cerr << "' duplicated." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 2873920e296Sopenharmony_ci return false; 2883920e296Sopenharmony_ci } 2893920e296Sopenharmony_ci attrs.push_back(quantityValue); 2903920e296Sopenharmony_ci values.push_back(quantityValue); 2913920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(arrayItem, TAG_VALUE.c_str()); 2923920e296Sopenharmony_ci if (!valueNode || !cJSON_IsString(valueNode)) { 2933920e296Sopenharmony_ci return false; 2943920e296Sopenharmony_ci } 2953920e296Sopenharmony_ci values.push_back(valueNode->valuestring); 2963920e296Sopenharmony_ci return true; 2973920e296Sopenharmony_ci }); 2983920e296Sopenharmony_ci if (!result) { 2993920e296Sopenharmony_ci return false; 3003920e296Sopenharmony_ci } 3013920e296Sopenharmony_ci if (find(attrs.begin(), attrs.end(), "other") == attrs.end()) { 3023920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity must contains 'other'."; 3033920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3043920e296Sopenharmony_ci return false; 3053920e296Sopenharmony_ci } 3063920e296Sopenharmony_ci return true; 3073920e296Sopenharmony_ci} 3083920e296Sopenharmony_ci 3093920e296Sopenharmony_cibool JsonCompiler::HandleSymbol(const cJSON *objectNode, ResourceItem &resourceItem) const 3103920e296Sopenharmony_ci{ 3113920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str()); 3123920e296Sopenharmony_ci if (!CheckJsonSymbolValue(valueNode, resourceItem)) { 3133920e296Sopenharmony_ci return false; 3143920e296Sopenharmony_ci } 3153920e296Sopenharmony_ci return PushString(valueNode->valuestring, resourceItem); 3163920e296Sopenharmony_ci} 3173920e296Sopenharmony_ci 3183920e296Sopenharmony_cibool JsonCompiler::PushString(const string &value, ResourceItem &resourceItem) const 3193920e296Sopenharmony_ci{ 3203920e296Sopenharmony_ci if (!resourceItem.SetData(reinterpret_cast<const int8_t *>(value.c_str()), value.length())) { 3213920e296Sopenharmony_ci cerr << "Error: resourceItem setdata fail,'" << resourceItem.GetName() << "'."; 3223920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3233920e296Sopenharmony_ci return false; 3243920e296Sopenharmony_ci } 3253920e296Sopenharmony_ci return true; 3263920e296Sopenharmony_ci} 3273920e296Sopenharmony_ci 3283920e296Sopenharmony_cibool JsonCompiler::CheckJsonStringValue(const cJSON *valueNode, const ResourceItem &resourceItem) const 3293920e296Sopenharmony_ci{ 3303920e296Sopenharmony_ci if (!valueNode || !cJSON_IsString(valueNode)) { 3313920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value not string."; 3323920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3333920e296Sopenharmony_ci return false; 3343920e296Sopenharmony_ci } 3353920e296Sopenharmony_ci 3363920e296Sopenharmony_ci const map<ResType, string> REFS = { 3373920e296Sopenharmony_ci { ResType::STRING, "\\$(ohos:)?string:" }, 3383920e296Sopenharmony_ci { ResType::STRARRAY, "\\$(ohos:)?string:" }, 3393920e296Sopenharmony_ci { ResType::COLOR, "\\$(ohos:)?color:" }, 3403920e296Sopenharmony_ci { ResType::FLOAT, "\\$(ohos:)?float:" } 3413920e296Sopenharmony_ci }; 3423920e296Sopenharmony_ci 3433920e296Sopenharmony_ci string value = valueNode->valuestring; 3443920e296Sopenharmony_ci ResType type = resourceItem.GetResType(); 3453920e296Sopenharmony_ci if (type == ResType::COLOR && !CheckColorValue(value.c_str())) { 3463920e296Sopenharmony_ci string error = "invalid color value '" + value + \ 3473920e296Sopenharmony_ci "', only support refer '$color:xxx' or '#rgb','#argb','#rrggbb','#aarrggbb'."; 3483920e296Sopenharmony_ci cerr << "Error: " << error << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3493920e296Sopenharmony_ci return false; 3503920e296Sopenharmony_ci } 3513920e296Sopenharmony_ci regex ref("^\\$.+:"); 3523920e296Sopenharmony_ci smatch result; 3533920e296Sopenharmony_ci if (regex_search(value, result, ref) && !regex_match(result[0].str(), regex(REFS.at(type)))) { 3543920e296Sopenharmony_ci cerr << "Error: '" << value << "', only refer '"<< REFS.at(type) << "xxx'."; 3553920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3563920e296Sopenharmony_ci return false; 3573920e296Sopenharmony_ci } 3583920e296Sopenharmony_ci return true; 3593920e296Sopenharmony_ci} 3603920e296Sopenharmony_ci 3613920e296Sopenharmony_cibool JsonCompiler::CheckJsonIntegerValue(const cJSON *valueNode, const ResourceItem &resourceItem) const 3623920e296Sopenharmony_ci{ 3633920e296Sopenharmony_ci if (!valueNode) { 3643920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value is empty"; 3653920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3663920e296Sopenharmony_ci return false; 3673920e296Sopenharmony_ci } 3683920e296Sopenharmony_ci if (cJSON_IsString(valueNode)) { 3693920e296Sopenharmony_ci regex ref("^\\$(ohos:)?integer:.*"); 3703920e296Sopenharmony_ci if (!regex_match(valueNode->valuestring, ref)) { 3713920e296Sopenharmony_ci cerr << "Error: '" << valueNode->valuestring << "', only refer '$integer:xxx'."; 3723920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3733920e296Sopenharmony_ci return false; 3743920e296Sopenharmony_ci } 3753920e296Sopenharmony_ci } else if (!ResourceUtil::IsIntValue(valueNode)) { 3763920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value not integer."; 3773920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3783920e296Sopenharmony_ci return false; 3793920e296Sopenharmony_ci } 3803920e296Sopenharmony_ci return true; 3813920e296Sopenharmony_ci} 3823920e296Sopenharmony_ci 3833920e296Sopenharmony_cibool JsonCompiler::CheckJsonSymbolValue(const cJSON *valueNode, const ResourceItem &resourceItem) const 3843920e296Sopenharmony_ci{ 3853920e296Sopenharmony_ci if (!valueNode || !cJSON_IsString(valueNode)) { 3863920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value not string."; 3873920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3883920e296Sopenharmony_ci return false; 3893920e296Sopenharmony_ci } 3903920e296Sopenharmony_ci string unicodeStr = valueNode->valuestring; 3913920e296Sopenharmony_ci if (regex_match(unicodeStr, regex("^\\$(ohos:)?symbol:.*"))) { 3923920e296Sopenharmony_ci return true; 3933920e296Sopenharmony_ci } 3943920e296Sopenharmony_ci int unicode = strtol(unicodeStr.c_str(), nullptr, 16); 3953920e296Sopenharmony_ci if (!ResourceUtil::isUnicodeInPlane15or16(unicode)) { 3963920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value must in 0xF0000 ~ 0xFFFFF or 0x100000 ~ 0x10FFFF."; 3973920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 3983920e296Sopenharmony_ci return false; 3993920e296Sopenharmony_ci } 4003920e296Sopenharmony_ci return true; 4013920e296Sopenharmony_ci} 4023920e296Sopenharmony_ci 4033920e296Sopenharmony_cibool JsonCompiler::ParseValueArray(const cJSON *objectNode, ResourceItem &resourceItem, 4043920e296Sopenharmony_ci const vector<string> &extra, HandleValue callback) const 4053920e296Sopenharmony_ci{ 4063920e296Sopenharmony_ci cJSON *arrayNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str()); 4073920e296Sopenharmony_ci if (!cJSON_IsArray(arrayNode)) { 4083920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value not array."; 4093920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4103920e296Sopenharmony_ci return false; 4113920e296Sopenharmony_ci } 4123920e296Sopenharmony_ci 4133920e296Sopenharmony_ci if (cJSON_GetArraySize(arrayNode) == 0) { 4143920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' value empty."; 4153920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4163920e296Sopenharmony_ci return false; 4173920e296Sopenharmony_ci } 4183920e296Sopenharmony_ci 4193920e296Sopenharmony_ci vector<string> contents; 4203920e296Sopenharmony_ci if (!extra.empty()) { 4213920e296Sopenharmony_ci contents.assign(extra.begin(), extra.end()); 4223920e296Sopenharmony_ci } 4233920e296Sopenharmony_ci for (cJSON *item = arrayNode->child; item; item = item->next) { 4243920e296Sopenharmony_ci vector<string> values; 4253920e296Sopenharmony_ci if (!callback(item, resourceItem, values)) { 4263920e296Sopenharmony_ci return false; 4273920e296Sopenharmony_ci } 4283920e296Sopenharmony_ci contents.insert(contents.end(), values.begin(), values.end()); 4293920e296Sopenharmony_ci } 4303920e296Sopenharmony_ci 4313920e296Sopenharmony_ci string data = ResourceUtil::ComposeStrings(contents); 4323920e296Sopenharmony_ci if (data.empty()) { 4333920e296Sopenharmony_ci cerr << "Error: '" << resourceItem.GetName() << "' array too large."; 4343920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4353920e296Sopenharmony_ci return false; 4363920e296Sopenharmony_ci } 4373920e296Sopenharmony_ci return PushString(data, resourceItem); 4383920e296Sopenharmony_ci} 4393920e296Sopenharmony_ci 4403920e296Sopenharmony_cibool JsonCompiler::ParseParent(const cJSON *objectNode, const ResourceItem &resourceItem, 4413920e296Sopenharmony_ci vector<string> &extra) const 4423920e296Sopenharmony_ci{ 4433920e296Sopenharmony_ci cJSON *parentNode = cJSON_GetObjectItem(objectNode, TAG_PARENT.c_str()); 4443920e296Sopenharmony_ci string type = ResourceUtil::ResTypeToString(resourceItem.GetResType()); 4453920e296Sopenharmony_ci if (parentNode) { 4463920e296Sopenharmony_ci if (!cJSON_IsString(parentNode)) { 4473920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' parent not string."; 4483920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4493920e296Sopenharmony_ci return false; 4503920e296Sopenharmony_ci } 4513920e296Sopenharmony_ci string parentValue = parentNode->valuestring; 4523920e296Sopenharmony_ci if (parentValue.empty()) { 4533920e296Sopenharmony_ci cerr << "Error: " << type << " '"<< resourceItem.GetName() << "' parent empty."; 4543920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4553920e296Sopenharmony_ci return false; 4563920e296Sopenharmony_ci } 4573920e296Sopenharmony_ci if (regex_match(parentValue, regex("^ohos:" + type + ":.+"))) { 4583920e296Sopenharmony_ci parentValue = "$" + parentValue; 4593920e296Sopenharmony_ci } else { 4603920e296Sopenharmony_ci parentValue = "$" + type + ":" + parentValue; 4613920e296Sopenharmony_ci } 4623920e296Sopenharmony_ci extra.push_back(parentValue); 4633920e296Sopenharmony_ci } 4643920e296Sopenharmony_ci return true; 4653920e296Sopenharmony_ci} 4663920e296Sopenharmony_ci 4673920e296Sopenharmony_cibool JsonCompiler::ParseAttribute(const cJSON *arrayItem, const ResourceItem &resourceItem, 4683920e296Sopenharmony_ci vector<string> &values) const 4693920e296Sopenharmony_ci{ 4703920e296Sopenharmony_ci string type = ResourceUtil::ResTypeToString(resourceItem.GetResType()); 4713920e296Sopenharmony_ci if (!arrayItem || !cJSON_IsObject(arrayItem)) { 4723920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute not object."; 4733920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4743920e296Sopenharmony_ci return false; 4753920e296Sopenharmony_ci } 4763920e296Sopenharmony_ci cJSON *nameNode = cJSON_GetObjectItem(arrayItem, TAG_NAME.c_str()); 4773920e296Sopenharmony_ci if (!nameNode) { 4783920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute name empty."; 4793920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4803920e296Sopenharmony_ci return false; 4813920e296Sopenharmony_ci } 4823920e296Sopenharmony_ci if (!cJSON_IsString(nameNode)) { 4833920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute name not string."; 4843920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4853920e296Sopenharmony_ci return false; 4863920e296Sopenharmony_ci } 4873920e296Sopenharmony_ci values.push_back(nameNode->valuestring); 4883920e296Sopenharmony_ci 4893920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(arrayItem, TAG_VALUE.c_str()); 4903920e296Sopenharmony_ci if (!valueNode) { 4913920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute '" << nameNode->valuestring; 4923920e296Sopenharmony_ci cerr << "' value empty." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4933920e296Sopenharmony_ci return false; 4943920e296Sopenharmony_ci } 4953920e296Sopenharmony_ci if (!cJSON_IsString(valueNode)) { 4963920e296Sopenharmony_ci cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute '" << nameNode->valuestring; 4973920e296Sopenharmony_ci cerr << "' value not string." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 4983920e296Sopenharmony_ci return false; 4993920e296Sopenharmony_ci } 5003920e296Sopenharmony_ci values.push_back(valueNode->valuestring); 5013920e296Sopenharmony_ci return true; 5023920e296Sopenharmony_ci} 5033920e296Sopenharmony_ci 5043920e296Sopenharmony_cibool JsonCompiler::CheckPluralValue(const cJSON *arrayItem, const ResourceItem &resourceItem) const 5053920e296Sopenharmony_ci{ 5063920e296Sopenharmony_ci if (!arrayItem || !cJSON_IsObject(arrayItem)) { 5073920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' array item not object."; 5083920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5093920e296Sopenharmony_ci return false; 5103920e296Sopenharmony_ci } 5113920e296Sopenharmony_ci cJSON *quantityNode = cJSON_GetObjectItem(arrayItem, TAG_QUANTITY.c_str()); 5123920e296Sopenharmony_ci if (!quantityNode) { 5133920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity empty."; 5143920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5153920e296Sopenharmony_ci return false; 5163920e296Sopenharmony_ci } 5173920e296Sopenharmony_ci if (!cJSON_IsString(quantityNode)) { 5183920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity not string."; 5193920e296Sopenharmony_ci cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5203920e296Sopenharmony_ci return false; 5213920e296Sopenharmony_ci } 5223920e296Sopenharmony_ci string quantityValue = quantityNode->valuestring; 5233920e296Sopenharmony_ci if (find(QUANTITY_ATTRS.begin(), QUANTITY_ATTRS.end(), quantityValue) == QUANTITY_ATTRS.end()) { 5243920e296Sopenharmony_ci string buffer(" "); 5253920e296Sopenharmony_ci for_each(QUANTITY_ATTRS.begin(), QUANTITY_ATTRS.end(), [&buffer](auto iter) { 5263920e296Sopenharmony_ci buffer.append(iter).append(" "); 5273920e296Sopenharmony_ci }); 5283920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; 5293920e296Sopenharmony_ci cerr << "' not in [" << buffer << "]." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5303920e296Sopenharmony_ci return false; 5313920e296Sopenharmony_ci } 5323920e296Sopenharmony_ci 5333920e296Sopenharmony_ci cJSON *valueNode = cJSON_GetObjectItem(arrayItem, TAG_VALUE.c_str()); 5343920e296Sopenharmony_ci if (!valueNode) { 5353920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; 5363920e296Sopenharmony_ci cerr << "' value empty." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5373920e296Sopenharmony_ci return false; 5383920e296Sopenharmony_ci } 5393920e296Sopenharmony_ci if (!cJSON_IsString(valueNode)) { 5403920e296Sopenharmony_ci cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; 5413920e296Sopenharmony_ci cerr << "' value not string." << NEW_LINE_PATH << resourceItem.GetFilePath() << endl; 5423920e296Sopenharmony_ci return false; 5433920e296Sopenharmony_ci } 5443920e296Sopenharmony_ci return true; 5453920e296Sopenharmony_ci} 5463920e296Sopenharmony_ci 5473920e296Sopenharmony_cibool JsonCompiler::CheckColorValue(const char *s) const 5483920e296Sopenharmony_ci{ 5493920e296Sopenharmony_ci if (s == nullptr) { 5503920e296Sopenharmony_ci return false; 5513920e296Sopenharmony_ci } 5523920e296Sopenharmony_ci // color regex 5533920e296Sopenharmony_ci string regColor = "^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$"; 5543920e296Sopenharmony_ci if (regex_match(s, regex("^\\$.*")) || regex_match(s, regex(regColor))) { 5553920e296Sopenharmony_ci return true; 5563920e296Sopenharmony_ci } 5573920e296Sopenharmony_ci return false; 5583920e296Sopenharmony_ci} 5593920e296Sopenharmony_ci} 5603920e296Sopenharmony_ci} 5613920e296Sopenharmony_ci} 562