Hideaki Tai / msgpack-embedded

Dependents:   hello_message_pack

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers zbuffer.hpp Source File

zbuffer.hpp

00001 //
00002 // MessagePack for C++ deflate buffer implementation
00003 //
00004 // Copyright (C) 2010-2013 FURUHASHI Sadayuki and KONDO Takatoshi
00005 //
00006 //    Distributed under the Boost Software License, Version 1.0.
00007 //    (See accompanying file LICENSE_1_0.txt or copy at
00008 //    http://www.boost.org/LICENSE_1_0.txt)
00009 //
00010 #ifndef MSGPACK_ZBUFFER_HPP
00011 #define MSGPACK_ZBUFFER_HPP
00012 
00013 #include "msgpack/versioning.hpp"
00014 
00015 #include <stdexcept>
00016 #include <zlib.h>
00017 
00018 #ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
00019     #if defined (__MBED__)
00020         #define MSGPACK_ZBUFFER_RESERVE_SIZE 256
00021     #elif defined (__AVR__)
00022         #define MSGPACK_ZBUFFER_RESERVE_SIZE 64
00023     #else
00024         #define MSGPACK_ZBUFFER_RESERVE_SIZE 512
00025     #endif
00026 #endif
00027 
00028 #ifndef MSGPACK_ZBUFFER_INIT_SIZE
00029     #if defined (__MBED__)
00030         #define MSGPACK_ZBUFFER_INIT_SIZE 512
00031     #elif defined (__AVR__)
00032         #define MSGPACK_ZBUFFER_INIT_SIZE 128
00033     #else
00034         #define MSGPACK_ZBUFFER_INIT_SIZE 8192
00035     #endif
00036 #endif
00037 
00038 namespace msgpack {
00039 
00040 /// @cond
00041 MSGPACK_API_VERSION_NAMESPACE(v1) {
00042 /// @endcond
00043 
00044 class zbuffer {
00045 public:
00046     zbuffer(int level = Z_DEFAULT_COMPRESSION,
00047             size_t init_size = MSGPACK_ZBUFFER_INIT_SIZE)
00048         : m_data(nullptr), m_init_size(init_size)
00049     {
00050         m_stream.zalloc = Z_NULL;
00051         m_stream.zfree = Z_NULL;
00052         m_stream.opaque = Z_NULL;
00053         m_stream.next_out = Z_NULL;
00054         m_stream.avail_out = 0;
00055         if(deflateInit(&m_stream, level) != Z_OK) {
00056             throw std::bad_alloc();
00057         }
00058     }
00059 
00060     ~zbuffer()
00061     {
00062         deflateEnd(&m_stream);
00063         ::free(m_data);
00064     }
00065 
00066 public:
00067     void write(const char* buf, size_t len)
00068     {
00069         m_stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(buf));
00070         m_stream.avail_in = len;
00071 
00072         while(m_stream.avail_in > 0) {
00073             if(m_stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
00074                 if(!expand()) {
00075                     throw std::bad_alloc();
00076                 }
00077             }
00078 
00079             if(deflate(&m_stream, Z_NO_FLUSH) != Z_OK) {
00080                 throw std::bad_alloc();
00081             }
00082         }
00083     }
00084 
00085     char* flush()
00086     {
00087         while(true) {
00088             switch(deflate(&m_stream, Z_FINISH)) {
00089             case Z_STREAM_END:
00090                 return m_data;
00091             case Z_OK:
00092                 if(!expand()) {
00093                     throw std::bad_alloc();
00094                 }
00095                 break;
00096             default:
00097                 throw std::bad_alloc();
00098             }
00099         }
00100     }
00101 
00102     char* data()
00103     {
00104         return m_data;
00105     }
00106 
00107     const char* data() const
00108     {
00109         return m_data;
00110     }
00111 
00112     size_t size() const
00113     {
00114         return reinterpret_cast<char*>(m_stream.next_out) - m_data;
00115     }
00116 
00117     void reset()
00118     {
00119         if(deflateReset(&m_stream) != Z_OK) {
00120             throw std::bad_alloc();
00121         }
00122         reset_buffer();
00123     }
00124 
00125     void reset_buffer()
00126     {
00127         m_stream.avail_out += reinterpret_cast<char*>(m_stream.next_out) - m_data;
00128         m_stream.next_out = reinterpret_cast<Bytef*>(m_data);
00129     }
00130 
00131     char* release_buffer()
00132     {
00133         char* tmp = m_data;
00134         m_data = nullptr;
00135         m_stream.next_out = nullptr;
00136         m_stream.avail_out = 0;
00137         return tmp;
00138     }
00139 
00140 private:
00141     bool expand()
00142     {
00143         size_t used = reinterpret_cast<char*>(m_stream.next_out) - m_data;
00144         size_t csize = used + m_stream.avail_out;
00145         size_t nsize = (csize == 0) ? m_init_size : csize * 2;
00146 
00147         char* tmp = static_cast<char*>(::realloc(m_data, nsize));
00148         if(tmp == nullptr) {
00149             return false;
00150         }
00151 
00152         m_data = tmp;
00153         m_stream.next_out  = reinterpret_cast<Bytef*>(tmp + used);
00154         m_stream.avail_out = nsize - used;
00155 
00156         return true;
00157     }
00158 #if defined(MSGPACK_USE_CPP03)
00159 private:
00160     zbuffer(const zbuffer&);
00161     zbuffer& operator=(const zbuffer&);
00162 #else  // defined(MSGPACK_USE_CPP03)
00163     zbuffer(const zbuffer&) = delete;
00164     zbuffer& operator=(const zbuffer&) = delete;
00165 #endif // defined(MSGPACK_USE_CPP03)
00166 
00167 private:
00168     z_stream m_stream;
00169     char* m_data;
00170     size_t m_init_size;
00171 };
00172 
00173 /// @cond
00174 }  // MSGPACK_API_VERSION_NAMESPACE(v1)
00175 /// @endcond
00176 
00177 }  // namespace msgpack
00178 
00179 #endif /* msgpack/zbuffer.hpp */