LCOV - code coverage report
Current view: top level - src/util - serialize.cpp (source / functions) Hit Total Coverage
Test: report Lines: 38 289 13.1 %
Date: 2015-07-11 18:23:49 Functions: 6 12 50.0 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       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.
       9             : 
      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.
      14             : 
      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.
      18             : */
      19             : 
      20             : #include "serialize.h"
      21             : #include "pointer.h"
      22             : #include "porting.h"
      23             : #include "util/string.h"
      24             : #include "../exceptions.h"
      25             : #include "../irrlichttypes.h"
      26             : 
      27             : #include <sstream>
      28             : #include <iomanip>
      29             : #include <vector>
      30             : 
      31             : // Creates a string with the length as the first two bytes
      32          67 : std::string serializeString(const std::string &plain)
      33             : {
      34          67 :         if(plain.size() > 65535)
      35           0 :                 throw SerializationError("String too long for serializeString");
      36             :         char buf[2];
      37          67 :         writeU16((u8*)&buf[0], plain.size());
      38          67 :         std::string s;
      39          67 :         s.append(buf, 2);
      40          67 :         s.append(plain);
      41          67 :         return s;
      42             : }
      43             : 
      44             : // Creates a string with the length as the first two bytes from wide string
      45           0 : std::string serializeWideString(const std::wstring &plain)
      46             : {
      47           0 :         if(plain.size() > 65535)
      48           0 :                 throw SerializationError("String too long for serializeString");
      49             :         char buf[2];
      50           0 :         writeU16((u8*)buf, plain.size());
      51           0 :         std::string s;
      52           0 :         s.append(buf, 2);
      53           0 :         for(u32 i=0; i<plain.size(); i++)
      54             :         {
      55           0 :                 writeU16((u8*)buf, plain[i]);
      56           0 :                 s.append(buf, 2);
      57             :         }
      58           0 :         return s;
      59             : }
      60             : 
      61             : // Reads a string with the length as the first two bytes
      62      196362 : std::string deSerializeString(std::istream &is)
      63             : {
      64             :         char buf[2];
      65      196362 :         is.read(buf, 2);
      66      196362 :         if(is.gcount() != 2)
      67           0 :                 throw SerializationError("deSerializeString: size not read");
      68      196362 :         u16 s_size = readU16((u8*)buf);
      69      196362 :         std::string s;
      70      196362 :         if(s_size == 0)
      71       70873 :                 return s;
      72      250978 :         Buffer<char> buf2(s_size);
      73      125489 :         is.read(&buf2[0], s_size);
      74      125489 :         s.reserve(s_size);
      75      125489 :         s.append(&buf2[0], s_size);
      76      125489 :         return s;
      77             : }
      78             : 
      79             : // Reads a wide string with the length as the first two bytes
      80           0 : std::wstring deSerializeWideString(std::istream &is)
      81             : {
      82             :         char buf[2];
      83           0 :         is.read(buf, 2);
      84           0 :         if(is.gcount() != 2)
      85           0 :                 throw SerializationError("deSerializeString: size not read");
      86           0 :         u16 s_size = readU16((u8*)buf);
      87           0 :         std::wstring s;
      88           0 :         if(s_size == 0)
      89           0 :                 return s;
      90           0 :         s.reserve(s_size);
      91           0 :         for(u32 i=0; i<s_size; i++)
      92             :         {
      93           0 :                 is.read(&buf[0], 2);
      94           0 :                 wchar_t c16 = readU16((u8*)buf);
      95           0 :                 s.append(&c16, 1);
      96             :         }
      97           0 :         return s;
      98             : }
      99             : 
     100             : // Creates a string with the length as the first four bytes
     101          67 : std::string serializeLongString(const std::string &plain)
     102             : {
     103             :         char buf[4];
     104          67 :         writeU32((u8*)&buf[0], plain.size());
     105          67 :         std::string s;
     106          67 :         s.append(buf, 4);
     107          67 :         s.append(plain);
     108          67 :         return s;
     109             : }
     110             : 
     111             : // Reads a string with the length as the first four bytes
     112        4851 : std::string deSerializeLongString(std::istream &is)
     113             : {
     114             :         char buf[4];
     115        4851 :         is.read(buf, 4);
     116        4851 :         if(is.gcount() != 4)
     117           0 :                 throw SerializationError("deSerializeLongString: size not read");
     118        4851 :         u32 s_size = readU32((u8*)buf);
     119        4851 :         std::string s;
     120        4851 :         if(s_size == 0)
     121          15 :                 return s;
     122        9672 :         Buffer<char> buf2(s_size);
     123        4836 :         is.read(&buf2[0], s_size);
     124        4836 :         s.reserve(s_size);
     125        4836 :         s.append(&buf2[0], s_size);
     126        4836 :         return s;
     127             : }
     128             : 
     129             : // Creates a string encoded in JSON format (almost equivalent to a C string literal)
     130           0 : std::string serializeJsonString(const std::string &plain)
     131             : {
     132           0 :         std::ostringstream os(std::ios::binary);
     133           0 :         os<<"\"";
     134           0 :         for(size_t i = 0; i < plain.size(); i++)
     135             :         {
     136           0 :                 char c = plain[i];
     137           0 :                 switch(c)
     138             :                 {
     139           0 :                         case '"': os<<"\\\""; break;
     140           0 :                         case '\\': os<<"\\\\"; break;
     141           0 :                         case '/': os<<"\\/"; break;
     142           0 :                         case '\b': os<<"\\b"; break;
     143           0 :                         case '\f': os<<"\\f"; break;
     144           0 :                         case '\n': os<<"\\n"; break;
     145           0 :                         case '\r': os<<"\\r"; break;
     146           0 :                         case '\t': os<<"\\t"; break;
     147             :                         default:
     148             :                         {
     149           0 :                                 if(c >= 32 && c <= 126)
     150             :                                 {
     151           0 :                                         os<<c;
     152             :                                 }
     153             :                                 else
     154             :                                 {
     155           0 :                                         u32 cnum = (u32) (u8) c;
     156           0 :                                         os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
     157             :                                 }
     158           0 :                                 break;
     159             :                         }
     160             :                 }
     161             :         }
     162           0 :         os<<"\"";
     163           0 :         return os.str();
     164             : }
     165             : 
     166             : // Reads a string encoded in JSON format
     167           0 : std::string deSerializeJsonString(std::istream &is)
     168             : {
     169           0 :         std::ostringstream os(std::ios::binary);
     170             :         char c, c2;
     171             : 
     172             :         // Parse initial doublequote
     173           0 :         is >> c;
     174           0 :         if(c != '"')
     175           0 :                 throw SerializationError("JSON string must start with doublequote");
     176             : 
     177             :         // Parse characters
     178           0 :         for(;;)
     179             :         {
     180           0 :                 c = is.get();
     181           0 :                 if(is.eof())
     182           0 :                         throw SerializationError("JSON string ended prematurely");
     183           0 :                 if(c == '"')
     184             :                 {
     185           0 :                         return os.str();
     186             :                 }
     187           0 :                 else if(c == '\\')
     188             :                 {
     189           0 :                         c2 = is.get();
     190           0 :                         if(is.eof())
     191           0 :                                 throw SerializationError("JSON string ended prematurely");
     192           0 :                         switch(c2)
     193             :                         {
     194           0 :                                 default:  os<<c2; break;
     195           0 :                                 case 'b': os<<'\b'; break;
     196           0 :                                 case 'f': os<<'\f'; break;
     197           0 :                                 case 'n': os<<'\n'; break;
     198           0 :                                 case 'r': os<<'\r'; break;
     199           0 :                                 case 't': os<<'\t'; break;
     200             :                                 case 'u':
     201             :                                 {
     202             :                                         char hexdigits[4+1];
     203           0 :                                         is.read(hexdigits, 4);
     204           0 :                                         if(is.eof())
     205           0 :                                                 throw SerializationError("JSON string ended prematurely");
     206           0 :                                         hexdigits[4] = 0;
     207           0 :                                         std::istringstream tmp_is(hexdigits, std::ios::binary);
     208             :                                         int hexnumber;
     209           0 :                                         tmp_is >> std::hex >> hexnumber;
     210           0 :                                         os<<((char)hexnumber);
     211           0 :                                         break;
     212             :                                 }
     213             :                         }
     214             :                 }
     215             :                 else
     216             :                 {
     217           0 :                         os<<c;
     218             :                 }
     219             :         }
     220             :         return os.str();
     221             : }
     222             : 
     223             : 
     224           0 : bool deSerializeStringToStruct(std::string valstr,
     225             :         std::string format, void *out, size_t olen)
     226             : {
     227           0 :         size_t len = olen;
     228           0 :         std::vector<std::string *> strs_alloced;
     229             :         std::string *str;
     230             :         char *f, *snext;
     231             :         size_t pos;
     232             : 
     233           0 :         char *s = &valstr[0];
     234           0 :         char *buf = new char[len];
     235           0 :         char *bufpos = buf;
     236             : 
     237           0 :         char *fmtpos, *fmt = &format[0];
     238           0 :         while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
     239           0 :                 fmt = NULL;
     240             : 
     241           0 :                 bool is_unsigned = false;
     242           0 :                 int width = 0;
     243           0 :                 char valtype = *f;
     244             : 
     245           0 :                 width = (int)strtol(f + 1, &f, 10);
     246           0 :                 if (width && valtype == 's')
     247           0 :                         valtype = 'i';
     248             : 
     249           0 :                 switch (valtype) {
     250             :                         case 'u':
     251           0 :                                 is_unsigned = true;
     252             :                                 /* FALLTHROUGH */
     253             :                         case 'i':
     254           0 :                                 if (width == 16) {
     255           0 :                                         bufpos += PADDING(bufpos, u16);
     256           0 :                                         if ((bufpos - buf) + sizeof(u16) <= len) {
     257           0 :                                                 if (is_unsigned)
     258           0 :                                                         *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
     259             :                                                 else
     260           0 :                                                         *(s16 *)bufpos = (s16)strtol(s, &s, 10);
     261             :                                         }
     262           0 :                                         bufpos += sizeof(u16);
     263           0 :                                 } else if (width == 32) {
     264           0 :                                         bufpos += PADDING(bufpos, u32);
     265           0 :                                         if ((bufpos - buf) + sizeof(u32) <= len) {
     266           0 :                                                 if (is_unsigned)
     267           0 :                                                         *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
     268             :                                                 else
     269           0 :                                                         *(s32 *)bufpos = (s32)strtol(s, &s, 10);
     270             :                                         }
     271           0 :                                         bufpos += sizeof(u32);
     272           0 :                                 } else if (width == 64) {
     273           0 :                                         bufpos += PADDING(bufpos, u64);
     274           0 :                                         if ((bufpos - buf) + sizeof(u64) <= len) {
     275           0 :                                                 if (is_unsigned)
     276           0 :                                                         *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
     277             :                                                 else
     278           0 :                                                         *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
     279             :                                         }
     280           0 :                                         bufpos += sizeof(u64);
     281             :                                 }
     282           0 :                                 s = strchr(s, ',');
     283           0 :                                 break;
     284             :                         case 'b':
     285           0 :                                 snext = strchr(s, ',');
     286           0 :                                 if (snext)
     287           0 :                                         *snext++ = 0;
     288             : 
     289           0 :                                 bufpos += PADDING(bufpos, bool);
     290           0 :                                 if ((bufpos - buf) + sizeof(bool) <= len)
     291           0 :                                         *(bool *)bufpos = is_yes(std::string(s));
     292           0 :                                 bufpos += sizeof(bool);
     293             : 
     294           0 :                                 s = snext;
     295           0 :                                 break;
     296             :                         case 'f':
     297           0 :                                 bufpos += PADDING(bufpos, float);
     298           0 :                                 if ((bufpos - buf) + sizeof(float) <= len)
     299           0 :                                         *(float *)bufpos = strtof(s, &s);
     300           0 :                                 bufpos += sizeof(float);
     301             : 
     302           0 :                                 s = strchr(s, ',');
     303           0 :                                 break;
     304             :                         case 's':
     305           0 :                                 while (*s == ' ' || *s == '\t')
     306           0 :                                         s++;
     307           0 :                                 if (*s++ != '"') //error, expected string
     308           0 :                                         goto fail;
     309           0 :                                 snext = s;
     310             : 
     311           0 :                                 while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
     312           0 :                                         snext++;
     313           0 :                                 *snext++ = 0;
     314             : 
     315           0 :                                 bufpos += PADDING(bufpos, std::string *);
     316             : 
     317           0 :                                 str = new std::string(s);
     318           0 :                                 pos = 0;
     319           0 :                                 while ((pos = str->find("\\\"", pos)) != std::string::npos)
     320           0 :                                         str->erase(pos, 1);
     321             : 
     322           0 :                                 if ((bufpos - buf) + sizeof(std::string *) <= len)
     323           0 :                                         *(std::string **)bufpos = str;
     324           0 :                                 bufpos += sizeof(std::string *);
     325           0 :                                 strs_alloced.push_back(str);
     326             : 
     327           0 :                                 s = *snext ? snext + 1 : NULL;
     328           0 :                                 break;
     329             :                         case 'v':
     330           0 :                                 while (*s == ' ' || *s == '\t')
     331           0 :                                         s++;
     332           0 :                                 if (*s++ != '(') //error, expected vector
     333           0 :                                         goto fail;
     334             : 
     335           0 :                                 if (width == 2) {
     336           0 :                                         bufpos += PADDING(bufpos, v2f);
     337             : 
     338           0 :                                         if ((bufpos - buf) + sizeof(v2f) <= len) {
     339           0 :                                         v2f *v = (v2f *)bufpos;
     340           0 :                                                 v->X = strtof(s, &s);
     341           0 :                                                 s++;
     342           0 :                                                 v->Y = strtof(s, &s);
     343             :                                         }
     344             : 
     345           0 :                                         bufpos += sizeof(v2f);
     346           0 :                                 } else if (width == 3) {
     347           0 :                                         bufpos += PADDING(bufpos, v3f);
     348           0 :                                         if ((bufpos - buf) + sizeof(v3f) <= len) {
     349           0 :                                                 v3f *v = (v3f *)bufpos;
     350           0 :                                                 v->X = strtof(s, &s);
     351           0 :                                                 s++;
     352           0 :                                                 v->Y = strtof(s, &s);
     353           0 :                                                 s++;
     354           0 :                                                 v->Z = strtof(s, &s);
     355             :                                         }
     356             : 
     357           0 :                                         bufpos += sizeof(v3f);
     358             :                                 }
     359           0 :                                 s = strchr(s, ',');
     360           0 :                                 break;
     361             :                         default: //error, invalid format specifier
     362           0 :                                 goto fail;
     363             :                 }
     364             : 
     365           0 :                 if (s && *s == ',')
     366           0 :                         s++;
     367             : 
     368           0 :                 if ((size_t)(bufpos - buf) > len) //error, buffer too small
     369           0 :                         goto fail;
     370             :         }
     371             : 
     372           0 :         if (f && *f) { //error, mismatched number of fields and values
     373             : fail:
     374           0 :                 for (size_t i = 0; i != strs_alloced.size(); i++)
     375           0 :                         delete strs_alloced[i];
     376           0 :                 delete[] buf;
     377           0 :                 return false;
     378             :         }
     379             : 
     380           0 :         memcpy(out, buf, olen);
     381           0 :         delete[] buf;
     382           0 :         return true;
     383             : }
     384             : 
     385             : 
     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))
     388             : 
     389           0 : bool serializeStructToString(std::string *out,
     390             :         std::string format, void *value)
     391             : {
     392           0 :         std::ostringstream os;
     393           0 :         std::string str;
     394             :         char *f;
     395             :         size_t strpos;
     396             : 
     397           0 :         char *bufpos = (char *) value;
     398           0 :         char *fmtpos, *fmt = &format[0];
     399           0 :         while ((f = strtok_r(fmt, ",", &fmtpos))) {
     400           0 :                 fmt = NULL;
     401           0 :                 bool is_unsigned = false;
     402           0 :                 int width = 0;
     403           0 :                 char valtype = *f;
     404             : 
     405           0 :                 width = (int)strtol(f + 1, &f, 10);
     406           0 :                 if (width && valtype == 's')
     407           0 :                         valtype = 'i';
     408             : 
     409           0 :                 switch (valtype) {
     410             :                         case 'u':
     411           0 :                                 is_unsigned = true;
     412             :                                 /* FALLTHROUGH */
     413             :                         case 'i':
     414           0 :                                 if (width == 16) {
     415           0 :                                         bufpos += PADDING(bufpos, u16);
     416           0 :                                         os << SIGN_CAST(16, bufpos);
     417           0 :                                         bufpos += sizeof(u16);
     418           0 :                                 } else if (width == 32) {
     419           0 :                                         bufpos += PADDING(bufpos, u32);
     420           0 :                                         os << SIGN_CAST(32, bufpos);
     421           0 :                                         bufpos += sizeof(u32);
     422           0 :                                 } else if (width == 64) {
     423           0 :                                         bufpos += PADDING(bufpos, u64);
     424           0 :                                         os << SIGN_CAST(64, bufpos);
     425           0 :                                         bufpos += sizeof(u64);
     426             :                                 }
     427           0 :                                 break;
     428             :                         case 'b':
     429           0 :                                 bufpos += PADDING(bufpos, bool);
     430           0 :                                 os << std::boolalpha << *((bool *) bufpos);
     431           0 :                                 bufpos += sizeof(bool);
     432           0 :                                 break;
     433             :                         case 'f':
     434           0 :                                 bufpos += PADDING(bufpos, float);
     435           0 :                                 os << *((float *) bufpos);
     436           0 :                                 bufpos += sizeof(float);
     437           0 :                                 break;
     438             :                         case 's':
     439           0 :                                 bufpos += PADDING(bufpos, std::string *);
     440           0 :                                 str = **((std::string **) bufpos);
     441             : 
     442           0 :                                 strpos = 0;
     443           0 :                                 while ((strpos = str.find('"', strpos)) != std::string::npos) {
     444           0 :                                         str.insert(strpos, 1, '\\');
     445           0 :                                         strpos += 2;
     446             :                                 }
     447             : 
     448           0 :                                 os << str;
     449           0 :                                 bufpos += sizeof(std::string *);
     450           0 :                                 break;
     451             :                         case 'v':
     452           0 :                                 if (width == 2) {
     453           0 :                                         bufpos += PADDING(bufpos, v2f);
     454           0 :                                         v2f *v = (v2f *) bufpos;
     455           0 :                                         os << '(' << v->X << ", " << v->Y << ')';
     456           0 :                                         bufpos += sizeof(v2f);
     457             :                                 } else {
     458           0 :                                         bufpos += PADDING(bufpos, v3f);
     459           0 :                                         v3f *v = (v3f *) bufpos;
     460           0 :                                         os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
     461           0 :                                         bufpos += sizeof(v3f);
     462             :                                 }
     463           0 :                                 break;
     464             :                         default:
     465           0 :                                 return false;
     466             :                 }
     467           0 :                 os << ", ";
     468             :         }
     469           0 :         *out = os.str();
     470             : 
     471             :         // Trim off the trailing comma and space
     472           0 :         if (out->size() >= 2) {
     473           0 :                 out->resize(out->size() - 2);
     474             :         }
     475             : 
     476           0 :         return true;
     477           3 : }
     478             : 
     479             : #undef SIGN_CAST

Generated by: LCOV version 1.11