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*)¤t_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*)¤t_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