Line data Source code
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 : 22 : /** \file 23 : * \brief This file is the implementation of zipios::GZIPOutputStreambuf class. 24 : * 25 : * This class is an output stream filter which knows how to creates a .gz 26 : * file from the data you write to it. 27 : * 28 : * The compression makes use of the zlib library. 29 : */ 30 : 31 : #include "gzipoutputstreambuf.hpp" 32 : 33 : #include "zipios/zipiosexceptions.hpp" 34 : 35 : 36 : namespace zipios 37 : { 38 : 39 : /** \class GZIPOutputStreambuf 40 : * \brief Save the output stream buffer. 41 : * 42 : * This class is used to output the data of a file in a gzip stream 43 : * including the necessary header and footer. 44 : */ 45 : 46 : 47 : /** \brief Initialize a GZIPOutputStreambuf object. 48 : * 49 : * A newly constructed GZIPOutputStreambuf is ready to accept data. 50 : * 51 : * \param[in,out] outbuf The streambuf to use for output. 52 : * \param[in] compression_level The compression level to use to compress. 53 : */ 54 0 : GZIPOutputStreambuf::GZIPOutputStreambuf(std::streambuf * outbuf, FileEntry::CompressionLevel compression_level) 55 0 : : DeflateOutputStreambuf(outbuf) 56 : { 57 0 : if(!init(compression_level)) 58 : { 59 0 : throw InvalidStateException("GZIPOutputStreambuf::GZIPOutputStreambuf() failed initializing zlib."); 60 : } 61 0 : } 62 : 63 : 64 : /** \brief Ensures that the stream gets closed properly. 65 : * 66 : * This function makes sure that the stream gets closed properly 67 : * which means that the compress terminates by calling finish() 68 : * and the streams get closed. 69 : */ 70 0 : GZIPOutputStreambuf::~GZIPOutputStreambuf() 71 : { 72 0 : finish(); 73 0 : } 74 : 75 : 76 0 : void GZIPOutputStreambuf::setFilename(std::string const & filename) 77 : { 78 0 : m_filename = filename; 79 0 : } 80 : 81 : 82 0 : void GZIPOutputStreambuf::setComment(std::string const & comment) 83 : { 84 0 : m_comment = comment; 85 0 : } 86 : 87 : 88 : /** \brief Close the stream. 89 : * 90 : * This function ensures that the streams get closed. 91 : */ 92 0 : void GZIPOutputStreambuf::close() 93 : { 94 0 : finish(); 95 0 : } 96 : 97 : 98 : /** \brief Finishes the compression. 99 : * 100 : * Write whatever is still necessary and close the streams. 101 : */ 102 0 : void GZIPOutputStreambuf::finish() 103 : { 104 0 : if(!m_open) 105 : { 106 0 : return; 107 : } 108 0 : m_open = false; 109 : 110 0 : closeStream(); 111 0 : writeTrailer(); 112 : } 113 : 114 : 115 0 : int GZIPOutputStreambuf::overflow(int c) 116 : { 117 0 : if(!m_open) 118 : { 119 0 : writeHeader(); 120 0 : m_open = true; 121 : } 122 : 123 0 : return DeflateOutputStreambuf::overflow(c); 124 : } 125 : 126 : 127 0 : int GZIPOutputStreambuf::sync() 128 : { 129 0 : return DeflateOutputStreambuf::sync(); 130 : } 131 : 132 : 133 0 : void GZIPOutputStreambuf::writeHeader() 134 : { 135 : unsigned char const flg( 136 0 : (m_filename.empty() ? 0x00 : 0x08) 137 0 : | (m_comment.empty() ? 0x00 : 0x10) 138 0 : ); 139 : 140 : /** \TODO 141 : * We need to know of the last modification time instead of 142 : * saving all zeros for MTIME values. 143 : */ 144 : 145 : /** \todo: 146 : * I am thinking that the OS should be 3 under Unices. 147 : */ 148 : 149 0 : std::ostream os(m_outbuf); 150 0 : os << static_cast<unsigned char>(0x1f); // Magic # 151 0 : os << static_cast<unsigned char>(0x8b); // Magic # 152 0 : os << static_cast<unsigned char>(0x08); // Deflater.DEFLATED 153 0 : os << flg; // FLG 154 0 : os << static_cast<unsigned char>(0x00); // MTIME 155 0 : os << static_cast<unsigned char>(0x00); // MTIME 156 0 : os << static_cast<unsigned char>(0x00); // MTIME 157 0 : os << static_cast<unsigned char>(0x00); // MTIME 158 0 : os << static_cast<unsigned char>(0x00); // XFLG 159 0 : os << static_cast<unsigned char>(0x00); // OS 160 : 161 0 : if(!m_filename.empty()) 162 : { 163 0 : os << m_filename.c_str(); // Filename 164 0 : os << static_cast<unsigned char>(0x00); 165 : } 166 : 167 0 : if(!m_comment.empty()) 168 : { 169 0 : os << m_comment.c_str(); // Comment 170 0 : os << static_cast<unsigned char>(0x00); 171 : } 172 0 : } 173 : 174 : 175 0 : void GZIPOutputStreambuf::writeTrailer() 176 : { 177 : // write the CRC32 and Size at the end of the file 178 0 : writeInt(getCrc32()); 179 0 : writeInt(getSize()); 180 0 : } 181 : 182 : 183 0 : void GZIPOutputStreambuf::writeInt(uint32_t i) 184 : { 185 : /** \todo: add support for 64 bit files if it exists? */ 186 0 : std::ostream os(m_outbuf); 187 0 : os << static_cast<unsigned char>( i & 0xFF); 188 0 : os << static_cast<unsigned char>((i >> 8) & 0xFF); 189 0 : os << static_cast<unsigned char>((i >> 16) & 0xFF); 190 0 : os << static_cast<unsigned char>((i >> 24) & 0xFF); 191 0 : } 192 : 193 : 194 : } // zipios namespace 195 : 196 : // Local Variables: 197 : // mode: cpp 198 : // indent-tabs-mode: nil 199 : // c-basic-offset: 4 200 : // tab-width: 4 201 : // End: 202 : 203 : // vim: ts=4 sw=4 et