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