2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 * @File : FBaseUtil_FileUnzipperImpl.cpp
19 * @brief : Implementation for _FileUnzipperImpl Class
26 #include <sys/types.h>
28 #include <FBaseResult.h>
29 #include <FBaseSysLog.h>
30 #include <FBaseUtilStringUtil.h>
31 #include <FBase_NativeError.h>
33 #include "FBaseUtil_ZipEntryInfo.h"
34 #include "FBaseUtil_FileUnzipperImpl.h"
36 using namespace Tizen::Io;
38 namespace Tizen {namespace Base {namespace Utility
41 #define UNZ_COMP_CASE_SENSITIVE 1
42 #define UNZ_COMP_NO_CASE_SENSITIVE 2
44 #define UNZ_WRITE_BUF_LEN 4096 \
45 // _BADA_SLP_FIXME : TODO - Select an optimal value for this.
49 void operator ()(void* p)
60 void operator ()(FILE* p)
70 _FileUnzipperImpl::CreateDirectories(char* pFilePath)
75 char* pPos = pFilePath;
76 while ((pPos = strchr(pPos + 1, '/')) != null)
79 if (access(pFilePath, F_OK) != 0)
81 ret = mkdir(pFilePath, S_IRUSR | S_IWUSR | S_IXUSR);
84 r = _NativeError::ConvertNativeErrorToResult(errno, true);
85 SysSecureTryReturnResult(NID_BASE_UTIL,
86 (r == E_SUCCESS) || (r == E_FILE_ALREADY_EXIST), r, "Unable to create directory [%s]", pFilePath);
96 _FileUnzipperImpl::IsFileExistsInZip(const char pArchiveName[], const char* pFilePathForZip)
98 std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(pArchiveName));
99 if (pUnzipFile != null)
101 return unzLocateFile(pUnzipFile.get(), pFilePathForZip, UNZ_COMP_CASE_SENSITIVE) != UNZ_END_OF_LIST_OF_FILE;
107 _FileUnzipperImpl::_FileUnzipperImpl(void)
108 : __pArchiveName(null)
115 _FileUnzipperImpl::~_FileUnzipperImpl(void)
120 _FileUnzipperImpl::Construct(const String& filePath)
122 SysAssertf(__pArchiveName == null, "Already constructed! "
123 "Calling Construct() twice or more on a same instance is not allowed for this class");
125 std::unique_ptr< ByteBuffer > pFilePathBuff(StringUtil::StringToUtf8N(filePath));
126 SysTryReturnResult(NID_BASE_UTIL, pFilePathBuff != null, E_INVALID_ARG, "Invalid file path.");
128 const char* pFilePath = reinterpret_cast< const char* >(pFilePathBuff->GetPointer());
129 SysSecureTryReturnResult(NID_BASE_UTIL, access(pFilePath, F_OK) == 0, E_FILE_NOT_FOUND, "Invalid file path [%s].", pFilePath);
131 std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(pFilePath));
132 SysSecureTryReturnResult(NID_BASE_UTIL, pUnzipFile != null, E_IO, "Failed to open [%s].", pFilePath);
137 FilePath unzFileEntryName = {0};
138 unz_global_info gunzfileInfo = {0};
139 unz_file_info unzfileInfo = {0};
141 int err = unzGetGlobalInfo(pUnzipFile.get(), &gunzfileInfo);
142 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to open the zip entry.");
144 err = unzGoToFirstFile(pUnzipFile.get());
145 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to get the first file entry in the zip file.");
149 err = unzGetCurrentFileInfo(pUnzipFile.get(), &unzfileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
150 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to get file entry info from the zip file.");
152 (unzFileEntryName[strlen(unzFileEntryName) - 1] == '/') ? dirCount++ : fileCount++;
154 err = unzGoToNextFile(pUnzipFile.get());
155 SysTryReturnResult(NID_BASE_UTIL,
156 (err == UNZ_OK) || (err == UNZ_END_OF_LIST_OF_FILE), E_IO, "Failed to get the next entry in the zip file.");
159 while (UNZ_END_OF_LIST_OF_FILE != err);
161 int len = strlen(pFilePath);
162 std::unique_ptr< char[] > pArchiveName(new (std::nothrow) char[len + 1]);
163 SysTryReturnResult(NID_BASE_UTIL, pArchiveName != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
165 strncpy(pArchiveName.get(), pFilePath, len);
166 pArchiveName[len] = 0;
168 __pArchiveName = std::move(pArchiveName);
169 __entryCount = gunzfileInfo.number_entry;
170 __dirCount = dirCount;
171 __fileCount = fileCount;
178 _FileUnzipperImpl::UnzipCurrentFileTo(void* pUnZipFile, FilePath outPath, int usedBytes) const
180 unz_file_info unzfileInfo = {0};
181 int err = unzGetCurrentFileInfo(pUnZipFile, &unzfileInfo, &(outPath[usedBytes]), PATH_MAX - usedBytes, null, 0, null, 0);
182 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to get file entry info from the zip file.");
184 result r = _FileUnzipperImpl::CreateDirectories(outPath);
185 SysSecureTryReturnResult(NID_BASE_UTIL, r == E_SUCCESS, r, "Failed to create Directory [%s]", outPath);
187 if (outPath[strlen(outPath) - 1] != '/')
189 std::unique_ptr< FILE, CloseFile > pFile(fopen(outPath, "w"));
190 r = __ConvertNativeErrorToResult(errno);
191 SysSecureTryReturnResult(NID_BASE_UTIL, pFile != null, r, "Failed to open file [name: %s, errorno: %d].", outPath, errno);
193 err = unzOpenCurrentFile(pUnZipFile);
194 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to open current zip file.");
198 char writeBuf[UNZ_WRITE_BUF_LEN] = {0};
201 readLen = unzReadCurrentFile(pUnZipFile, writeBuf, sizeof(writeBuf));
202 r = (readLen < 0) ? E_IO : E_SUCCESS;
203 SysTryCatch(NID_BASE_UTIL, r == E_SUCCESS, unzCloseCurrentFile(pUnZipFile), r,
204 "[%s] Failed to read from zip file.", GetErrorMessage(E_IO));
208 writeCnt = fwrite(writeBuf, 1, readLen, pFile.get());
209 if (writeCnt < readLen)
211 int ret = ferror(pFile.get());
212 r = __ConvertNativeErrorToResult(ret);
213 SysTryCatch(NID_BASE_UTIL, ret != 0, unzCloseCurrentFile(pUnZipFile), r,
214 "[%s] Failed to perform write operation.", GetErrorMessage(r));
219 unzCloseCurrentFile(pUnZipFile);
227 _FileUnzipperImpl::UnzipTo(const String& dirPath) const
229 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
231 String dirPathStr(dirPath);
232 dirPathStr.Replace(L"\\", L"/");
233 if (dirPathStr.EndsWith(L"/") == false)
235 dirPathStr.Append(L"/");
238 std::unique_ptr< ByteBuffer > pDirBuff(StringUtil::StringToUtf8N(dirPathStr));
239 SysTryReturnResult(NID_BASE_UTIL, pDirBuff != null, E_INVALID_ARG, "Invalid file path.");
241 FilePath outPath = {0};
242 int dirPathLength = pDirBuff->GetCapacity() - 1;
243 strncat(outPath, reinterpret_cast< const char* >(pDirBuff->GetPointer()), dirPathLength);
245 std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(__pArchiveName.get()));
246 SysSecureTryReturnResult(NID_BASE_UTIL, pUnzipFile != null, E_IO, "Failed to open [%s].", __pArchiveName.get());
248 int err = unzGoToFirstFile(pUnzipFile.get());
249 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to get the first file entry in the zip file.");
251 result r = E_SUCCESS;
252 int entryCount = __entryCount;
255 r = UnzipCurrentFileTo(pUnzipFile.get(), outPath, dirPathLength);
256 SysTryReturnResult(NID_BASE_UTIL, r == E_SUCCESS, r, "Failed to unzip current file");
260 err = unzGoToNextFile(pUnzipFile.get());
261 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to fetch the next file entry in the zip file.");
269 _FileUnzipperImpl::UnzipTo(const String& dirPath, const String& zipEntryName) const
271 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
273 String dirPathStr = dirPath;
274 dirPathStr.Replace(L"\\", L"/");
275 if (dirPathStr.EndsWith(L"/") == false)
277 dirPathStr.Append(L"/");
280 std::unique_ptr< ByteBuffer > pDirBuff(StringUtil::StringToUtf8N(dirPathStr));
281 SysTryReturnResult(NID_BASE_UTIL, pDirBuff != null, E_INVALID_ARG, "Invalid file path.");
283 FilePath outPath = {0};
284 int dirPathLength = pDirBuff->GetCapacity() - 1;
285 strncat(outPath, reinterpret_cast< const char* >(pDirBuff->GetPointer()), dirPathLength);
287 std::unique_ptr< ByteBuffer > pZipEntryBuff(StringUtil::StringToUtf8N(zipEntryName));
288 SysTryReturnResult(NID_BASE_UTIL, pZipEntryBuff != null, E_INVALID_ARG, "[%s] Invalid zip Entry Name.", GetErrorMessage(E_INVALID_ARG));
290 const char* pZipEntryName = reinterpret_cast< const char* >(pZipEntryBuff->GetPointer());
292 std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(__pArchiveName.get()));
293 SysSecureTryReturnResult(NID_BASE_UTIL, pUnzipFile != null, E_IO, "Failed to open [%s].", __pArchiveName.get());
295 int err = unzLocateFile(pUnzipFile.get(), pZipEntryName, UNZ_COMP_CASE_SENSITIVE);
296 SysSecureTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_FILE_NOT_FOUND, "Failed to locate file entry (%s).", pZipEntryName);
298 return UnzipCurrentFileTo(pUnzipFile.get(), outPath, dirPathLength);
302 _FileUnzipperImpl::GetEntryCount(void) const
304 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
309 _FileUnzipperImpl::GetFileCount(void) const
311 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
316 _FileUnzipperImpl::GetDirectoryCount(void) const
318 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
323 _FileUnzipperImpl::GetCurrentFileInfo(void* pUnZipFile, ZipEntry& entry) const
325 unz_file_info unzFileInfo = {0};
326 char unzFileEntryName[PATH_MAX + 1];
328 // after locate, the current file is the entry, fetch its info
329 int err = unzGetCurrentFileInfo(pUnZipFile, &unzFileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
330 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to fetch information of current file in the zip entry.");
332 String fileEntryName;
333 result r = StringUtil::Utf8ToString(unzFileEntryName, fileEntryName);
334 SysTryReturnResult(NID_BASE_UTIL, r == E_SUCCESS, E_IO, "Invalid file path in Zip file.");
337 r = StringUtil::Utf8ToString(__pArchiveName.get(), archieveName);
338 SysTryReturnResult(NID_BASE_UTIL, r == E_SUCCESS, E_IO, "Invalid file path in Zip file.");
341 int level = DEFAULT_COMPRESSION;
343 err = unzOpenCurrentFile2(pUnZipFile, &method, &level, 1);
344 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to open the current entry in the zip file.");
346 err = unzCloseCurrentFile(pUnZipFile);
347 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to close the zip entry.");
349 _ZipEntryInfo* pZipEntryInfo = null;
350 if (entry.__unzFile == null)
352 pZipEntryInfo = new (std::nothrow) _ZipEntryInfo;
353 SysTryReturnResult(NID_BASE_UTIL, pZipEntryInfo != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
357 pZipEntryInfo = static_cast< _ZipEntryInfo* >(entry.__unzFile);
360 pZipEntryInfo->__name = fileEntryName;
361 if (level == Z_BEST_SPEED)
363 pZipEntryInfo->__compressionLevel = BEST_SPEED;
365 else if (level == Z_BEST_COMPRESSION)
367 pZipEntryInfo->__compressionLevel = BEST_COMPRESSION;
371 pZipEntryInfo->__compressionLevel = DEFAULT_COMPRESSION;
374 const int length = (pZipEntryInfo->__name).GetLength();
375 pZipEntryInfo->__isDirectory = ((pZipEntryInfo->__name)[length - 1] == '/') ? true : false;
376 pZipEntryInfo->__compressedSize = unzFileInfo.compressed_size;
377 pZipEntryInfo->__uncompressedSize = unzFileInfo.uncompressed_size;
378 pZipEntryInfo->__archiveName = archieveName;
379 pZipEntryInfo->__method = method;
381 // set the entry information
382 entry.Set(pZipEntryInfo);
388 _FileUnzipperImpl::GetEntry(const String& zipEntryName, ZipEntry& entry) const
390 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
392 std::unique_ptr< ByteBuffer > pZipEntryBuff(StringUtil::StringToUtf8N(zipEntryName));
393 SysTryReturnResult(NID_BASE_UTIL, pZipEntryBuff != null, E_INVALID_ARG, "Invalid file path.");
395 const char* pZipEntryName = reinterpret_cast< const char* >(pZipEntryBuff->GetPointer());
397 std::unique_ptr< void, CloseUnzipFile > pZipFile(unzOpen(__pArchiveName.get()));
398 SysSecureTryReturnResult(NID_BASE_UTIL, pZipFile != null, E_IO, "Failed to open [%s].", __pArchiveName.get());
400 int err = unzLocateFile(pZipFile.get(), pZipEntryName, UNZ_COMP_CASE_SENSITIVE);
401 SysSecureTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_FILE_NOT_FOUND, "Failed to locate file entry (%s).", pZipEntryName);
403 return GetCurrentFileInfo(pZipFile.get(), entry);
407 _FileUnzipperImpl::GetEntry(int index, ZipEntry& entry) const
409 SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
411 std::unique_ptr< void, CloseUnzipFile > pZipFile(unzOpen(__pArchiveName.get()));
412 SysSecureTryReturnResult(NID_BASE_UTIL, pZipFile != null, E_IO, "Failed to open [%s].", __pArchiveName.get());
414 // goto the first file in the archive
415 int err = unzGoToFirstFile(pZipFile.get());
416 SysTryReturnResult(NID_BASE_UTIL, (err == UNZ_OK), E_IO, "Failed to get the first file entry in the zip file.");
420 err = unzGoToNextFile(pZipFile.get());
421 SysTryReturnResult(NID_BASE_UTIL, err == UNZ_OK, E_IO, "Failed to move to the next entry in zip file.");
424 return GetCurrentFileInfo(pZipFile.get(), entry);
426 }}} // Tizen::Base::Utility