-//
-// Open Service Platform
-// Copyright (c) 2013 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-/**
- * @File FIo_ZipFileArchive.cpp
- * @brief This is the implementation file for _ZipFileArchive class.
- */
-
-#include <new>
-#include <errno.h>
-#include <unistd.h>
-#include <unzip.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unique_ptr.h>
-
-#include <FBaseResult.h>
-#include <FBaseSysLog.h>
-#include <FIo.h>
-
-#include <FBase_StringConverter.h>
-#include <FBase_NativeError.h>
-#include <FIo_DirEnumeratorImpl.h>
-#include <FApp_AppInfo.h>
-
-#include "FIo_ZipFileArchive.h"
-
-using namespace std;
-using namespace Tizen::Base;
-using namespace Tizen::App;
-
-namespace Tizen { namespace Io
-{
-
-static const int MAX_WRITE_BUF_LEN = 4096;
-const char _ZIP_ARCHIVE_DIR[] = "/tmp/osp/ZipArchive/\0";
-
-struct CloseUnzipFile
-{
- void operator ()(void* p)
- {
- if (p != null)
- {
- unzClose(p);
- }
- }
-};
-
-struct CloseFile
-{
- void operator ()(FILE* p)
- {
- if (p != null)
- {
- fclose(p);
- }
- }
-};
-
-result
-_ZipFileArchive::CreateDirectories(char* pFilePath)
-{
- char* pPos = pFilePath;
- while ((pPos = strchr(pPos + 1, '/')) != null)
- {
- *pPos = '\0';
- if (access(pFilePath, F_OK) != 0)
- {
- int ret = mkdir(pFilePath, S_IRUSR | S_IWUSR | S_IXUSR);
- if (ret == -1)
- {
- result r = __ConvertNativeErrorToResult(errno);
- SysTryReturnResult(NID_IO, r == E_FILE_ALREADY_EXIST, r, "Failed to create directory (%s)", pFilePath);
- }
- }
- *pPos = '/';
- }
-
- return E_SUCCESS;
-}
-
-_ZipFileArchive::_ZipFileArchive(void)
- : __pUnZipArchive(null)
-{
-}
-
-_ZipFileArchive::~_ZipFileArchive(void)
-{
-}
-
-result
-_ZipFileArchive::Construct(const String& zipFilePath)
-{
- SysAssertf(__pUnZipArchive == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
- SysTryReturnResult(NID_IO, zipFilePath.GetLength() > 0 && zipFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
- "Given zipFilePath length is invalid.");
-
- std::unique_ptr< char[] > pZipFilePath(_StringConverter::CopyToCharArrayN(zipFilePath));
- SysTryReturnResult(NID_IO, pZipFilePath != null, E_INVALID_ARG, "Invalid zip file archive path.");
-
- std::unique_ptr< void, CloseUnzipFile > pUnzipFile(unzOpen(pZipFilePath.get()));
- SysTryReturnResult(NID_IO, pUnzipFile != null, E_IO, "Failed to open [%s].", pZipFilePath.get());
-
- __pUnZipArchive = pUnzipFile.release();
-
- return E_SUCCESS;
-}
-
-File*
-_ZipFileArchive::GetFileN(const String& relativePath)
-{
- SysLog(NID_IO, "Enter");
-
- SysAssertf(__pUnZipArchive != null, "Not yet constructed. Construct() should be called before use.\n");
- SysTryReturn(NID_IO, relativePath.GetLength() > 0 && relativePath.GetLength() <= PATH_MAX, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
- SysTryReturn(NID_IO, relativePath.StartsWith(L"/", 0) == false || relativePath.EndsWith(L"/") == false, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
-
- char unzFileEntryName[PATH_MAX + 1] = { 0, };
- unz_file_info unzfileInfo = { 0, };
- bool fileEntryFound = false;
- String tempFilePath;
- result r = E_SUCCESS;
-
- int err = unzGoToFirstFile(__pUnZipArchive);
- SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get the first file entry in the zip file.");
-
- do
- {
- err = unzGetCurrentFileInfo(__pUnZipArchive, &unzfileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
- SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get file entry info from the zip file.");
-
- String filePath(unzFileEntryName);
- if (filePath.StartsWith(relativePath, 0))
- {
- fileEntryFound = true;
- break;
- }
- err = unzGoToNextFile(__pUnZipArchive);
- SysTryReturn(NID_IO,
- (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.");
-
- } while (err != UNZ_END_OF_LIST_OF_FILE);
- SysTryReturn(NID_IO, fileEntryFound == true, null, E_FILE_NOT_FOUND, "[E_FILE_NOT_FOUND] The specified file is not found in the archive.");
-
- tempFilePath.Append(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
- tempFilePath.Append(String(L"/") + String(unzFileEntryName));
- r = _ZipFileArchive::UnzipCurrentFileTo(__pUnZipArchive, tempFilePath);
- SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] File could not be decompressed.", GetErrorMessage(r));
-
- std::unique_ptr<File> pFile(new (std::nothrow) File());
- SysTryReturn(NID_IO, pFile != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
-
- r = pFile->Construct(tempFilePath, L"r");
- SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] Propagated.", GetErrorMessage(r));
-
- return pFile.release();
-}
-
-DirEnumerator*
-_ZipFileArchive::GetDirEnumeratorN(const String& subDirName)
-{
- SysAssertf(__pUnZipArchive != null, "Not yet constructed. Construct() should be called before use.\n");
- SysTryReturn(NID_IO, subDirName.GetLength() > 0 && subDirName.GetLength() <= PATH_MAX, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
- SysTryReturn(NID_IO, subDirName.StartsWith(L"/", 0) == false, null, E_INVALID_ARG, "[E_INVALID_ARG] Invalid input path.");
-
- char unzFileEntryName[PATH_MAX + 1] = {0};
- unz_file_info unzfileInfo = {0};
- bool dirEntryFound = false;
- String relativePath = subDirName;
- String tempRootDirPath(L"");
- result r = E_SUCCESS;
-
- if (relativePath.EndsWith(L'/') == false)
- {
- relativePath.Append(L'/');
- }
-
- int err = unzGoToFirstFile(__pUnZipArchive);
- SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get the first file entry in the zip file.");
-
- do
- {
- err = unzGetCurrentFileInfo(__pUnZipArchive, &unzfileInfo, unzFileEntryName, PATH_MAX, null, 0, null, 0);
- SysTryReturn(NID_IO, err == UNZ_OK, null, E_IO, "[E_IO] Failed to get file entry info from the zip file.");
-
- String filePath(unzFileEntryName);
- if (filePath.EndsWith(relativePath))
- {
- dirEntryFound = true;
- tempRootDirPath.Append(unzFileEntryName);
- }
-
- if (dirEntryFound == true)
- {
- String tempPath;
- tempPath.Append(unzFileEntryName);
- if (tempPath.StartsWith(tempRootDirPath, 0) == true)
- {
- String absoluteDirPath(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
- absoluteDirPath.Append(String(L"/") + String(unzFileEntryName));
- r = _ZipFileArchive::UnzipCurrentFileTo(__pUnZipArchive, absoluteDirPath);
- SysTryReturn(NID_IO, !IsFailed(r), null, r, "[%s] Propogating to caller...", GetErrorMessage(r));
- }
- }
- err = unzGoToNextFile(__pUnZipArchive);
- SysTryReturn(NID_IO,
- (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.");
-
- } while (err != UNZ_END_OF_LIST_OF_FILE);
-
- SysTryReturn(NID_IO, dirEntryFound == true, null, E_IO, "[E_IO] The specified subDirName is not found in the archive.");
-
- String absoluteDirPath(String(_ZIP_ARCHIVE_DIR) + _AppInfo::GetApplicationId());
- absoluteDirPath.Append(String(L"/") + tempRootDirPath);
-
- unique_ptr<DirEnumerator> pDirEnum(_DirEnumeratorImpl::CreateDirEnumeratorInstanceN(absoluteDirPath));
- SysTryReturn(NID_IO, pDirEnum != null, null, E_OUT_OF_MEMORY,
- "[E_OUT_OF_MEMORY] The memory is insufficient.");
-
- SysLog(NID_IO, "Exit");
-
- return pDirEnum.release();
-}
-
-result
-_ZipFileArchive::UnzipCurrentFileTo(void* pUnZipArchive, const String& filePath)
-{
- SysLog(NID_IO, "Enter with filePath(%ls))", filePath.GetPointer());
-
- std::unique_ptr< char[] > pOutPath(_StringConverter::CopyToCharArrayN(filePath));
- SysTryReturn(NID_IO, pOutPath != null, GetLastResult(), GetLastResult(), "[%s] Failed to create Directory [%s]", GetErrorMessage(GetLastResult()), pOutPath.get());
-
- result r = _ZipFileArchive::CreateDirectories(pOutPath.get());
- SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to create Directory [%s]", pOutPath.get());
-
- if(pOutPath[strlen(pOutPath.get()) - 1] != '/')
- {
- std::unique_ptr< FILE, CloseFile > pFile(fopen(pOutPath.get(), "w"));
- r = __ConvertNativeErrorToResult(errno);
- SysTryReturnResult(NID_IO, pFile != null, r, "Failed to open file [name: %s, errorno: %d].", pOutPath.get(), errno);
-
- int err = unzOpenCurrentFile(pUnZipArchive);
- SysTryReturnResult(NID_IO, err == UNZ_OK, E_IO, "Failed to open current zip file.");
-
- int writeCnt = 0;
- int readLen = 1;
- char writeBuf[MAX_WRITE_BUF_LEN] = {0};
- while (readLen > 0)
- {
- readLen = unzReadCurrentFile(pUnZipArchive, writeBuf, sizeof(writeBuf));
- r = (readLen < 0) ? E_IO : E_SUCCESS;
- SysTryCatch(NID_IO, r == E_SUCCESS, unzCloseCurrentFile(pUnZipArchive), r,
- "[%s] Failed to read from zip file (%s).", GetErrorMessage(E_IO), pOutPath.get());
-
- if (readLen > 0)
- {
- writeCnt = fwrite(writeBuf, 1, readLen, pFile.get());
- if (writeCnt < readLen)
- {
- int ret = ferror(pFile.get());
- r = __ConvertNativeErrorToResult(ret);
- SysTryCatch(NID_IO, ret != 0, unzCloseCurrentFile(pUnZipArchive), r,
- "[%s] Failed to perform write operation.", GetErrorMessage(r));
- }
- }
- }
-
- unzCloseCurrentFile(pUnZipArchive);
- }
-
-CATCH:
- return r;
-}
-
-}}