Skip to content

Instantly share code, notes, and snippets.

@redboltz
Last active June 26, 2017 05:14
Show Gist options
  • Save redboltz/c782774e4a2eea3a348e0828e22f9d38 to your computer and use it in GitHub Desktop.
Save redboltz/c782774e4a2eea3a348e0828e22f9d38 to your computer and use it in GitHub Desktop.
Use zlib directly instead of boost::iostreams::filtering_istream on uncompress.
#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;
}
}
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