Upload UI
[lsnes.git] / src / library / streamcompress-gzip.cpp
blob48b9a5610b96261b4a929ce64bd33ce5c788554f
1 #include <boost/iostreams/categories.hpp>
2 #include <boost/iostreams/copy.hpp>
3 #include <boost/iostreams/stream.hpp>
4 #include <boost/iostreams/stream_buffer.hpp>
5 #include <boost/iostreams/filter/symmetric.hpp>
6 #include <boost/iostreams/filter/zlib.hpp>
7 #include <boost/iostreams/filtering_stream.hpp>
8 #include <boost/iostreams/device/back_inserter.hpp>
9 #include "streamcompress.hpp"
10 #include "serialization.hpp"
11 #include "string.hpp"
12 #include <zlib.h>
13 #include <stdexcept>
15 namespace
17 void* zalloc(void* opaque, unsigned items, unsigned size)
19 return calloc(items, size);
22 void zfree(void* opaque, void* ptr)
24 free(ptr);
27 struct stream_compressor_gzip : public stream_compressor_base
29 stream_compressor_gzip(unsigned level)
31 memset(&strm, 0, sizeof(z_stream));
32 strm.zalloc = zalloc;
33 strm.zfree = zfree;
34 if(level > 9) level = 9;
35 deflateInit2(&strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
36 crc = crc32(0, NULL, 0);
37 size = 0;
38 hdr = 0;
39 trl = 0;
40 data_output = false;
42 ~stream_compressor_gzip()
44 deflateEnd(&strm);
46 bool process(uint8_t*& in, size_t& insize, uint8_t*& out, size_t& outsize, bool final)
48 uint8_t header[] = {31, 139, 8, 0, 0, 0, 0, 0, 0, 255};
49 uint8_t trailer[8];
50 write32ule(trailer + 0, crc);
51 write32ule(trailer + 4, size);
52 while(hdr < 10) {
53 if(!outsize) return false;
54 *(out++) = header[hdr++];
55 outsize--;
57 if(data_output) {
58 while(trl < 8) {
59 if(!outsize) return false;
60 *(out++) = trailer[trl++];
61 outsize--;
63 return true;
66 strm.next_in = in;
67 strm.avail_in = insize;
68 strm.next_out = out;
69 strm.avail_out = outsize;
70 int r = deflate(&strm, final ? Z_FINISH : 0);
71 size += (insize - strm.avail_in);
72 crc = crc32(crc, in, insize - strm.avail_in);
73 in = strm.next_in;
74 insize = strm.avail_in;
75 out = strm.next_out;
76 outsize = strm.avail_out;
77 if(r == Z_STREAM_END) data_output = true;
78 if(r < 0) {
79 if(r == Z_ERRNO) throw std::runtime_error("OS error");
80 if(r == Z_STREAM_ERROR) throw std::runtime_error("Streams error");
81 if(r == Z_DATA_ERROR) throw std::runtime_error("Data error");
82 if(r == Z_MEM_ERROR) throw std::runtime_error("Memory error");
83 if(r == Z_BUF_ERROR) throw std::runtime_error("Buffer error");
84 if(r == Z_VERSION_ERROR) throw std::runtime_error("Version error");
85 throw std::runtime_error("Unknown error");
87 return false;
89 private:
90 z_stream strm;
91 uint32_t crc;
92 uint32_t size;
93 unsigned hdr;
94 unsigned trl;
95 bool data_output;
98 struct foo {
99 foo() {
100 stream_compressor_base::do_register("gzip", [](const std::string& v) ->
101 stream_compressor_base* {
102 auto a = stream_compressor_parse_attributes(v);
103 unsigned compression = 7;
104 if(a.count("level")) compression = parse_value<unsigned>(a["level"]);
105 return new stream_compressor_gzip(compression);
108 ~foo() {
109 stream_compressor_base::do_unregister("gzip");
111 } _foo;
113 class stdin_input
115 public:
116 typedef char char_type;
117 typedef boost::iostreams::source_tag category;
119 stdin_input()
123 void close()
127 std::streamsize read(char* s, std::streamsize x)
129 std::cin.read(s, x);
130 if(!std::cin.gcount() && !std::cin) return -1;
131 return std::cin.gcount();
134 ~stdin_input()
137 private:
138 stdin_input& operator=(const stdin_input& f);
143 #ifdef STREAMCOMPRESS_GZIP_TEST
144 int main()
146 std::vector<char> out;
147 stream_compressor_base* X = stream_compressor_base::create_compressor("gzip", "level=7");
148 boost::iostreams::filtering_istream* s = new boost::iostreams::filtering_istream();
149 s->push(iostream_compressor(X));
150 s->push(stdin_input());
151 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
152 boost::iostreams::copy(*s, rd);
153 delete s;
154 delete X;
156 std::cout.write(&out[0], out.size());
157 return 0;
159 #endif