]> git.lizzy.rs Git - dragonfireclient.git/blob - src/util/serialize.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[dragonfireclient.git] / src / util / serialize.cpp
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 "../exceptions.h"
23
24 #include <sstream>
25 #include <iomanip>
26
27 // Creates a string with the length as the first two bytes
28 std::string serializeString(const std::string &plain)
29 {
30         //assert(plain.size() <= 65535);
31         if(plain.size() > 65535)
32                 throw SerializationError("String too long for serializeString");
33         char buf[2];
34         writeU16((u8*)&buf[0], plain.size());
35         std::string s;
36         s.append(buf, 2);
37         s.append(plain);
38         return s;
39 }
40
41 // Creates a string with the length as the first two bytes from wide string
42 std::string serializeWideString(const std::wstring &plain)
43 {
44         //assert(plain.size() <= 65535);
45         if(plain.size() > 65535)
46                 throw SerializationError("String too long for serializeString");
47         char buf[2];
48         writeU16((u8*)buf, plain.size());
49         std::string s;
50         s.append(buf, 2);
51         for(u32 i=0; i<plain.size(); i++)
52         {
53                 writeU16((u8*)buf, plain[i]);
54                 s.append(buf, 2);
55         }
56         return s;
57 }
58
59 // Reads a string with the length as the first two bytes
60 std::string deSerializeString(std::istream &is)
61 {
62         char buf[2];
63         is.read(buf, 2);
64         if(is.gcount() != 2)
65                 throw SerializationError("deSerializeString: size not read");
66         u16 s_size = readU16((u8*)buf);
67         if(s_size == 0)
68                 return "";
69         Buffer<char> buf2(s_size);
70         is.read(&buf2[0], s_size);
71         std::string s;
72         s.reserve(s_size);
73         s.append(&buf2[0], s_size);
74         return s;
75 }
76
77 // Reads a wide string with the length as the first two bytes
78 std::wstring deSerializeWideString(std::istream &is)
79 {
80         char buf[2];
81         is.read(buf, 2);
82         if(is.gcount() != 2)
83                 throw SerializationError("deSerializeString: size not read");
84         u16 s_size = readU16((u8*)buf);
85         if(s_size == 0)
86                 return L"";
87         std::wstring s;
88         s.reserve(s_size);
89         for(u32 i=0; i<s_size; i++)
90         {
91                 is.read(&buf[0], 2);
92                 wchar_t c16 = readU16((u8*)buf);
93                 s.append(&c16, 1);
94         }
95         return s;
96 }
97
98 // Creates a string with the length as the first four bytes
99 std::string serializeLongString(const std::string &plain)
100 {
101         char buf[4];
102         writeU32((u8*)&buf[0], plain.size());
103         std::string s;
104         s.append(buf, 4);
105         s.append(plain);
106         return s;
107 }
108
109 // Reads a string with the length as the first four bytes
110 std::string deSerializeLongString(std::istream &is)
111 {
112         char buf[4];
113         is.read(buf, 4);
114         if(is.gcount() != 4)
115                 throw SerializationError("deSerializeLongString: size not read");
116         u32 s_size = readU32((u8*)buf);
117         if(s_size == 0)
118                 return "";
119         Buffer<char> buf2(s_size);
120         is.read(&buf2[0], s_size);
121         std::string s;
122         s.reserve(s_size);
123         s.append(&buf2[0], s_size);
124         return s;
125 }
126
127 // Creates a string encoded in JSON format (almost equivalent to a C string literal)
128 std::string serializeJsonString(const std::string &plain)
129 {
130         std::ostringstream os(std::ios::binary);
131         os<<"\"";
132         for(size_t i = 0; i < plain.size(); i++)
133         {
134                 char c = plain[i];
135                 switch(c)
136                 {
137                         case '"': os<<"\\\""; break;
138                         case '\\': os<<"\\\\"; break;
139                         case '/': os<<"\\/"; break;
140                         case '\b': os<<"\\b"; break;
141                         case '\f': os<<"\\f"; break;
142                         case '\n': os<<"\\n"; break;
143                         case '\r': os<<"\\r"; break;
144                         case '\t': os<<"\\t"; break;
145                         default:
146                         {
147                                 if(c >= 32 && c <= 126)
148                                 {
149                                         os<<c;
150                                 }
151                                 else
152                                 {
153                                         u32 cnum = (u32) (u8) c;
154                                         os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
155                                 }
156                                 break;
157                         }
158                 }
159         }
160         os<<"\"";
161         return os.str();
162 }
163
164 // Reads a string encoded in JSON format
165 std::string deSerializeJsonString(std::istream &is)
166 {
167         std::ostringstream os(std::ios::binary);
168         char c, c2;
169
170         // Parse initial doublequote
171         is >> c;
172         if(c != '"')
173                 throw SerializationError("JSON string must start with doublequote");
174
175         // Parse characters
176         for(;;)
177         {
178                 c = is.get();
179                 if(is.eof())
180                         throw SerializationError("JSON string ended prematurely");
181                 if(c == '"')
182                 {
183                         return os.str();
184                 }
185                 else if(c == '\\')
186                 {
187                         c2 = is.get();
188                         if(is.eof())
189                                 throw SerializationError("JSON string ended prematurely");
190                         switch(c2)
191                         {
192                                 default:  os<<c2; break;
193                                 case 'b': os<<'\b'; break;
194                                 case 'f': os<<'\f'; break;
195                                 case 'n': os<<'\n'; break;
196                                 case 'r': os<<'\r'; break;
197                                 case 't': os<<'\t'; break;
198                                 case 'u':
199                                 {
200                                         char hexdigits[4+1];
201                                         is.read(hexdigits, 4);
202                                         if(is.eof())
203                                                 throw SerializationError("JSON string ended prematurely");
204                                         hexdigits[4] = 0;
205                                         std::istringstream tmp_is(hexdigits, std::ios::binary);
206                                         int hexnumber;
207                                         tmp_is >> std::hex >> hexnumber;
208                                         os<<((char)hexnumber);
209                                         break;
210                                 }
211                         }
212                 }
213                 else
214                 {
215                         os<<c;
216                 }
217         }
218         return os.str();
219 }
220
221