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