zipios++  2.0.2
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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_open_entry(false) -- auto-init
95  //, m_open(true) -- auto-init
96 {
97 }
98 
99 
114 {
115  // avoid possible exceptions when writing the central directory
116  try
117  {
118  finish();
119  }
120  catch(...)
121  {
122  }
123 }
124 
125 
132 {
133  if(!m_open_entry)
134  {
135  return;
136  }
137 
138  switch(m_compression_level)
139  {
141  overflow(); // flush
142  break;
143 
144  default:
145  closeStream();
146  break;
147 
148  }
149 
152 }
153 
154 
161 {
162  finish();
163 }
164 
165 
174 {
175  if(!m_open)
176  {
177  return;
178  }
179  m_open = false;
180 
181  std::ostream os(m_outbuf);
182  closeEntry();
184 }
185 
186 
198 {
199  closeEntry();
200 
201  // if the method is STORED force uncompressed data
202  if(entry->getMethod() == StorageMethod::STORED)
203  {
204  // force to "no compression" when the method is STORED
206  }
207  else
208  {
209  // get the user defined compression level
210  m_compression_level = entry->getLevel();
211  }
212  m_overflown_bytes = 0;
213  switch(m_compression_level)
214  {
216  setp(&m_invec[0], &m_invec[0] + getBufferSize());
217  break;
218 
219  default:
221  break;
222 
223  }
224 
225  m_entries.push_back(entry);
226 
227  std::ostream os(m_outbuf);
228 
229  // Update entry header info
230  entry->setEntryOffset(os.tellp());
235  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
236 
237  m_open_entry = true;
238 }
239 
240 
253 void ZipOutputStreambuf::setComment(std::string const& comment)
254 {
255  m_zip_comment = comment;
256 }
257 
258 
259 //
260 // Protected and private methods
261 //
262 
274 {
275  size_t const size(pptr() - pbase());
276  m_overflown_bytes += size;
277  switch(m_compression_level)
278  {
280  {
281  // Ok, we are STORED, so we handle it ourselves to avoid "side
282  // effects" from zlib, which adds markers every now and then.
283  size_t const bc(m_outbuf->sputn(&m_invec[0], size));
284  if(size != bc)
285  {
286  // Without implementing our own stream in our test, this
287  // cannot really be reached because it is all happening
288  // inside the same loop in ZipFile::saveCollectionToArchive()
289  throw IOException("ZipOutputStreambuf::overflow(): write to buffer failed."); // LCOV_EXCL_LINE
290  }
291  setp(&m_invec[0], &m_invec[0] + getBufferSize());
292 
293  if(c != EOF)
294  {
295  *pptr() = c;
296  pbump(1);
297  }
298 
299  return 0;
300  }
301 
302  default:
304 
305  }
306 }
307 
308 
309 
318 int ZipOutputStreambuf::sync() // LCOV_EXCL_LINE
319 {
320  return DeflateOutputStreambuf::sync(); // LCOV_EXCL_LINE
321 }
322 
323 
324 
332 {
333  m_open_entry = false;
334 
339 }
340 
341 
354 {
355  if(!m_open_entry)
356  {
357  return;
358  }
359 
360  std::ostream os(m_outbuf);
361  int const curr_pos(os.tellp());
362 
363  // update fields in m_entries.back()
364  FileEntry::pointer_t entry(m_entries.back());
365  entry->setSize(getSize());
366  entry->setCrc(getCrc32());
371  entry->setCompressedSize(curr_pos - entry->getEntryOffset() - static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::getHeaderSize());
372 
373  // write ZipLocalEntry header to header position
374  os.seekp(entry->getEntryOffset());
379  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
380  os.seekp(curr_pos);
381 }
382 
383 
384 } // zipios namespace
385 
386 // Local Variables:
387 // mode: cpp
388 // indent-tabs-mode: nil
389 // c-basic-offset: 4
390 // tab-width: 4
391 // End:
392 
393 // vim: ts=4 sw=4 et
void setCount(size_t c)
Set the number of entries.
FileEntry::CompressionLevel m_compression_level
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:77
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:78