Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-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 "serialize.h"
21 : #include "pointer.h"
22 : #include "porting.h"
23 : #include "util/string.h"
24 : #include "../exceptions.h"
25 : #include "../irrlichttypes.h"
26 :
27 : #include <sstream>
28 : #include <iomanip>
29 : #include <vector>
30 :
31 : // Creates a string with the length as the first two bytes
32 67 : std::string serializeString(const std::string &plain)
33 : {
34 67 : if(plain.size() > 65535)
35 0 : throw SerializationError("String too long for serializeString");
36 : char buf[2];
37 67 : writeU16((u8*)&buf[0], plain.size());
38 67 : std::string s;
39 67 : s.append(buf, 2);
40 67 : s.append(plain);
41 67 : return s;
42 : }
43 :
44 : // Creates a string with the length as the first two bytes from wide string
45 0 : std::string serializeWideString(const std::wstring &plain)
46 : {
47 0 : if(plain.size() > 65535)
48 0 : throw SerializationError("String too long for serializeString");
49 : char buf[2];
50 0 : writeU16((u8*)buf, plain.size());
51 0 : std::string s;
52 0 : s.append(buf, 2);
53 0 : for(u32 i=0; i<plain.size(); i++)
54 : {
55 0 : writeU16((u8*)buf, plain[i]);
56 0 : s.append(buf, 2);
57 : }
58 0 : return s;
59 : }
60 :
61 : // Reads a string with the length as the first two bytes
62 196362 : std::string deSerializeString(std::istream &is)
63 : {
64 : char buf[2];
65 196362 : is.read(buf, 2);
66 196362 : if(is.gcount() != 2)
67 0 : throw SerializationError("deSerializeString: size not read");
68 196362 : u16 s_size = readU16((u8*)buf);
69 196362 : std::string s;
70 196362 : if(s_size == 0)
71 70873 : return s;
72 250978 : Buffer<char> buf2(s_size);
73 125489 : is.read(&buf2[0], s_size);
74 125489 : s.reserve(s_size);
75 125489 : s.append(&buf2[0], s_size);
76 125489 : return s;
77 : }
78 :
79 : // Reads a wide string with the length as the first two bytes
80 0 : std::wstring deSerializeWideString(std::istream &is)
81 : {
82 : char buf[2];
83 0 : is.read(buf, 2);
84 0 : if(is.gcount() != 2)
85 0 : throw SerializationError("deSerializeString: size not read");
86 0 : u16 s_size = readU16((u8*)buf);
87 0 : std::wstring s;
88 0 : if(s_size == 0)
89 0 : return s;
90 0 : s.reserve(s_size);
91 0 : for(u32 i=0; i<s_size; i++)
92 : {
93 0 : is.read(&buf[0], 2);
94 0 : wchar_t c16 = readU16((u8*)buf);
95 0 : s.append(&c16, 1);
96 : }
97 0 : return s;
98 : }
99 :
100 : // Creates a string with the length as the first four bytes
101 67 : std::string serializeLongString(const std::string &plain)
102 : {
103 : char buf[4];
104 67 : writeU32((u8*)&buf[0], plain.size());
105 67 : std::string s;
106 67 : s.append(buf, 4);
107 67 : s.append(plain);
108 67 : return s;
109 : }
110 :
111 : // Reads a string with the length as the first four bytes
112 4851 : std::string deSerializeLongString(std::istream &is)
113 : {
114 : char buf[4];
115 4851 : is.read(buf, 4);
116 4851 : if(is.gcount() != 4)
117 0 : throw SerializationError("deSerializeLongString: size not read");
118 4851 : u32 s_size = readU32((u8*)buf);
119 4851 : std::string s;
120 4851 : if(s_size == 0)
121 15 : return s;
122 9672 : Buffer<char> buf2(s_size);
123 4836 : is.read(&buf2[0], s_size);
124 4836 : s.reserve(s_size);
125 4836 : s.append(&buf2[0], s_size);
126 4836 : return s;
127 : }
128 :
129 : // Creates a string encoded in JSON format (almost equivalent to a C string literal)
130 0 : std::string serializeJsonString(const std::string &plain)
131 : {
132 0 : std::ostringstream os(std::ios::binary);
133 0 : os<<"\"";
134 0 : for(size_t i = 0; i < plain.size(); i++)
135 : {
136 0 : char c = plain[i];
137 0 : switch(c)
138 : {
139 0 : case '"': os<<"\\\""; break;
140 0 : case '\\': os<<"\\\\"; break;
141 0 : case '/': os<<"\\/"; break;
142 0 : case '\b': os<<"\\b"; break;
143 0 : case '\f': os<<"\\f"; break;
144 0 : case '\n': os<<"\\n"; break;
145 0 : case '\r': os<<"\\r"; break;
146 0 : case '\t': os<<"\\t"; break;
147 : default:
148 : {
149 0 : if(c >= 32 && c <= 126)
150 : {
151 0 : os<<c;
152 : }
153 : else
154 : {
155 0 : u32 cnum = (u32) (u8) c;
156 0 : os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
157 : }
158 0 : break;
159 : }
160 : }
161 : }
162 0 : os<<"\"";
163 0 : return os.str();
164 : }
165 :
166 : // Reads a string encoded in JSON format
167 0 : std::string deSerializeJsonString(std::istream &is)
168 : {
169 0 : std::ostringstream os(std::ios::binary);
170 : char c, c2;
171 :
172 : // Parse initial doublequote
173 0 : is >> c;
174 0 : if(c != '"')
175 0 : throw SerializationError("JSON string must start with doublequote");
176 :
177 : // Parse characters
178 0 : for(;;)
179 : {
180 0 : c = is.get();
181 0 : if(is.eof())
182 0 : throw SerializationError("JSON string ended prematurely");
183 0 : if(c == '"')
184 : {
185 0 : return os.str();
186 : }
187 0 : else if(c == '\\')
188 : {
189 0 : c2 = is.get();
190 0 : if(is.eof())
191 0 : throw SerializationError("JSON string ended prematurely");
192 0 : switch(c2)
193 : {
194 0 : default: os<<c2; break;
195 0 : case 'b': os<<'\b'; break;
196 0 : case 'f': os<<'\f'; break;
197 0 : case 'n': os<<'\n'; break;
198 0 : case 'r': os<<'\r'; break;
199 0 : case 't': os<<'\t'; break;
200 : case 'u':
201 : {
202 : char hexdigits[4+1];
203 0 : is.read(hexdigits, 4);
204 0 : if(is.eof())
205 0 : throw SerializationError("JSON string ended prematurely");
206 0 : hexdigits[4] = 0;
207 0 : std::istringstream tmp_is(hexdigits, std::ios::binary);
208 : int hexnumber;
209 0 : tmp_is >> std::hex >> hexnumber;
210 0 : os<<((char)hexnumber);
211 0 : break;
212 : }
213 : }
214 : }
215 : else
216 : {
217 0 : os<<c;
218 : }
219 : }
220 : return os.str();
221 : }
222 :
223 :
224 0 : bool deSerializeStringToStruct(std::string valstr,
225 : std::string format, void *out, size_t olen)
226 : {
227 0 : size_t len = olen;
228 0 : std::vector<std::string *> strs_alloced;
229 : std::string *str;
230 : char *f, *snext;
231 : size_t pos;
232 :
233 0 : char *s = &valstr[0];
234 0 : char *buf = new char[len];
235 0 : char *bufpos = buf;
236 :
237 0 : char *fmtpos, *fmt = &format[0];
238 0 : while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
239 0 : fmt = NULL;
240 :
241 0 : bool is_unsigned = false;
242 0 : int width = 0;
243 0 : char valtype = *f;
244 :
245 0 : width = (int)strtol(f + 1, &f, 10);
246 0 : if (width && valtype == 's')
247 0 : valtype = 'i';
248 :
249 0 : switch (valtype) {
250 : case 'u':
251 0 : is_unsigned = true;
252 : /* FALLTHROUGH */
253 : case 'i':
254 0 : if (width == 16) {
255 0 : bufpos += PADDING(bufpos, u16);
256 0 : if ((bufpos - buf) + sizeof(u16) <= len) {
257 0 : if (is_unsigned)
258 0 : *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
259 : else
260 0 : *(s16 *)bufpos = (s16)strtol(s, &s, 10);
261 : }
262 0 : bufpos += sizeof(u16);
263 0 : } else if (width == 32) {
264 0 : bufpos += PADDING(bufpos, u32);
265 0 : if ((bufpos - buf) + sizeof(u32) <= len) {
266 0 : if (is_unsigned)
267 0 : *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
268 : else
269 0 : *(s32 *)bufpos = (s32)strtol(s, &s, 10);
270 : }
271 0 : bufpos += sizeof(u32);
272 0 : } else if (width == 64) {
273 0 : bufpos += PADDING(bufpos, u64);
274 0 : if ((bufpos - buf) + sizeof(u64) <= len) {
275 0 : if (is_unsigned)
276 0 : *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
277 : else
278 0 : *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
279 : }
280 0 : bufpos += sizeof(u64);
281 : }
282 0 : s = strchr(s, ',');
283 0 : break;
284 : case 'b':
285 0 : snext = strchr(s, ',');
286 0 : if (snext)
287 0 : *snext++ = 0;
288 :
289 0 : bufpos += PADDING(bufpos, bool);
290 0 : if ((bufpos - buf) + sizeof(bool) <= len)
291 0 : *(bool *)bufpos = is_yes(std::string(s));
292 0 : bufpos += sizeof(bool);
293 :
294 0 : s = snext;
295 0 : break;
296 : case 'f':
297 0 : bufpos += PADDING(bufpos, float);
298 0 : if ((bufpos - buf) + sizeof(float) <= len)
299 0 : *(float *)bufpos = strtof(s, &s);
300 0 : bufpos += sizeof(float);
301 :
302 0 : s = strchr(s, ',');
303 0 : break;
304 : case 's':
305 0 : while (*s == ' ' || *s == '\t')
306 0 : s++;
307 0 : if (*s++ != '"') //error, expected string
308 0 : goto fail;
309 0 : snext = s;
310 :
311 0 : while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
312 0 : snext++;
313 0 : *snext++ = 0;
314 :
315 0 : bufpos += PADDING(bufpos, std::string *);
316 :
317 0 : str = new std::string(s);
318 0 : pos = 0;
319 0 : while ((pos = str->find("\\\"", pos)) != std::string::npos)
320 0 : str->erase(pos, 1);
321 :
322 0 : if ((bufpos - buf) + sizeof(std::string *) <= len)
323 0 : *(std::string **)bufpos = str;
324 0 : bufpos += sizeof(std::string *);
325 0 : strs_alloced.push_back(str);
326 :
327 0 : s = *snext ? snext + 1 : NULL;
328 0 : break;
329 : case 'v':
330 0 : while (*s == ' ' || *s == '\t')
331 0 : s++;
332 0 : if (*s++ != '(') //error, expected vector
333 0 : goto fail;
334 :
335 0 : if (width == 2) {
336 0 : bufpos += PADDING(bufpos, v2f);
337 :
338 0 : if ((bufpos - buf) + sizeof(v2f) <= len) {
339 0 : v2f *v = (v2f *)bufpos;
340 0 : v->X = strtof(s, &s);
341 0 : s++;
342 0 : v->Y = strtof(s, &s);
343 : }
344 :
345 0 : bufpos += sizeof(v2f);
346 0 : } else if (width == 3) {
347 0 : bufpos += PADDING(bufpos, v3f);
348 0 : if ((bufpos - buf) + sizeof(v3f) <= len) {
349 0 : v3f *v = (v3f *)bufpos;
350 0 : v->X = strtof(s, &s);
351 0 : s++;
352 0 : v->Y = strtof(s, &s);
353 0 : s++;
354 0 : v->Z = strtof(s, &s);
355 : }
356 :
357 0 : bufpos += sizeof(v3f);
358 : }
359 0 : s = strchr(s, ',');
360 0 : break;
361 : default: //error, invalid format specifier
362 0 : goto fail;
363 : }
364 :
365 0 : if (s && *s == ',')
366 0 : s++;
367 :
368 0 : if ((size_t)(bufpos - buf) > len) //error, buffer too small
369 0 : goto fail;
370 : }
371 :
372 0 : if (f && *f) { //error, mismatched number of fields and values
373 : fail:
374 0 : for (size_t i = 0; i != strs_alloced.size(); i++)
375 0 : delete strs_alloced[i];
376 0 : delete[] buf;
377 0 : return false;
378 : }
379 :
380 0 : memcpy(out, buf, olen);
381 0 : delete[] buf;
382 0 : return true;
383 : }
384 :
385 :
386 : // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
387 : #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
388 :
389 0 : bool serializeStructToString(std::string *out,
390 : std::string format, void *value)
391 : {
392 0 : std::ostringstream os;
393 0 : std::string str;
394 : char *f;
395 : size_t strpos;
396 :
397 0 : char *bufpos = (char *) value;
398 0 : char *fmtpos, *fmt = &format[0];
399 0 : while ((f = strtok_r(fmt, ",", &fmtpos))) {
400 0 : fmt = NULL;
401 0 : bool is_unsigned = false;
402 0 : int width = 0;
403 0 : char valtype = *f;
404 :
405 0 : width = (int)strtol(f + 1, &f, 10);
406 0 : if (width && valtype == 's')
407 0 : valtype = 'i';
408 :
409 0 : switch (valtype) {
410 : case 'u':
411 0 : is_unsigned = true;
412 : /* FALLTHROUGH */
413 : case 'i':
414 0 : if (width == 16) {
415 0 : bufpos += PADDING(bufpos, u16);
416 0 : os << SIGN_CAST(16, bufpos);
417 0 : bufpos += sizeof(u16);
418 0 : } else if (width == 32) {
419 0 : bufpos += PADDING(bufpos, u32);
420 0 : os << SIGN_CAST(32, bufpos);
421 0 : bufpos += sizeof(u32);
422 0 : } else if (width == 64) {
423 0 : bufpos += PADDING(bufpos, u64);
424 0 : os << SIGN_CAST(64, bufpos);
425 0 : bufpos += sizeof(u64);
426 : }
427 0 : break;
428 : case 'b':
429 0 : bufpos += PADDING(bufpos, bool);
430 0 : os << std::boolalpha << *((bool *) bufpos);
431 0 : bufpos += sizeof(bool);
432 0 : break;
433 : case 'f':
434 0 : bufpos += PADDING(bufpos, float);
435 0 : os << *((float *) bufpos);
436 0 : bufpos += sizeof(float);
437 0 : break;
438 : case 's':
439 0 : bufpos += PADDING(bufpos, std::string *);
440 0 : str = **((std::string **) bufpos);
441 :
442 0 : strpos = 0;
443 0 : while ((strpos = str.find('"', strpos)) != std::string::npos) {
444 0 : str.insert(strpos, 1, '\\');
445 0 : strpos += 2;
446 : }
447 :
448 0 : os << str;
449 0 : bufpos += sizeof(std::string *);
450 0 : break;
451 : case 'v':
452 0 : if (width == 2) {
453 0 : bufpos += PADDING(bufpos, v2f);
454 0 : v2f *v = (v2f *) bufpos;
455 0 : os << '(' << v->X << ", " << v->Y << ')';
456 0 : bufpos += sizeof(v2f);
457 : } else {
458 0 : bufpos += PADDING(bufpos, v3f);
459 0 : v3f *v = (v3f *) bufpos;
460 0 : os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
461 0 : bufpos += sizeof(v3f);
462 : }
463 0 : break;
464 : default:
465 0 : return false;
466 : }
467 0 : os << ", ";
468 : }
469 0 : *out = os.str();
470 :
471 : // Trim off the trailing comma and space
472 0 : if (out->size() >= 2) {
473 0 : out->resize(out->size() - 2);
474 : }
475 :
476 0 : return true;
477 3 : }
478 :
479 : #undef SIGN_CAST
|