• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "translatable_parser.h"
17 #include <algorithm>
18 #include <iostream>
19 #include "restool_errors.h"
20 #include "resource_util.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace Restool {
25 using namespace std;
26 const string TAG_VALUE = "value";
27 const string TAG_ATTR = "attr";
28 const string TAG_TRANSLATABLE = "translatable";
29 const string TAG_PRIORITY = "priority";
30 const string NO_TRANSLATE_START = "{noTranslateStart}";
31 const string NO_TRANSLATE_END = "{noTranslateEnd}";
32 const vector<string> PRIORITY_ATTRS = { "code", "translate", "LT", "customer" };
33 
ParseTranslatable(cJSON * objectNode,const FileInfo & fileInfo,const string & name)34 bool TranslatableParse::ParseTranslatable(cJSON *objectNode, const FileInfo &fileInfo, const string &name)
35 {
36     if (fileInfo.fileType == ResType::STRING) {
37         return ParseTranslatable(objectNode, fileInfo.filePath);
38     }
39     cJSON *arrayNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str());
40     if (!arrayNode || !cJSON_IsArray(arrayNode)) {
41         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(name.c_str(), "array")
42             .SetPosition(fileInfo.filePath));
43         return false;
44     }
45 
46     if (cJSON_GetArraySize(arrayNode) == 0) {
47         PrintError(GetError(ERR_CODE_JSON_NODE_EMPTY).FormatCause(name.c_str()).SetPosition(fileInfo.filePath));
48         return false;
49     }
50     int32_t index = -1;
51     for (cJSON *item = arrayNode->child; item; item = item->next) {
52         index++;
53         if (!item || !cJSON_IsObject(item)) {
54             PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH)
55                            .FormatCause("value's child", "object")
56                            .SetPosition(fileInfo.filePath));
57             return false;
58         }
59 
60         if (!ParseTranslatable(item, fileInfo.filePath)) {
61             return false;
62         }
63     }
64     return true;
65 }
66 
ParseTranslatable(cJSON * objectNode,const string & filePath)67 bool TranslatableParse::ParseTranslatable(cJSON *objectNode, const string &filePath)
68 {
69     if (!CheckBaseStringAttr(objectNode, filePath)) {
70         return false;
71     }
72     if (!ReplaceTranslateTags(objectNode, TAG_VALUE.c_str(), filePath)) {
73         return false;
74     }
75     return true;
76 }
77 
CheckBaseStringAttr(const cJSON * objectNode,const std::string & filePath)78 bool TranslatableParse::CheckBaseStringAttr(const cJSON *objectNode, const std::string &filePath)
79 {
80     cJSON *attrNode = cJSON_GetObjectItem(objectNode, TAG_ATTR.c_str());
81     if (!attrNode) {
82         return true;
83     }
84 
85     if (!cJSON_IsObject(attrNode)) {
86         PrintError(
87             GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(TAG_ATTR.c_str(), "object").SetPosition(filePath));
88         return false;
89     }
90     return CheckBaseStringTranslatable(attrNode, filePath);
91 }
92 
CheckBaseStringTranslatable(const cJSON * attrNode,const std::string & filePath)93 bool TranslatableParse::CheckBaseStringTranslatable(const cJSON *attrNode, const std::string &filePath)
94 {
95     cJSON *translatableNode = cJSON_GetObjectItem(attrNode, TAG_TRANSLATABLE.c_str());
96     if (!translatableNode) {
97         return CheckBaseStringPriority(attrNode, filePath);
98     }
99     if (!cJSON_IsBool(translatableNode)) {
100         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH)
101                        .FormatCause(TAG_TRANSLATABLE.c_str(), "bool")
102                        .SetPosition(filePath));
103         return false;
104     }
105     return CheckBaseStringPriority(attrNode, filePath);
106 }
107 
CheckBaseStringPriority(const cJSON * attrNode,const std::string & filePath)108 bool TranslatableParse::CheckBaseStringPriority(const cJSON *attrNode, const std::string &filePath)
109 {
110     cJSON *priorityNode = cJSON_GetObjectItem(attrNode, TAG_PRIORITY.c_str());
111     if (!priorityNode) {
112         return true;
113     }
114     if (!cJSON_IsString(priorityNode)) {
115         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH)
116                        .FormatCause(TAG_PRIORITY.c_str(), "string")
117                        .SetPosition(filePath));
118         return false;
119     }
120     string priorityValue = priorityNode->valuestring;
121     if (find(PRIORITY_ATTRS.begin(), PRIORITY_ATTRS.end(), priorityValue) == PRIORITY_ATTRS.end()) {
122         string message("[");
123         for (const auto &value : PRIORITY_ATTRS) {
124             message.append("\"" + value + "\",");
125         }
126         message.pop_back();
127         message.append("]");
128         PrintError(GetError(ERR_CODE_INVALID_TRANSLATE_PRIORITY)
129                        .FormatCause(priorityValue.c_str(), message.c_str())
130                        .SetPosition(filePath));
131         return false;
132     }
133     return true;
134 }
135 
ReplaceTranslateTags(cJSON * node,const char * key,const std::string & filePath)136 bool TranslatableParse::ReplaceTranslateTags(cJSON *node, const char *key, const std::string &filePath)
137 {
138     cJSON *valueNode = cJSON_GetObjectItem(node, TAG_VALUE.c_str());
139     if (!valueNode || !cJSON_IsString(valueNode)) {
140         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(TAG_VALUE.c_str(), "string")
141             .SetPosition(filePath));
142         return false;
143     }
144 
145     string value = valueNode->valuestring;
146     if (GetReplaceStringTranslate(value)) {
147         return cJSON_ReplaceItemInObject(node, key, cJSON_CreateString(value.c_str()));
148     }
149     return true;
150 }
151 
GetReplaceStringTranslate(string & str)152 bool TranslatableParse::GetReplaceStringTranslate(string &str)
153 {
154     vector<size_t> posData;
155     if (!FindTranslatePairs(str, posData) || posData.empty()) {
156         return false;
157     }
158     size_t startIndex = 0;
159     string tmp;
160     for (size_t index = 0; index < posData.size(); index++) {
161         tmp.append(str, startIndex, posData[index] - startIndex);
162         startIndex = posData[++index];
163     }
164     str = tmp.append(str, posData.back());
165     return true;
166 }
167 
FindTranslatePairs(const string & str,vector<size_t> & posData)168 bool TranslatableParse::FindTranslatePairs(const string &str, vector<size_t> &posData)
169 {
170     auto startPos = str.find(NO_TRANSLATE_START, 0);
171     auto endPos = str.find(NO_TRANSLATE_END, 0);
172     auto startLength = NO_TRANSLATE_START.length();
173     auto endLength = NO_TRANSLATE_END.length();
174     while (!(startPos == string::npos && endPos == string::npos)) {
175         if (startPos == string::npos || endPos == string::npos) {
176             return false;
177         }
178         if (startPos >= endPos || (!posData.empty() && posData.back() >= startPos)) {
179             return false;
180         }
181         posData.emplace_back(startPos);
182         posData.emplace_back(startPos + startLength);
183         posData.emplace_back(endPos);
184         posData.emplace_back(endPos + endLength);
185         startPos = str.find(NO_TRANSLATE_START, startPos + startLength);
186         endPos = str.find(NO_TRANSLATE_END, endPos + endLength);
187     }
188     return true;
189 }
190 }
191 }
192 }
193