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 SerializationError eof_ser_err("Attempted read past end of data");
37 bool BufReader::getStringNoEx(std::string *val)
40 if (!getU16NoEx(&num_chars))
43 if (pos + num_chars > size) {
44 pos -= sizeof(num_chars);
48 val->assign((const char *)data + pos, num_chars);
54 bool BufReader::getWideStringNoEx(std::wstring *val)
57 if (!getU16NoEx(&num_chars))
60 if (pos + num_chars * 2 > size) {
61 pos -= sizeof(num_chars);
65 for (size_t i = 0; i != num_chars; i++) {
66 val->push_back(readU16(data + pos));
73 bool BufReader::getLongStringNoEx(std::string *val)
76 if (!getU32NoEx(&num_chars))
79 if (pos + num_chars > size) {
80 pos -= sizeof(num_chars);
84 val->assign((const char *)data + pos, num_chars);
90 bool BufReader::getRawDataNoEx(void *val, size_t len)
95 memcpy(val, data + pos, len);
106 std::string serializeString(const std::string &plain)
111 if (plain.size() > STRING_MAX_LEN)
112 throw SerializationError("String too long for serializeString");
114 writeU16((u8 *)&buf[0], plain.size());
121 std::string deSerializeString(std::istream &is)
127 if (is.gcount() != 2)
128 throw SerializationError("deSerializeString: size not read");
130 u16 s_size = readU16((u8 *)buf);
134 Buffer<char> buf2(s_size);
135 is.read(&buf2[0], s_size);
136 if (is.gcount() != s_size)
137 throw SerializationError("deSerializeString: couldn't read all chars");
140 s.append(&buf2[0], s_size);
148 std::string serializeWideString(const std::wstring &plain)
153 if (plain.size() > WIDE_STRING_MAX_LEN)
154 throw SerializationError("String too long for serializeWideString");
156 writeU16((u8 *)buf, plain.size());
159 for (u32 i = 0; i < plain.size(); i++) {
160 writeU16((u8 *)buf, plain[i]);
166 std::wstring deSerializeWideString(std::istream &is)
172 if (is.gcount() != 2)
173 throw SerializationError("deSerializeWideString: size not read");
175 u16 s_size = readU16((u8 *)buf);
180 for (u32 i = 0; i < s_size; i++) {
182 if (is.gcount() != 2) {
183 throw SerializationError(
184 "deSerializeWideString: couldn't read all chars");
187 wchar_t c16 = readU16((u8 *)buf);
197 std::string serializeLongString(const std::string &plain)
201 if (plain.size() > LONG_STRING_MAX_LEN)
202 throw SerializationError("String too long for serializeLongString");
204 writeU32((u8*)&buf[0], plain.size());
211 std::string deSerializeLongString(std::istream &is)
217 if (is.gcount() != 4)
218 throw SerializationError("deSerializeLongString: size not read");
220 u32 s_size = readU32((u8 *)buf);
224 // We don't really want a remote attacker to force us to allocate 4GB...
225 if (s_size > LONG_STRING_MAX_LEN) {
226 throw SerializationError("deSerializeLongString: "
227 "string too long: " + itos(s_size) + " bytes");
230 Buffer<char> buf2(s_size);
231 is.read(&buf2[0], s_size);
232 if ((u32)is.gcount() != s_size)
233 throw SerializationError("deSerializeLongString: couldn't read all chars");
236 s.append(&buf2[0], s_size);
244 std::string serializeJsonString(const std::string &plain)
246 std::ostringstream os(std::ios::binary);
249 for (size_t i = 0; i < plain.size(); i++) {
277 if (c >= 32 && c <= 126) {
281 os << "\\u" << std::hex << std::setw(4)
282 << std::setfill('0') << cnum;
293 std::string deSerializeJsonString(std::istream &is)
295 std::ostringstream os(std::ios::binary);
298 // Parse initial doublequote
301 throw SerializationError("JSON string must start with doublequote");
307 throw SerializationError("JSON string ended prematurely");
311 } else if (c == '\\') {
314 throw SerializationError("JSON string ended prematurely");
333 char hexdigits[4 + 1];
335 is.read(hexdigits, 4);
337 throw SerializationError("JSON string ended prematurely");
340 std::istringstream tmp_is(hexdigits, std::ios::binary);
341 tmp_is >> std::hex >> hexnumber;
342 os << (char)hexnumber;
357 std::string serializeJsonStringIfNeeded(const std::string &s)
359 for (size_t i = 0; i < s.size(); ++i) {
360 if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
361 return serializeJsonString(s);
366 std::string deSerializeJsonStringIfNeeded(std::istream &is)
368 std::ostringstream tmp_os;
369 bool expect_initial_quote = true;
370 bool is_json = false;
371 bool was_backslash = false;
377 if (expect_initial_quote && c == '"') {
383 was_backslash = false;
385 was_backslash = true;
387 break; // Found end of string
397 expect_initial_quote = false;
400 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
401 return deSerializeJsonString(tmp_is);
407 //// String/Struct conversions
410 bool deSerializeStringToStruct(std::string valstr,
411 std::string format, void *out, size_t olen)
414 std::vector<std::string *> strs_alloced;
419 char *s = &valstr[0];
420 char *buf = new char[len];
423 char *fmtpos, *fmt = &format[0];
424 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
427 bool is_unsigned = false;
431 width = (int)strtol(f + 1, &f, 10);
432 if (width && valtype == 's')
441 bufpos += PADDING(bufpos, u16);
442 if ((bufpos - buf) + sizeof(u16) <= len) {
444 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
446 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
448 bufpos += sizeof(u16);
449 } else if (width == 32) {
450 bufpos += PADDING(bufpos, u32);
451 if ((bufpos - buf) + sizeof(u32) <= len) {
453 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
455 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
457 bufpos += sizeof(u32);
458 } else if (width == 64) {
459 bufpos += PADDING(bufpos, u64);
460 if ((bufpos - buf) + sizeof(u64) <= len) {
462 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
464 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
466 bufpos += sizeof(u64);
471 snext = strchr(s, ',');
475 bufpos += PADDING(bufpos, bool);
476 if ((bufpos - buf) + sizeof(bool) <= len)
477 *(bool *)bufpos = is_yes(std::string(s));
478 bufpos += sizeof(bool);
483 bufpos += PADDING(bufpos, float);
484 if ((bufpos - buf) + sizeof(float) <= len)
485 *(float *)bufpos = strtof(s, &s);
486 bufpos += sizeof(float);
491 while (*s == ' ' || *s == '\t')
493 if (*s++ != '"') //error, expected string
497 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
501 bufpos += PADDING(bufpos, std::string *);
503 str = new std::string(s);
505 while ((pos = str->find("\\\"", pos)) != std::string::npos)
508 if ((bufpos - buf) + sizeof(std::string *) <= len)
509 *(std::string **)bufpos = str;
510 bufpos += sizeof(std::string *);
511 strs_alloced.push_back(str);
513 s = *snext ? snext + 1 : NULL;
516 while (*s == ' ' || *s == '\t')
518 if (*s++ != '(') //error, expected vector
522 bufpos += PADDING(bufpos, v2f);
524 if ((bufpos - buf) + sizeof(v2f) <= len) {
525 v2f *v = (v2f *)bufpos;
526 v->X = strtof(s, &s);
528 v->Y = strtof(s, &s);
531 bufpos += sizeof(v2f);
532 } else if (width == 3) {
533 bufpos += PADDING(bufpos, v3f);
534 if ((bufpos - buf) + sizeof(v3f) <= len) {
535 v3f *v = (v3f *)bufpos;
536 v->X = strtof(s, &s);
538 v->Y = strtof(s, &s);
540 v->Z = strtof(s, &s);
543 bufpos += sizeof(v3f);
547 default: //error, invalid format specifier
554 if ((size_t)(bufpos - buf) > len) //error, buffer too small
558 if (f && *f) { //error, mismatched number of fields and values
560 for (size_t i = 0; i != strs_alloced.size(); i++)
561 delete strs_alloced[i];
566 memcpy(out, buf, olen);
571 // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
572 #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
574 bool serializeStructToString(std::string *out,
575 std::string format, void *value)
577 std::ostringstream os;
582 char *bufpos = (char *) value;
583 char *fmtpos, *fmt = &format[0];
584 while ((f = strtok_r(fmt, ",", &fmtpos))) {
586 bool is_unsigned = false;
590 width = (int)strtol(f + 1, &f, 10);
591 if (width && valtype == 's')
600 bufpos += PADDING(bufpos, u16);
601 os << SIGN_CAST(16, bufpos);
602 bufpos += sizeof(u16);
603 } else if (width == 32) {
604 bufpos += PADDING(bufpos, u32);
605 os << SIGN_CAST(32, bufpos);
606 bufpos += sizeof(u32);
607 } else if (width == 64) {
608 bufpos += PADDING(bufpos, u64);
609 os << SIGN_CAST(64, bufpos);
610 bufpos += sizeof(u64);
614 bufpos += PADDING(bufpos, bool);
615 os << std::boolalpha << *((bool *) bufpos);
616 bufpos += sizeof(bool);
619 bufpos += PADDING(bufpos, float);
620 os << *((float *) bufpos);
621 bufpos += sizeof(float);
624 bufpos += PADDING(bufpos, std::string *);
625 str = **((std::string **) bufpos);
628 while ((strpos = str.find('"', strpos)) != std::string::npos) {
629 str.insert(strpos, 1, '\\');
634 bufpos += sizeof(std::string *);
638 bufpos += PADDING(bufpos, v2f);
639 v2f *v = (v2f *) bufpos;
640 os << '(' << v->X << ", " << v->Y << ')';
641 bufpos += sizeof(v2f);
643 bufpos += PADDING(bufpos, v3f);
644 v3f *v = (v3f *) bufpos;
645 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
646 bufpos += sizeof(v3f);
656 // Trim off the trailing comma and space
657 if (out->size() >= 2)
658 out->resize(out->size() - 2);
669 std::string serializeHexString(const std::string &data, bool insert_spaces)
672 result.reserve(data.size() * (2 + insert_spaces));
674 static const char hex_chars[] = "0123456789abcdef";
676 const size_t len = data.size();
677 for (size_t i = 0; i != len; i++) {
679 result.push_back(hex_chars[(byte >> 4) & 0x0F]);
680 result.push_back(hex_chars[(byte >> 0) & 0x0F]);
681 if (insert_spaces && i != len - 1)
682 result.push_back(' ');