SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
ZipUtils.cpp
Go to the documentation of this file.
1 /**
2  * \file ZipUtils.cpp
3  * \authors Luc Girod
4  * \date 2020
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8 */
9 
10 #include <cstring>
11 #include <string>
12 #include <iostream>
13 #include <functional>
14 #include <Utils.h>
15 #include <minizip/unzip.h>
16 #include <minizip/zip.h>
17 
18 namespace ZipUtils
19 {
20 //-----------------------------------------------------------------------------
21 /*!
22  *
23  * \param zfile ???
24  * \param dirname ???
25  * \return ???
26  */
27 static bool zip_add_dir(zipFile zfile, string dirname)
28 {
29  char* temp;
30  size_t len;
31  int ret;
32 
33  if (zfile == nullptr || dirname.empty())
34  return false;
35 
36  len = dirname.size();
37  temp = new char[len + 2];
38  memcpy(temp, dirname.c_str(), len);
39  if (temp[len - 1] != '/')
40  {
41  temp[len] = '/';
42  temp[len + 1] = '\0';
43  }
44  else
45  {
46  temp[len] = '\0';
47  }
48 
49  ret = zipOpenNewFileInZip64(zfile,
50  temp,
51  NULL,
52  NULL,
53  0,
54  NULL,
55  0,
56  NULL,
57  0,
58  0,
59  0);
60 
61  delete[] temp;
62  if (ret != ZIP_OK)
63  return false;
64 
65  zipCloseFileInZip(zfile);
66  return true;
67 }
68 //-----------------------------------------------------------------------------
69 /*!
70  *
71  * \param zfile ???
72  * \param fs ???
73  * \param filename ???
74  * \param zipPath ???
75  * \return ???
76  */
77 static bool zip_add_file(zipFile zfile,
78  std::ifstream& fs,
79  string filename,
80  string zipPath = "")
81 {
82  size_t size = (size_t)Utils::getFileSize(fs);
83 
84  zipPath = Utils::unifySlashes(zipPath);
85  int ret = zipOpenNewFileInZip64(zfile,
86  (zipPath + filename).c_str(),
87  NULL,
88  NULL,
89  0,
90  NULL,
91  0,
92  NULL,
93  Z_DEFLATED,
94  Z_DEFAULT_COMPRESSION,
95  (size > 0xffffffff) ? 1 : 0);
96 
97  if (ret != ZIP_OK)
98  {
99  zipClose(zfile, nullptr);
100  return false;
101  }
102 
103  char buf[8192];
104  size_t n;
105  while ((n = fs.readsome(buf, sizeof(buf))) > 0)
106  {
107  ret = zipWriteInFileInZip(zfile, buf, (unsigned int)n);
108  if (ret != ZIP_OK)
109  {
110  zipCloseFileInZip(zfile);
111  return false;
112  }
113  }
114  zipCloseFileInZip(zfile);
115  return true;
116 }
117 //-----------------------------------------------------------------------------
118 /*!
119  *
120  * \param zfile ???
121  * \param filepath ???
122  * \param zipPath ???
123  * \return ???
124  */
125 static bool zip_add_file(zipFile zfile,
126  string filepath,
127  string zipPath = "")
128 {
129  std::ifstream fs(filepath, std::ios::binary);
130  if (fs.fail())
131  {
132  return false;
133  }
134 
135  return zip_add_file(zfile,
136  fs,
137  Utils::getFileName(filepath),
138  zipPath);
139 }
140 //-----------------------------------------------------------------------------
141 /*!
142  *
143  @param zipfile ???
144  @param processFile ???
145  @param writeChunk ???
146  @param processDir ???
147  @param progress Progress function to call for progress visualization
148  @return ???
149  */
150 bool unzip(string zipfile,
151  function<bool(string path, string filename)> processFile,
152  function<bool(const char* data, size_t len)> writeChunk,
153  function<bool(string path)> processDir,
154  function<int(int currentFile, int totalFiles)> progress = nullptr)
155 {
156  unzFile uzfile;
157  bool ret = true;
158  size_t n;
159  char name[256];
160  int nbProcessedFile = 0;
161 
162  uzfile = unzOpen64(zipfile.c_str());
163  if (uzfile == NULL)
164  return false;
165 
166  // Get info about the zip file
167  unz_global_info global_info;
168  if (unzGetGlobalInfo(uzfile, &global_info) != UNZ_OK)
169  {
170  unzClose(uzfile);
171  return (bool)-1;
172  }
173 
174  do
175  {
176  unz_file_info64 finfo;
177  unsigned char buf[8192];
178  if (unzGetCurrentFileInfo64(uzfile,
179  &finfo,
180  name,
181  sizeof(name),
182  NULL,
183  0,
184  NULL,
185  0) != UNZ_OK)
186  {
187  ret = false;
188  break;
189  }
190 
191  string dirname = Utils::getDirName(Utils::trimRightString(name, "/"));
192  string filename = Utils::getFileName(Utils::trimRightString(name, "/"));
193 
194  processDir(dirname);
195  if (progress != nullptr && progress(nbProcessedFile++, (int)global_info.number_entry))
196  {
197  unzClose(uzfile);
198  return false;
199  }
200 
201  if (finfo.uncompressed_size == 0 && strlen(name) > 0 && name[strlen(name) - 1] == '/')
202  {
203  if (unzGoToNextFile(uzfile) != UNZ_OK)
204  break;
205  continue;
206  }
207 
208  if (unzOpenCurrentFile(uzfile) != UNZ_OK)
209  {
210  ret = false;
211  unzCloseCurrentFile(uzfile);
212  break;
213  }
214 
215  if (processFile(dirname, filename))
216  {
217  while ((n = unzReadCurrentFile(uzfile, buf, sizeof(buf))) > 0)
218  {
219  if (!writeChunk((const char*)buf, n))
220  {
221  unzCloseCurrentFile(uzfile);
222  ret = false;
223  break;
224  }
225  }
226 
227  writeChunk(nullptr, 0);
228  if (n < 0)
229  {
230  unzCloseCurrentFile(uzfile);
231  ret = false;
232  break;
233  }
234  }
235 
236  unzCloseCurrentFile(uzfile);
237  if (unzGoToNextFile(uzfile) != UNZ_OK)
238  break;
239 
240  } while (1);
241 
242  unzClose(uzfile);
243 
244  if (progress != nullptr)
245  progress((int)global_info.number_entry, (int)global_info.number_entry);
246  return ret;
247 }
248 //-----------------------------------------------------------------------------
249 /*!
250  *
251  * \param path ???
252  * \param zipname ???
253  * \return ???
254  */
255 bool zip(string path, string zipname)
256 {
257  path = Utils::trimRightString(path, "/");
258 
259  if (zipname.empty())
260  zipname = path + ".zip";
261 
262  zipFile zfile = zipOpen64(zipname.c_str(), 0);
263 
264  if (zfile == nullptr)
265  {
266  zipClose(zfile, nullptr);
267  return false;
268  }
269 
270  bool ret = true;
271  string zipRootPath = Utils::getDirName(path);
272 
274  path,
275  [zfile,
276  &ret,
277  zipRootPath](string path,
278  string baseName,
279  int depth) -> void
280  {
281  ret = ret && zip_add_file(zfile,
282  path + baseName,
283  path.erase(0,
284  zipRootPath.size()));
285  },
286  [zfile, &ret, zipRootPath](string path,
287  string baseName,
288  int depth) -> void
289  {
290  ret = ret && zip_add_dir(zfile,
291  path.erase(0, zipRootPath.size()) + baseName);
292  },
293  0);
294 
295  if (!ret)
296  {
297  free(zfile);
298  Utils::removeFile(zipname);
299  return false;
300  }
301 
302  zipClose(zfile, NULL);
303  return true;
304 }
305 //-----------------------------------------------------------------------------
306 /*!
307  Unzips a zip file
308  @param path ???
309  @param dest ???
310  @param override Overrides existing files on destination
311  @param progress Progress function to call for progress visualization
312  @return Returns true on success
313  */
314 bool unzip(string path,
315  string dest,
316  bool override,
317  function<int(int currentFile, int totalFiles)> progress)
318 {
319  std::ofstream fs;
320 
321  dest = Utils::unifySlashes(dest);
322  unzip(
323  path,
324  [&fs, &override, dest](string path, string filename) -> bool
325  {
326  if (override || !Utils::fileExists(dest + path + filename))
327  {
328  fs.open(dest + path + filename, std::ios::binary);
329  return true;
330  }
331  return false;
332  },
333  [&fs](const char* data, size_t len) -> bool
334  {
335  if (data != nullptr)
336  {
337  try
338  {
339  fs.write(data, len);
340  }
341  catch (std::exception& e)
342  {
343  std::cout << e.what() << std::endl;
344  return false;
345  }
346  }
347  else
348  fs.close();
349  return true;
350  },
351  [dest](string path) -> bool
352  {
353  if (!Utils::dirExists(dest + path))
354  return Utils::makeDir(dest + path);
355  return true;
356  },
357  progress);
358  return true;
359 }
360 //-----------------------------------------------------------------------------
361 }
string unifySlashes(const string &inputDir, bool withTrailingSlash)
Returns the inputDir string with unified forward slashes, e.g.: "dirA/dirB/".
Definition: Utils.cpp:368
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:897
bool dirExists(const string &path)
Returns true if a directory exists.
Definition: Utils.cpp:790
bool makeDir(const string &path)
Creates a directory with given path.
Definition: Utils.cpp:810
unsigned int getFileSize(const string &pathfilename)
Returns the file size in bytes.
Definition: Utils.cpp:912
string getFileName(const string &pathFilename)
Returns the filename of path-filename string.
Definition: Utils.cpp:580
string getDirName(const string &pathFilename)
Strip last component from file name.
Definition: Utils.cpp:598
void removeFile(const string &path)
RemoveFile deletes a file with given path.
Definition: Utils.cpp:875
string trimRightString(const string &s, const string &drop)
trims a string at the right end
Definition: Utils.cpp:136
void loopFileSystemRec(const string &path, function< void(string path, string baseName, int depth)> processFile, function< void(string path, string baseName, int depth)> processDir, const int depth)
process all files and folders recursively naturally sorted
Definition: Utils.cpp:1016
ZipUtils provides compressing & decompressing files and folders.
Definition: ZipUtils.cpp:19
static bool zip_add_dir(zipFile zfile, string dirname)
Definition: ZipUtils.cpp:27
static bool zip_add_file(zipFile zfile, std::ifstream &fs, string filename, string zipPath="")
Definition: ZipUtils.cpp:77
bool zip(string path, string zipname)
Definition: ZipUtils.cpp:255
bool unzip(string zipfile, function< bool(string path, string filename)> processFile, function< bool(const char *data, size_t len)> writeChunk, function< bool(string path)> processDir, function< int(int currentFile, int totalFiles)> progress=nullptr)
Definition: ZipUtils.cpp:150