Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / library / streamcompress-gzip.cpp
blobfa16da0cc277a6f23f0f3642f46bc8d4514063f3
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 gzip : public streamcompress::base
29 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 ~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 serialization::u32l(trailer + 0, crc);
51 serialization::u32l(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;
65 strm.next_in = in;
66 strm.avail_in = insize;
67 strm.next_out = out;
68 strm.avail_out = outsize;
69 int r = deflate(&strm, final ? Z_FINISH : 0);
70 size += (insize - strm.avail_in);
71 crc = crc32(crc, in, insize - strm.avail_in);
72 in = strm.next_in;
73 insize = strm.avail_in;
74 out = strm.next_out;
75 outsize = strm.avail_out;
76 if(r == Z_STREAM_END) data_output = true;
77 if(r < 0) {
78 if(r == Z_ERRNO) throw std::runtime_error("OS error");
79 if(r == Z_STREAM_ERROR) throw std::runtime_error("Streams error");
80 if(r == Z_DATA_ERROR) throw std::runtime_error("Data error");
81 if(r == Z_MEM_ERROR) throw std::runtime_error("Memory error");
82 if(r == Z_BUF_ERROR) throw std::runtime_error("Buffer error");
83 if(r == Z_VERSION_ERROR) throw std::runtime_error("Version error");
84 throw std::runtime_error("Unknown error");
86 return false;
88 private:
89 z_stream strm;
90 uint32_t crc;
91 uint32_t size;
92 unsigned hdr;
93 unsigned trl;
94 bool data_output;
97 struct foo {
98 foo() {
99 streamcompress::base::do_register("gzip", [](const std::string& v) ->
100 streamcompress::base* {
101 auto a = streamcompress::parse_attributes(v);
102 unsigned compression = 7;
103 if(a.count("level")) compression = parse_value<unsigned>(a["level"]);
104 return new gzip(compression);
107 ~foo() {
108 streamcompress::base::do_unregister("gzip");
110 } _foo;
112 class stdin_input
114 public:
115 typedef char char_type;
116 typedef boost::iostreams::source_tag category;
118 stdin_input()
122 void close()
126 std::streamsize read(char* s, std::streamsize x)
128 std::cin.read(s, x);
129 if(!std::cin.gcount() && !std::cin) return -1;
130 return std::cin.gcount();
133 ~stdin_input()
136 private:
137 stdin_input& operator=(const stdin_input& f);
142 #ifdef STREAMCOMPRESS_GZIP_TEST
143 int main()
145 std::vector<char> out;
146 streamcompress::base* X = streamcompress::base::create_compressor("gzip", "level=7");
147 boost::iostreams::filtering_istream* s = new boost::iostreams::filtering_istream();
148 s->push(streamcompress::iostream(X));
149 s->push(stdin_input());
150 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
151 boost::iostreams::copy(*s, rd);
152 delete s;
153 delete X;
155 std::cout.write(&out[0], out.size());
156 return 0;
158 #endif