Merge "Replace gmtime to gmtime_r for TimeZone" into tizen_2.2
[platform/framework/native/appfw.git] / src / base / utility / FBaseUtil_FileZipperImpl.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 //
16
17 /**
18  * @File        :       FBaseUtil_FileZipperImpl.cpp
19  * @brief       :   Implementation for _FileZipperImpl Class
20  */
21 #include <new>
22 #include <zip.h>
23 #include <errno.h>
24
25 #include <FBaseResult.h>
26 #include <FBaseSysLog.h>
27 #include <FBaseUtilStringUtil.h>
28 #include <FBaseUtilFileZipper.h>
29
30 #include "FBase_NativeError.h"
31 #include "FBaseUtil_FileUnzipperImpl.h"
32 #include "FBaseUtil_FileZipperImpl.h"
33
34 using namespace Tizen::Io;
35
36 namespace Tizen { namespace Base { namespace Utility
37 {
38
39 struct ZipFileDeleter
40 {
41         void operator ()(void* p)
42         {
43                 if (p != null)
44                 {
45                         zipClose(p, null);
46                 }
47         }
48 };
49
50 #define UNZ_COMP_CASE_SENSITIVE 1
51 #define UNZ_COMP_NO_CASE_SENSITIVE  2
52
53 #define ZIP_WRITE_BUF_LEN 4096
54
55 _FileZipperImpl::_FileZipperImpl(void)
56         : __pArchiveName(null)
57         , __overwrite(false)
58 {
59 }
60
61 _FileZipperImpl::~_FileZipperImpl(void)
62 {
63 }
64
65 result
66 _FileZipperImpl::Construct(const String& filePath)
67 {
68         SysAssertf(__pArchiveName == null, "Already constructed! "
69                         "Calling Construct() twice or more on a same instance is not allowed for this class");
70
71         std::unique_ptr< ByteBuffer > pFilePathBuff(StringUtil::StringToUtf8N(filePath));
72         SysTryReturnResult(NID_BASE_UTIL, pFilePathBuff != null, E_INVALID_ARG, "Invalid file path.");
73
74         const char* pFilePath = reinterpret_cast< const char* >(pFilePathBuff->GetPointer());
75
76         result r = IsFileExists(pFilePath);
77         SysSecureTryReturnResult(NID_BASE_UTIL, (r == E_SUCCESS) || (r == E_FILE_NOT_FOUND), r, "Invalid file path [%s].", pFilePath);
78
79         int createOption = (r == E_FILE_NOT_FOUND) ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP;
80         std::unique_ptr< void, ZipFileDeleter > pZfile(zipOpen(pFilePath, createOption));
81         SysSecureTryReturnResult(NID_BASE_UTIL, pZfile != null, E_IO, "Invalid file path [%s].", pFilePath);
82
83         int len = strlen(pFilePath);
84         std::unique_ptr< char[] > pArchiveName(new (std::nothrow) char[len + 1]);
85         SysTryReturnResult(NID_BASE_UTIL, pArchiveName != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
86
87         strncpy(pArchiveName.get(), pFilePath, len);
88         pArchiveName[len] = 0;
89
90         __pArchiveName = std::move(pArchiveName);
91
92         ClearLastResult();
93         return E_SUCCESS;
94 }
95
96 result
97 _FileZipperImpl::AddToZip(const String& filePath, bool excludePath, CompressionLevel level)
98 {
99         SysAssertf(__pArchiveName != null, "Not yet constructed! Construct() should be called before use");
100
101         std::unique_ptr< ByteBuffer > pFilePathBuff(StringUtil::StringToUtf8N(filePath));
102         SysTryReturnResult(NID_BASE_UTIL, pFilePathBuff != null, E_INVALID_ARG, "Invalid file path argument.");
103
104         const char* pFilePath = reinterpret_cast< const char* >(pFilePathBuff->GetPointer());
105
106         result r = IsFileExists(pFilePath);
107         SysTryReturnResult(NID_BASE_UTIL, r == E_SUCCESS, E_FILE_NOT_FOUND, "The file is not found.");
108
109         const char* pFilePathForZip = pFilePath;
110         if (excludePath == true)
111         {
112                 const char* pPos = strrchr(pFilePathForZip, '/');
113                 if (pPos)
114                 {
115                         pFilePathForZip = pPos;
116                 }
117
118                 if (pFilePathForZip[0] == '/')
119                 {
120                         pFilePathForZip++;
121                 }
122         }
123
124         int compLevel = DEFAULT_COMPRESSION;
125         if (level == BEST_SPEED)
126         {
127                 compLevel = Z_BEST_SPEED;
128         }
129         else if (level == BEST_COMPRESSION)
130         {
131                 compLevel = Z_BEST_COMPRESSION;
132         }
133
134         if (_FileUnzipperImpl::IsFileExistsInZip(__pArchiveName.get(), pFilePathForZip))
135         {
136                 SysTryReturnResult(NID_BASE_UTIL, __overwrite == true, E_FILE_ALREADY_EXIST, "File already exist but overwrite flag is not set");
137                 return OverwriteInZip(pFilePath, pFilePathForZip, compLevel);
138         }
139
140         return AddToZip(pFilePath, pFilePathForZip, compLevel);
141 }
142
143 bool
144 _FileZipperImpl::GetOverwriteFlag(void) const
145 {
146         return __overwrite;
147 }
148
149 void
150 _FileZipperImpl::SetOverwriteFlag(bool flag)
151 {
152         __overwrite = flag;
153 }
154
155 result
156 _FileZipperImpl::AddToZip(const char* pFilePath, const char* pFilePathForZip, int level)
157 {
158         int err = ZIP_OK;
159         result r = E_SUCCESS;
160
161         std::unique_ptr< void, ZipFileDeleter > pZfile(zipOpen(__pArchiveName.get(), APPEND_STATUS_ADDINZIP));
162         SysSecureTryReturnResult(NID_BASE_UTIL, pZfile != null, E_IO, "Invalid file path [%s].", __pArchiveName.get());
163
164         zip_fileinfo zipInfo = {{0}};
165         err = zipOpenNewFileInZip(pZfile.get(), pFilePathForZip, &zipInfo, null, 0, null, 0, null, Z_DEFLATED, level);
166         SysTryReturnResult(NID_BASE_UTIL, err == ZIP_OK, E_IO, "Failed to open new file in zip.");
167
168         FILE* pFile = fopen(pFilePath, "r");
169         if (pFile == null)
170         {
171                 zipCloseFileInZip(pZfile.get());
172                 SysTryReturnResult(NID_BASE_UTIL, pFile != null, __ConvertNativeErrorToResult(errno), "Failed to open the file.");
173         }
174
175         int readCnt = 1;
176         char buffer[ZIP_WRITE_BUF_LEN] = {0};
177         while (readCnt > 0 && !feof(pFile))
178         {
179                 readCnt = fread(buffer, 1, ZIP_WRITE_BUF_LEN, pFile);
180                 if (readCnt > 0)
181                 {
182                         err = zipWriteInFileInZip(pZfile.get(), buffer, readCnt);
183                         SysTryCatch(NID_BASE_UTIL, err == ZIP_OK, r = E_IO, E_IO, "[%s] Failed to write in zip file.", GetErrorMessage(E_IO));
184                 }
185         }
186
187         // fall through
188 CATCH:
189         zipCloseFileInZip(pZfile.get());
190         if (pFile != null)
191         {
192                 fclose(pFile);
193         }
194
195         SetLastResult(r);
196         return r;
197 }
198
199 result
200 _FileZipperImpl::OverwriteInZip(const char* pFilePath, const char* pFilePathForZip, int level)
201 {
202         // TODO: Add Support for overwriting
203         return AddToZip(pFilePath, pFilePathForZip, level);
204 }
205
206 result
207 _FileZipperImpl::IsFileExists(const char* pFilePath)
208 {
209         if (access(pFilePath, F_OK) != 0)
210         {
211                 return __ConvertNativeErrorToResult(errno);
212         }
213
214         return E_SUCCESS;
215 }
216 }}} // Tizen::Base::Utility