1 /*
2 serialization.cpp
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5 
6 /*
7 This file is part of Freeminer.
8 
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Freeminer  is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Freeminer.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "serialization.h"
24 
25 #include "util/serialize.h"
26 #ifdef _WIN32
27 	#define ZLIB_WINAPI
28 #endif
29 #include "zlib.h"
30 
31 /* report a zlib or i/o error */
zerr(int ret)32 void zerr(int ret)
33 {
34     dstream<<"zerr: ";
35     switch (ret) {
36     case Z_ERRNO:
37         if (ferror(stdin))
38             dstream<<"error reading stdin"<<std::endl;
39         if (ferror(stdout))
40             dstream<<"error writing stdout"<<std::endl;
41         break;
42     case Z_STREAM_ERROR:
43         dstream<<"invalid compression level"<<std::endl;
44         break;
45     case Z_DATA_ERROR:
46         dstream<<"invalid or incomplete deflate data"<<std::endl;
47         break;
48     case Z_MEM_ERROR:
49         dstream<<"out of memory"<<std::endl;
50         break;
51     case Z_VERSION_ERROR:
52         dstream<<"zlib version mismatch!"<<std::endl;
53 		break;
54 	default:
55 		dstream<<"return value = "<<ret<<std::endl;
56     }
57 }
58 
compressZlib(SharedBuffer<u8> data,std::ostream & os,int level)59 void compressZlib(SharedBuffer<u8> data, std::ostream &os, int level)
60 {
61 	z_stream z;
62 	const s32 bufsize = 16384;
63 	char output_buffer[bufsize];
64 	int status = 0;
65 	int ret;
66 
67 	z.zalloc = Z_NULL;
68 	z.zfree = Z_NULL;
69 	z.opaque = Z_NULL;
70 
71 	ret = deflateInit(&z, level);
72 	if(ret != Z_OK)
73 		throw SerializationError("compressZlib: deflateInit failed");
74 
75 	// Point zlib to our input buffer
76 	z.next_in = (Bytef*)&data[0];
77 	z.avail_in = data.getSize();
78 	// And get all output
79 	for(;;)
80 	{
81 		z.next_out = (Bytef*)output_buffer;
82 		z.avail_out = bufsize;
83 
84 		status = deflate(&z, Z_FINISH);
85 		if(status == Z_NEED_DICT || status == Z_DATA_ERROR
86 				|| status == Z_MEM_ERROR)
87 		{
88 			zerr(status);
89 			throw SerializationError("compressZlib: deflate failed");
90 		}
91 		int count = bufsize - z.avail_out;
92 		if(count)
93 			os.write(output_buffer, count);
94 		// This determines zlib has given all output
95 		if(status == Z_STREAM_END)
96 			break;
97 	}
98 
99 	deflateEnd(&z);
100 }
101 
compressZlib(const std::string & data,std::ostream & os,int level)102 void compressZlib(const std::string &data, std::ostream &os, int level)
103 {
104 	SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
105 	compressZlib(databuf, os, level);
106 }
107 
decompressZlib(std::istream & is,std::ostream & os)108 void decompressZlib(std::istream &is, std::ostream &os)
109 {
110 	z_stream z;
111 	const s32 bufsize = 16384;
112 	char input_buffer[bufsize];
113 	char output_buffer[bufsize];
114 	int status = 0;
115 	int ret;
116 	int bytes_read = 0;
117 	int input_buffer_len = 0;
118 
119 	z.zalloc = Z_NULL;
120 	z.zfree = Z_NULL;
121 	z.opaque = Z_NULL;
122 
123 	ret = inflateInit(&z);
124 	if(ret != Z_OK)
125 		throw SerializationError("dcompressZlib: inflateInit failed");
126 
127 	z.avail_in = 0;
128 
129 	//dstream<<"initial fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
130 
131 	for(;;)
132 	{
133 		z.next_out = (Bytef*)output_buffer;
134 		z.avail_out = bufsize;
135 
136 		if(z.avail_in == 0)
137 		{
138 			z.next_in = (Bytef*)input_buffer;
139 			input_buffer_len = is.readsome(input_buffer, bufsize);
140 			z.avail_in = input_buffer_len;
141 			//dstream<<"read fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
142 		}
143 		if(z.avail_in == 0)
144 		{
145 			//dstream<<"z.avail_in == 0"<<std::endl;
146 			break;
147 		}
148 
149 		//dstream<<"1 z.avail_in="<<z.avail_in<<std::endl;
150 		status = inflate(&z, Z_NO_FLUSH);
151 		//dstream<<"2 z.avail_in="<<z.avail_in<<std::endl;
152 		bytes_read += is.gcount() - z.avail_in;
153 		//dstream<<"bytes_read="<<bytes_read<<std::endl;
154 
155 		if(status == Z_NEED_DICT || status == Z_DATA_ERROR
156 				|| status == Z_MEM_ERROR)
157 		{
158 			zerr(status);
159 			throw SerializationError("decompressZlib: inflate failed");
160 		}
161 		int count = bufsize - z.avail_out;
162 		//dstream<<"count="<<count<<std::endl;
163 		if(count)
164 			os.write(output_buffer, count);
165 		if(status == Z_STREAM_END)
166 		{
167 			//dstream<<"Z_STREAM_END"<<std::endl;
168 
169 			//dstream<<"z.avail_in="<<z.avail_in<<std::endl;
170 			//dstream<<"fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
171 			// Unget all the data that inflate didn't take
172 			for(u32 i=0; i < z.avail_in; i++)
173 			{
174 				is.unget();
175 				if(is.fail() || is.bad())
176 				{
177 					dstream<<"unget #"<<i<<" failed"<<std::endl;
178 					dstream<<"fail="<<is.fail()<<" bad="<<is.bad()<<std::endl;
179 					throw SerializationError("decompressZlib: unget failed");
180 				}
181 			}
182 
183 			break;
184 		}
185 	}
186 
187 	inflateEnd(&z);
188 }
189 
compress(SharedBuffer<u8> data,std::ostream & os,u8 version)190 void compress(SharedBuffer<u8> data, std::ostream &os, u8 version)
191 {
192 	if(version >= 11)
193 	{
194 		compressZlib(data, os);
195 		return;
196 	}
197 
198 	if(data.getSize() == 0)
199 		return;
200 
201 	// Write length (u32)
202 
203 	u8 tmp[4];
204 	writeU32(tmp, data.getSize());
205 	os.write((char*)tmp, 4);
206 
207 	// We will be writing 8-bit pairs of more_count and byte
208 	u8 more_count = 0;
209 	u8 current_byte = data[0];
210 	for(u32 i=1; i<data.getSize(); i++)
211 	{
212 		if(
213 			data[i] != current_byte
214 			|| more_count == 255
215 		)
216 		{
217 			// write count and byte
218 			os.write((char*)&more_count, 1);
219 			os.write((char*)&current_byte, 1);
220 			more_count = 0;
221 			current_byte = data[i];
222 		}
223 		else
224 		{
225 			more_count++;
226 		}
227 	}
228 	// write count and byte
229 	os.write((char*)&more_count, 1);
230 	os.write((char*)&current_byte, 1);
231 }
232 
decompress(std::istream & is,std::ostream & os,u8 version)233 void decompress(std::istream &is, std::ostream &os, u8 version)
234 {
235 	if(version >= 11)
236 	{
237 		decompressZlib(is, os);
238 		return;
239 	}
240 
241 	// Read length (u32)
242 
243 	u8 tmp[4];
244 	is.read((char*)tmp, 4);
245 	u32 len = readU32(tmp);
246 
247 	// We will be reading 8-bit pairs of more_count and byte
248 	u32 count = 0;
249 	for(;;)
250 	{
251 		u8 more_count=0;
252 		u8 byte=0;
253 
254 		is.read((char*)&more_count, 1);
255 
256 		is.read((char*)&byte, 1);
257 
258 		if(is.eof())
259 			throw SerializationError("decompress: stream ended halfway");
260 
261 		for(s32 i=0; i<(u16)more_count+1; i++)
262 			os.write((char*)&byte, 1);
263 
264 		count += (u16)more_count+1;
265 
266 		if(count == len)
267 			break;
268 	}
269 }
270 
271 
272