lsnes rr2-β24
[lsnes.git] / src / library / zlibstream.cpp
blob36b51689ef7cebdaa15e7c4b62f8c76ca440a832
1 #include "zlibstream.hpp"
2 #include "minmax.hpp"
3 #include <stdexcept>
4 #include <cstring>
5 #include <cerrno>
7 namespace
9 void throw_zlib_error(int x)
11 switch(x) {
12 case Z_NEED_DICT: throw std::runtime_error("Dictionary needed");
13 case Z_ERRNO: throw std::runtime_error(std::string("OS error: ") + strerror(errno));
14 case Z_STREAM_ERROR: throw std::runtime_error("Stream error");
15 case Z_DATA_ERROR: throw std::runtime_error("Data error");
16 case Z_MEM_ERROR: throw std::bad_alloc();
17 case Z_BUF_ERROR: throw std::runtime_error("Buffer error");
18 case Z_VERSION_ERROR: throw std::runtime_error("Version error");
19 case Z_OK:
20 case Z_STREAM_END:
21 break;
22 default: throw std::runtime_error("Unknown error");
27 zlibstream::zlibstream(unsigned compression)
29 streamsize = 0;
30 memset(&z, 0, sizeof(z));
31 throw_zlib_error(deflateInit(&z, compression));
34 zlibstream::~zlibstream()
36 deflateEnd(&z);
39 void zlibstream::reset(uint8_t* data, size_t datalen)
41 _reset(data, datalen, true);
44 void zlibstream::_reset(uint8_t* data, size_t datalen, bool doactually)
46 std::list<struct page> tmp;
47 size_t odatalen = datalen;
48 while(datalen > 0) {
49 tmp.push_back(page());
50 size_t copylen = min(datalen, static_cast<size_t>(ZLIB_PAGE_STORAGE));
51 memcpy(&tmp.back().data[0], data, copylen);
52 tmp.back().used = copylen;
53 data += copylen;
54 datalen -= copylen;
56 if(doactually)
57 deflateReset(&z);
58 streamsize = odatalen;
59 flag = false;
60 tmp.swap(storage);
63 void zlibstream::write(uint8_t* data, size_t datalen)
65 flushpage(data, datalen, 0);
68 void zlibstream::read(std::vector<char>& out)
70 _read(out, Z_FINISH);
73 void zlibstream::_read(std::vector<char>& out, int mode)
75 flushpage(NULL, 0, mode);
76 out.resize(streamsize);
77 size_t itr = 0;
78 for(auto& i : storage) {
79 memcpy(&out[itr], i.data, i.used);
80 itr += i.used;
84 void zlibstream::flushpage(uint8_t* data, size_t datalen, int mode)
86 z.next_in = data;
87 z.avail_in = datalen;
88 while(z.avail_in || mode) {
89 if(storage.empty() || storage.back().used == ZLIB_PAGE_STORAGE) {
90 storage.push_back(page());
91 storage.back().used = 0;
93 z.next_out = storage.back().data + storage.back().used;
94 z.avail_out = ZLIB_PAGE_STORAGE - storage.back().used;
95 size_t itmp = z.avail_out;
96 int x = deflate(&z, mode);
97 storage.back().used += (itmp - z.avail_out);
98 streamsize += (itmp - z.avail_out);
99 throw_zlib_error(x);
100 if(mode && !z.avail_in && z.avail_out)
101 break;
105 void zlibstream::readsync(std::vector<char>& out)
107 _read(out, Z_SYNC_FLUSH);
110 void zlibstream::adddata(uint8_t* data, size_t datalen)
112 _reset(data, datalen, false);
115 void zlibstream::set_flag(bool f)
117 flag = f;
120 bool zlibstream::get_flag()
122 return flag;