summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp181
1 files changed, 121 insertions, 60 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
index 4a0b2fa52e2..c03db71742d 100644
--- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
+++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
@@ -21,100 +21,161 @@
#ifndef ZLIBOUTPUTSTREAM_HPP
#define ZLIBOUTPUTSTREAM_HPP
+#include <fstream>
#include <ostream>
+#include <vector>
#include <zlib.h>
+#include "MessageException.hpp"
-class ZLibOutputStream;
+#ifdef _WIN32
+# include <fcntl.h>
+# include <io.h>
+#endif
+
+struct ZLibException : public MessageException {
+ ZLibException (const std::string &msg) : MessageException(msg) {}
+};
-class ZLibOutputBuffer : public std::streambuf
-{
- friend class ZLibOutputStream;
+enum ZLibCompressionFormat {ZLIB_DEFLATE=0, ZLIB_GZIP=16};
+
+class ZLibOutputBuffer : public std::streambuf {
public:
- ~ZLibOutputBuffer () {close();}
+ ZLibOutputBuffer () {}
+
+ ZLibOutputBuffer (std::streambuf *sbuf, ZLibCompressionFormat format, int zipLevel) {
+ open(sbuf, format, zipLevel);
+ }
- /** Opens the buffer object for writing.
- * @param[in] fname name of gzip file
+ ~ZLibOutputBuffer () {
+ close();
+ }
+
+ /** Opens the buffer for writing.
+ * @param[in] sink stream buffer taking the compressed data
+ * @param[in] format compression format (deflate or gzip)
* @param[in] zipLevel compression level (1-9)
- * @return true on success */
- bool open (const char *fname, int zipLevel) {
- if (_opened)
- return false;
- zipLevel = std::max(1, std::min(9, zipLevel));
- std::string modestr = "wb0";
- modestr[2] += zipLevel;
- _gzfile = gzopen(fname, modestr.c_str());
- return _opened = (_gzfile != nullptr);
+ * @return true if buffer is ready for writing */
+ bool open (std::streambuf *sink, ZLibCompressionFormat format, int zipLevel) {
+ if (sink) {
+ _inbuf.reserve(4096);
+ _zbuf.resize(4096);
+ _zstream.zalloc = Z_NULL;
+ _zstream.zfree = Z_NULL;
+ _zstream.opaque = Z_NULL;
+ zipLevel = std::max(1, std::min(9, zipLevel));
+ if (deflateInit2(&_zstream, zipLevel, Z_DEFLATED, 15+format, 8, Z_DEFAULT_STRATEGY) != Z_OK)
+ throw ZLibException("failed to initialize deflate compression");
+ _sink = sink;
+ _opened = true;
+ }
+ return _opened;
}
- /** Closes the buffer object. */
- bool close () {
- if (!_opened)
- return false;
- sync();
- _opened = false;
- return gzclose(_gzfile) == Z_OK;
+ /** Flushes the remaining data, finishes the compression process, and
+ * closes the buffer so that further output doesn't reach the sink. */
+ void close () {
+ close(true);
}
- int overflow (int c) override {
- if (!_opened)
- return EOF;
- if (c != EOF) {
- *pptr() = c;
- pbump(1);
+ int_type overflow (int_type c) override {
+ if (c == traits_type::eof()) {
+ close();
+ }
+ else {
+ if (_inbuf.size() == _inbuf.capacity())
+ flush(Z_NO_FLUSH);
+ _inbuf.push_back(c);
}
- return (flush() == EOF) ? EOF : c;
+ return c;
}
int sync () override {
- return (pptr() && pptr() > pbase() && flush() == EOF) ? -1 : 0;
+ flush(Z_NO_FLUSH);
+ return 0;
}
protected:
- ZLibOutputBuffer () : _gzfile(nullptr), _opened(false) {
- setp(_buffer, _buffer+SIZE-1);
+ /** Compresses the chunk of data present in the input buffer
+ * and writes it to the assigned output stream.
+ * @param[in] flushmode flush mode of deflate function (Z_NO_FLUSH or Z_FINISH)
+ * @throws ZLibException if compression failed */
+ void flush (int flushmode) {
+ if (_opened) {
+ _zstream.avail_in = _inbuf.size();
+ _zstream.next_in = _inbuf.data();
+ do {
+ _zstream.avail_out = _zbuf.size();
+ _zstream.next_out = _zbuf.data();
+ int ret = deflate(&_zstream, flushmode);
+ if (ret == Z_STREAM_ERROR) {
+ close(false);
+ throw ZLibException("stream error during data compression");
+ }
+ auto have = _zbuf.size()-_zstream.avail_out;
+ _sink->sputn(reinterpret_cast<char*>(_zbuf.data()), have);
+ } while (_zstream.avail_out == 0);
+ }
+ _inbuf.clear();
}
- /** Forces to write the buffer data to the output file. */
- int flush () {
- int w = pptr()-pbase();
- if (gzwrite(_gzfile, pbase(), w) != w)
- return EOF;
- pbump(-w);
- return w;
+ /** Closes the buffer so that further output doesn't reach the sink.
+ * @param[in] finish if true, flushes the remaining data and finishes the compression process */
+ void close (bool finish) {
+ if (_opened) {
+ if (finish)
+ flush(Z_FINISH);
+ deflateEnd(&_zstream);
+ _sink = nullptr;
+ _opened = false;
+ }
}
private:
- static constexpr int SIZE = 512;
- gzFile _gzfile;
- char _buffer[SIZE];
- bool _opened;
+ z_stream _zstream;
+ std::streambuf *_sink = nullptr; ///< target buffer where the compressded data is flushed to
+ std::vector<Bytef> _inbuf; ///< buffer holding a chunk of data to be compressed
+ std::vector<Bytef> _zbuf; ///< buffer holding a chunk of compressed data
+ bool _opened = false; ///< true if ready to process the incoming data correctly
};
-class ZLibOutputStream : public virtual std::ios, public std::ostream
-{
+class ZLibOutputStream : private ZLibOutputBuffer, public std::ostream {
public:
- ZLibOutputStream () : std::ostream(&_buf) {init(&_buf);}
- ZLibOutputStream (const char *fname, int zipLevel) : ZLibOutputStream() {open(fname, zipLevel);}
- ZLibOutputStream (const std::string &fname, int zipLevel) : ZLibOutputStream(fname.c_str(), zipLevel) {}
+ ZLibOutputStream () : std::ostream(this) {}
+
+ ZLibOutputStream (std::ostream &os, ZLibCompressionFormat format, int zipLevel)
+ : ZLibOutputBuffer(os.rdbuf(), format, zipLevel), std::ostream(this) {}
+
~ZLibOutputStream () {close();}
- ZLibOutputBuffer* rdbuf() {return &_buf;}
-
- /** Opens the output stream for writing.
- * @param[in] fname name of gzip file
- * @param[in] zipLevel compression level (1-9) */
- void open (const char *name, int zipLevel) {
- if (!_buf.open(name, zipLevel))
- clear(rdstate()|std::ios::badbit);
+
+ bool open (std::ostream &os, ZLibCompressionFormat format, int zipLevel) {
+ ZLibOutputBuffer::close();
+ return ZLibOutputBuffer::open(os.rdbuf(), format, zipLevel);
}
void close () {
- if (!_buf.close())
- clear(rdstate()|std::ios::badbit);
+ ZLibOutputBuffer::close();
}
+};
+
+
+class ZLibOutputFileStream : public ZLibOutputStream {
+ public:
+ ZLibOutputFileStream (const std::string &fname, ZLibCompressionFormat format, int zipLevel)
+ : _ofs(fname, std::ios::binary)
+ {
+ if (_ofs) {
+ if (_ofs.rdbuf())
+ open(_ofs, format, zipLevel);
+ else
+ _ofs.close();
+ }
+ }
+
+ ~ZLibOutputFileStream () {close();}
private:
- ZLibOutputBuffer _buf;
+ std::ofstream _ofs;
};
#endif