1// 2// MessagePack for C++ deflate buffer implementation 3// 4// Copyright (C) 2010-2013 FURUHASHI Sadayuki and KONDO Takatoshi 5// 6// Distributed under the Boost Software License, Version 1.0. 7// (See accompanying file LICENSE_1_0.txt or copy at 8// http://www.boost.org/LICENSE_1_0.txt) 9// 10#ifndef MSGPACK_ZBUFFER_HPP 11#define MSGPACK_ZBUFFER_HPP 12 13#include "msgpack/versioning.hpp" 14 15#include <stdexcept> 16#include <zlib.h> 17 18#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE 19#define MSGPACK_ZBUFFER_RESERVE_SIZE 512 20#endif 21 22#ifndef MSGPACK_ZBUFFER_INIT_SIZE 23#define MSGPACK_ZBUFFER_INIT_SIZE 8192 24#endif 25 26namespace msgpack { 27 28/// @cond 29MSGPACK_API_VERSION_NAMESPACE(v1) { 30/// @endcond 31 32class zbuffer { 33public: 34 zbuffer(int level = Z_DEFAULT_COMPRESSION, 35 size_t init_size = MSGPACK_ZBUFFER_INIT_SIZE) 36 : m_data(nullptr), m_init_size(init_size) 37 { 38 m_stream.zalloc = Z_NULL; 39 m_stream.zfree = Z_NULL; 40 m_stream.opaque = Z_NULL; 41 m_stream.next_out = Z_NULL; 42 m_stream.avail_out = 0; 43 if(deflateInit(&m_stream, level) != Z_OK) { 44 throw std::bad_alloc(); 45 } 46 } 47 48 ~zbuffer() 49 { 50 deflateEnd(&m_stream); 51 ::free(m_data); 52 } 53 54public: 55 void write(const char* buf, size_t len) 56 { 57 m_stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(buf)); 58 m_stream.avail_in = len; 59 60 while(m_stream.avail_in > 0) { 61 if(m_stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) { 62 if(!expand()) { 63 throw std::bad_alloc(); 64 } 65 } 66 67 if(deflate(&m_stream, Z_NO_FLUSH) != Z_OK) { 68 throw std::bad_alloc(); 69 } 70 } 71 } 72 73 char* flush() 74 { 75 while(true) { 76 switch(deflate(&m_stream, Z_FINISH)) { 77 case Z_STREAM_END: 78 return m_data; 79 case Z_OK: 80 if(!expand()) { 81 throw std::bad_alloc(); 82 } 83 break; 84 default: 85 throw std::bad_alloc(); 86 } 87 } 88 } 89 90 char* data() 91 { 92 return m_data; 93 } 94 95 const char* data() const 96 { 97 return m_data; 98 } 99 100 size_t size() const 101 { 102 return reinterpret_cast<char*>(m_stream.next_out) - m_data; 103 } 104 105 void reset() 106 { 107 if(deflateReset(&m_stream) != Z_OK) { 108 throw std::bad_alloc(); 109 } 110 reset_buffer(); 111 } 112 113 void reset_buffer() 114 { 115 m_stream.avail_out += reinterpret_cast<char*>(m_stream.next_out) - m_data; 116 m_stream.next_out = reinterpret_cast<Bytef*>(m_data); 117 } 118 119 char* release_buffer() 120 { 121 char* tmp = m_data; 122 m_data = nullptr; 123 m_stream.next_out = nullptr; 124 m_stream.avail_out = 0; 125 return tmp; 126 } 127 128private: 129 bool expand() 130 { 131 size_t used = reinterpret_cast<char*>(m_stream.next_out) - m_data; 132 size_t csize = used + m_stream.avail_out; 133 size_t nsize = (csize == 0) ? m_init_size : csize * 2; 134 135 char* tmp = static_cast<char*>(::realloc(m_data, nsize)); 136 if(tmp == nullptr) { 137 return false; 138 } 139 140 m_data = tmp; 141 m_stream.next_out = reinterpret_cast<Bytef*>(tmp + used); 142 m_stream.avail_out = nsize - used; 143 144 return true; 145 } 146#if defined(MSGPACK_USE_CPP03) 147private: 148 zbuffer(const zbuffer&); 149 zbuffer& operator=(const zbuffer&); 150#else // defined(MSGPACK_USE_CPP03) 151 zbuffer(const zbuffer&) = delete; 152 zbuffer& operator=(const zbuffer&) = delete; 153#endif // defined(MSGPACK_USE_CPP03) 154 155private: 156 z_stream m_stream; 157 char* m_data; 158 size_t m_init_size; 159}; 160 161/// @cond 162} // MSGPACK_API_VERSION_NAMESPACE(v1) 163/// @endcond 164 165} // namespace msgpack 166 167#endif /* msgpack/zbuffer.hpp */ 168