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"
31 // Creates a string with the length as the first two bytes
32 std::string serializeString(const std::string &plain)
34 //assert(plain.size() <= 65535);
35 if(plain.size() > 65535)
36 throw SerializationError("String too long for serializeString");
38 writeU16((u8*)&buf[0], plain.size());
45 // Creates a string with the length as the first two bytes from wide string
46 std::string serializeWideString(const std::wstring &plain)
48 //assert(plain.size() <= 65535);
49 if(plain.size() > 65535)
50 throw SerializationError("String too long for serializeString");
52 writeU16((u8*)buf, plain.size());
55 for(u32 i=0; i<plain.size(); i++)
57 writeU16((u8*)buf, plain[i]);
63 // Reads a string with the length as the first two bytes
64 std::string deSerializeString(std::istream &is)
69 throw SerializationError("deSerializeString: size not read");
70 u16 s_size = readU16((u8*)buf);
73 Buffer<char> buf2(s_size);
74 is.read(&buf2[0], s_size);
77 s.append(&buf2[0], s_size);
81 // Reads a wide string with the length as the first two bytes
82 std::wstring deSerializeWideString(std::istream &is)
87 throw SerializationError("deSerializeString: size not read");
88 u16 s_size = readU16((u8*)buf);
93 for(u32 i=0; i<s_size; i++)
96 wchar_t c16 = readU16((u8*)buf);
102 // Creates a string with the length as the first four bytes
103 std::string serializeLongString(const std::string &plain)
106 writeU32((u8*)&buf[0], plain.size());
113 // Reads a string with the length as the first four bytes
114 std::string deSerializeLongString(std::istream &is)
119 throw SerializationError("deSerializeLongString: size not read");
120 u32 s_size = readU32((u8*)buf);
123 Buffer<char> buf2(s_size);
124 is.read(&buf2[0], s_size);
127 s.append(&buf2[0], s_size);
131 // Creates a string encoded in JSON format (almost equivalent to a C string literal)
132 std::string serializeJsonString(const std::string &plain)
134 std::ostringstream os(std::ios::binary);
136 for(size_t i = 0; i < plain.size(); i++)
141 case '"': os<<"\\\""; break;
142 case '\\': os<<"\\\\"; break;
143 case '/': os<<"\\/"; break;
144 case '\b': os<<"\\b"; break;
145 case '\f': os<<"\\f"; break;
146 case '\n': os<<"\\n"; break;
147 case '\r': os<<"\\r"; break;
148 case '\t': os<<"\\t"; break;
151 if(c >= 32 && c <= 126)
157 u32 cnum = (u32) (u8) c;
158 os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
168 // Reads a string encoded in JSON format
169 std::string deSerializeJsonString(std::istream &is)
171 std::ostringstream os(std::ios::binary);
174 // Parse initial doublequote
177 throw SerializationError("JSON string must start with doublequote");
184 throw SerializationError("JSON string ended prematurely");
193 throw SerializationError("JSON string ended prematurely");
196 default: os<<c2; break;
197 case 'b': os<<'\b'; break;
198 case 'f': os<<'\f'; break;
199 case 'n': os<<'\n'; break;
200 case 'r': os<<'\r'; break;
201 case 't': os<<'\t'; break;
205 is.read(hexdigits, 4);
207 throw SerializationError("JSON string ended prematurely");
209 std::istringstream tmp_is(hexdigits, std::ios::binary);
211 tmp_is >> std::hex >> hexnumber;
212 os<<((char)hexnumber);
226 bool deSerializeStringToStruct(std::string valstr,
227 std::string format, void *out, size_t olen)
230 std::vector<std::string *> strs_alloced;
235 char *s = &valstr[0];
236 char *buf = new char[len];
239 char *fmtpos, *fmt = &format[0];
240 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
243 bool is_unsigned = false;
247 width = (int)strtol(f + 1, &f, 10);
248 if (width && valtype == 's')
257 bufpos += PADDING(bufpos, u16);
258 if ((bufpos - buf) + sizeof(u16) <= len) {
260 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
262 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
264 bufpos += sizeof(u16);
265 } else if (width == 32) {
266 bufpos += PADDING(bufpos, u32);
267 if ((bufpos - buf) + sizeof(u32) <= len) {
269 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
271 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
273 bufpos += sizeof(u32);
274 } else if (width == 64) {
275 bufpos += PADDING(bufpos, u64);
276 if ((bufpos - buf) + sizeof(u64) <= len) {
278 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
280 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
282 bufpos += sizeof(u64);
287 snext = strchr(s, ',');
291 bufpos += PADDING(bufpos, bool);
292 if ((bufpos - buf) + sizeof(bool) <= len)
293 *(bool *)bufpos = is_yes(std::string(s));
294 bufpos += sizeof(bool);
299 bufpos += PADDING(bufpos, float);
300 if ((bufpos - buf) + sizeof(float) <= len)
301 *(float *)bufpos = strtof(s, &s);
302 bufpos += sizeof(float);
307 while (*s == ' ' || *s == '\t')
309 if (*s++ != '"') //error, expected string
313 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
317 bufpos += PADDING(bufpos, std::string *);
319 str = new std::string(s);
321 while ((pos = str->find("\\\"", pos)) != std::string::npos)
324 if ((bufpos - buf) + sizeof(std::string *) <= len)
325 *(std::string **)bufpos = str;
326 bufpos += sizeof(std::string *);
327 strs_alloced.push_back(str);
329 s = *snext ? snext + 1 : NULL;
332 while (*s == ' ' || *s == '\t')
334 if (*s++ != '(') //error, expected vector
338 bufpos += PADDING(bufpos, v2f);
340 if ((bufpos - buf) + sizeof(v2f) <= len) {
341 v2f *v = (v2f *)bufpos;
342 v->X = strtof(s, &s);
344 v->Y = strtof(s, &s);
347 bufpos += sizeof(v2f);
348 } else if (width == 3) {
349 bufpos += PADDING(bufpos, v3f);
350 if ((bufpos - buf) + sizeof(v3f) <= len) {
351 v3f *v = (v3f *)bufpos;
352 v->X = strtof(s, &s);
354 v->Y = strtof(s, &s);
356 v->Z = strtof(s, &s);
359 bufpos += sizeof(v3f);
363 default: //error, invalid format specifier
370 if ((size_t)(bufpos - buf) > len) //error, buffer too small
374 if (f && *f) { //error, mismatched number of fields and values
376 for (size_t i = 0; i != strs_alloced.size(); i++)
377 delete strs_alloced[i];
382 memcpy(out, buf, olen);
388 // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
389 #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
391 bool serializeStructToString(std::string *out,
392 std::string format, void *value)
394 std::ostringstream os;
399 char *bufpos = (char *) value;
400 char *fmtpos, *fmt = &format[0];
401 while ((f = strtok_r(fmt, ",", &fmtpos))) {
403 bool is_unsigned = false;
407 width = (int)strtol(f + 1, &f, 10);
408 if (width && valtype == 's')
417 bufpos += PADDING(bufpos, u16);
418 os << SIGN_CAST(16, bufpos);
419 bufpos += sizeof(u16);
420 } else if (width == 32) {
421 bufpos += PADDING(bufpos, u32);
422 os << SIGN_CAST(32, bufpos);
423 bufpos += sizeof(u32);
424 } else if (width == 64) {
425 bufpos += PADDING(bufpos, u64);
426 os << SIGN_CAST(64, bufpos);
427 bufpos += sizeof(u64);
431 bufpos += PADDING(bufpos, bool);
432 os << std::boolalpha << *((bool *) bufpos);
433 bufpos += sizeof(bool);
436 bufpos += PADDING(bufpos, float);
437 os << *((float *) bufpos);
438 bufpos += sizeof(float);
441 bufpos += PADDING(bufpos, std::string *);
442 str = **((std::string **) bufpos);
445 while ((strpos = str.find('"', strpos)) != std::string::npos) {
446 str.insert(strpos, 1, '\\');
451 bufpos += sizeof(std::string *);
455 bufpos += PADDING(bufpos, v2f);
456 v2f *v = (v2f *) bufpos;
457 os << '(' << v->X << ", " << v->Y << ')';
458 bufpos += sizeof(v2f);
460 bufpos += PADDING(bufpos, v3f);
461 v3f *v = (v3f *) bufpos;
462 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
463 bufpos += sizeof(v3f);
473 // Trim off the trailing comma and space
474 if (out->size() >= 2) {
475 out->resize(out->size() - 2);