1 /*
2 * Copyright (c) 2024-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 "resource_dumper.h"
17
18 #include <cstdint>
19 #include <iostream>
20 #include <memory>
21 #include <ostream>
22 #include <set>
23 #include <sstream>
24 #include <functional>
25 #include "cJSON.h"
26 #include "resource_item.h"
27 #include "resource_table.h"
28 #include "resource_util.h"
29 #include "restool_errors.h"
30
31
32 namespace OHOS {
33 namespace Global {
34 namespace Restool {
35
36 constexpr int PAIR_SIZE = 2;
37
38 static std::map<std::string, std::function<std::unique_ptr<ResourceDumper>()>> dumpMap_ = {
39 {"config", std::make_unique<ConfigDumper>}
40 };
41
Dump(const DumpParserBase & packageParser)42 uint32_t ResourceDumper::Dump(const DumpParserBase &packageParser)
43 {
44 inputPath_ = packageParser.GetInputPath();
45 if (LoadHap() != RESTOOL_SUCCESS) {
46 return RESTOOL_ERROR;
47 }
48 std::string jsonStr;
49 if (DumpRes(jsonStr) != RESTOOL_SUCCESS) {
50 return RESTOOL_ERROR;
51 }
52 std::cout << jsonStr << std::endl;
53 return RESTOOL_SUCCESS;
54 }
55
LoadHap()56 uint32_t ResourceDumper::LoadHap()
57 {
58 unzFile zipFile = unzOpen64(inputPath_.c_str());
59 if (!zipFile) {
60 PrintError(GetError(ERR_CODE_PARSE_HAP_ERROR).FormatCause("can't unzip hap").SetPosition(inputPath_));
61 return RESTOOL_ERROR;
62 }
63 std::unique_ptr<char[]> buffer;
64 size_t len;
65 if (ReadFileFromZip(zipFile, "module.json", buffer, len) == RESTOOL_SUCCESS) {
66 ReadHapInfo(buffer, len);
67 } else if (ReadFileFromZip(zipFile, "config.json", buffer, len) == RESTOOL_SUCCESS) {
68 ReadHapInfo(buffer, len);
69 }
70 if (ReadFileFromZip(zipFile, "resources.index", buffer, len) != RESTOOL_SUCCESS) {
71 unzClose(zipFile);
72 PrintError(GetError(ERR_CODE_PARSE_HAP_ERROR)
73 .FormatCause("read resources.index failed").SetPosition(inputPath_));
74 return RESTOOL_ERROR;
75 }
76 unzClose(zipFile);
77 std::stringstream stream;
78 stream.write(buffer.get(), len);
79 if (ResourceTable::LoadResTable(stream, resInfos_) != RESTOOL_SUCCESS) {
80 return RESTOOL_ERROR;
81 }
82 return RESTOOL_SUCCESS;
83 }
84
ReadHapInfo(const std::unique_ptr<char[]> & buffer,size_t len)85 void ResourceDumper::ReadHapInfo(const std::unique_ptr<char[]> &buffer, size_t len)
86 {
87 cJSON *config = cJSON_Parse(buffer.get());
88 if (!config) {
89 return;
90 }
91 cJSON *appConfig = cJSON_GetObjectItemCaseSensitive(config, "app");
92 cJSON *moduleConfig = cJSON_GetObjectItemCaseSensitive(config, "module");
93 if (appConfig) {
94 cJSON *bundleName = cJSON_GetObjectItemCaseSensitive(appConfig, "bundleName");
95 if (cJSON_IsString(bundleName) && bundleName->valuestring) {
96 bundleName_ = bundleName->valuestring;
97 }
98 }
99 if (moduleConfig) {
100 cJSON *moduleName = cJSON_GetObjectItemCaseSensitive(moduleConfig, "name");
101 if (cJSON_IsString(moduleName) && moduleName->valuestring) {
102 moduleName_ = moduleName->valuestring;
103 }
104 }
105 cJSON_Delete(config);
106 }
107
ReadFileFromZip(unzFile & zipFile,const char * fileName,std::unique_ptr<char[]> & buffer,size_t & len)108 uint32_t ResourceDumper::ReadFileFromZip(
109 unzFile &zipFile, const char *fileName, std::unique_ptr<char[]> &buffer, size_t &len)
110 {
111 unz_file_info fileInfo;
112 if (unzLocateFile2(zipFile, fileName, 1) != UNZ_OK) {
113 return RESTOOL_ERROR;
114 }
115 char filenameInZip[256];
116 int err = unzGetCurrentFileInfo(zipFile, &fileInfo, filenameInZip, sizeof(filenameInZip), nullptr, 0, nullptr, 0);
117 if (err != UNZ_OK) {
118 return RESTOOL_ERROR;
119 }
120
121 len = fileInfo.uncompressed_size;
122 buffer = std::make_unique<char[]>(len);
123 if (!buffer) {
124 return RESTOOL_ERROR;
125 }
126
127 err = unzOpenCurrentFilePassword(zipFile, nullptr);
128 if (err != UNZ_OK) {
129 return RESTOOL_ERROR;
130 }
131 err = unzReadCurrentFile(zipFile, buffer.get(), len);
132 if (err < 0) {
133 return RESTOOL_ERROR;
134 }
135 return RESTOOL_SUCCESS;
136 }
137
DumpRes(std::string & out) const138 uint32_t CommonDumper::DumpRes(std::string &out) const
139 {
140 std::unique_ptr<cJSON, std::function<void(cJSON*)>> root(cJSON_CreateObject(),
141 [](cJSON* node) { cJSON_Delete(node); });
142 if (!root) {
143 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for root object"));
144 return RESTOOL_ERROR;
145 }
146 if (!bundleName_.empty() && !moduleName_.empty()) {
147 cJSON *bundleName = cJSON_CreateString(bundleName_.c_str());
148 cJSON *moduleName = cJSON_CreateString(moduleName_.c_str());
149 if (bundleName) {
150 cJSON_AddItemToObject(root.get(), "bundleName", bundleName);
151 }
152 if (moduleName) {
153 cJSON_AddItemToObject(root.get(), "moduleName", moduleName);
154 }
155 }
156 cJSON *resource = cJSON_CreateArray();
157 if (!resource) {
158 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR)
159 .FormatCause("unable to create cJSON object for resource array"));
160 return RESTOOL_ERROR;
161 }
162 cJSON_AddItemToObject(root.get(), "resource", resource);
163 for (auto it = resInfos_.begin(); it != resInfos_.end(); it++) {
164 if (AddResourceToJson(it->first, it->second, resource)) {
165 return RESTOOL_ERROR;
166 }
167 }
168 char *rawStr = cJSON_Print(root.get());
169 if (!rawStr) {
170 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("covert json object to str failed"));
171 return RESTOOL_ERROR;
172 }
173 out = rawStr;
174 cJSON_free(rawStr);
175 rawStr = nullptr;
176 return RESTOOL_SUCCESS;
177 }
178
AddKeyParamsToJson(const std::vector<KeyParam> & keyParams,cJSON * json) const179 uint32_t CommonDumper::AddKeyParamsToJson(const std::vector<KeyParam> &keyParams, cJSON *json) const
180 {
181 if (!json) {
182 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("add keyparam to null json object"));
183 return RESTOOL_ERROR;
184 }
185 for (const auto &keyParam : keyParams) {
186 std::string valueStr = ResourceUtil::GetKeyParamValue(keyParam);
187 cJSON *value = cJSON_CreateString(valueStr.c_str());
188 if (!value) {
189 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for keyparam"));
190 return RESTOOL_ERROR;
191 }
192 cJSON_AddItemToObject(json, ResourceUtil::KeyTypeToStr(keyParam.keyType).c_str(), value);
193 }
194 return RESTOOL_SUCCESS;
195 }
196
AddItemCommonPropToJson(int64_t resId,const ResourceItem & item,cJSON * json) const197 uint32_t CommonDumper::AddItemCommonPropToJson(int64_t resId, const ResourceItem &item, cJSON* json) const
198 {
199 if (!json) {
200 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("add item common property to null json object"));
201 return RESTOOL_ERROR;
202 }
203 cJSON *id = cJSON_CreateNumber(resId);
204 if (!id) {
205 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource id"));
206 return RESTOOL_ERROR;
207 }
208 cJSON_AddItemToObject(json, "id", id);
209
210 cJSON *name = cJSON_CreateString(item.GetName().c_str());
211 if (!name) {
212 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource name"));
213 return RESTOOL_ERROR;
214 }
215 cJSON_AddItemToObject(json, "name", name);
216
217 cJSON *type = cJSON_CreateString((ResourceUtil::ResTypeToString(item.GetResType())).c_str());
218 if (!type) {
219 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource type"));
220 return RESTOOL_ERROR;
221 }
222 cJSON_AddItemToObject(json, "type", type);
223 return RESTOOL_SUCCESS;
224 }
225
AddResourceToJson(int64_t resId,const std::vector<ResourceItem> & items,cJSON * json) const226 uint32_t CommonDumper::AddResourceToJson(int64_t resId, const std::vector<ResourceItem> &items, cJSON *json) const
227 {
228 if (items.empty()) {
229 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("resource items is empty"));
230 return RESTOOL_ERROR;
231 }
232 if (!json) {
233 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("add resource to null json object"));
234 return RESTOOL_ERROR;
235 }
236 cJSON *resource = cJSON_CreateObject();
237 if (!resource) {
238 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource item"));
239 return RESTOOL_ERROR;
240 }
241 cJSON_AddItemToArray(json, resource);
242 if (AddItemCommonPropToJson(resId, items[0], resource) != RESTOOL_SUCCESS) {
243 return RESTOOL_ERROR;
244 };
245 cJSON *entryCount = cJSON_CreateNumber(items.size());
246 if (!entryCount) {
247 PrintError(
248 GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource value count"));
249 return RESTOOL_ERROR;
250 }
251 cJSON_AddItemToObject(resource, "entryCount", entryCount);
252
253 cJSON *entryValues = cJSON_CreateArray();
254 if (!resource) {
255 PrintError(
256 GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for resource value array"));
257 return RESTOOL_ERROR;
258 }
259 cJSON_AddItemToObject(resource, "entryValues", entryValues);
260
261 for (const ResourceItem &item : items) {
262 cJSON *value = cJSON_CreateObject();
263 if (!value) {
264 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR)
265 .FormatCause("unable to create cJSON object for value item"));
266 return RESTOOL_ERROR;
267 }
268 cJSON_AddItemToArray(entryValues, value);
269 if (AddValueToJson(item, value) != RESTOOL_SUCCESS) {
270 return RESTOOL_ERROR;
271 }
272 if (AddKeyParamsToJson(item.GetKeyParam(), value) != RESTOOL_SUCCESS) {
273 return RESTOOL_ERROR;
274 }
275 }
276 return RESTOOL_SUCCESS;
277 }
278
AddPairVauleToJson(const ResourceItem & item,cJSON * json) const279 uint32_t CommonDumper::AddPairVauleToJson(const ResourceItem &item, cJSON *json) const
280 {
281 if (!json) {
282 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("add pair vaule to null json object"));
283 return RESTOOL_ERROR;
284 }
285 cJSON *value = cJSON_CreateObject();
286 if (!value) {
287 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for value object"));
288 return RESTOOL_ERROR;
289 }
290 cJSON_AddItemToObject(json, "value", value);
291 const std::vector<std::string> rawValues = item.SplitValue();
292 uint32_t index = 1;
293 if (rawValues.size() % PAIR_SIZE != 0) {
294 cJSON *parent = cJSON_CreateString(rawValues[0].c_str());
295 if (!parent) {
296 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for parent"));
297 return RESTOOL_ERROR;
298 }
299 cJSON_AddItemToObject(json, "parent", parent);
300 index++;
301 }
302 for (; index < rawValues.size(); index += PAIR_SIZE) {
303 cJSON *item = cJSON_CreateString(rawValues[index].c_str());
304 if (!item) {
305 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR)
306 .FormatCause("unable to create cJSON object for value item"));
307 return RESTOOL_ERROR;
308 }
309 cJSON_AddItemToObject(value, rawValues[index -1].c_str(), item);
310 }
311 return RESTOOL_SUCCESS;
312 }
313
AddValueToJson(const ResourceItem & item,cJSON * json) const314 uint32_t CommonDumper::AddValueToJson(const ResourceItem &item, cJSON *json) const
315 {
316 if (!json) {
317 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("add value to null json object"));
318 return RESTOOL_ERROR;
319 }
320 if (item.IsArray()) {
321 cJSON *values = cJSON_CreateArray();
322 if (!values) {
323 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR)
324 .FormatCause("unable to create cJSON object for value array"));
325 return RESTOOL_ERROR;
326 }
327 cJSON_AddItemToObject(json, "value", values);
328 const std::vector<std::string> rawValues = item.SplitValue();
329 for (const std::string &value : rawValues) {
330 cJSON *valueItem = cJSON_CreateString(value.c_str());
331 if (!valueItem) {
332 PrintError(
333 GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for value item"));
334 return RESTOOL_ERROR;
335 }
336 cJSON_AddItemToArray(values, valueItem);
337 }
338 return RESTOOL_SUCCESS;
339 }
340 if (item.IsPair()) {
341 return AddPairVauleToJson(item, json);
342 }
343 std::string rawValue = std::string(reinterpret_cast<const char*>(item.GetData()), item.GetDataLength());
344 cJSON *value = cJSON_CreateString(rawValue.c_str());
345 if (!value) {
346 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for value"));
347 return RESTOOL_ERROR;
348 }
349 cJSON_AddItemToObject(json, "value", value);
350 return RESTOOL_SUCCESS;
351 }
352
DumpRes(std::string & out) const353 uint32_t ConfigDumper::DumpRes(std::string &out) const
354 {
355 std::unique_ptr<cJSON, std::function<void(cJSON*)>> root(cJSON_CreateObject(),
356 [](cJSON* node) { cJSON_Delete(node); });
357 if (!root) {
358 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for root object"));
359 return RESTOOL_ERROR;
360 }
361 cJSON *configs = cJSON_CreateArray();
362 if (!configs) {
363 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for config array"));
364 return RESTOOL_ERROR;
365 }
366 cJSON_AddItemToObject(root.get(), "config", configs);
367
368 std::set<std::string> configSet;
369 for (auto it = resInfos_.cbegin(); it != resInfos_.cend(); it++) {
370 for (const auto &item : it->second) {
371 const std::string &limitKey = item.GetLimitKey();
372 if (configSet.count(limitKey) != 0) {
373 continue;
374 }
375 configSet.emplace(limitKey);
376 cJSON *config = cJSON_CreateString(limitKey.c_str());
377 if (!config) {
378 PrintError(
379 GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("unable to create cJSON object for limitkey"));
380 return RESTOOL_ERROR;
381 }
382 cJSON_AddItemToArray(configs, config);
383 }
384 }
385 char *rawStr = cJSON_Print(root.get());
386 if (!rawStr) {
387 PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause("covert config json object to str failed"));
388 return RESTOOL_ERROR;
389 }
390 out = rawStr;
391 cJSON_free(rawStr);
392 rawStr = nullptr;
393 return RESTOOL_SUCCESS;
394 }
395 }
396 }
397 }