Merge lp:~widelands-dev/widelands/fix_zip_filesystem into lp:widelands

Proposed by SirVer
Status: Merged
Merged at revision: 7711
Proposed branch: lp:~widelands-dev/widelands/fix_zip_filesystem
Merge into: lp:widelands
Diff against target: 819 lines (+277/-283)
2 files modified
src/io/filesystem/zip_filesystem.cc (+209/-253)
src/io/filesystem/zip_filesystem.h (+68/-30)
To merge this branch: bzr merge lp:~widelands-dev/widelands/fix_zip_filesystem
Reviewer Review Type Date Requested Status
TiborB Approve
Review via email: mp+282884@code.launchpad.net

Commit message

Use std::shared_ptr to properly share zip files between classes.

ZipFilesystem, any child filesystems created by make_sub_file_system, and any ZipStream[Write|Read] created from such a filesystem access the same physical zip file and corresponding state. If one wrote while the other read, the outcome was undefined.

This changes the code to move the zip file abstraction into a wrapper class that properly reopens files for the correct access.

This also get's rid of the improper (and deprecated) use of the implicit copy constructor - the state was copied, but not properly shared before.

Description of the change

Fix deprecated use of implicit copy constructor and the mess that ZipFilesystem was in general.

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

Testers: This should be a refactoring only to make sure we are not broken by c++14 (which deprecates our inproper use of Copy construction in this case). No noticeable changes in behavior.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Hi, I am bunnybot (https://github.com/widelands/bunnybot).

I am keeping the source branch lp:~widelands-dev/widelands/fix_zip_filesystem mirrored to https://github.com/widelands/widelands/tree/_widelands_dev_widelands_fix_zip_filesystem

You can give me commands by starting a line with @bunnybot <command>. I understand:
 merge: Merges the source branch into the target branch, closing the merge proposal. I will use the proposed commit message if it is set.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 295 has changed state to: passed. Details: https://travis-ci.org/widelands/widelands/builds/103019352.

Revision history for this message
TiborB (tiborb95) wrote :

Tested - briefly - no issues

code looks good to me as far as I can tell

review: Approve
Revision history for this message
SirVer (sirver) wrote :

Thanks!

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/io/filesystem/zip_filesystem.cc'
2--- src/io/filesystem/zip_filesystem.cc 2015-10-25 15:44:36 +0000
3+++ src/io/filesystem/zip_filesystem.cc 2016-01-17 21:52:36 +0000
4@@ -35,28 +35,99 @@
5 #include "io/streamread.h"
6 #include "io/streamwrite.h"
7
8+ZipFilesystem::ZipFile::ZipFile(const std::string& zipfile)
9+ : state_(State::kIdle),
10+ path_(zipfile),
11+ basename_(fs_filename(zipfile.c_str())),
12+ write_handle_(nullptr),
13+ read_handle_(nullptr) {
14+}
15+
16+ZipFilesystem::ZipFile::~ZipFile() {
17+ close();
18+}
19+
20+void ZipFilesystem::ZipFile::close() {
21+ if (state_ == State::kZipping) {
22+ zipClose(write_handle_, nullptr);
23+ } else if (state_ == State::kUnzipping) {
24+ unzClose(read_handle_);
25+ }
26+ state_ = State::kIdle;
27+}
28+
29+void ZipFilesystem::ZipFile::open_for_zip() {
30+ if (state_ == State::kZipping)
31+ return;
32+
33+ close();
34+
35+ write_handle_ = zipOpen(path_.c_str(), APPEND_STATUS_ADDINZIP);
36+ if (!write_handle_) {
37+ // Couldn't open for append, so create new.
38+ write_handle_ = zipOpen(path_.c_str(), APPEND_STATUS_CREATE);
39+ }
40+
41+ state_ = State::kZipping;
42+}
43+
44+void ZipFilesystem::ZipFile::open_for_unzip() {
45+ if (state_ == State::kUnzipping)
46+ return;
47+
48+ close();
49+
50+ read_handle_ = unzOpen(path_.c_str());
51+ if (!read_handle_)
52+ throw FileTypeError
53+ ("ZipFilesystem::open_for_unzip", path_, "not a .zip file");
54+ state_ = State::kUnzipping;
55+}
56+
57+std::string ZipFilesystem::ZipFile::strip_basename(const std::string& filename) {
58+ if (filename.compare(0, basename_.length(), basename_) == 0)
59+ {
60+ // filename contains the name of the zip file as first element. This means
61+ // this is an old zip file where all data were in a directory named as the
62+ // file inside the zip file.
63+ // return the filename without the first element
64+ return filename.substr(basename_.length() + 1);
65+ }
66+
67+ // seems to be a new zipfile without directory or a old zipfile was renamed
68+ if (*filename.begin() == '/')
69+ return filename.substr(1);
70+ return filename;
71+}
72+
73+const zipFile& ZipFilesystem::ZipFile::write_handle() {
74+ open_for_zip();
75+ return write_handle_;
76+}
77+
78+const unzFile& ZipFilesystem::ZipFile::read_handle() {
79+ open_for_unzip();
80+ return read_handle_;
81+}
82+
83+const std::string& ZipFilesystem::ZipFile::path() const {
84+ return path_;
85+}
86+
87 /**
88 * Initialize the real file-system
89 */
90-ZipFilesystem::ZipFilesystem(const std::string & zipfile)
91-:
92-m_state (STATE_IDLE),
93-m_zipfile (nullptr),
94-m_unzipfile (nullptr),
95-m_oldzip (false),
96-m_zipfilename(zipfile),
97-m_basenamezip(fs_filename(zipfile.c_str())),
98-m_basename ()
99-{
100+ZipFilesystem::ZipFilesystem(const std::string& zipfile)
101+ : zip_file_(new ZipFile(zipfile)), basedir_in_zip_file_() {
102 // TODO(unknown): check OS permissions on whether the file is writable
103 }
104
105-/**
106- * Cleanup code
107- */
108-ZipFilesystem::~ZipFilesystem()
109-{
110- m_close();
111+ZipFilesystem::ZipFilesystem(const std::shared_ptr<ZipFile>& shared_data,
112+ const std::string& basedir_in_zip_file)
113+ : zip_file_(shared_data), basedir_in_zip_file_(basedir_in_zip_file) {
114+}
115+
116+ZipFilesystem::~ZipFilesystem() {
117 }
118
119 /**
120@@ -72,11 +143,9 @@
121 * cross-platform way of doing this
122 */
123 std::set<std::string> ZipFilesystem::list_directory(const std::string& path_in) {
124- m_open_unzip();
125-
126 assert(path_in.size()); // prevent invalid read below
127
128- std::string path = m_basename;
129+ std::string path = basedir_in_zip_file_;
130 if (*path_in.begin() != '/')
131 path += "/";
132 path += path_in;
133@@ -85,18 +154,18 @@
134 if (*path.begin() == '/')
135 path = path.substr(1);
136
137- unzCloseCurrentFile(m_unzipfile);
138- unzGoToFirstFile(m_unzipfile);
139+ unzCloseCurrentFile(zip_file_->read_handle());
140+ unzGoToFirstFile(zip_file_->read_handle());
141
142 unz_file_info file_info;
143 char filename_inzip[256];
144 std::set<std::string> results;
145 for (;;) {
146 unzGetCurrentFileInfo
147- (m_unzipfile, &file_info, filename_inzip, sizeof(filename_inzip),
148+ (zip_file_->read_handle(), &file_info, filename_inzip, sizeof(filename_inzip),
149 nullptr, 0, nullptr, 0);
150
151- std::string complete_filename = strip_basename(filename_inzip);
152+ std::string complete_filename = zip_file_->strip_basename(filename_inzip);
153 std::string filename = fs_filename(complete_filename.c_str());
154 std::string filepath =
155 complete_filename.substr
156@@ -108,9 +177,9 @@
157 if
158 (('/' + path == filepath || path == filepath || path.length() == 1)
159 && filename.size())
160- results.insert(complete_filename.substr(m_basename.size()));
161+ results.insert(complete_filename.substr(basedir_in_zip_file_.size()));
162
163- if (unzGoToNextFile(m_unzipfile) == UNZ_END_OF_LIST_OF_FILE)
164+ if (unzGoToNextFile(zip_file_->read_handle()) == UNZ_END_OF_LIST_OF_FILE)
165 break;
166 }
167 return results;
168@@ -120,18 +189,19 @@
169 * Returns true if the given file exists, and false if it doesn't.
170 * Also returns false if the pathname is invalid
171 */
172-bool ZipFilesystem::file_exists(const std::string & path) {
173+bool ZipFilesystem::file_exists(const std::string& path) {
174 try {
175- m_open_unzip(); // TODO(unknown): check return value
176+ unzGoToFirstFile(zip_file_->read_handle());
177 } catch (...) {
178+ // The zip file could not be opened. I guess this means 'path' does not
179+ // exist.
180 return false;
181 }
182- unzGoToFirstFile(m_unzipfile);
183 unz_file_info file_info;
184 char filename_inzip[256];
185 memset(filename_inzip, ' ', 256);
186
187- std::string path_in = m_basename + "/" + path;
188+ std::string path_in = basedir_in_zip_file_ + "/" + path;
189
190 if (*path_in.begin() == '/')
191 path_in = path_in.substr(1);
192@@ -140,10 +210,10 @@
193
194 for (;;) {
195 unzGetCurrentFileInfo
196- (m_unzipfile, &file_info, filename_inzip, sizeof(filename_inzip),
197+ (zip_file_->read_handle(), &file_info, filename_inzip, sizeof(filename_inzip),
198 nullptr, 0, nullptr, 0);
199
200- std::string complete_filename = strip_basename(filename_inzip);
201+ std::string complete_filename = zip_file_->strip_basename(filename_inzip);
202
203 if (*complete_filename.rbegin() == '/')
204 complete_filename.resize(complete_filename.size() - 1);
205@@ -151,7 +221,7 @@
206 if (path_in == complete_filename)
207 return true;
208
209- if (unzGoToNextFile(m_unzipfile) == UNZ_END_OF_LIST_OF_FILE)
210+ if (unzGoToNextFile(zip_file_->read_handle()) == UNZ_END_OF_LIST_OF_FILE)
211 break;
212 }
213 return false;
214@@ -170,7 +240,7 @@
215 char filename_inzip[256];
216
217 unzGetCurrentFileInfo
218- (m_unzipfile, &file_info, filename_inzip, sizeof(filename_inzip),
219+ (zip_file_->read_handle(), &file_info, filename_inzip, sizeof(filename_inzip),
220 nullptr, 0, nullptr, 0);
221
222 return filename_inzip[strlen(filename_inzip) - 1] == '/';
223@@ -180,8 +250,6 @@
224 * Create a sub filesystem out of this filesystem
225 */
226 FileSystem * ZipFilesystem::make_sub_file_system(const std::string & path) {
227- m_open_unzip();
228-
229 if (!file_exists(path)) {
230 throw wexception("ZipFilesystem::make_sub_file_system: The path does not exist.");
231 }
232@@ -189,17 +257,11 @@
233 throw wexception("ZipFilesystem::make_sub_file_system: The path needs to be a directory.");
234 }
235
236- m_close();
237-
238 std::string localpath = path;
239-
240- if (*localpath.begin() == '/')
241+ if (*localpath.begin() == '/') {
242 localpath = localpath.substr(1);
243-
244- ZipFilesystem * newfs = new ZipFilesystem(m_zipfilename);
245- newfs->m_basename = m_basename + "/" + localpath;
246-
247- return newfs;
248+ }
249+ return new ZipFilesystem(zip_file_, basedir_in_zip_file_ + "/" + localpath);
250 }
251
252 /**
253@@ -217,23 +279,15 @@
254 if (type != FileSystem::DIR)
255 throw ZipOperationError
256 ("ZipFilesystem::create_sub_file_system",
257- path, m_zipfilename,
258+ path, zip_file_->path(),
259 "can not create ZipFilesystem inside another ZipFilesystem");
260
261 ensure_directory_exists(path);
262
263- m_close();
264-
265 std::string localpath = path;
266-
267 if (*localpath.begin() == '/')
268 localpath = localpath.substr(1);
269-
270- ZipFilesystem * newfs = new ZipFilesystem(*this);
271-
272- newfs->m_basename = m_basename + "/" + localpath;
273-
274- return newfs;
275+ return new ZipFilesystem(zip_file_, basedir_in_zip_file_ + "/" + localpath);
276 }
277 /**
278 * Remove a number of files
279@@ -243,7 +297,7 @@
280 throw ZipOperationError
281 ("ZipFilesystem::unlink",
282 filename,
283- m_zipfilename,
284+ zip_file_->path(),
285 "unlinking is not supported inside zipfiles");
286 }
287
288@@ -267,8 +321,6 @@
289 * if either ondir or otherdir is missing
290 */
291 void ZipFilesystem::make_directory(const std::string & dirname) {
292- m_open_zip();
293-
294 zip_fileinfo zi;
295
296 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
297@@ -277,7 +329,7 @@
298 zi.internal_fa = 0;
299 zi.external_fa = 0;
300
301- std::string complete_filename = m_basename;
302+ std::string complete_filename = basedir_in_zip_file_;
303 complete_filename += "/";
304 complete_filename += dirname;
305
306@@ -285,21 +337,9 @@
307 if (*complete_filename.rbegin() != '/')
308 complete_filename += '/';
309
310- switch
311- (zipOpenNewFileInZip3
312- (m_zipfile,
313- complete_filename.c_str(),
314- &zi,
315- nullptr, 0, nullptr, 0, nullptr /* comment*/,
316- Z_DEFLATED,
317- Z_BEST_COMPRESSION,
318- 0,
319- -MAX_WBITS,
320- DEF_MEM_LEVEL,
321- Z_DEFAULT_STRATEGY,
322- nullptr,
323- 0))
324- {
325+ switch (zipOpenNewFileInZip3(zip_file_->write_handle(), complete_filename.c_str(), &zi, nullptr,
326+ 0, nullptr, 0, nullptr /* comment*/, Z_DEFLATED, Z_BEST_COMPRESSION,
327+ 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0)) {
328 case ZIP_OK:
329 break;
330 case ZIP_ERRNO:
331@@ -309,8 +349,7 @@
332 throw FileError
333 ("ZipFilesystem::make_directory", complete_filename);
334 }
335-
336- zipCloseFileInZip(m_zipfile);
337+ zipCloseFileInZip(zip_file_->write_handle());
338 }
339
340 /**
341@@ -322,34 +361,34 @@
342 throw ZipOperationError
343 ("ZipFilesystem::load",
344 fname,
345- m_zipfilename,
346+ zip_file_->path(),
347 "could not open file from zipfile");
348
349 char buffer[1024];
350 size_t totallen = 0;
351- unzOpenCurrentFile(m_unzipfile);
352+ unzOpenCurrentFile(zip_file_->read_handle());
353 for (;;) {
354 const int32_t len =
355- unzReadCurrentFile(m_unzipfile, buffer, sizeof(buffer));
356+ unzReadCurrentFile(zip_file_->read_handle(), buffer, sizeof(buffer));
357 if (len == 0)
358 break;
359 if (len < 0) {
360- unzCloseCurrentFile(m_unzipfile);
361+ unzCloseCurrentFile(zip_file_->read_handle());
362 const std::string errormessage = (boost::format("read error %i") % len).str();
363 throw ZipOperationError
364- ("ZipFilesystem::load", fname, m_zipfilename, errormessage.c_str());
365+ ("ZipFilesystem::load", fname, zip_file_->path(), errormessage.c_str());
366 }
367
368 totallen += len;
369 }
370- unzCloseCurrentFile(m_unzipfile);
371+ unzCloseCurrentFile(zip_file_->read_handle());
372
373 void * const result = malloc(totallen + 1);
374 if (!result)
375 throw std::bad_alloc();
376- unzOpenCurrentFile(m_unzipfile);
377- unzReadCurrentFile(m_unzipfile, result, totallen);
378- unzCloseCurrentFile(m_unzipfile);
379+ unzOpenCurrentFile(zip_file_->read_handle());
380+ unzReadCurrentFile(zip_file_->read_handle(), result, totallen);
381+ unzCloseCurrentFile(zip_file_->read_handle());
382
383 static_cast<uint8_t *>(result)[totallen] = 0;
384 length = totallen;
385@@ -367,36 +406,27 @@
386 std::string filename = fname;
387 std::replace(filename.begin(), filename.end(), '\\', '/');
388
389- m_open_zip();
390-
391 zip_fileinfo zi;
392-
393 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
394 zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
395 zi.dosDate = 0;
396 zi.internal_fa = 0;
397 zi.external_fa = 0;
398
399- std::string complete_filename = m_basename + "/" + filename;
400+ std::string complete_filename = basedir_in_zip_file_ + "/" + filename;
401
402 // create file
403- switch
404- (zipOpenNewFileInZip3
405- (m_zipfile, complete_filename.c_str(), &zi,
406- nullptr, 0, nullptr, 0, nullptr /* comment*/,
407- Z_DEFLATED,
408- Z_BEST_COMPRESSION, 0,
409- -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
410- nullptr, 0))
411- {
412+ switch (zipOpenNewFileInZip3(zip_file_->write_handle(), complete_filename.c_str(), &zi, nullptr,
413+ 0, nullptr, 0, nullptr /* comment*/, Z_DEFLATED, Z_BEST_COMPRESSION,
414+ 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0)) {
415 case ZIP_OK:
416 break;
417 default:
418- throw ZipOperationError
419- ("ZipFilesystem::write", complete_filename, m_zipfilename);
420+ throw ZipOperationError(
421+ "ZipFilesystem::write", complete_filename, zip_file_->path());
422 }
423
424- switch (zipWriteInFileInZip (m_zipfile, data, length)) {
425+ switch (zipWriteInFileInZip (zip_file_->write_handle(), data, length)) {
426 case ZIP_OK:
427 break;
428 case ZIP_ERRNO:
429@@ -407,22 +437,80 @@
430 ("ZipFilesystem::write", complete_filename);
431 }
432
433- zipCloseFileInZip(m_zipfile);
434-}
435-
436-//
437-// Stream Read
438-//
439-
440-ZipFilesystem::ZipStreamRead::ZipStreamRead(zipFile file, ZipFilesystem* zipfs)
441-: m_unzipfile(file), m_zipfs(zipfs) {}
442+ zipCloseFileInZip(zip_file_->write_handle());
443+}
444+
445+StreamRead* ZipFilesystem::open_stream_read(const std::string& fname) {
446+ if (!file_exists(fname.c_str()) || is_directory(fname.c_str()))
447+ throw ZipOperationError
448+ ("ZipFilesystem::load",
449+ fname,
450+ zip_file_->path(),
451+ "could not open file from zipfile");
452+
453+ int32_t method;
454+ int result = unzOpenCurrentFile3(zip_file_->read_handle(), &method, nullptr, 1, nullptr);
455+ switch (result) {
456+ case ZIP_OK:
457+ break;
458+ default:
459+ throw ZipOperationError
460+ ("ZipFilesystem: Failed to open streamwrite", fname, zip_file_->path());
461+ }
462+ return new ZipStreamRead(zip_file_);
463+}
464+
465+StreamWrite * ZipFilesystem::open_stream_write(const std::string & fname) {
466+ zip_fileinfo zi;
467+
468+ zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
469+ zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
470+ zi.dosDate = 0;
471+ zi.internal_fa = 0;
472+ zi.external_fa = 0;
473+
474+ std::string complete_filename = basedir_in_zip_file_ + "/" + fname;
475+ // create file
476+ switch
477+ (zipOpenNewFileInZip3
478+ (zip_file_->write_handle(), complete_filename.c_str(), &zi,
479+ nullptr, 0, nullptr, 0, nullptr /* comment*/,
480+ Z_DEFLATED,
481+ Z_BEST_COMPRESSION, 0,
482+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
483+ nullptr, 0))
484+ {
485+ case ZIP_OK:
486+ break;
487+ default:
488+ throw ZipOperationError
489+ ("ZipFilesystem: Failed to open streamwrite", complete_filename, zip_file_->path());
490+ }
491+ return new ZipStreamWrite(zip_file_);
492+}
493+
494+void ZipFilesystem::fs_rename(const std::string &, const std::string &) {
495+ throw wexception("rename inside zip FS is not implemented yet");
496+}
497+
498+unsigned long long ZipFilesystem::disk_space() {
499+ return 0;
500+}
501+
502+std::string ZipFilesystem::get_basename() {
503+ return zip_file_->path();
504+}
505+
506+ZipFilesystem::ZipStreamRead::ZipStreamRead(const std::shared_ptr<ZipFile>& shared_data)
507+ : zip_file_(shared_data) {
508+}
509+
510 ZipFilesystem::ZipStreamRead::~ZipStreamRead() {
511- m_zipfs->m_close();
512 }
513
514 size_t ZipFilesystem::ZipStreamRead::data(void* read_data, size_t bufsize)
515 {
516- int copied = unzReadCurrentFile(m_unzipfile, read_data, bufsize);
517+ int copied = unzReadCurrentFile(zip_file_->read_handle(), read_data, bufsize);
518 if (copied < 0) {
519 throw new DataError("Failed to read from zip file");
520 }
521@@ -431,46 +519,22 @@
522 }
523 return copied;
524 }
525+
526 bool ZipFilesystem::ZipStreamRead::end_of_file() const
527 {
528- return unzReadCurrentFile(m_unzipfile, nullptr, 1) == 0;
529-}
530-
531-StreamRead* ZipFilesystem::open_stream_read(const std::string& fname) {
532- if (!file_exists(fname.c_str()) || is_directory(fname.c_str()))
533- throw ZipOperationError
534- ("ZipFilesystem::load",
535- fname,
536- m_zipfilename,
537- "could not open file from zipfile");
538-
539- int32_t method;
540- m_open_unzip();
541- int result = unzOpenCurrentFile3(m_unzipfile, &method, nullptr, 1, nullptr);
542- switch (result) {
543- case ZIP_OK:
544- break;
545- default:
546- throw ZipOperationError
547- ("ZipFilesystem: Failed to open streamwrite", fname, m_zipfilename);
548- }
549- return new ZipStreamRead(m_unzipfile, this);
550-}
551-
552-//
553-// Stream write
554-//
555-
556-ZipFilesystem::ZipStreamWrite::ZipStreamWrite(zipFile file, ZipFilesystem* zipfs)
557-: m_zipfile(file), m_zipfs(zipfs) {}
558-ZipFilesystem::ZipStreamWrite::~ZipStreamWrite()
559-{
560- m_zipfs->m_close();
561+ return unzReadCurrentFile(zip_file_->read_handle(), nullptr, 1) == 0;
562+}
563+
564+ZipFilesystem::ZipStreamWrite::ZipStreamWrite(const std::shared_ptr<ZipFile>& shared_data)
565+ : zip_file_(shared_data) {
566+}
567+
568+ZipFilesystem::ZipStreamWrite::~ZipStreamWrite() {
569 }
570
571 void ZipFilesystem::ZipStreamWrite::data(const void* const write_data, const size_t size)
572 {
573- int result = zipWriteInFileInZip(m_zipfile, write_data, size);
574+ int result = zipWriteInFileInZip(zip_file_->write_handle(), write_data, size);
575 switch (result) {
576 case ZIP_OK:
577 break;
578@@ -478,111 +542,3 @@
579 throw wexception("Failed to write into zipfile");
580 }
581 }
582-
583-StreamWrite * ZipFilesystem::open_stream_write(const std::string & fname) {
584- m_open_zip();
585-
586- zip_fileinfo zi;
587-
588- zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
589- zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
590- zi.dosDate = 0;
591- zi.internal_fa = 0;
592- zi.external_fa = 0;
593-
594- std::string complete_filename = m_basename + "/" + fname;
595- // create file
596- switch
597- (zipOpenNewFileInZip3
598- (m_zipfile, complete_filename.c_str(), &zi,
599- nullptr, 0, nullptr, 0, nullptr /* comment*/,
600- Z_DEFLATED,
601- Z_BEST_COMPRESSION, 0,
602- -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
603- nullptr, 0))
604- {
605- case ZIP_OK:
606- break;
607- default:
608- throw ZipOperationError
609- ("ZipFilesystem: Failed to open streamwrite", complete_filename, m_zipfilename);
610- }
611- return new ZipStreamWrite(m_zipfile, this);
612-}
613-
614-
615-/**
616- * Private Functions below
617- */
618-void ZipFilesystem::m_close() {
619- if (m_state == STATE_ZIPPING)
620- zipClose(m_zipfile, nullptr);
621- else if (m_state == STATE_UNZIPPPING)
622- unzClose(m_unzipfile);
623-
624- m_state = STATE_IDLE;
625-}
626-
627-/**
628- * Open a zipfile for compressing
629- */
630-void ZipFilesystem::m_open_zip() {
631- if (m_state == STATE_ZIPPING)
632- return;
633-
634- m_close();
635-
636- m_zipfile = zipOpen(m_zipfilename.c_str(), APPEND_STATUS_ADDINZIP);
637- if (!m_zipfile) {
638- // Couldn't open for append, so create new.
639- m_zipfile = zipOpen(m_zipfilename.c_str(), APPEND_STATUS_CREATE);
640- }
641-
642- m_state = STATE_ZIPPING;
643-}
644-
645-/**
646- * Open a zipfile for extraction
647- * \throw FileTypeError
648- */
649-void ZipFilesystem::m_open_unzip() {
650- if (m_state == STATE_UNZIPPPING)
651- return;
652-
653- m_close();
654-
655- m_unzipfile = unzOpen(m_zipfilename.c_str());
656- if (!m_unzipfile)
657- throw FileTypeError
658- ("ZipFilesystem::m_open_unzip", m_zipfilename, "not a .zip file");
659-
660- m_state = STATE_UNZIPPPING;
661-}
662-
663-void ZipFilesystem::fs_rename(const std::string &, const std::string &) {
664- throw wexception("rename inside zip FS is not implemented yet");
665-}
666-
667-unsigned long long ZipFilesystem::disk_space() {
668- return 0;
669-}
670-
671-std::string ZipFilesystem::strip_basename(std::string filename)
672-{
673-
674- if (filename.compare(0, m_basenamezip.length(), m_basenamezip) == 0)
675- {
676- // filename contains the name of the zip file as first element. This means
677- // this is an old zip file where all data were in a directory named as the
678- // file inside the zip file.
679- // return the filename without the first element
680- m_oldzip = true;
681- return filename.substr(m_basenamezip.length() + 1);
682- }
683-
684- // seems to be a new zipfile without directory or a old zipfile was renamed
685- m_oldzip = false;
686- if (*filename.begin() == '/')
687- return filename.substr(1);
688- return filename;
689-}
690
691=== modified file 'src/io/filesystem/zip_filesystem.h'
692--- src/io/filesystem/zip_filesystem.h 2014-09-29 13:30:46 +0000
693+++ src/io/filesystem/zip_filesystem.h 2016-01-17 21:52:36 +0000
694@@ -21,6 +21,7 @@
695 #define WL_IO_FILESYSTEM_ZIP_FILESYSTEM_H
696
697 #include <cstring>
698+#include <memory>
699 #include <string>
700
701 #include "base/macros.h"
702@@ -63,50 +64,87 @@
703
704 static FileSystem * create_from_directory(const std::string & directory);
705
706- std::string get_basename() override {return m_zipfilename;}
707-
708-protected:
709- void m_open_unzip();
710- void m_open_zip();
711- void m_close();
712- std::string strip_basename(std::string);
713-
714- enum State {
715- STATE_IDLE,
716- STATE_ZIPPING,
717- STATE_UNZIPPPING
718+ std::string get_basename() override;
719+
720+private:
721+ enum class State {kIdle, kZipping, kUnzipping};
722+
723+ // All zip filesystems that use the same zip file have a shared
724+ // state, which is represented in this struct. This is usually
725+ // shared between the root file system, plus every filesystem generated
726+ // through 'make_sub_file_system'.
727+ class ZipFile {
728+ public:
729+ ZipFile(const std::string& zipfile);
730+
731+ // Calls 'close()'.
732+ ~ZipFile();
733+
734+ // Make 'filename' into a relative part, dealing with legacy Widelands
735+ // zip file format.
736+ std::string strip_basename(const std::string& filename);
737+
738+ // Full path to the zip file.
739+ const std::string& path() const;
740+
741+ // Closes the file if it is open, reopens it for writing, and
742+ // returns the minizip handle.
743+ const zipFile& write_handle();
744+
745+ // Closes the file if it is open, reopens it for reading, and returns the
746+ // minizip handle.
747+ const unzFile& read_handle();
748+
749+ private:
750+ // Closes 'path_' and reopens it for unzipping (read).
751+ void open_for_unzip();
752+
753+ // Closes 'path_' and reopens it for zipping (write).
754+ void open_for_zip();
755+
756+ // Closes 'path_' if it is opened.
757+ void close();
758+
759+ State state_;
760+
761+ // E.g. "path/to/filename.zip"
762+ std::string path_;
763+
764+ // E.g. "filename.zip"
765+ std::string basename_;
766+
767+ // File handles for zipping and unzipping.
768+ zipFile write_handle_;
769+ unzFile read_handle_;
770 };
771
772- State m_state;
773- zipFile m_zipfile;
774- unzFile m_unzipfile;
775- /// if true data is in a directory named as the zipfile. This is set by
776- /// strip_basename()
777- bool m_oldzip;
778- std::string m_zipfilename;
779- std::string m_basenamezip;
780- std::string m_basename;
781-
782 struct ZipStreamRead : StreamRead {
783- explicit ZipStreamRead(zipFile file, ZipFilesystem* zipfs);
784+ explicit ZipStreamRead(const std::shared_ptr<ZipFile>& shared_data);
785 virtual ~ZipStreamRead();
786 size_t data(void* data, size_t bufsize) override;
787 bool end_of_file() const override;
788 private:
789- zipFile m_unzipfile;
790- ZipFilesystem* m_zipfs;
791+ std::shared_ptr<ZipFile> zip_file_;
792 };
793+
794 struct ZipStreamWrite : StreamWrite {
795- explicit ZipStreamWrite(zipFile file, ZipFilesystem* zipfs);
796+ explicit ZipStreamWrite(const std::shared_ptr<ZipFile>& shared_data);
797 virtual ~ZipStreamWrite();
798 void data(const void* const data, size_t size) override;
799 private:
800- zipFile m_zipfile;
801- ZipFilesystem* m_zipfs;
802+ std::shared_ptr<ZipFile> zip_file_;
803 };
804
805+ // Used for creating sub filesystems.
806+ ZipFilesystem(const std::shared_ptr<ZipFile>& shared_data, const std::string& basedir_in_zip_file);
807+
808+ // The data shared between all zip filesystems with the same
809+ // underlying zip file.
810+ std::shared_ptr<ZipFile> zip_file_;
811+
812+ // If we are a sub filesystem, this points to our base
813+ // directory, otherwise it is the empty string.
814+ std::string basedir_in_zip_file_;
815 };
816
817-
818-
819 #endif // end of include guard: WL_IO_FILESYSTEM_ZIP_FILESYSTEM_H

Subscribers

People subscribed via source and target branches

to status/vote changes: