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