2 // Open Service Platform
3 // Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @File FIo_ZipFileArchive.cpp
20 * @brief This is the implementation file for _ZipFileArchive class.
28 #include <sys/types.h>
29 #include <unique_ptr.h>
31 #include <FBaseResult.h>
32 #include <FBaseSysLog.h>
35 #include <FBase_StringConverter.h>
36 #include <FBase_NativeError.h>
37 #include <FIo_DirEnumeratorImpl.h>
38 #include <FApp_AppInfo.h>
40 #include "FIo_ZipFileArchive.h"
43 using namespace Tizen::Base;
44 using namespace Tizen::App;
46 namespace Tizen { namespace Io
49 static const int MAX_WRITE_BUF_LEN = 4096;
50 const char _ZIP_ARCHIVE_DIR[] = "/tmp/osp/ZipArchive/\0";
54 void operator ()(void* p)
65 void operator ()(FILE* p)
75 _ZipFileArchive::CreateDirectories(char* pFilePath)
77 char* pPos = pFilePath;
78 while ((pPos = strchr(pPos + 1, '/')) != null)
81 if (access(pFilePath, F_OK) != 0)
83 int ret = mkdir(pFilePath, S_IRUSR | S_IWUSR | S_IXUSR);
86 result r = __ConvertNativeErrorToResult(errno);
87 SysTryReturnResult(NID_IO, r == E_FILE_ALREADY_EXIST, r, "Failed to create directory (%s)", pFilePath);
96 _ZipFileArchive::_ZipFileArchive(void)
97 : __pUnZipArchive(null)
101 _ZipFileArchive::~_ZipFileArchive(void)
106 _ZipFileArchive::Construct(const String& zipFilePath)
108 SysAssertf(__pUnZipArchive == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
109 SysTryReturnResult(NID_IO, zipFilePath.GetLength() > 0 && zipFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
110 "Given zipFilePath length is invalid.");
112 std::unique_ptr< char[] > pZipFilePath(_StringConverter::CopyToCharArrayN(zipFilePath));
113 SysTryReturnResult(NID_IO, pZipFilePath != null, E_INVALID_ARG, "Invalid zip file archive path.");
115 std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(pZipFilePath.get()));
116 SysTryReturnResult(NID_IO, pUnzipFile != null, E_IO, "Failed to open [%s].", pZipFilePath.get());
118 __pUnZipArchive = pUnzipFile.release();
124 _ZipFileArchive::GetFileN(const String& relativePath)
126 SysLog(NID_IO, "Enter");
128 SysAssertf(__pUnZipArchive != null, "Not yet constructed. Construct() should be called before use.\n");
129 SysTryReturn(NID_IO, relativePath.GetLength() > 0 && relativePath.GetLength() <= PATH_MAX, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
130 SysTryReturn(NID_IO, relativePath.StartsWith(L"/", 0) == false || relativePath.EndsWith(L"/") == false, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
132 char unzFileEntryName[PATH_MAX + 1] = { 0, };
133 unz_file_info unzfileInfo = { 0, };
134 bool fileEntryFound = false;
136 result r = E_SUCCESS;
138 int err = unzGoToFirstFile(__pUnZipArchive);
139 SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get the first file entry in the zip file.");
143 err = unzGetCurrentFileInfo(__pUnZipArchive, &unzfileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
144 SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get file entry info from the zip file.");
146 String filePath(unzFileEntryName);
147 if (filePath.StartsWith(relativePath, 0))
149 fileEntryFound = true;
152 err = unzGoToNextFile(__pUnZipArchive);
154 (err == UNZ_OK) || (err == UNZ_END_OF_LIST_OF_FILE), null, E_IO, "[E_IO] Failed to get the next entry in the zip file.");
156 } while (err != UNZ_END_OF_LIST_OF_FILE);
157 SysTryReturn(NID_IO, fileEntryFound == true, null, E_FILE_NOT_FOUND, "[E_FILE_NOT_FOUND] The specified file is not found in the archive.");
159 tempFilePath.Append(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
160 tempFilePath.Append(String(L"/") + String(unzFileEntryName));
161 r = _ZipFileArchive::UnzipCurrentFileTo(__pUnZipArchive, tempFilePath);
162 SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] File could not be decompressed.", GetErrorMessage(r));
164 std::unique_ptr<File> pFile(new (std::nothrow) File());
165 SysTryReturn(NID_IO, pFile != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
167 r = pFile->Construct(tempFilePath, L"r");
168 SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] Propagated.", GetErrorMessage(r));
170 return pFile.release();
174 _ZipFileArchive::GetDirEnumeratorN(const String& subDirName)
176 SysAssertf(__pUnZipArchive != null, "Not yet constructed. Construct() should be called before use.\n");
177 SysTryReturn(NID_IO, subDirName.GetLength() > 0 && subDirName.GetLength() <= PATH_MAX, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
178 SysTryReturn(NID_IO, subDirName.StartsWith(L"/", 0) == false, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
180 char unzFileEntryName[PATH_MAX + 1] = {0};
181 unz_file_info unzfileInfo = {0};
182 bool dirEntryFound = false;
183 String relativePath = subDirName;
184 String tempRootDirPath(L"");
185 result r = E_SUCCESS;
187 if (relativePath.EndsWith(L'/') == false)
189 relativePath.Append(L'/');
192 int err = unzGoToFirstFile(__pUnZipArchive);
193 SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get the first file entry in the zip file.");
197 err = unzGetCurrentFileInfo(__pUnZipArchive, &unzfileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
198 SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get file entry info from the zip file.");
200 String filePath(unzFileEntryName);
201 if (filePath.EndsWith(relativePath))
203 dirEntryFound = true;
204 tempRootDirPath.Append(unzFileEntryName);
207 if (dirEntryFound == true)
210 tempPath.Append(unzFileEntryName);
211 if (tempPath.StartsWith(tempRootDirPath, 0) == true)
213 String absoluteDirPath(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
214 absoluteDirPath.Append(String(L"/") + String(unzFileEntryName));
215 r = _ZipFileArchive::UnzipCurrentFileTo(__pUnZipArchive, absoluteDirPath);
216 SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] Propogating to caller...", GetErrorMessage(r));
219 err = unzGoToNextFile(__pUnZipArchive);
221 (err == UNZ_OK) || (err == UNZ_END_OF_LIST_OF_FILE), null, E_IO, "[E_IO] Failed to get the next entry in the zip file.");
223 } while (err != UNZ_END_OF_LIST_OF_FILE);
225 SysTryReturn(NID_IO, dirEntryFound == true, null, E_IO, "[E_IO] The specified subDirName is not found in the archive.");
227 String absoluteDirPath(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
228 absoluteDirPath.Append(String(L"/") + tempRootDirPath);
230 unique_ptr<DirEnumerator> pDirEnum(_DirEnumeratorImpl::CreateDirEnumeratorInstanceN(absoluteDirPath));
231 SysTryReturn(NID_IO, pDirEnum != null, null, E_OUT_OF_MEMORY,
232 "[E_OUT_OF_MEMORY] The memory is insufficient.");
234 SysLog(NID_IO, "Exit");
236 return pDirEnum.release();
240 _ZipFileArchive::UnzipCurrentFileTo(void* pUnZipArchive, const String& filePath)
242 SysLog(NID_IO, "Enter with filePath(%ls))", filePath.GetPointer());
244 std::unique_ptr< char[] > pOutPath(_StringConverter::CopyToCharArrayN(filePath));
245 SysTryReturn(NID_IO, pOutPath != null, GetLastResult(), GetLastResult(), "[%s] Failed to create Directory [%s]", GetErrorMessage(GetLastResult()), pOutPath.get());
247 result r = _ZipFileArchive::CreateDirectories(pOutPath.get());
248 SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to create Directory [%s]", pOutPath.get());
250 if(pOutPath[strlen(pOutPath.get()) - 1] != '/')
252 std::unique_ptr< FILE, CloseFile > pFile(fopen(pOutPath.get(), "w"));
253 r = __ConvertNativeErrorToResult(errno);
254 SysTryReturnResult(NID_IO, pFile != null, r, "Failed to open file [name: %s, errorno: %d].", pOutPath.get(), errno);
256 int err = unzOpenCurrentFile(pUnZipArchive);
257 SysTryReturnResult(NID_IO, err == UNZ_OK, E_IO, "Failed to open current zip file.");
261 char writeBuf[MAX_WRITE_BUF_LEN] = {0};
264 readLen = unzReadCurrentFile(pUnZipArchive, writeBuf, sizeof(writeBuf));
265 r = (readLen < 0) ? E_IO : E_SUCCESS;
266 SysTryCatch(NID_IO, r == E_SUCCESS, unzCloseCurrentFile(pUnZipArchive), r,
267 "[%s] Failed to read from zip file (%s).", GetErrorMessage(E_IO), pOutPath.get());
271 writeCnt = fwrite(writeBuf, 1, readLen, pFile.get());
272 if (writeCnt < readLen)
274 int ret = ferror(pFile.get());
275 r = __ConvertNativeErrorToResult(ret);
276 SysTryCatch(NID_IO, ret != 0, unzCloseCurrentFile(pUnZipArchive), r,
277 "[%s] Failed to perform write operation.", GetErrorMessage(r));
282 unzCloseCurrentFile(pUnZipArchive);