Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / library / streamcompress-xz.cpp
blob3dde46bebb9d6adb2cb71051cc6a77cea9ab4a2a
1 #ifdef LIBLZMA_AVAILABLE
2 #include <boost/iostreams/categories.hpp>
3 #include <boost/iostreams/copy.hpp>
4 #include <boost/iostreams/stream.hpp>
5 #include <boost/iostreams/stream_buffer.hpp>
6 #include <boost/iostreams/filter/symmetric.hpp>
7 #include <boost/iostreams/filter/zlib.hpp>
8 #include <boost/iostreams/filtering_stream.hpp>
9 #include <boost/iostreams/device/back_inserter.hpp>
10 #include "streamcompress.hpp"
11 #include "serialization.hpp"
12 #include "string.hpp"
13 #include <lzma.h>
14 #include <stdexcept>
16 namespace
18 struct lzma_options
20 bool xz;
21 lzma_filter* fchain;
22 lzma_check check;
23 lzma_options_lzma lzmaopts;
26 struct lzma : public streamcompress::base
28 lzma(lzma_options& opts)
30 memset(&strm, 0, sizeof(strm));
31 lzma_ret r;
32 if(opts.xz) {
33 r = lzma_stream_encoder(&strm, opts.fchain, opts.check);
34 } else {
35 r = lzma_alone_encoder(&strm, &opts.lzmaopts);
37 if(r >= 5) {
38 if(r == LZMA_MEM_ERROR) throw std::runtime_error("Memory error");
39 if(r == LZMA_MEMLIMIT_ERROR) throw std::runtime_error("Memory limit exceeded");
40 if(r == LZMA_FORMAT_ERROR) throw std::runtime_error("File format error");
41 if(r == LZMA_OPTIONS_ERROR) throw std::runtime_error("Options error");
42 if(r == LZMA_DATA_ERROR) throw std::runtime_error("Data error");
43 if(r == LZMA_BUF_ERROR) throw std::runtime_error("Buffer error");
44 if(r == LZMA_PROG_ERROR) throw std::runtime_error("Programming error");
45 throw std::runtime_error("Unknown error");
48 ~lzma()
50 lzma_end(&strm);
52 bool process(uint8_t*& in, size_t& insize, uint8_t*& out, size_t& outsize, bool final)
54 strm.next_in = in;
55 strm.avail_in = insize;
56 strm.next_out = out;
57 strm.avail_out = outsize;
58 lzma_ret r = lzma_code(&strm, final ? LZMA_FINISH : LZMA_RUN);
59 in = (uint8_t*)strm.next_in;
60 insize = strm.avail_in;
61 out = strm.next_out;
62 outsize = strm.avail_out;
63 if(r == LZMA_STREAM_END) return true;
64 if(r >= 5) {
65 if(r == LZMA_MEM_ERROR) throw std::runtime_error("Memory error");
66 if(r == LZMA_MEMLIMIT_ERROR) throw std::runtime_error("Memory limit exceeded");
67 if(r == LZMA_FORMAT_ERROR) throw std::runtime_error("File format error");
68 if(r == LZMA_OPTIONS_ERROR) throw std::runtime_error("Options error");
69 if(r == LZMA_DATA_ERROR) throw std::runtime_error("Data error");
70 if(r == LZMA_BUF_ERROR) throw std::runtime_error("Buffer error");
71 if(r == LZMA_PROG_ERROR) throw std::runtime_error("Programming error");
72 throw std::runtime_error("Unknown error");
74 return false;
76 private:
77 lzma_stream strm;
80 struct foo {
81 foo() {
82 streamcompress::base::do_register("lzma", [](const std::string& v) -> streamcompress::base* {
83 lzma_options opts;
84 auto a = streamcompress::parse_attributes(v);
85 unsigned level = 7;
86 bool extreme = false;
87 if(a.count("level")) level = parse_value<unsigned>(a["level"]);
88 if(level > 9) level = 9;
89 if(a.count("extreme")) extreme = parse_value<bool>(a["level"]);
90 opts.xz = false;
91 lzma_lzma_preset(&opts.lzmaopts, level | (extreme ? LZMA_PRESET_EXTREME : 0));
92 return new lzma(opts);
93 });
94 streamcompress::base::do_register("xz", [](const std::string& v) -> streamcompress::base* {
95 lzma_options opts;
96 auto a = streamcompress::parse_attributes(v);
97 unsigned level = 7;
98 bool extreme = false;
99 lzma_options_lzma opt_lzma2;
100 if(a.count("level")) level = parse_value<unsigned>(a["level"]);
101 if(level > 9) level = 9;
102 if(a.count("extreme")) extreme = parse_value<bool>(a["level"]);
103 lzma_lzma_preset(&opt_lzma2, level | (extreme ? LZMA_PRESET_EXTREME : 0));
104 lzma_filter filterchain[] = {
105 { LZMA_FILTER_LZMA2, &opt_lzma2 },
106 { LZMA_VLI_UNKNOWN }
108 opts.fchain = filterchain;
109 opts.check = LZMA_CHECK_CRC64;
110 opts.xz = true;
111 return new lzma(opts);
114 ~foo() {
115 streamcompress::base::do_unregister("lzma");
116 streamcompress::base::do_unregister("xz");
118 } _foo;
120 class stdin_input
122 public:
123 typedef char char_type;
124 typedef boost::iostreams::source_tag category;
126 stdin_input()
130 void close()
134 std::streamsize read(char* s, std::streamsize x)
136 std::cin.read(s, x);
137 if(!std::cin.gcount() && !std::cin) return -1;
138 return std::cin.gcount();
141 ~stdin_input()
144 private:
145 stdin_input& operator=(const stdin_input& f);
150 #ifdef STREAMCOMPRESS_LZMA_TEST
151 int main()
153 std::vector<char> out;
154 streamcompress::base* X = streamcompress::base::create_compressor("xz", "level=7,extreme=true");
155 boost::iostreams::filtering_istream* s = new boost::iostreams::filtering_istream();
156 s->push(streamcompress::iostream(X));
157 s->push(stdin_input());
158 boost::iostreams::back_insert_device<std::vector<char>> rd(out);
159 boost::iostreams::copy(*s, rd);
160 delete s;
161 delete X;
163 std::cout.write(&out[0], out.size());
164 return 0;
166 #endif
167 #endif