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 (wchar_t i : plain) {
160 writeU16((u8 *)buf, 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 (char c : plain) {
276 if (c >= 32 && c <= 126) {
280 os << "\\u" << std::hex << std::setw(4)
281 << std::setfill('0') << cnum;
292 std::string deSerializeJsonString(std::istream &is)
294 std::ostringstream os(std::ios::binary);
297 // Parse initial doublequote
300 throw SerializationError("JSON string must start with doublequote");
306 throw SerializationError("JSON string ended prematurely");
315 throw SerializationError("JSON string ended prematurely");
334 char hexdigits[4 + 1];
336 is.read(hexdigits, 4);
338 throw SerializationError("JSON string ended prematurely");
341 std::istringstream tmp_is(hexdigits, std::ios::binary);
342 tmp_is >> std::hex >> hexnumber;
343 os << (char)hexnumber;
358 std::string serializeJsonStringIfNeeded(const std::string &s)
360 for (size_t i = 0; i < s.size(); ++i) {
361 if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
362 return serializeJsonString(s);
367 std::string deSerializeJsonStringIfNeeded(std::istream &is)
369 std::ostringstream tmp_os;
370 bool expect_initial_quote = true;
371 bool is_json = false;
372 bool was_backslash = false;
378 if (expect_initial_quote && c == '"') {
384 was_backslash = false;
386 was_backslash = true;
388 break; // Found end of string
398 expect_initial_quote = false;
401 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
402 return deSerializeJsonString(tmp_is);
409 //// String/Struct conversions
412 bool deSerializeStringToStruct(std::string valstr,
413 std::string format, void *out, size_t olen)
416 std::vector<std::string *> strs_alloced;
421 char *s = &valstr[0];
422 char *buf = new char[len];
425 char *fmtpos, *fmt = &format[0];
426 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
429 bool is_unsigned = false;
433 width = (int)strtol(f + 1, &f, 10);
434 if (width && valtype == 's')
443 bufpos += PADDING(bufpos, u16);
444 if ((bufpos - buf) + sizeof(u16) <= len) {
446 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
448 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
450 bufpos += sizeof(u16);
451 } else if (width == 32) {
452 bufpos += PADDING(bufpos, u32);
453 if ((bufpos - buf) + sizeof(u32) <= len) {
455 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
457 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
459 bufpos += sizeof(u32);
460 } else if (width == 64) {
461 bufpos += PADDING(bufpos, u64);
462 if ((bufpos - buf) + sizeof(u64) <= len) {
464 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
466 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
468 bufpos += sizeof(u64);
473 snext = strchr(s, ',');
477 bufpos += PADDING(bufpos, bool);
478 if ((bufpos - buf) + sizeof(bool) <= len)
479 *(bool *)bufpos = is_yes(std::string(s));
480 bufpos += sizeof(bool);
485 bufpos += PADDING(bufpos, float);
486 if ((bufpos - buf) + sizeof(float) <= len)
487 *(float *)bufpos = strtof(s, &s);
488 bufpos += sizeof(float);
493 while (*s == ' ' || *s == '\t')
495 if (*s++ != '"') //error, expected string
499 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
503 bufpos += PADDING(bufpos, std::string *);
505 str = new std::string(s);
507 while ((pos = str->find("\\\"", pos)) != std::string::npos)
510 if ((bufpos - buf) + sizeof(std::string *) <= len)
511 *(std::string **)bufpos = str;
512 bufpos += sizeof(std::string *);
513 strs_alloced.push_back(str);
515 s = *snext ? snext + 1 : nullptr;
518 while (*s == ' ' || *s == '\t')
520 if (*s++ != '(') //error, expected vector
524 bufpos += PADDING(bufpos, v2f);
526 if ((bufpos - buf) + sizeof(v2f) <= len) {
527 v2f *v = (v2f *)bufpos;
528 v->X = strtof(s, &s);
530 v->Y = strtof(s, &s);
533 bufpos += sizeof(v2f);
534 } else if (width == 3) {
535 bufpos += PADDING(bufpos, v3f);
536 if ((bufpos - buf) + sizeof(v3f) <= len) {
537 v3f *v = (v3f *)bufpos;
538 v->X = strtof(s, &s);
540 v->Y = strtof(s, &s);
542 v->Z = strtof(s, &s);
545 bufpos += sizeof(v3f);
549 default: //error, invalid format specifier
556 if ((size_t)(bufpos - buf) > len) //error, buffer too small
560 if (f && *f) { //error, mismatched number of fields and values
562 for (size_t i = 0; i != strs_alloced.size(); i++)
563 delete strs_alloced[i];
568 memcpy(out, buf, olen);
573 // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
574 #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
576 bool serializeStructToString(std::string *out,
577 std::string format, void *value)
579 std::ostringstream os;
584 char *bufpos = (char *) value;
585 char *fmtpos, *fmt = &format[0];
586 while ((f = strtok_r(fmt, ",", &fmtpos))) {
588 bool is_unsigned = false;
592 width = (int)strtol(f + 1, &f, 10);
593 if (width && valtype == 's')
602 bufpos += PADDING(bufpos, u16);
603 os << SIGN_CAST(16, bufpos);
604 bufpos += sizeof(u16);
605 } else if (width == 32) {
606 bufpos += PADDING(bufpos, u32);
607 os << SIGN_CAST(32, bufpos);
608 bufpos += sizeof(u32);
609 } else if (width == 64) {
610 bufpos += PADDING(bufpos, u64);
611 os << SIGN_CAST(64, bufpos);
612 bufpos += sizeof(u64);
616 bufpos += PADDING(bufpos, bool);
617 os << std::boolalpha << *((bool *) bufpos);
618 bufpos += sizeof(bool);
621 bufpos += PADDING(bufpos, float);
622 os << *((float *) bufpos);
623 bufpos += sizeof(float);
626 bufpos += PADDING(bufpos, std::string *);
627 str = **((std::string **) bufpos);
630 while ((strpos = str.find('"', strpos)) != std::string::npos) {
631 str.insert(strpos, 1, '\\');
636 bufpos += sizeof(std::string *);
640 bufpos += PADDING(bufpos, v2f);
641 v2f *v = (v2f *) bufpos;
642 os << '(' << v->X << ", " << v->Y << ')';
643 bufpos += sizeof(v2f);
645 bufpos += PADDING(bufpos, v3f);
646 v3f *v = (v3f *) bufpos;
647 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
648 bufpos += sizeof(v3f);
658 // Trim off the trailing comma and space
659 if (out->size() >= 2)
660 out->resize(out->size() - 2);
671 std::string serializeHexString(const std::string &data, bool insert_spaces)
674 result.reserve(data.size() * (2 + insert_spaces));
676 static const char hex_chars[] = "0123456789abcdef";
678 const size_t len = data.size();
679 for (size_t i = 0; i != len; i++) {
681 result.push_back(hex_chars[(byte >> 4) & 0x0F]);
682 result.push_back(hex_chars[(byte >> 0) & 0x0F]);
683 if (insert_spaces && i != len - 1)
684 result.push_back(' ');