3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "serialize.h"
23 #include "util/string.h"
24 #include "../exceptions.h"
25 #include "../irrlichttypes.h"
27 #include <inttypes.h> // For PRIxN, cinttypes is C++11-only
32 // Creates a string with the length as the first two bytes
33 std::string serializeString(const std::string &plain)
35 //assert(plain.size() <= 65535);
36 if(plain.size() > 65535)
37 throw SerializationError("String too long for serializeString");
39 writeU16((u8*)&buf[0], plain.size());
46 // Creates a string with the length as the first two bytes from wide string
47 std::string serializeWideString(const std::wstring &plain)
49 //assert(plain.size() <= 65535);
50 if(plain.size() > 65535)
51 throw SerializationError("String too long for serializeString");
53 writeU16((u8*)buf, plain.size());
56 for(u32 i=0; i<plain.size(); i++)
58 writeU16((u8*)buf, plain[i]);
64 // Reads a string with the length as the first two bytes
65 std::string deSerializeString(std::istream &is)
70 throw SerializationError("deSerializeString: size not read");
71 u16 s_size = readU16((u8*)buf);
74 Buffer<char> buf2(s_size);
75 is.read(&buf2[0], s_size);
78 s.append(&buf2[0], s_size);
82 // Reads a wide string with the length as the first two bytes
83 std::wstring deSerializeWideString(std::istream &is)
88 throw SerializationError("deSerializeString: size not read");
89 u16 s_size = readU16((u8*)buf);
94 for(u32 i=0; i<s_size; i++)
97 wchar_t c16 = readU16((u8*)buf);
103 // Creates a string with the length as the first four bytes
104 std::string serializeLongString(const std::string &plain)
107 writeU32((u8*)&buf[0], plain.size());
114 // Reads a string with the length as the first four bytes
115 std::string deSerializeLongString(std::istream &is)
120 throw SerializationError("deSerializeLongString: size not read");
121 u32 s_size = readU32((u8*)buf);
124 Buffer<char> buf2(s_size);
125 is.read(&buf2[0], s_size);
128 s.append(&buf2[0], s_size);
132 // Creates a string encoded in JSON format (almost equivalent to a C string literal)
133 std::string serializeJsonString(const std::string &plain)
135 std::ostringstream os(std::ios::binary);
137 for(size_t i = 0; i < plain.size(); i++)
142 case '"': os<<"\\\""; break;
143 case '\\': os<<"\\\\"; break;
144 case '/': os<<"\\/"; break;
145 case '\b': os<<"\\b"; break;
146 case '\f': os<<"\\f"; break;
147 case '\n': os<<"\\n"; break;
148 case '\r': os<<"\\r"; break;
149 case '\t': os<<"\\t"; break;
152 if(c >= 32 && c <= 126)
158 u32 cnum = (u32) (u8) c;
159 os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
169 // Reads a string encoded in JSON format
170 std::string deSerializeJsonString(std::istream &is)
172 std::ostringstream os(std::ios::binary);
175 // Parse initial doublequote
178 throw SerializationError("JSON string must start with doublequote");
185 throw SerializationError("JSON string ended prematurely");
194 throw SerializationError("JSON string ended prematurely");
197 default: os<<c2; break;
198 case 'b': os<<'\b'; break;
199 case 'f': os<<'\f'; break;
200 case 'n': os<<'\n'; break;
201 case 'r': os<<'\r'; break;
202 case 't': os<<'\t'; break;
206 is.read(hexdigits, 4);
208 throw SerializationError("JSON string ended prematurely");
210 std::istringstream tmp_is(hexdigits, std::ios::binary);
212 tmp_is >> std::hex >> hexnumber;
213 os<<((char)hexnumber);
227 bool deSerializeStringToStruct(std::string valstr,
228 std::string format, void *out, size_t olen)
231 std::vector<std::string *> strs_alloced;
236 char *s = &valstr[0];
237 char *buf = new char[len];
240 char *fmtpos, *fmt = &format[0];
241 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
244 bool is_unsigned = false;
248 width = (int)strtol(f + 1, &f, 10);
249 if (width && valtype == 's')
258 bufpos += PADDING(bufpos, u16);
259 if ((bufpos - buf) + sizeof(u16) <= len) {
261 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
263 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
265 bufpos += sizeof(u16);
266 } else if (width == 32) {
267 bufpos += PADDING(bufpos, u32);
268 if ((bufpos - buf) + sizeof(u32) <= len) {
270 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
272 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
274 bufpos += sizeof(u32);
275 } else if (width == 64) {
276 bufpos += PADDING(bufpos, u64);
277 if ((bufpos - buf) + sizeof(u64) <= len) {
279 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
281 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
283 bufpos += sizeof(u64);
288 snext = strchr(s, ',');
292 bufpos += PADDING(bufpos, bool);
293 if ((bufpos - buf) + sizeof(bool) <= len)
294 *(bool *)bufpos = is_yes(std::string(s));
295 bufpos += sizeof(bool);
300 bufpos += PADDING(bufpos, float);
301 if ((bufpos - buf) + sizeof(float) <= len)
302 *(float *)bufpos = strtof(s, &s);
303 bufpos += sizeof(float);
308 while (*s == ' ' || *s == '\t')
310 if (*s++ != '"') //error, expected string
314 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
318 bufpos += PADDING(bufpos, std::string *);
320 str = new std::string(s);
322 while ((pos = str->find("\\\"", pos)) != std::string::npos)
325 if ((bufpos - buf) + sizeof(std::string *) <= len)
326 *(std::string **)bufpos = str;
327 bufpos += sizeof(std::string *);
328 strs_alloced.push_back(str);
330 s = *snext ? snext + 1 : NULL;
333 while (*s == ' ' || *s == '\t')
335 if (*s++ != '(') //error, expected vector
339 bufpos += PADDING(bufpos, v2f);
341 if ((bufpos - buf) + sizeof(v2f) <= len) {
342 v2f *v = (v2f *)bufpos;
343 v->X = strtof(s, &s);
345 v->Y = strtof(s, &s);
348 bufpos += sizeof(v2f);
349 } else if (width == 3) {
350 bufpos += PADDING(bufpos, v3f);
351 if ((bufpos - buf) + sizeof(v3f) <= len) {
352 v3f *v = (v3f *)bufpos;
353 v->X = strtof(s, &s);
355 v->Y = strtof(s, &s);
357 v->Z = strtof(s, &s);
360 bufpos += sizeof(v3f);
364 default: //error, invalid format specifier
371 if ((size_t)(bufpos - buf) > len) //error, buffer too small
375 if (f && *f) { //error, mismatched number of fields and values
377 for (size_t i = 0; i != strs_alloced.size(); i++)
378 delete strs_alloced[i];
383 memcpy(out, buf, olen);
389 bool serializeStructToString(std::string *outstr,
390 std::string format, void *value)
393 int sbuflen = sizeof(sbuf) - 1;
400 char *bufpos = (char *)value;
401 char *fmtpos, *fmt = &format[0];
402 while ((f = strtok_r(fmt, ",", &fmtpos))) {
404 bool is_unsigned = false;
405 int width = 0, nprinted = 0;
408 width = (int)strtol(f + 1, &f, 10);
409 if (width && valtype == 's')
418 bufpos += PADDING(bufpos, u16);
419 nprinted = snprintf(sbuf + pos, sbuflen,
420 is_unsigned ? "%" PRIu16 ", " : "%" PRIi16 ", ",
422 bufpos += sizeof(u16);
423 } else if (width == 32) {
424 bufpos += PADDING(bufpos, u32);
425 nprinted = snprintf(sbuf + pos, sbuflen,
426 is_unsigned ? "%" PRIu32 ", " : "%" PRIi32 ", ",
428 bufpos += sizeof(u32);
429 } else if (width == 64) {
430 bufpos += PADDING(bufpos, u64);
431 nprinted = snprintf(sbuf + pos, sbuflen,
432 is_unsigned ? "%" PRIu64 ", " : "%" PRIi64 ", ",
434 bufpos += sizeof(u64);
438 bufpos += PADDING(bufpos, bool);
439 nprinted = snprintf(sbuf + pos, sbuflen, "%s, ",
440 *((bool *)bufpos) ? "true" : "false");
441 bufpos += sizeof(bool);
444 bufpos += PADDING(bufpos, float);
445 nprinted = snprintf(sbuf + pos, sbuflen, "%f, ",
447 bufpos += sizeof(float);
450 bufpos += PADDING(bufpos, std::string *);
451 str = **((std::string **)bufpos);
454 while ((fpos = str.find('"', fpos)) != std::string::npos) {
455 str.insert(fpos, 1, '\\');
459 nprinted = snprintf(sbuf + pos, sbuflen, "\"%s\", ",
460 (*((std::string **)bufpos))->c_str());
461 bufpos += sizeof(std::string *);
465 bufpos += PADDING(bufpos, v2f);
466 v2f *v = (v2f *)bufpos;
467 nprinted = snprintf(sbuf + pos, sbuflen,
468 "(%f, %f), ", v->X, v->Y);
469 bufpos += sizeof(v2f);
471 bufpos += PADDING(bufpos, v3f);
472 v3f *v = (v3f *)bufpos;
473 nprinted = snprintf(sbuf + pos, sbuflen,
474 "(%f, %f, %f), ", v->X, v->Y, v->Z);
475 bufpos += sizeof(v3f);
481 if (nprinted < 0) //error, buffer too small
487 // this is to trim off the trailing comma