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;
358 //// String/Struct conversions
361 bool deSerializeStringToStruct(std::string valstr,
362 std::string format, void *out, size_t olen)
365 std::vector<std::string *> strs_alloced;
370 char *s = &valstr[0];
371 char *buf = new char[len];
374 char *fmtpos, *fmt = &format[0];
375 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
378 bool is_unsigned = false;
382 width = (int)strtol(f + 1, &f, 10);
383 if (width && valtype == 's')
392 bufpos += PADDING(bufpos, u16);
393 if ((bufpos - buf) + sizeof(u16) <= len) {
395 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
397 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
399 bufpos += sizeof(u16);
400 } else if (width == 32) {
401 bufpos += PADDING(bufpos, u32);
402 if ((bufpos - buf) + sizeof(u32) <= len) {
404 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
406 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
408 bufpos += sizeof(u32);
409 } else if (width == 64) {
410 bufpos += PADDING(bufpos, u64);
411 if ((bufpos - buf) + sizeof(u64) <= len) {
413 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
415 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
417 bufpos += sizeof(u64);
422 snext = strchr(s, ',');
426 bufpos += PADDING(bufpos, bool);
427 if ((bufpos - buf) + sizeof(bool) <= len)
428 *(bool *)bufpos = is_yes(std::string(s));
429 bufpos += sizeof(bool);
434 bufpos += PADDING(bufpos, float);
435 if ((bufpos - buf) + sizeof(float) <= len)
436 *(float *)bufpos = strtof(s, &s);
437 bufpos += sizeof(float);
442 while (*s == ' ' || *s == '\t')
444 if (*s++ != '"') //error, expected string
448 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
452 bufpos += PADDING(bufpos, std::string *);
454 str = new std::string(s);
456 while ((pos = str->find("\\\"", pos)) != std::string::npos)
459 if ((bufpos - buf) + sizeof(std::string *) <= len)
460 *(std::string **)bufpos = str;
461 bufpos += sizeof(std::string *);
462 strs_alloced.push_back(str);
464 s = *snext ? snext + 1 : NULL;
467 while (*s == ' ' || *s == '\t')
469 if (*s++ != '(') //error, expected vector
473 bufpos += PADDING(bufpos, v2f);
475 if ((bufpos - buf) + sizeof(v2f) <= len) {
476 v2f *v = (v2f *)bufpos;
477 v->X = strtof(s, &s);
479 v->Y = strtof(s, &s);
482 bufpos += sizeof(v2f);
483 } else if (width == 3) {
484 bufpos += PADDING(bufpos, v3f);
485 if ((bufpos - buf) + sizeof(v3f) <= len) {
486 v3f *v = (v3f *)bufpos;
487 v->X = strtof(s, &s);
489 v->Y = strtof(s, &s);
491 v->Z = strtof(s, &s);
494 bufpos += sizeof(v3f);
498 default: //error, invalid format specifier
505 if ((size_t)(bufpos - buf) > len) //error, buffer too small
509 if (f && *f) { //error, mismatched number of fields and values
511 for (size_t i = 0; i != strs_alloced.size(); i++)
512 delete strs_alloced[i];
517 memcpy(out, buf, olen);
522 // Casts *buf to a signed or unsigned fixed-width integer of 'w' width
523 #define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
525 bool serializeStructToString(std::string *out,
526 std::string format, void *value)
528 std::ostringstream os;
533 char *bufpos = (char *) value;
534 char *fmtpos, *fmt = &format[0];
535 while ((f = strtok_r(fmt, ",", &fmtpos))) {
537 bool is_unsigned = false;
541 width = (int)strtol(f + 1, &f, 10);
542 if (width && valtype == 's')
551 bufpos += PADDING(bufpos, u16);
552 os << SIGN_CAST(16, bufpos);
553 bufpos += sizeof(u16);
554 } else if (width == 32) {
555 bufpos += PADDING(bufpos, u32);
556 os << SIGN_CAST(32, bufpos);
557 bufpos += sizeof(u32);
558 } else if (width == 64) {
559 bufpos += PADDING(bufpos, u64);
560 os << SIGN_CAST(64, bufpos);
561 bufpos += sizeof(u64);
565 bufpos += PADDING(bufpos, bool);
566 os << std::boolalpha << *((bool *) bufpos);
567 bufpos += sizeof(bool);
570 bufpos += PADDING(bufpos, float);
571 os << *((float *) bufpos);
572 bufpos += sizeof(float);
575 bufpos += PADDING(bufpos, std::string *);
576 str = **((std::string **) bufpos);
579 while ((strpos = str.find('"', strpos)) != std::string::npos) {
580 str.insert(strpos, 1, '\\');
585 bufpos += sizeof(std::string *);
589 bufpos += PADDING(bufpos, v2f);
590 v2f *v = (v2f *) bufpos;
591 os << '(' << v->X << ", " << v->Y << ')';
592 bufpos += sizeof(v2f);
594 bufpos += PADDING(bufpos, v3f);
595 v3f *v = (v3f *) bufpos;
596 os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
597 bufpos += sizeof(v3f);
607 // Trim off the trailing comma and space
608 if (out->size() >= 2)
609 out->resize(out->size() - 2);
620 std::string serializeHexString(const std::string &data, bool insert_spaces)
623 result.reserve(data.size() * (2 + insert_spaces));
625 static const char hex_chars[] = "0123456789abcdef";
627 const size_t len = data.size();
628 for (size_t i = 0; i != len; i++) {
630 result.push_back(hex_chars[(byte >> 4) & 0x0F]);
631 result.push_back(hex_chars[(byte >> 0) & 0x0F]);
632 if (insert_spaces && i != len - 1)
633 result.push_back(' ');