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