zipios  2.2.0
Zipios – a small C++ library that provides easy access to .zip files.
zipoutputstreambuf.cpp
Go to the documentation of this file.
1 /*
2  Zipios -- a small C++ library that provides easy access to .zip files.
3 
4  Copyright (C) 2000-2007 Thomas Sondergaard
5  Copyright (C) 2015-2019 Made to Order Software Corporation
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
29 #include "zipoutputstreambuf.hpp"
30 
32 
33 #include "ziplocalentry.hpp"
35 
36 
37 namespace zipios
38 {
39 
40 
41 namespace
42 {
43 
44 
56 void writeZipCentralDirectory(std::ostream &os, FileEntry::vector_t& entries, std::string const& comment)
57 {
58  ZipEndOfCentralDirectory eocd(comment);
59  eocd.setOffset(os.tellp()); // start position
60  eocd.setCount(entries.size());
61 
62  size_t central_directory_size(0);
63  for(auto it = entries.begin(); it != entries.end(); ++it)
64  {
65  (*it)->write(os);
66  central_directory_size += (*it)->getHeaderSize();
67  }
68 
69  eocd.setCentralDirectorySize(central_directory_size);
70  eocd.write(os);
71 }
72 
73 
74 } // no name namespace
75 
76 
93  : DeflateOutputStreambuf(outbuf)
94  //, m_zip_comment("") -- auto-init
95  //, m_entries() -- auto-init
96  //, m_compression_level(FileEntry::COMPRESSION_LEVEL_DEFAULT) -- auto-init
97  //, m_open_entry(false) -- auto-init
98  //, m_open(true) -- auto-init
99 {
100 }
101 
102 
117 {
118  // avoid possible exceptions when writing the central directory
119  try
120  {
121  finish();
122  }
123  catch(...)
124  {
125  }
126 }
127 
128 
135 {
136  if(!m_open_entry)
137  {
138  return;
139  }
140 
141  switch(m_compression_level)
142  {
144  overflow(); // flush
145  break;
146 
147  default:
148  closeStream();
149  break;
150 
151  }
152 
155 }
156 
157 
164 {
165  finish();
166 }
167 
168 
177 {
178  if(!m_open)
179  {
180  return;
181  }
182  m_open = false;
183 
184  std::ostream os(m_outbuf);
185  closeEntry();
187 }
188 
189 
201 {
202  closeEntry();
203 
204  // if the method is STORED force uncompressed data
205  if(entry->getMethod() == StorageMethod::STORED)
206  {
207  // force to "no compression" when the method is STORED
209  }
210  else
211  {
212  // get the user defined compression level
213  m_compression_level = entry->getLevel();
214  }
215  m_overflown_bytes = 0;
216  switch(m_compression_level)
217  {
219  setp(&m_invec[0], &m_invec[0] + getBufferSize());
220  break;
221 
222  default:
224  break;
225 
226  }
227 
228  m_entries.push_back(entry);
229 
230  std::ostream os(m_outbuf);
231 
232  // Update entry header info
233  entry->setEntryOffset(os.tellp());
238  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
239 
240  m_open_entry = true;
241 }
242 
243 
256 void ZipOutputStreambuf::setComment(std::string const& comment)
257 {
258  m_zip_comment = comment;
259 }
260 
261 
262 //
263 // Protected and private methods
264 //
265 
277 {
278  size_t const size(pptr() - pbase());
279  m_overflown_bytes += size;
280  switch(m_compression_level)
281  {
283  {
284  // Ok, we are STORED, so we handle it ourselves to avoid "side
285  // effects" from zlib, which adds markers every now and then.
286  size_t const bc(m_outbuf->sputn(&m_invec[0], size));
287  if(size != bc)
288  {
289  // Without implementing our own stream in our test, this
290  // cannot really be reached because it is all happening
291  // inside the same loop in ZipFile::saveCollectionToArchive()
292  throw IOException("ZipOutputStreambuf::overflow(): write to buffer failed."); // LCOV_EXCL_LINE
293  }
294  setp(&m_invec[0], &m_invec[0] + getBufferSize());
295 
296  if(c != EOF)
297  {
298  *pptr() = c;
299  pbump(1);
300  }
301 
302  return 0;
303  }
304 
305  default:
307 
308  }
309 }
310 
311 
312 
321 int ZipOutputStreambuf::sync() // LCOV_EXCL_LINE
322 {
323  return DeflateOutputStreambuf::sync(); // LCOV_EXCL_LINE
324 }
325 
326 
327 
335 {
336  m_open_entry = false;
337 
342 }
343 
344 
357 {
358  if(!m_open_entry)
359  {
360  return;
361  }
362 
363  std::ostream os(m_outbuf);
364  int const curr_pos(os.tellp());
365 
366  // update fields in m_entries.back()
367  FileEntry::pointer_t entry(m_entries.back());
368  entry->setSize(getSize());
369  entry->setCrc(getCrc32());
374  entry->setCompressedSize(curr_pos - entry->getEntryOffset() - static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::getHeaderSize());
375 
376  // write ZipLocalEntry header to header position
377  os.seekp(entry->getEntryOffset());
382  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
383  os.seekp(curr_pos);
384 }
385 
386 
387 } // zipios namespace
388 
389 // Local Variables:
390 // mode: cpp
391 // indent-tabs-mode: nil
392 // c-basic-offset: 4
393 // tab-width: 4
394 // End:
395 
396 // vim: ts=4 sw=4 et
void setCount(size_t c)
Set the number of entries.
FileEntry::CompressionLevel m_compression_level
The zipios namespace includes the Zipios library definitions.
Definition: backbuffer.cpp:35
virtual ~ZipOutputStreambuf()
Clean up the buffer.
void setEntryClosedState()
Mark the current entry as closed.
void write(std::ostream &os)
Write the ZipEndOfCentralDirectory structure to a stream.
Various exceptions used throughout the Zipios library, all based on zipios::Exception.
void finish()
Finish up an output stream buffer.
virtual int overflow(int c=EOF)
Handle an overflow.
void closeStream()
Closing the stream.
virtual int sync()
Synchronize the buffer.
ZipOutputStreambuf(std::streambuf *outbuf)
Initialize a ZipOutputStreambuf object.
virtual size_t getHeaderSize() const override
Retrieve the size of the header.
An implementation of the FileEntry for Zip archives.
void close()
Close the output stream buffer.
void setCentralDirectorySize(size_t size)
Define the size of the central directory.
Define the zipios::ZipOutputStreambuf class.
bool init(FileEntry::CompressionLevel compression_level)
Initialize the zlib library.
static CompressionLevel const COMPRESSION_LEVEL_NONE
Definition: fileentry.hpp:90
void setOffset(offset_t new_offset)
Offset of the Central Directory.
virtual int sync() override
Implement the sync() functionality.
Marker at the end of a Zip archive file.
void putNextEntry(FileEntry::pointer_t entry)
Start saving an entry in the output buffer.
An IOException is used to signal an I/O error.
virtual void write(std::ostream &os) override
Write a ZipLocalEntry to os.
Declare the zipios::ZipLocalEntry class used to handle Zip entries.
virtual int overflow(int c=EOF) override
Implementation of the overflow() function.
size_t getBufferSize()
Declaration of the zipios::ZipEndOfCentralDirectory class.
void setComment(std::string const &comment)
Set the archive comment.
void updateEntryHeaderInfo()
Save the header information.
size_t getSize() const
Retrieve the size of the file deflated.
void closeEntry()
Close this buffer entry.
std::shared_ptr< FileEntry > pointer_t
Definition: fileentry.hpp:78
uint32_t getCrc32() const
Get the CRC32 of the file.
A class to handle stream deflate on the fly.
void writeZipCentralDirectory(std::ostream &os, FileEntry::vector_t &entries, std::string const &comment)
Help function used to write the central directory.
std::vector< pointer_t > vector_t
Definition: fileentry.hpp:79