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"
35 std::string serializeString(const std::string &plain)
40 if (plain.size() > STRING_MAX_LEN)
41 throw SerializationError("String too long for serializeString");
43 writeU16((u8 *)&buf[0], plain.size());
50 std::string deSerializeString(std::istream &is)
57 throw SerializationError("deSerializeString: size not read");
59 u16 s_size = readU16((u8 *)buf);
63 Buffer<char> buf2(s_size);
64 is.read(&buf2[0], s_size);
65 if (is.gcount() != s_size)
66 throw SerializationError("deSerializeString: couldn't read all chars");
69 s.append(&buf2[0], s_size);
77 std::string serializeWideString(const std::wstring &plain)
82 if (plain.size() > WIDE_STRING_MAX_LEN)
83 throw SerializationError("String too long for serializeWideString");
85 writeU16((u8 *)buf, plain.size());
88 for (u32 i = 0; i < plain.size(); i++) {
89 writeU16((u8 *)buf, plain[i]);
95 std::wstring deSerializeWideString(std::istream &is)
101 if (is.gcount() != 2)
102 throw SerializationError("deSerializeWideString: size not read");
104 u16 s_size = readU16((u8 *)buf);
109 for (u32 i = 0; i < s_size; i++) {
111 if (is.gcount() != 2) {
112 throw SerializationError(
113 "deSerializeWideString: couldn't read all chars");
116 wchar_t c16 = readU16((u8 *)buf);
126 std::string serializeLongString(const std::string &plain)
130 if (plain.size() > LONG_STRING_MAX_LEN)
131 throw SerializationError("String too long for serializeLongString");
133 writeU32((u8*)&buf[0], plain.size());
140 std::string deSerializeLongString(std::istream &is)
146 if (is.gcount() != 4)
147 throw SerializationError("deSerializeLongString: size not read");
149 u32 s_size = readU32((u8 *)buf);
153 // We don't really want a remote attacker to force us to allocate 4GB...
154 if (s_size > LONG_STRING_MAX_LEN) {
155 throw SerializationError("deSerializeLongString: "
156 "string too long: " + itos(s_size) + " bytes");
159 Buffer<char> buf2(s_size);
160 is.read(&buf2[0], s_size);
161 if (is.gcount() != s_size)
162 throw SerializationError("deSerializeLongString: couldn't read all chars");
165 s.append(&buf2[0], s_size);
173 std::string serializeJsonString(const std::string &plain)
175 std::ostringstream os(std::ios::binary);
178 for (size_t i = 0; i < plain.size(); i++) {
206 if (c >= 32 && c <= 126) {
210 os << "\\u" << std::hex << std::setw(4)
211 << std::setfill('0') << cnum;
222 std::string deSerializeJsonString(std::istream &is)
224 std::ostringstream os(std::ios::binary);
227 // Parse initial doublequote
230 throw SerializationError("JSON string must start with doublequote");
236 throw SerializationError("JSON string ended prematurely");
240 } else if (c == '\\') {
243 throw SerializationError("JSON string ended prematurely");
262 char hexdigits[4 + 1];
264 is.read(hexdigits, 4);
266 throw SerializationError("JSON string ended prematurely");
269 std::istringstream tmp_is(hexdigits, std::ios::binary);
270 tmp_is >> std::hex >> hexnumber;
271 os << (char)hexnumber;
287 //// String/Struct conversions
290 bool deSerializeStringToStruct(std::string valstr,
291 std::string format, void *out, size_t olen)
294 std::vector<std::string *> strs_alloced;
299 char *s = &valstr[0];
300 char *buf = new char[len];
303 char *fmtpos, *fmt = &format[0];
304 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
307 bool is_unsigned = false;
311 width = (int)strtol(f + 1, &f, 10);
312 if (width && valtype == 's')
321 bufpos += PADDING(bufpos, u16);
322 if ((bufpos - buf) + sizeof(u16) <= len) {
324 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
326 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
328 bufpos += sizeof(u16);
329 } else if (width == 32) {
330 bufpos += PADDING(bufpos, u32);
331 if ((bufpos - buf) + sizeof(u32) <= len) {
333 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
335 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
337 bufpos += sizeof(u32);
338 } else if (width == 64) {
339 bufpos += PADDING(bufpos, u64);
340 if ((bufpos - buf) + sizeof(u64) <= len) {
342 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
344 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
346 bufpos += sizeof(u64);
351 snext = strchr(s, ',');
355 bufpos += PADDING(bufpos, bool);
356 if ((bufpos - buf) + sizeof(bool) <= len)
357 *(bool *)bufpos = is_yes(std::string(s));
358 bufpos += sizeof(bool);
363 bufpos += PADDING(bufpos, float);
364 if ((bufpos - buf) + sizeof(float) <= len)
365 *(float *)bufpos = strtof(s, &s);
366 bufpos += sizeof(float);
371 while (*s == ' ' || *s == '\t')
373 if (*s++ != '"') //error, expected string
377 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
381 bufpos += PADDING(bufpos, std::string *);
383 str = new std::string(s);
385 while ((pos = str->find("\\\"", pos)) != std::string::npos)
388 if ((bufpos - buf) + sizeof(std::string *) <= len)
389 *(std::string **)bufpos = str;
390 bufpos += sizeof(std::string *);
391 strs_alloced.push_back(str);
393 s = *snext ? snext + 1 : NULL;
396 while (*s == ' ' || *s == '\t')
398 if (*s++ != '(') //error, expected vector
402 bufpos += PADDING(bufpos, v2f);
404 if ((bufpos - buf) + sizeof(v2f) <= len) {
405 v2f *v = (v2f *)bufpos;
406 v->X = strtof(s, &s);
408 v->Y = strtof(s, &s);
411 bufpos += sizeof(v2f);
412 } else if (width == 3) {
413 bufpos += PADDING(bufpos, v3f);
414 if ((bufpos - buf) + sizeof(v3f) <= len) {
415 v3f *v = (v3f *)bufpos;
416 v->X = strtof(s, &s);
418 v->Y = strtof(s, &s);
420 v->Z = strtof(s, &s);
423 bufpos += sizeof(v3f);
427 default: //error, invalid format specifier
434 if ((size_t)(bufpos - buf) > len) //error, buffer too small
438 if (f && *f) { //error, mismatched number of fields and values
440 for (size_t i = 0; i != strs_alloced.size(); i++)
441 delete strs_alloced[i];
446 memcpy(out, buf, olen);
451 // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
452 #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
454 bool serializeStructToString(std::string *out,
455 std::string format, void *value)
457 std::ostringstream os;
462 char *bufpos = (char *) value;
463 char *fmtpos, *fmt = &format[0];
464 while ((f = strtok_r(fmt, ",", &fmtpos))) {
466 bool is_unsigned = false;
470 width = (int)strtol(f + 1, &f, 10);
471 if (width && valtype == 's')
480 bufpos += PADDING(bufpos, u16);
481 os << SIGN_CAST(16, bufpos);
482 bufpos += sizeof(u16);
483 } else if (width == 32) {
484 bufpos += PADDING(bufpos, u32);
485 os << SIGN_CAST(32, bufpos);
486 bufpos += sizeof(u32);
487 } else if (width == 64) {
488 bufpos += PADDING(bufpos, u64);
489 os << SIGN_CAST(64, bufpos);
490 bufpos += sizeof(u64);
494 bufpos += PADDING(bufpos, bool);
495 os << std::boolalpha << *((bool *) bufpos);
496 bufpos += sizeof(bool);
499 bufpos += PADDING(bufpos, float);
500 os << *((float *) bufpos);
501 bufpos += sizeof(float);
504 bufpos += PADDING(bufpos, std::string *);
505 str = **((std::string **) bufpos);
508 while ((strpos = str.find('"', strpos)) != std::string::npos) {
509 str.insert(strpos, 1, '\\');
514 bufpos += sizeof(std::string *);
518 bufpos += PADDING(bufpos, v2f);
519 v2f *v = (v2f *) bufpos;
520 os << '(' << v->X << ", " << v->Y << ')';
521 bufpos += sizeof(v2f);
523 bufpos += PADDING(bufpos, v3f);
524 v3f *v = (v3f *) bufpos;
525 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
526 bufpos += sizeof(v3f);
536 // Trim off the trailing comma and space
537 if (out->size() >= 2)
538 out->resize(out->size() - 2);
549 std::string serializeHexString(const std::string &data, bool insert_spaces)
552 result.reserve(data.size() * (2 + insert_spaces));
554 static const char hex_chars[] = "0123456789abcdef";
556 const size_t len = data.size();
557 for (size_t i = 0; i != len; i++) {
559 result.push_back(hex_chars[(byte >> 4) & 0x0F]);
560 result.push_back(hex_chars[(byte >> 0) & 0x0F]);
561 if (insert_spaces && i != len - 1)
562 result.push_back(' ');