Also support dumping JMD and SDMP over TCP/IP
[lsnes.git] / src / library / zlibstream.cpp
blobe7509ef9d1f9d67f2cbfdb0b280690a5cea1c9f5
1 #include "library/zlibstream.hpp"
2 #include "library/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 std::list<struct page> tmp;
42 size_t odatalen = datalen;
43 while(datalen > 0) {
44 tmp.push_back(page());
45 size_t copylen = min(datalen, static_cast<size_t>(ZLIB_PAGE_STORAGE));
46 memcpy(&tmp.back().data[0], data, copylen);
47 tmp.back().used = copylen;
48 data += copylen;
49 datalen -= copylen;
51 deflateReset(&z);
52 streamsize = odatalen;
53 flag = false;
54 tmp.swap(storage);
57 void zlibstream::write(uint8_t* data, size_t datalen)
59 flushpage(data, datalen, false);
62 void zlibstream::read(std::vector<char>& out)
64 flushpage(NULL, 0, true);
65 out.resize(streamsize);
66 size_t itr = 0;
67 for(auto& i : storage) {
68 memcpy(&out[itr], i.data, i.used);
69 itr += i.used;
73 extern void* orig_return_address;
74 extern void* orig_return_address2;
76 void zlibstream::flushpage(uint8_t* data, size_t datalen, bool final)
78 z.next_in = data;
79 z.avail_in = datalen;
80 while(z.avail_in || final) {
81 if(storage.empty() || storage.back().used == ZLIB_PAGE_STORAGE) {
82 storage.push_back(page());
83 storage.back().used = 0;
85 z.next_out = storage.back().data + storage.back().used;
86 z.avail_out = ZLIB_PAGE_STORAGE - storage.back().used;
87 size_t itmp = z.avail_out;
88 int x = deflate(&z, final ? Z_FINISH : 0);
89 storage.back().used += (itmp - z.avail_out);
90 streamsize += (itmp - z.avail_out);
91 throw_zlib_error(x);
92 if(final && x == Z_STREAM_END)
93 break;
97 void zlibstream::set_flag(bool f)
99 flag = f;
102 bool zlibstream::get_flag()
104 return flag;