fw4spl
WriteZipArchive.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2015.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include <iosfwd> // streamsize
8 #include <fstream>
9 #include <functional>
10 
11 
12 #include <boost/iostreams/stream.hpp>
13 #include <boost/iostreams/stream_buffer.hpp>
14 #include <boost/iostreams/categories.hpp> // sink_tag
15 
16 #include <boost/filesystem/path.hpp>
17 #include <boost/filesystem/operations.hpp>
18 
19 #include <boost/date_time/posix_time/posix_time_types.hpp>
20 #include <boost/date_time/posix_time/conversion.hpp>
21 
22 #include <fwCore/exceptionmacros.hpp>
23 
24 #include "minizip/zip.h"
25 #include "fwZip/WriteZipArchive.hpp"
26 #include "fwZip/exception/Write.hpp"
27 
28 
29 namespace fwZip
30 {
31 
32 //-----------------------------------------------------------------------------
33 
34 zipFile openWriteZipArchive( const ::boost::filesystem::path &archive )
35 {
36  int append = (::boost::filesystem::exists(archive)) ? APPEND_STATUS_ADDINZIP : APPEND_STATUS_CREATE;
37  zipFile zip = zipOpen(archive.string().c_str(), append);
38 
39  FW_RAISE_EXCEPTION_IF(
40  ::fwZip::exception::Write("Archive '" + archive.string() + "' cannot be opened."),
41  zip == NULL);
42 
43  return zip;
44 }
45 
46 //-----------------------------------------------------------------------------
47 
48 /*
49  * @brief Open a file in the zip archive for writing
50  * @note Z_BEST_SPEED compression level for '.raw' files,
51  * Z_NO_COMPRESSION for 'raw.gz', Z_DEFAULT_COMPRESSION otherwise.
52  */
53 std::streamsize openFile(zipFile zipDescriptor, const ::boost::filesystem::path &path)
54 {
55  const std::string extension = path.extension().string();
56  int compressLevel = Z_DEFAULT_COMPRESSION;
57  if(extension == ".raw")
58  {
59  compressLevel = Z_BEST_SPEED;
60  }
61  else if(extension == ".raw.gz")
62  {
63  compressLevel = Z_NO_COMPRESSION;
64  }
65  zip_fileinfo zfi;
66  zfi.internal_fa = 0;
67  zfi.external_fa = 0;// @todo FIXME
68 
69  ::boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
70  std::tm ptm = ::boost::posix_time::to_tm(now);
71  zfi.dosDate = 0;
72  zfi.tmz_date.tm_year = ptm.tm_year;
73  zfi.tmz_date.tm_mon = ptm.tm_mon;
74  zfi.tmz_date.tm_mday = ptm.tm_mday;
75  zfi.tmz_date.tm_hour = ptm.tm_hour;
76  zfi.tmz_date.tm_min = ptm.tm_min;
77  zfi.tmz_date.tm_sec = ptm.tm_sec;
78 
79  std::streamsize nRet = zipOpenNewFileInZip(zipDescriptor,
80  path.generic_string().c_str(),
81  &zfi,
82  NULL,
83  0,
84  NULL,
85  0,
86  NULL,
87  Z_DEFLATED,
88  compressLevel);
89 
90  return nRet;
91 }
92 
93 //-----------------------------------------------------------------------------
94 
95 class ZipSink
96 {
97 public:
98  typedef char char_type;
99  typedef ::boost::iostreams::sink_tag category;
100 
101  ZipSink( const ::boost::filesystem::path &archive, const ::boost::filesystem::path &path,
102  const std::string comment ) :
103  m_zipDescriptor(
104  openWriteZipArchive(archive),
105  [comment](zipFile zipDescriptor)
106  {
107  zipClose(zipDescriptor, comment.c_str());
108  }),
109  m_archive(archive),
110  m_path(path)
111  {
112  std::streamsize nRet = openFile(m_zipDescriptor.get(), m_path);
113  FW_RAISE_EXCEPTION_IF(
114  ::fwZip::exception::Write("Cannot open file '" + path.string() +
115  "' in archive '"+ archive.string() + "'."),
116  nRet != Z_OK);
117  }
118 
119  std::streamsize write(const char* s, std::streamsize n)
120  {
121  std::streamsize nRet = zipWriteInFileInZip(m_zipDescriptor.get(), s, static_cast< unsigned int >(n));
122  FW_RAISE_EXCEPTION_IF(
123  ::fwZip::exception::Write("Error occurred while writing archive '" + m_archive.string()
124  + ":" + m_path.string() + "'."),
125  nRet < 0);
126  return n;
127  }
128 
129 protected:
130  SPTR(void) m_zipDescriptor;
131  ::boost::filesystem::path m_archive;
132  ::boost::filesystem::path m_path;
133 };
134 
135 //-----------------------------------------------------------------------------
136 
137 WriteZipArchive::WriteZipArchive( const ::boost::filesystem::path &archive ) :
138  m_archive(archive),
139  m_comment("")
140 {
141 }
142 
143 //-----------------------------------------------------------------------------
144 
145 WriteZipArchive::WriteZipArchive( const ::boost::filesystem::path &archive, const std::string& comment ) :
146  m_archive(archive),
147  m_comment(comment)
148 {
149 }
150 
151 //-----------------------------------------------------------------------------
152 
153 WriteZipArchive::~WriteZipArchive()
154 {
155 }
156 
157 //-----------------------------------------------------------------------------
158 
159 SPTR(std::ostream) WriteZipArchive::createFile(const ::boost::filesystem::path &path)
160 {
161  SPTR(::boost::iostreams::stream<ZipSink>) os
162  = std::make_shared< ::boost::iostreams::stream<ZipSink> >(m_archive, path, m_comment);
163  return os;
164 }
165 
166 //-----------------------------------------------------------------------------
167 
168 void WriteZipArchive::putFile(const ::boost::filesystem::path &sourceFile, const ::boost::filesystem::path &path)
169 {
170  std::ifstream is(sourceFile.string().c_str(), std::ios::binary);
171  FW_RAISE_EXCEPTION_IF(::fwZip::exception::Write("Source file '" + sourceFile.string() + "' cannot be opened."),
172  !is.good());
173 
174  {
175  SPTR(std::ostream) os = this->createFile(path);
176  *os << is.rdbuf();
177  }
178  is.close();
179 }
180 
181 //-----------------------------------------------------------------------------
182 
183 bool WriteZipArchive::createDir(const ::boost::filesystem::path &path)
184 {
185  zipFile zipDescriptor = openWriteZipArchive(m_archive);
186  const std::streamsize nRet = openFile(zipDescriptor, path);
187 
188  zipCloseFileInZip(zipDescriptor);
189  zipClose(zipDescriptor, m_comment.c_str());
190 
191  return nRet == ZIP_OK;
192 }
193 
194 //-----------------------------------------------------------------------------
195 
196 const ::boost::filesystem::path WriteZipArchive::getArchivePath() const
197 {
198  return m_archive;
199 }
200 
201 //-----------------------------------------------------------------------------
202 
203 }
204 
#define SPTR(_cls_)
FWZIP_API bool createDir(const ::boost::filesystem::path &path) override
Creates a folder in archive.
FWZIP_API WriteZipArchive(const ::boost::filesystem::path &archive)
Constructors. Initializes archive path.
Write exception.
Definition: Write.hpp:21
FWZIP_APIconst::boost::filesystem::path getArchivePath() const override
Returns archive path.
This class defines functions to write a file in a zip archive.
FWZIP_API std::shared_ptr< std::ostream > createFile(const ::boost::filesystem::path &path) override
Creates a new file entry in archive and returns output stream for this file.
FWZIP_API void putFile(const ::boost::filesystem::path &sourceFile, const ::boost::filesystem::path &path) override
Writes source file in archive.
The namespace fwZip provides IO for compress/uncompress .zip files using zlib .
Definition: Read.hpp:14