libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNZip.cpp
Go to the documentation of this file.
1 /* Copyright 2013-2016 INSA-Lyon, CoReNum
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNZip.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <CRN.h>
23 #ifdef CRN_USING_LIBZIP
24 
25 #include <CRNIO/CRNZip.h>
26 #include <zip.h>
27 #include <CRNException.h>
28 #include <CRNIO/CRNIO.h>
29 #include <CRNi18n.h>
30 
31 #if LIBZIP_VERSION_MINOR == 10
32 #define zip_dir_add(arch, name, flags) zip_add_dir(arch, name)
33 #define zip_file_add(arch, name, source, flags) zip_add(arch, name, source)
34 using zip_flags_t = int;
35 #define ZIP_FL_OVERWRITE 0
36 #define ZIP_FL_ENC_UTF_8 0
37 #define ZIP_TRUNCATE 0
38 #endif
39 using namespace crn;
40 
42 struct Zip::Impl
43 {
44  Impl(const Path &f, bool c):zipfile(nullptr),autosave(true),saved(false),fname(f),check(c) { }
45  ~Impl()
46  {
47  if (!zipfile)
48  return;
49  if (autosave)
50  {
51 #if LIBZIP_VERSION_MINOR != 10
52  if (!saved)
53  {
54 #endif
55  int res = zip_close(zipfile);
56  if (res == -1)
57  {
58  // do not throw because it is quite evil
59  CRNError(zip_strerror(zipfile));
60  }
61  /* TODO check if needed
62 #ifdef CRN_PF_MSVC
63  // remove read-only attribute...
64  SetFileAttributes(String(fname).CWStr(), FILE_ATTRIBUTE_NORMAL);
65 #endif
66 */
67 #if LIBZIP_VERSION_MINOR != 10
68  }
69  else
70  {
71  zip_discard(zipfile);
72  }
73 #endif
74  }
75  else
76  {
77 #if LIBZIP_VERSION_MINOR == 10
78  throw ExceptionRuntime(_("libzip version is too old to support zip_discard()."));
79 #else
80  zip_discard(zipfile);
81 #endif
82  }
83  }
84 
85  zip *zipfile;
86  bool autosave;
87  bool saved;
88  const Path &fname;
89  bool check;
90 };
102 Zip Zip::NewFromFile(const Path &fname, bool check_consistency)
103 {
104  return Zip(fname, false, false, check_consistency);
105 }
106 
117 Zip Zip::Create(const Path &fname, bool overwrite, bool check_consistency)
118 {
119  return Zip(fname, true, overwrite, check_consistency);
120 }
121 
132 Zip::Zip(const Path &fname, bool create, bool overwrite, bool check_consistency):
133  pimpl(std::make_unique<Impl>(fname, check_consistency))
134 {
135  int flags = 0;
136  if (create)
137  {
138  flags |= ZIP_CREATE;
139  if (overwrite)
140  flags |= ZIP_TRUNCATE;
141  else
142  flags |= ZIP_EXCL;
143  pimpl->saved = false;
144  }
145  if (check_consistency)
146  flags |= ZIP_CHECKCONS;
147  int error = 0;
148  zip *zfile = zip_open(fname.CStr(), flags, &error);
149  if (error == 0)
150  pimpl->zipfile = zfile;
151  else
152  {
153  switch (error)
154  {
155  case ZIP_ER_EXISTS:
156  throw ExceptionIO(_("The file already exists."));
157  case ZIP_ER_INCONS:
158  throw ExceptionRuntime(_("The file is inconsistent."));
159  // case ZIP_ER_INVAL: // cannot happen!
160  case ZIP_ER_MEMORY:
161  throw ExceptionRuntime(_("Not enough memory."));
162  case ZIP_ER_NOZIP:
163  throw ExceptionRuntime(_("This is not a zip file."));
164  case ZIP_ER_NOENT:
165  case ZIP_ER_OPEN:
166  throw ExceptionIO(_("Cannot open file."));
167  case ZIP_ER_READ:
168  case ZIP_ER_SEEK:
169  throw ExceptionIO(_("Cannot read file."));
170  default:
171  throw ExceptionRuntime(_("Unknown zip error."));
172  }
173  }
174 }
175 
176 Zip::~Zip()
177 {
178 }
179 
180 Zip::Zip(Zip &&z) noexcept:
181  pimpl(std::move(z.pimpl))
182 {
183 }
184 
185 Zip& Zip::operator=(Zip &&z) noexcept
186 {
187  pimpl = std::move(z.pimpl);
188  return *this;
189 }
190 
192 void Zip::Save()
193 {
194  if (!pimpl->saved)
195  {
196  // close to save
197  int res = zip_close(pimpl->zipfile);
198  pimpl->zipfile = nullptr;
199  if (res == -1)
200  {
201  throw ExceptionIO(zip_strerror(pimpl->zipfile));
202  }
203  /* TODO check if needed
204 #ifdef CRN_PF_MSVC
205  // remove read-only attribute...
206  SetFileAttributes(String(pimpl->fname).CWStr(), FILE_ATTRIBUTE_NORMAL);
207 #endif
208  */
209  // reopen
210  int error = 0;
211  zip *zfile = zip_open(pimpl->fname.CStr(), 0, &error);
212  if (error == 0)
213  pimpl->zipfile = zfile;
214  else
215  {
216  switch (error)
217  {
218  case ZIP_ER_EXISTS:
219  throw ExceptionIO(_("The file already exists."));
220  case ZIP_ER_INCONS:
221  throw ExceptionRuntime(_("The file is inconsistent."));
222  // case ZIP_ER_INVAL: // cannot happen!
223  case ZIP_ER_MEMORY:
224  throw ExceptionRuntime(_("Not enough memory."));
225  case ZIP_ER_NOZIP:
226  throw ExceptionRuntime(_("This is not a zip file."));
227  case ZIP_ER_NOENT:
228  case ZIP_ER_OPEN:
229  throw ExceptionIO(_("Cannot open file."));
230  case ZIP_ER_READ:
231  case ZIP_ER_SEEK:
232  throw ExceptionIO(_("Cannot read file."));
233  default:
234  throw ExceptionRuntime(_("Unknown zip error."));
235  }
236  }
237  pimpl->saved = true;
238  }
239 }
240 
245 void Zip::SetAutoSave(bool autosave)
246 {
247  pimpl->autosave = autosave;
248 }
249 
257 void Zip::AddFile(const StringUTF8 &path, const void *data, size_t len, bool overwrite)
258 {
259  zip_flags_t flags = ZIP_FL_ENC_UTF_8;
260  if (overwrite)
261  flags |= ZIP_FL_OVERWRITE;
262  zip_source *source = zip_source_buffer(pimpl->zipfile, data, len, 0);
263  if (!source)
264  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
265  zip_int64_t res = zip_file_add(pimpl->zipfile, path.CStr(), source, flags);
266  if (res < 0)
267  {
268  zip_source_free(source);
269  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
270  }
271 }
272 
279 void Zip::AddFile(const StringUTF8 &path, const Path &original_file, bool overwrite)
280 {
281  zip_flags_t flags = ZIP_FL_ENC_UTF_8;
282  if (overwrite)
283  flags |= ZIP_FL_OVERWRITE;
284  zip_source *source = zip_source_file(pimpl->zipfile, original_file.CStr(), 0, 0);
285  if (!source)
286  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
287  zip_int64_t res = zip_file_add(pimpl->zipfile, path.CStr(), source, flags);
288  if (res < 0)
289  {
290  zip_source_free(source);
291  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
292  }
293 }
294 
300 StringUTF8 Zip::ReadTextFile(const StringUTF8 &path)
301 {
302  // get file size
303  struct zip_stat fstat;
304  if (zip_stat(pimpl->zipfile, path.CStr(), ZIP_STAT_SIZE, &fstat) == -1)
305  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
306 
307  // get file handler
308  zip_file *f = zip_fopen(pimpl->zipfile, path.CStr(), 0);
309  if (!f)
310  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
311 
312  // read data
313  StringUTF8 str('\0', size_t(fstat.size));
314  zip_int64_t res = zip_fread(f, &(str[0]), fstat.size);
315 
316  // close file
317  zip_fclose(f);
318 
319  if (res == -1)
320  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
321 
322  return str;
323 }
324 
329 void Zip::AddDirectory(const StringUTF8 &path)
330 {
331  if (zip_dir_add(pimpl->zipfile, path.CStr(), ZIP_FL_ENC_UTF_8) == -1)
332  throw ExceptionRuntime(zip_strerror(pimpl->zipfile));
333 }
334 
340 bool Zip::Exists(const StringUTF8 &path)
341 {
342  struct zip_stat fstat;
343  if (zip_stat(pimpl->zipfile, path.CStr(), ZIP_STAT_NAME, &fstat) == -1)
344  return false;
345  else
346  return true;
347 }
348 
349 #endif// CRN_USING_LIBZIP
A generic runtime error.
Definition: CRNException.h:131
#define _(String)
Definition: CRNi18n.h:51
#define false
Definition: ConvertUTF.cpp:56
const char * CStr() const noexcept
Conversion to UTF8 cstring.
A convenience class for file paths.
Definition: CRNPath.h:39
#define CRNError(x)
Definition: CRNIO.h:147
#define true
Definition: ConvertUTF.cpp:57
A character string class.
Definition: CRNStringUTF8.h:49
I/O error.
Definition: CRNException.h:179