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 if(plain.size() > 65535)
35 throw SerializationError("String too long for serializeString");
37 writeU16((u8*)&buf[0], plain.size());
44 // Creates a string with the length as the first two bytes from wide string
45 std::string serializeWideString(const std::wstring &plain)
47 if(plain.size() > 65535)
48 throw SerializationError("String too long for serializeString");
50 writeU16((u8*)buf, plain.size());
53 for(u32 i=0; i<plain.size(); i++)
55 writeU16((u8*)buf, plain[i]);
61 // Reads a string with the length as the first two bytes
62 std::string deSerializeString(std::istream &is)
67 throw SerializationError("deSerializeString: size not read");
68 u16 s_size = readU16((u8*)buf);
72 Buffer<char> buf2(s_size);
73 is.read(&buf2[0], s_size);
75 s.append(&buf2[0], s_size);
79 // Reads a wide string with the length as the first two bytes
80 std::wstring deSerializeWideString(std::istream &is)
85 throw SerializationError("deSerializeString: size not read");
86 u16 s_size = readU16((u8*)buf);
91 for(u32 i=0; i<s_size; i++)
94 wchar_t c16 = readU16((u8*)buf);
100 // Creates a string with the length as the first four bytes
101 std::string serializeLongString(const std::string &plain)
104 writeU32((u8*)&buf[0], plain.size());
111 // Reads a string with the length as the first four bytes
112 std::string deSerializeLongString(std::istream &is)
117 throw SerializationError("deSerializeLongString: size not read");
118 u32 s_size = readU32((u8*)buf);
122 Buffer<char> buf2(s_size);
123 is.read(&buf2[0], s_size);
125 s.append(&buf2[0], s_size);
129 // Creates a string encoded in JSON format (almost equivalent to a C string literal)
130 std::string serializeJsonString(const std::string &plain)
132 std::ostringstream os(std::ios::binary);
134 for(size_t i = 0; i < plain.size(); i++)
139 case '"': os<<"\\\""; break;
140 case '\\': os<<"\\\\"; break;
141 case '/': os<<"\\/"; break;
142 case '\b': os<<"\\b"; break;
143 case '\f': os<<"\\f"; break;
144 case '\n': os<<"\\n"; break;
145 case '\r': os<<"\\r"; break;
146 case '\t': os<<"\\t"; break;
149 if(c >= 32 && c <= 126)
155 u32 cnum = (u32) (u8) c;
156 os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
166 // Reads a string encoded in JSON format
167 std::string deSerializeJsonString(std::istream &is)
169 std::ostringstream os(std::ios::binary);
172 // Parse initial doublequote
175 throw SerializationError("JSON string must start with doublequote");
182 throw SerializationError("JSON string ended prematurely");
191 throw SerializationError("JSON string ended prematurely");
194 default: os<<c2; break;
195 case 'b': os<<'\b'; break;
196 case 'f': os<<'\f'; break;
197 case 'n': os<<'\n'; break;
198 case 'r': os<<'\r'; break;
199 case 't': os<<'\t'; break;
203 is.read(hexdigits, 4);
205 throw SerializationError("JSON string ended prematurely");
207 std::istringstream tmp_is(hexdigits, std::ios::binary);
209 tmp_is >> std::hex >> hexnumber;
210 os<<((char)hexnumber);
224 bool deSerializeStringToStruct(std::string valstr,
225 std::string format, void *out, size_t olen)
228 std::vector<std::string *> strs_alloced;
233 char *s = &valstr[0];
234 char *buf = new char[len];
237 char *fmtpos, *fmt = &format[0];
238 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
241 bool is_unsigned = false;
245 width = (int)strtol(f + 1, &f, 10);
246 if (width && valtype == 's')
255 bufpos += PADDING(bufpos, u16);
256 if ((bufpos - buf) + sizeof(u16) <= len) {
258 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
260 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
262 bufpos += sizeof(u16);
263 } else if (width == 32) {
264 bufpos += PADDING(bufpos, u32);
265 if ((bufpos - buf) + sizeof(u32) <= len) {
267 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
269 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
271 bufpos += sizeof(u32);
272 } else if (width == 64) {
273 bufpos += PADDING(bufpos, u64);
274 if ((bufpos - buf) + sizeof(u64) <= len) {
276 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
278 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
280 bufpos += sizeof(u64);
285 snext = strchr(s, ',');
289 bufpos += PADDING(bufpos, bool);
290 if ((bufpos - buf) + sizeof(bool) <= len)
291 *(bool *)bufpos = is_yes(std::string(s));
292 bufpos += sizeof(bool);
297 bufpos += PADDING(bufpos, float);
298 if ((bufpos - buf) + sizeof(float) <= len)
299 *(float *)bufpos = strtof(s, &s);
300 bufpos += sizeof(float);
305 while (*s == ' ' || *s == '\t')
307 if (*s++ != '"') //error, expected string
311 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
315 bufpos += PADDING(bufpos, std::string *);
317 str = new std::string(s);
319 while ((pos = str->find("\\\"", pos)) != std::string::npos)
322 if ((bufpos - buf) + sizeof(std::string *) <= len)
323 *(std::string **)bufpos = str;
324 bufpos += sizeof(std::string *);
325 strs_alloced.push_back(str);
327 s = *snext ? snext + 1 : NULL;
330 while (*s == ' ' || *s == '\t')
332 if (*s++ != '(') //error, expected vector
336 bufpos += PADDING(bufpos, v2f);
338 if ((bufpos - buf) + sizeof(v2f) <= len) {
339 v2f *v = (v2f *)bufpos;
340 v->X = strtof(s, &s);
342 v->Y = strtof(s, &s);
345 bufpos += sizeof(v2f);
346 } else if (width == 3) {
347 bufpos += PADDING(bufpos, v3f);
348 if ((bufpos - buf) + sizeof(v3f) <= len) {
349 v3f *v = (v3f *)bufpos;
350 v->X = strtof(s, &s);
352 v->Y = strtof(s, &s);
354 v->Z = strtof(s, &s);
357 bufpos += sizeof(v3f);
361 default: //error, invalid format specifier
368 if ((size_t)(bufpos - buf) > len) //error, buffer too small
372 if (f && *f) { //error, mismatched number of fields and values
374 for (size_t i = 0; i != strs_alloced.size(); i++)
375 delete strs_alloced[i];
380 memcpy(out, buf, olen);
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))
389 bool serializeStructToString(std::string *out,
390 std::string format, void *value)
392 std::ostringstream os;
397 char *bufpos = (char *) value;
398 char *fmtpos, *fmt = &format[0];
399 while ((f = strtok_r(fmt, ",", &fmtpos))) {
401 bool is_unsigned = false;
405 width = (int)strtol(f + 1, &f, 10);
406 if (width && valtype == 's')
415 bufpos += PADDING(bufpos, u16);
416 os << SIGN_CAST(16, bufpos);
417 bufpos += sizeof(u16);
418 } else if (width == 32) {
419 bufpos += PADDING(bufpos, u32);
420 os << SIGN_CAST(32, bufpos);
421 bufpos += sizeof(u32);
422 } else if (width == 64) {
423 bufpos += PADDING(bufpos, u64);
424 os << SIGN_CAST(64, bufpos);
425 bufpos += sizeof(u64);
429 bufpos += PADDING(bufpos, bool);
430 os << std::boolalpha << *((bool *) bufpos);
431 bufpos += sizeof(bool);
434 bufpos += PADDING(bufpos, float);
435 os << *((float *) bufpos);
436 bufpos += sizeof(float);
439 bufpos += PADDING(bufpos, std::string *);
440 str = **((std::string **) bufpos);
443 while ((strpos = str.find('"', strpos)) != std::string::npos) {
444 str.insert(strpos, 1, '\\');
449 bufpos += sizeof(std::string *);
453 bufpos += PADDING(bufpos, v2f);
454 v2f *v = (v2f *) bufpos;
455 os << '(' << v->X << ", " << v->Y << ')';
456 bufpos += sizeof(v2f);
458 bufpos += PADDING(bufpos, v3f);
459 v3f *v = (v3f *) bufpos;
460 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
461 bufpos += sizeof(v3f);
471 // Trim off the trailing comma and space
472 if (out->size() >= 2) {
473 out->resize(out->size() - 2);