1 /* === S Y N F I G ========================================================= */
2 /*!	\file zstreambuf.cpp
3 **	\brief zstreambuf
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	......... ... 2013 Ivan Mahonin
9 **
10 **	This package is free software; you can redistribute it and/or
11 **	modify it under the terms of the GNU General Public License as
12 **	published by the Free Software Foundation; either version 2 of
13 **	the License, or (at your option) any later version.
14 **
15 **	This package is distributed in the hope that it will be useful,
16 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **	General Public License for more details.
19 **	\endlegal
20 */
21 /* ========================================================================= */
22 
23 /* === H E A D E R S ======================================================= */
24 
25 #ifdef USING_PCH
26 #	include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #	include <config.h>
30 #endif
31 
32 #include <cstring>
33 #include "zstreambuf.h"
34 
35 #endif
36 
37 /* === U S I N G =========================================================== */
38 
39 using namespace std;
40 using namespace etl;
41 using namespace synfig;
42 
43 /* === M A C R O S ========================================================= */
44 
45 /* === G L O B A L S ======================================================= */
46 
47 /* === P R O C E D U R E S ================================================= */
48 
49 /* === M E T H O D S ======================================================= */
50 
zstreambuf(std::streambuf * buf)51 zstreambuf::zstreambuf(std::streambuf *buf):
52 	buf_(buf),
53 	inflate_initialized(false),
54 	deflate_initialized(false)
55 {
56 }
57 
~zstreambuf()58 zstreambuf::~zstreambuf()
59 {
60 	sync();
61 	if (inflate_initialized) inflateEnd(&inflate_stream_);
62 	if (deflate_initialized) deflateEnd(&deflate_stream_);
63 }
64 
pack(std::vector<char> & dest,const void * src,size_t size,bool fast)65 bool zstreambuf::pack(std::vector<char> &dest, const void *src, size_t size, bool fast) {
66 	z_stream stream;
67 	memset(&stream, 0, sizeof(stream));
68 	if (Z_OK != deflateInit2(&stream,
69 			fast ? fast_option_compression_level : option_compression_level,
70 			option_method,
71 			option_window_bits,
72 			fast ? fast_option_mem_level : option_mem_level,
73 			fast ? fast_option_strategy : option_strategy
74 	)) return false;
75 
76 	stream.avail_in = size;
77 	stream.next_in = (z_const Bytef*)src;
78 	bool result = true;
79 	do
80 	{
81 		if (stream.avail_out < option_bufsize) {
82 			size_t s = option_bufsize - stream.avail_out;
83 			dest.resize(dest.size() + s);
84 			stream.avail_out = option_bufsize;
85 			stream.next_out = (Bytef*)&dest[dest.size() - stream.avail_out];
86 		}
87 		if (Z_STREAM_ERROR == ::deflate(&stream, Z_FINISH))
88 			{ result = false; break; }
89 	} while (stream.avail_out == 0);
90 	if (stream.avail_in != 0) result = false;
91 	deflateEnd(&stream);
92 	return result;
93 }
94 
pack(void * dest,size_t dest_size,const void * src,size_t src_size,bool fast)95 size_t zstreambuf::pack(void *dest, size_t dest_size, const void *src, size_t src_size, bool fast) {
96 	z_stream stream;
97 	memset(&stream, 0, sizeof(stream));
98 	if (Z_OK != deflateInit2(&stream,
99 			fast ? fast_option_compression_level : option_compression_level,
100 			option_method,
101 			option_window_bits,
102 			fast ? fast_option_mem_level : option_mem_level,
103 			fast ? fast_option_strategy : option_strategy
104 	)) return 0;
105 
106 	stream.avail_in = src_size;
107 	stream.next_in = (z_const Bytef*)src;
108 	stream.avail_out = dest_size;
109 	stream.next_out = (Bytef*)dest;
110 	size_t size = 0;
111 	if (Z_STREAM_ERROR != ::deflate(&stream, Z_FINISH))
112 		size = dest_size - stream.avail_out;
113 	deflateEnd(&stream);
114 	return size;
115 }
116 
unpack(std::vector<char> & dest,const void * src,size_t size)117 bool zstreambuf::unpack(std::vector<char> &dest, const void *src, size_t size) {
118 	z_stream stream;
119 	memset(&stream, 0, sizeof(stream));
120 	if (Z_OK != inflateInit2(&stream, option_window_bits )) return false;
121 
122 	stream.avail_in = size;
123 	stream.next_in = (z_const Bytef*)src;
124 	bool result = true;
125 	do
126 	{
127 		if (stream.avail_out < option_bufsize) {
128 			size_t s = option_bufsize - stream.avail_out;
129 			dest.resize(dest.size() + s);
130 			stream.avail_out = option_bufsize;
131 			stream.next_out = (Bytef*)&dest[dest.size() - stream.avail_out];
132 		}
133 		if (Z_STREAM_ERROR == ::inflate(&stream, Z_NO_FLUSH))
134 			{ result = false; break; }
135 	} while (stream.avail_out == 0);
136 	if (stream.avail_in != 0) result = false;
137 	inflateEnd(&stream);
138 	return result;
139 }
140 
unpack(void * dest,size_t dest_size,const void * src,size_t src_size)141 size_t zstreambuf::unpack(void *dest, size_t dest_size, const void *src, size_t src_size) {
142 	z_stream stream;
143 	memset(&stream, 0, sizeof(stream));
144 	if (Z_OK != inflateInit2(&stream, option_window_bits )) return 0;
145 
146 	stream.avail_in = src_size;
147 	stream.next_in = (z_const Bytef*)src;
148 	stream.avail_out = dest_size;
149 	stream.next_out = (Bytef*)dest;
150 	size_t size = 0;
151 	if (Z_STREAM_ERROR != ::inflate(&stream, Z_FINISH))
152 		size = dest_size - stream.avail_out;
153 	inflateEnd(&stream);
154 	return size;
155 }
156 
inflate_buf()157 bool zstreambuf::inflate_buf()
158 {
159     // initialize inflate if need
160     if (!inflate_initialized)
161     {
162     	memset(&inflate_stream_, 0, sizeof(inflate_stream_));
163     	if (Z_OK != inflateInit2(&inflate_stream_, option_window_bits)) return false;
164     	inflate_initialized = true;
165     }
166 
167     // read and inflate new chunk of data
168     char in_buf[option_bufsize];
169     inflate_stream_.avail_in = buf_->sgetn(in_buf, sizeof(in_buf));
170     inflate_stream_.next_in = (Bytef*)in_buf;
171 	read_buffer_.resize(0);
172 	do
173 	{
174 		inflate_stream_.avail_out = option_bufsize;
175 		read_buffer_.resize(read_buffer_.size() + inflate_stream_.avail_out);
176 		inflate_stream_.next_out = (Bytef*)(&read_buffer_.back() + 1 - inflate_stream_.avail_out);
177 		int ret = ::inflate(&inflate_stream_, Z_NO_FLUSH);
178 		read_buffer_.resize(read_buffer_.size() - inflate_stream_.avail_out);
179 		if (ret != Z_OK) break;
180 	} while (inflate_stream_.avail_out == 0);
181 	assert(inflate_stream_.avail_in == 0);
182 
183 	// nothing to read
184 	if (read_buffer_.empty()) return false;
185 
186 	// set new read buffer
187 	char *pointer = &read_buffer_.front();
188     setg(pointer, pointer, pointer + read_buffer_.size());
189     return true;
190 }
191 
deflate_buf(bool flush)192 bool zstreambuf::deflate_buf(bool flush)
193 {
194 	if (pbase() != NULL && pptr() > pbase())
195 	{
196 		// initialize deflate if need
197 		if (!deflate_initialized)
198 		{
199 			memset(&deflate_stream_, 0, sizeof(deflate_stream_));
200 
201 			if (Z_OK != deflateInit2(&deflate_stream_,
202 					option_compression_level,
203 					option_method,
204 					option_window_bits,
205 					option_mem_level,
206 					option_strategy
207 			)) return false;
208 
209 			deflate_initialized = true;
210 		}
211 
212 		// deflate and write new chunk of data
213 		char out_buf[option_bufsize];
214 		deflate_stream_.avail_in = (uInt)(pptr() - pbase());
215 		deflate_stream_.next_in = (Bytef*)pbase();
216 		do
217 		{
218 			deflate_stream_.avail_out = sizeof(out_buf);
219 			deflate_stream_.next_out = (Bytef*)out_buf;
220 			if (Z_STREAM_ERROR == deflate(&deflate_stream_, flush ? Z_FINISH : Z_NO_FLUSH))
221 				return false;
222 			if (deflate_stream_.avail_out < sizeof(out_buf))
223 				buf_->sputn(out_buf, sizeof(out_buf) - deflate_stream_.avail_out);
224 		} while (deflate_stream_.avail_out == 0);
225 		assert(deflate_stream_.avail_in == 0);
226 		setp(NULL, NULL);
227 	}
228 	return true;
229 }
230 
sync()231 int zstreambuf::sync()
232 {
233 	bool deflate_success = deflate_buf(true);
234 	bool buf_sync_success = 0 == buf_->pubsync();
235 	return deflate_success && buf_sync_success ? 0 : -1;
236 }
237 
underflow()238 int zstreambuf::underflow()
239 {
240 	// is it actually underflow?
241     if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
242     if (!inflate_buf()) return EOF;
243 	return *(unsigned char *)gptr();
244 }
245 
overflow(int c)246 int zstreambuf::overflow(int c)
247 {
248 	// flush
249 	if (c == EOF) { sync(); return EOF; }
250 
251 	// save data and prepare new buffer
252 	if (pptr() >= epptr())
253 	{
254 		if (!deflate_buf(false)) return EOF;
255 		if (write_buffer_.size() < option_bufsize) write_buffer_.resize(option_bufsize);
256 		char *pointer = &write_buffer_.front();
257 		setp(pointer, pointer + write_buffer_.size());
258 	}
259 
260 	// put character
261 	*pptr() = traits_type::to_char_type(c);
262 	pbump(1);
263 	return c;
264 }
265 
266 /* === E N T R Y P O I N T ================================================= */
267 
268