zipios  2.3.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-2022 Made to Order Software Corp. All Rights Reserved
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 
57  std::ostream & os
58  , FileEntry::vector_t & entries
59  , std::string const & comment)
60 {
61  ZipEndOfCentralDirectory eocd(comment);
62  eocd.setOffset(os.tellp()); // start position
63  eocd.setCount(entries.size());
64 
65  std::size_t central_directory_size(0);
66  for(auto it = entries.begin(); it != entries.end(); ++it)
67  {
68  (*it)->write(os);
69  central_directory_size += (*it)->getHeaderSize();
70  }
71 
72  eocd.setCentralDirectorySize(central_directory_size);
73  eocd.write(os);
74 }
75 
76 
77 } // no name namespace
78 
79 
96  : DeflateOutputStreambuf(outbuf)
97 {
98 }
99 
100 
115 {
116  // avoid possible exceptions when writing the central directory
117  try
118  {
119  finish();
120  }
121  catch(...)
122  {
123  }
124 }
125 
126 
133 {
134  if(!m_open_entry)
135  {
136  return;
137  }
138 
139  switch(m_compression_level)
140  {
142  overflow(); // flush
143  break;
144 
145  default:
146  closeStream();
147  break;
148 
149  }
150 
153 }
154 
155 
162 {
163  finish();
164 }
165 
166 
175 {
176  if(!m_open)
177  {
178  return;
179  }
180  m_open = false;
181 
182  std::ostream os(m_outbuf);
183  closeEntry();
185 }
186 
187 
199 {
200  closeEntry();
201 
202  // if the method is STORED force uncompressed data
203  if(entry->getMethod() == StorageMethod::STORED)
204  {
205  // force to "no compression" when the method is STORED
207  }
208  else
209  {
210  // get the user defined compression level
211  m_compression_level = entry->getLevel();
212  }
213  m_overflown_bytes = 0;
214  switch(m_compression_level)
215  {
217  setp(&m_invec[0], &m_invec[0] + getBufferSize());
218  break;
219 
220  default:
222  break;
223 
224  }
225 
226  m_entries.push_back(entry);
227 
228  std::ostream os(m_outbuf);
229 
230  // Update entry header info
231  entry->setEntryOffset(os.tellp());
236  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
237 
238  m_open_entry = true;
239 }
240 
241 
254 void ZipOutputStreambuf::setComment(std::string const & comment)
255 {
256  m_zip_comment = comment;
257 }
258 
259 
260 //
261 // Protected and private methods
262 //
263 
279 {
280  std::size_t const size(pptr() - pbase());
281  m_overflown_bytes += size;
282  switch(m_compression_level)
283  {
285  {
286  // Ok, we are STORED, so we handle it ourselves to avoid "side
287  // effects" from zlib, which adds markers every now and then.
288  m_crc32 = crc32(m_crc32, reinterpret_cast<Bytef const *>(&m_invec[0]), size); // update crc32
289  size_t const bc(m_outbuf->sputn(&m_invec[0], size));
290  if(size != bc)
291  {
292  // Without implementing our own stream in our test, this
293  // cannot really be reached because it is all happening
294  // inside the same loop in ZipFile::saveCollectionToArchive()
295  throw IOException("ZipOutputStreambuf::overflow(): write to buffer failed."); // LCOV_EXCL_LINE
296  }
297  setp(&m_invec[0], &m_invec[0] + getBufferSize());
298 
299  if(c != EOF)
300  {
301  *pptr() = c;
302  pbump(1);
303  }
304 
305  return 0;
306  }
307 
308  default:
310 
311  }
312 }
313 
314 
315 
324 int ZipOutputStreambuf::sync() // LCOV_EXCL_LINE
325 {
326  return DeflateOutputStreambuf::sync(); // LCOV_EXCL_LINE
327 }
328 
329 
330 
338 {
339  m_open_entry = false;
340  m_crc32 = crc32(0, nullptr, 0);
341 
346 }
347 
348 
361 {
362  if(!m_open_entry)
363  {
364  return;
365  }
366 
367  std::ostream os(m_outbuf);
368  int const curr_pos(os.tellp());
369 
370  // update fields in m_entries.back()
371  FileEntry::pointer_t entry(m_entries.back());
372  entry->setSize(getSize());
373  entry->setCrc(getCrc32());
378  entry->setCompressedSize(curr_pos - entry->getEntryOffset() - static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::getHeaderSize());
379 
380  // write ZipLocalEntry header to header position
381  os.seekp(entry->getEntryOffset());
386  static_cast<ZipLocalEntry *>(entry.get())->ZipLocalEntry::write(os);
387  os.seekp(curr_pos);
388 }
389 
390 
391 } // zipios namespace
392 
393 // Local Variables:
394 // mode: cpp
395 // indent-tabs-mode: nil
396 // c-basic-offset: 4
397 // tab-width: 4
398 // End:
399 
400 // 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.
size_t getSize() const
Retrieve the size of the file deflated.
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.
uint32_t getCrc32() const
Get the CRC32 of the file.
void updateEntryHeaderInfo()
Save the header information.
void closeEntry()
Close this buffer entry.
std::shared_ptr< FileEntry > pointer_t
Definition: fileentry.hpp:78
A class to handle stream deflate on the fly.
void writeZipCentralDirectory(std::ostream &os, FileEntry::vector_t &entries, std::string const &comment)
Helper function used to write the central directory.
std::vector< pointer_t > vector_t
Definition: fileentry.hpp:79