Last active
June 26, 2017 05:14
-
-
Save redboltz/c782774e4a2eea3a348e0828e22f9d38 to your computer and use it in GitHub Desktop.
Use zlib directly instead of boost::iostreams::filtering_istream on uncompress.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sstream> | |
#include <string> | |
#include <iostream> | |
#include <iomanip> | |
#include <algorithm> | |
#include <boost/iostreams/filtering_stream.hpp> | |
#include <boost/iostreams/filtering_streambuf.hpp> | |
#include <boost/iostreams/copy.hpp> | |
#include <boost/iostreams/filter/zlib.hpp> | |
#include <boost/asio.hpp> | |
#include <zlib.h> | |
void hexdump(std::string const& buf) { | |
for (std::string::const_iterator it = buf.begin(), end = buf.end(); | |
it != end; | |
++it) { | |
std::cout | |
<< std::setw(2) | |
<< std::hex | |
<< std::setfill('0') | |
<< (static_cast<int>(*it) & 0xff) | |
<< ' '; | |
} | |
std::cout << std::dec << std::endl; | |
} | |
std::string prepare_compressed_data(std::string const& str) { | |
std::stringstream sender; | |
boost::iostreams::filtering_streambuf<boost::iostreams::input> out; | |
out.push(boost::iostreams::zlib_compressor()); | |
out.push(sender); | |
sender << str; | |
std::stringstream compressed; | |
boost::iostreams::copy(out, compressed); | |
return compressed.str(); | |
} | |
#define CHUNK 16384 | |
int main() { | |
auto str = prepare_compressed_data("Hello world"); | |
std::cout << "compressed data: "; | |
hexdump(str); | |
// Test settings | |
#if 0 | |
// send all at conce | |
std::size_t const send_size = str.size(); | |
#else | |
// send 5 byte chunks | |
std::size_t const send_size = 5; | |
#endif | |
std::size_t const buf_size = 256; | |
// Prepare decompressing istream | |
boost::asio::streambuf sbuf; | |
unsigned have; | |
z_stream strm; | |
int ret; | |
/* allocate inflate state */ | |
strm.zalloc = Z_NULL; | |
strm.zfree = Z_NULL; | |
strm.opaque = Z_NULL; | |
strm.avail_in = 0; | |
strm.next_in = Z_NULL; | |
ret = inflateInit(&strm); | |
if (ret != Z_OK) { | |
std::cout << "inflateInit() error = " << ret << std::endl; | |
return -1; | |
} | |
// Network (asio socket send-receive) emulation | |
auto str_it = str.begin(); | |
auto rest = str.size(); | |
while (rest != 0) { | |
auto copy_size = std::min(rest, send_size); | |
// Emulate receive | |
// In actual code, it is `socket.read_some(mbuf)` | |
// and its return value is `copy_size`. | |
auto mbuf = sbuf.prepare(copy_size); | |
char* p = boost::asio::buffer_cast<char*>(mbuf); | |
std::copy(str_it, str_it + copy_size, p); | |
sbuf.commit(copy_size); | |
hexdump(std::string(boost::asio::buffer_cast<char const*>(sbuf.data()), sbuf.size())); | |
std::cout << "sbuf.size():" << sbuf.size() << std::endl; | |
{ // decompress | |
std::cout << "<<< try decompress >>>" << std::endl; | |
/* decompress until deflate stream ends or end of file */ | |
strm.avail_in = sbuf.size(); | |
if (strm.avail_in == 0) break; | |
strm.next_in = | |
reinterpret_cast<unsigned char *>( | |
const_cast<char *>( | |
boost::asio::buffer_cast<char const*>(sbuf.data()) | |
) | |
); | |
/* run inflate() on input until output buffer not full */ | |
do { | |
char buf[buf_size] = {}; | |
strm.avail_out = buf_size; | |
strm.next_out = reinterpret_cast<unsigned char*>(buf); | |
ret = inflate(&strm, Z_NO_FLUSH); | |
assert(ret != Z_STREAM_ERROR); /* state not clobbered */ | |
sbuf.consume(copy_size); | |
switch (ret) { | |
case Z_NEED_DICT: | |
ret = Z_DATA_ERROR; | |
// fall through | |
case Z_DATA_ERROR: | |
case Z_MEM_ERROR: | |
(void)inflateEnd(&strm); | |
std::cout << "error = " << ret << std::endl; | |
return ret; | |
} | |
int decompressed_size = buf_size - strm.avail_out; | |
std::cout << " decompressedsize:" << decompressed_size << std::endl; | |
std::cout << " decompressed data: " << buf << std::endl; | |
} while (strm.avail_out == 0); | |
/* done when inflate() says it's done */ | |
if (ret == Z_STREAM_END) { | |
/* clean up and return */ | |
(void)inflateEnd(&strm); | |
std::cout << "Z_STREAM_END" << std::endl; | |
} | |
std::cout << "<<< decompress loop out >>>" << std::endl; | |
} | |
rest -= copy_size; | |
str_it += copy_size; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
compressed data: 78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d | |
78 9c f3 48 cd | |
sbuf.size():5 | |
<<< try decompress >>> | |
decompressedsize:2 | |
decompressed data: He | |
<<< decompress loop out >>> | |
c9 c9 57 28 cf | |
sbuf.size():5 | |
<<< try decompress >>> | |
decompressedsize:5 | |
decompressed data: llo w | |
<<< decompress loop out >>> | |
2f ca 49 01 00 | |
sbuf.size():5 | |
<<< try decompress >>> | |
decompressedsize:4 | |
decompressed data: orld | |
<<< decompress loop out >>> | |
18 ab 04 3d | |
sbuf.size():4 | |
<<< try decompress >>> | |
decompressedsize:0 | |
decompressed data: | |
Z_STREAM_END | |
<<< decompress loop out >>> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment