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