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 "zip_utils.h"
17
18#include <algorithm>
19#include <cstring>
20#include <map>
21#include <iostream>
22
23#include "log.h"
24#include "utils.h"
25
26namespace OHOS {
27namespace AppPackingTool {
28namespace {
29const std::string RESOURCE_PATH = "resources/base/profile/";
30}
31
32ZipUtils::ZipUtils()
33{}
34
35ZipUtils::~ZipUtils()
36{}
37
38int32_t ZipUtils::Zip(const std::string& filePath, const std::string& zipFilePath,
39    const std::string& zipPath, const ZipLevel& zipLevel, const int32_t& append)
40{
41    ZipWrapper zipWrapper(zipFilePath);
42    if (zipWrapper.Open(append) != ZIP_ERR_SUCCESS) {
43        LOGE("ZipWrapper Open failed!");
44        return ZIP_ERR_FAILURE;
45    }
46    if (zipLevel != ZipLevel::ZIP_LEVEL_DEFAULT) {
47        zipWrapper.SetZipLevel(zipLevel);
48    }
49    int32_t ret = zipWrapper.AddFileOrDirectoryToZip(filePath, zipPath);
50    if (ret != ZIP_ERR_SUCCESS) {
51        LOGE("ZipWrapper AddFileOrDirectoryToZip failed!");
52    }
53    zipWrapper.Close();
54    return ret;
55}
56
57int32_t ZipUtils::Unzip(const std::string& zipPath, const std::string& filePath)
58{
59    UnzipWrapper unzipWrapper(zipPath);
60    if (unzipWrapper.Open() != ZIP_ERR_SUCCESS) {
61        LOGE("UnzipWrapper Open failed!");
62        return ZIP_ERR_FAILURE;
63    }
64    int32_t ret = unzipWrapper.UnzipFile(filePath);
65    if (ret != ZIP_ERR_SUCCESS) {
66        LOGE("UnzipWrapper UnzipFile failed!");
67    }
68    unzipWrapper.Close();
69    return ret;
70}
71
72bool ZipUtils::IsFileExistsInZip(const std::string& zipFilePath, const std::string& filename)
73{
74    fs::path fsZipFilePath(zipFilePath);
75    if (!fs::is_regular_file(fsZipFilePath)) {
76        LOGE("Zip file is not a regular file!");
77        return false;
78    }
79    unzFile unzipFile = unzOpen64(zipFilePath.c_str());
80    if (unzipFile == nullptr) {
81        LOGE("Open zip file failed! zipFilePath=%s", zipFilePath.c_str());
82        return false;
83    }
84    unz_global_info64 unzGlobalInfo;
85    if (unzGetGlobalInfo64(unzipFile, &unzGlobalInfo) != UNZ_OK) {
86        LOGE("Get zip global info! zipFilePath=%s", zipFilePath.c_str());
87        unzClose(unzipFile);
88        return false;
89    }
90    char filePathInZip[MAX_ZIP_BUFFER_SIZE] = {0};
91    unz_file_info64 fileInfo;
92    int ret = 0;
93    bool isExist = false;
94    for (size_t i = 0; i < unzGlobalInfo.number_entry; ++i) {
95        if (unzGetCurrentFileInfo64(unzipFile, &fileInfo, filePathInZip, MAX_ZIP_BUFFER_SIZE, NULL, 0, NULL, 0) !=
96            UNZ_OK) {
97            LOGE("Get current file info in zip failed!");
98            break;
99        }
100        std::string strFilePathInZip(filePathInZip);
101        if (fileInfo.external_fa != ZIP_FILE_ATTR_DIRECTORY && strFilePathInZip.length() >= filename.length()) {
102            std::transform(strFilePathInZip.begin(), strFilePathInZip.end(), strFilePathInZip.begin(), ::tolower);
103            if (strFilePathInZip.compare(filename) == 0) {
104                isExist = true;
105                break;
106            }
107        }
108        ret = unzGoToNextFile(unzipFile);
109        if (ret == UNZ_END_OF_LIST_OF_FILE) {
110            break;
111        } else if (ret != UNZ_OK) {
112            LOGE("Go to next file in zip failed!");
113            break;
114        }
115    }
116    unzClose(unzipFile);
117    return isExist;
118}
119
120bool ZipUtils::IsFileNameExistsInZip(const std::string& zipFilePath, const std::string& filename)
121{
122    fs::path fsZipFilePath(zipFilePath);
123    if (!fs::is_regular_file(fsZipFilePath)) {
124        LOGE("Zip file is not a regular file!");
125        return false;
126    }
127    unzFile unzipFile = unzOpen64(zipFilePath.c_str());
128    if (unzipFile == nullptr) {
129        LOGE("Open zip file failed! zipFilePath=%s", zipFilePath.c_str());
130        return false;
131    }
132    unz_global_info64 unzGlobalInfo;
133    if (unzGetGlobalInfo64(unzipFile, &unzGlobalInfo) != UNZ_OK) {
134        LOGE("Get zip global info! zipFilePath=%s", zipFilePath.c_str());
135        unzClose(unzipFile);
136        return false;
137    }
138    char filePathInZip[MAX_ZIP_BUFFER_SIZE] = {0};
139    unz_file_info64 fileInfo;
140    int ret = 0;
141    bool isExist = false;
142    for (size_t i = 0; i < unzGlobalInfo.number_entry; ++i) {
143        if (unzGetCurrentFileInfo64(unzipFile, &fileInfo, filePathInZip, MAX_ZIP_BUFFER_SIZE, NULL, 0, NULL, 0) !=
144            UNZ_OK) {
145            LOGE("Get current file info in zip failed!");
146            break;
147        }
148        std::string strFilePathInZip(filePathInZip);
149        if (fileInfo.external_fa != ZIP_FILE_ATTR_DIRECTORY && strFilePathInZip.length() >= filename.length()) {
150            if (strFilePathInZip.substr(strFilePathInZip.length() - filename.length()).compare(filename) == 0) {
151                isExist = true;
152                break;
153            }
154        }
155        ret = unzGoToNextFile(unzipFile);
156        if (ret == UNZ_END_OF_LIST_OF_FILE) {
157            break;
158        } else if (ret != UNZ_OK) {
159            LOGE("Go to next file in zip failed!");
160            break;
161        }
162    }
163    unzClose(unzipFile);
164    return isExist;
165}
166
167bool ZipUtils::GetFileContentFromZip(const std::string& zipFilePath, const std::string& filename,
168    std::string& fileContent)
169{
170    fs::path fsZipFilePath(zipFilePath);
171    if (!fs::is_regular_file(fsZipFilePath)) {
172        LOGE("Zip file is not a regular file!");
173        return false;
174    }
175    unzFile unzipFile = unzOpen64(zipFilePath.c_str());
176    if (unzipFile == nullptr) {
177        LOGE("Open zip file failed! zipFilePath=%s", zipFilePath.c_str());
178        return false;
179    }
180    if (unzLocateFile(unzipFile, filename.c_str(), 0) != UNZ_OK) {
181        LOGE("Locate file failed! filename=%s", filename.c_str());
182        unzClose(unzipFile);
183        return false;
184    }
185    unz_file_info64 fileInfo;
186    char filePathInZip[MAX_ZIP_BUFFER_SIZE] = {0};
187    if (unzGetCurrentFileInfo64(unzipFile, &fileInfo, filePathInZip, MAX_ZIP_BUFFER_SIZE, NULL, 0, NULL, 0) !=
188        UNZ_OK) {
189        LOGE("Get current file info in zip failed! filename=%s", filename.c_str());
190        unzClose(unzipFile);
191        return false;
192    }
193    if (unzOpenCurrentFile(unzipFile) != UNZ_OK) {
194        LOGE("Open current file in zip failed! filename=%s", filename.c_str());
195        unzClose(unzipFile);
196        return false;
197    }
198    char buffer[MAX_ZIP_BUFFER_SIZE];
199    int readLen = 0;
200    fileContent = "";
201    do {
202        std::fill_n(buffer, MAX_ZIP_BUFFER_SIZE, '\0');
203        readLen = unzReadCurrentFile(unzipFile, buffer, MAX_ZIP_BUFFER_SIZE);
204        if (readLen < 0) {
205            LOGE("Read current file in zip failed! filename=%s", filename.c_str());
206            unzCloseCurrentFile(unzipFile);
207            unzClose(unzipFile);
208            return false;
209        } else if (readLen == 0) {
210            break;
211        }
212        fileContent += std::string(buffer);
213    } while (readLen > 0);
214    unzCloseCurrentFile(unzipFile);
215    unzClose(unzipFile);
216    return true;
217}
218
219bool ZipUtils::GetUnzipCurrentFileContent(unzFile& unzipFile, std::string& fileContent)
220{
221    if (unzipFile == nullptr) {
222        return false;
223    }
224    if (unzOpenCurrentFile(unzipFile) != UNZ_OK) {
225        LOGE("Open current file in zip failed!");
226        return false;
227    }
228    char buffer[MAX_ZIP_BUFFER_SIZE];
229    int readLen = 0;
230    fileContent = "";
231    do {
232        std::fill_n(buffer, MAX_ZIP_BUFFER_SIZE, '\0');
233        readLen = unzReadCurrentFile(unzipFile, buffer, MAX_ZIP_BUFFER_SIZE);
234        if (readLen < 0) {
235            LOGE("Read current file in zip failed!");
236            unzCloseCurrentFile(unzipFile);
237            return false;
238        } else if (readLen == 0) {
239            break;
240        }
241        fileContent += std::string(buffer);
242    } while (readLen > 0);
243    unzCloseCurrentFile(unzipFile);
244    return true;
245}
246
247bool ZipUtils::AddToResourceMap(unzFile& unzipFile, const std::string& filePathInZip,
248    std::map<std::string, std::string>& resourceMap)
249{
250    if (unzipFile == nullptr) {
251        LOGE("zip file not open!");
252        return false;
253    }
254    if (filePathInZip.find(RESOURCE_PATH) != std::string::npos) {
255        std::string fileName = Utils::ReplaceAll(filePathInZip, RESOURCE_PATH, "");
256        std::string fileContent;
257        if (!GetUnzipCurrentFileContent(unzipFile, fileContent)) {
258            LOGE("Get current file content failed! filename=%s", filePathInZip.c_str());
259            return false;
260        } else {
261            resourceMap.emplace(fileName, fileContent);
262        }
263    }
264    return true;
265}
266
267bool ZipUtils::GetResourceMapFromZip(const std::string& zipFilePath, std::map<std::string, std::string>& resourceMap)
268{
269    fs::path fsZipFilePath(zipFilePath);
270    if (!fs::is_regular_file(fsZipFilePath)) {
271        LOGE("Zip file is not a regular file!");
272        return false;
273    }
274    unzFile unzipFile = unzOpen64(zipFilePath.c_str());
275    if (unzipFile == nullptr) {
276        LOGE("Open zip file failed! zipFilePath=%s", zipFilePath.c_str());
277        return false;
278    }
279    unz_global_info64 unzGlobalInfo;
280    if (unzGetGlobalInfo64(unzipFile, &unzGlobalInfo) != UNZ_OK) {
281        LOGE("Get zip global info! zipFilePath=%s", zipFilePath.c_str());
282        unzClose(unzipFile);
283        return false;
284    }
285    char filePathInZip[MAX_ZIP_BUFFER_SIZE] = {0};
286    unz_file_info64 fileInfo;
287    int ret = 0;
288    for (size_t i = 0; i < unzGlobalInfo.number_entry; ++i) {
289        if (unzGetCurrentFileInfo64(unzipFile, &fileInfo, filePathInZip, MAX_ZIP_BUFFER_SIZE, NULL, 0, NULL, 0) !=
290            UNZ_OK) {
291            LOGE("Get current file info in zip failed!");
292            break;
293        }
294        std::string strFilePathInZip(filePathInZip);
295        if (fileInfo.external_fa != ZIP_FILE_ATTR_DIRECTORY && strFilePathInZip.length() > RESOURCE_PATH.length()) {
296            AddToResourceMap(unzipFile, strFilePathInZip, resourceMap);
297        }
298        ret = unzGoToNextFile(unzipFile);
299        if (ret == UNZ_END_OF_LIST_OF_FILE) {
300            break;
301        } else if (ret != UNZ_OK) {
302            LOGE("Go to next file in zip failed!");
303            break;
304        }
305    }
306    unzClose(unzipFile);
307    return true;
308}
309} // namespace AppPackingTool
310} // namespace OHOS
311