Luanti 5.18.0-dev
Loading...
Searching...
No Matches
serialize.h
Go to the documentation of this file.
1// Luanti
2// SPDX-License-Identifier: LGPL-2.1-or-later
3// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5#pragma once
6
8#include "exceptions.h" // for SerializationError
9#include "ieee_float.h"
10
11#include "config.h"
12#include <cstring> // for memcpy
13#include <cassert>
14#include <iostream>
15#include <string>
16#include <vector>
17#include <string_view>
18
19/* make sure BYTE_ORDER macros are available */
20#if HAVE_ENDIAN_H
21 #include <endian.h>
22#elif defined(_WIN32)
23 #define BYTE_ORDER 1234
24#elif defined(__MACH__) && defined(__APPLE__)
25 #include <machine/endian.h>
26#elif defined(__FreeBSD__) || defined(__DragonFly__)
27 #include <sys/endian.h>
28#else
29 #error "Can't detect endian (missing header)"
30#endif
31#ifndef LITTLE_ENDIAN
32 #define LITTLE_ENDIAN 1234
33#endif
34#ifndef BIG_ENDIAN
35 #define BIG_ENDIAN 4321
36#endif
37#if !defined(BYTE_ORDER) && defined(_BYTE_ORDER)
38 #define BYTE_ORDER _BYTE_ORDER
39#elif !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
40 #define BYTE_ORDER __BYTE_ORDER
41#endif
42
43#define FIXEDPOINT_FACTOR 1000.0f
44
45// 0x7FFFFFFF / 1000.0f is not serializable.
46// The limited float precision at this magnitude may cause the result to round
47// to a greater value than can be represented by a 32 bit integer when increased
48// by a factor of FIXEDPOINT_FACTOR. As a result, [F1000_MIN..F1000_MAX] does
49// not represent the full range, but rather the largest safe range, of values on
50// all supported architectures. Note: This definition makes assumptions on
51// platform float-to-int conversion behavior.
52static constexpr float F1000_MIN = (s32)((float)(S32_MIN) / FIXEDPOINT_FACTOR);
53static constexpr float F1000_MAX = (s32)((float)(S32_MAX) / FIXEDPOINT_FACTOR);
54
55#define STRING_MAX_LEN 0xFFFF
56#define WIDE_STRING_MAX_LEN 0xFFFF
57// 64 MB ought to be enough for anybody - Billy G.
58#define LONG_STRING_MAX_LEN (64 * 1024 * 1024)
59
60
62
63#if HAVE_ENDIAN_H
64// use machine native byte swapping routines
65// Note: memcpy below is optimized out by modern compilers
66
67inline u16 readU16(const u8 *data)
68{
69 u16 val;
70 memcpy(&val, data, 2);
71 return be16toh(val);
72}
73
74inline u32 readU32(const u8 *data)
75{
76 u32 val;
77 memcpy(&val, data, 4);
78 return be32toh(val);
79}
80
81inline u64 readU64(const u8 *data)
82{
83 u64 val;
84 memcpy(&val, data, 8);
85 return be64toh(val);
86}
87
88inline void writeU16(u8 *data, u16 i)
89{
90 u16 val = htobe16(i);
91 memcpy(data, &val, 2);
92}
93
94inline void writeU32(u8 *data, u32 i)
95{
96 u32 val = htobe32(i);
97 memcpy(data, &val, 4);
98}
99
100inline void writeU64(u8 *data, u64 i)
101{
102 u64 val = htobe64(i);
103 memcpy(data, &val, 8);
104}
105
106#else
107// generic byte-swapping implementation
108
109inline u16 readU16(const u8 *data)
110{
111 return
112 ((u16)data[0] << 8) | ((u16)data[1] << 0);
113}
114
115inline u32 readU32(const u8 *data)
116{
117 return
118 ((u32)data[0] << 24) | ((u32)data[1] << 16) |
119 ((u32)data[2] << 8) | ((u32)data[3] << 0);
120}
121
122inline u64 readU64(const u8 *data)
123{
124 return
125 ((u64)data[0] << 56) | ((u64)data[1] << 48) |
126 ((u64)data[2] << 40) | ((u64)data[3] << 32) |
127 ((u64)data[4] << 24) | ((u64)data[5] << 16) |
128 ((u64)data[6] << 8) | ((u64)data[7] << 0);
129}
130
131inline void writeU16(u8 *data, u16 i)
132{
133 data[0] = (i >> 8) & 0xFF;
134 data[1] = (i >> 0) & 0xFF;
135}
136
137inline void writeU32(u8 *data, u32 i)
138{
139 data[0] = (i >> 24) & 0xFF;
140 data[1] = (i >> 16) & 0xFF;
141 data[2] = (i >> 8) & 0xFF;
142 data[3] = (i >> 0) & 0xFF;
143}
144
145inline void writeU64(u8 *data, u64 i)
146{
147 data[0] = (i >> 56) & 0xFF;
148 data[1] = (i >> 48) & 0xFF;
149 data[2] = (i >> 40) & 0xFF;
150 data[3] = (i >> 32) & 0xFF;
151 data[4] = (i >> 24) & 0xFF;
152 data[5] = (i >> 16) & 0xFF;
153 data[6] = (i >> 8) & 0xFF;
154 data[7] = (i >> 0) & 0xFF;
155}
156
157#endif // HAVE_ENDIAN_H
158
160
161inline u8 readU8(const u8 *data)
162{
163 return data[0];
164}
165
166inline s8 readS8(const u8 *data)
167{
168 return (s8)readU8(data);
169}
170
171inline s16 readS16(const u8 *data)
172{
173 return (s16)readU16(data);
174}
175
176inline s32 readS32(const u8 *data)
177{
178 return (s32)readU32(data);
179}
180
181inline s64 readS64(const u8 *data)
182{
183 return (s64)readU64(data);
184}
185
186inline f32 readF1000(const u8 *data)
187{
188 return (f32)readS32(data) / FIXEDPOINT_FACTOR;
189}
190
191inline f32 readF32(const u8 *data)
192{
193 u32 u = readU32(data);
194
195 switch (g_serialize_f32_type) {
196 case FLOATTYPE_SYSTEM: {
197 f32 f;
198 memcpy(&f, &u, 4);
199 return f;
200 }
201 case FLOATTYPE_SLOW:
202 return u32Tof32Slow(u);
203 case FLOATTYPE_UNKNOWN: // First initialization
205 return readF32(data);
206 }
207 throw SerializationError("readF32: Unreachable code");
208}
209
210inline video::SColor readARGB8(const u8 *data)
211{
212 video::SColor p(readU32(data));
213 return p;
214}
215
216inline v2s16 readV2S16(const u8 *data)
217{
218 v2s16 p;
219 p.X = readS16(&data[0]);
220 p.Y = readS16(&data[2]);
221 return p;
222}
223
224inline v3s16 readV3S16(const u8 *data)
225{
226 v3s16 p;
227 p.X = readS16(&data[0]);
228 p.Y = readS16(&data[2]);
229 p.Z = readS16(&data[4]);
230 return p;
231}
232
233inline v2s32 readV2S32(const u8 *data)
234{
235 v2s32 p;
236 p.X = readS32(&data[0]);
237 p.Y = readS32(&data[4]);
238 return p;
239}
240
241inline v3s32 readV3S32(const u8 *data)
242{
243 v3s32 p;
244 p.X = readS32(&data[0]);
245 p.Y = readS32(&data[4]);
246 p.Z = readS32(&data[8]);
247 return p;
248}
249
250inline v3f readV3F1000(const u8 *data)
251{
252 v3f p;
253 p.X = readF1000(&data[0]);
254 p.Y = readF1000(&data[4]);
255 p.Z = readF1000(&data[8]);
256 return p;
257}
258
259inline v2f readV2F32(const u8 *data)
260{
261 v2f p;
262 p.X = readF32(&data[0]);
263 p.Y = readF32(&data[4]);
264 return p;
265}
266
267inline v3f readV3F32(const u8 *data)
268{
269 v3f p;
270 p.X = readF32(&data[0]);
271 p.Y = readF32(&data[4]);
272 p.Z = readF32(&data[8]);
273 return p;
274}
275
277
278inline void writeU8(u8 *data, u8 i)
279{
280 data[0] = i;
281}
282
283inline void writeS8(u8 *data, s8 i)
284{
285 writeU8(data, (u8)i);
286}
287
288inline void writeS16(u8 *data, s16 i)
289{
290 writeU16(data, (u16)i);
291}
292
293inline void writeS32(u8 *data, s32 i)
294{
295 writeU32(data, (u32)i);
296}
297
298inline void writeS64(u8 *data, s64 i)
299{
300 writeU64(data, (u64)i);
301}
302
303inline void writeF1000(u8 *data, f32 i)
304{
305 assert(i >= F1000_MIN && i <= F1000_MAX);
306 writeS32(data, i * FIXEDPOINT_FACTOR);
307}
308
309inline void writeF32(u8 *data, f32 i)
310{
311 switch (g_serialize_f32_type) {
312 case FLOATTYPE_SYSTEM: {
313 u32 u;
314 memcpy(&u, &i, 4);
315 return writeU32(data, u);
316 }
317 case FLOATTYPE_SLOW:
318 return writeU32(data, f32Tou32Slow(i));
319 case FLOATTYPE_UNKNOWN: // First initialization
321 return writeF32(data, i);
322 }
323 throw SerializationError("writeF32: Unreachable code");
324}
325
326inline void writeARGB8(u8 *data, video::SColor p)
327{
328 writeU32(data, p.color);
329}
330
331inline void writeV2S16(u8 *data, v2s16 p)
332{
333 writeS16(&data[0], p.X);
334 writeS16(&data[2], p.Y);
335}
336
337inline void writeV3S16(u8 *data, v3s16 p)
338{
339 writeS16(&data[0], p.X);
340 writeS16(&data[2], p.Y);
341 writeS16(&data[4], p.Z);
342}
343
344inline void writeV2S32(u8 *data, v2s32 p)
345{
346 writeS32(&data[0], p.X);
347 writeS32(&data[4], p.Y);
348}
349
350inline void writeV3S32(u8 *data, v3s32 p)
351{
352 writeS32(&data[0], p.X);
353 writeS32(&data[4], p.Y);
354 writeS32(&data[8], p.Z);
355}
356
357inline void writeV3F1000(u8 *data, v3f p)
358{
359 writeF1000(&data[0], p.X);
360 writeF1000(&data[4], p.Y);
361 writeF1000(&data[8], p.Z);
362}
363
364inline void writeV2F32(u8 *data, v2f p)
365{
366 writeF32(&data[0], p.X);
367 writeF32(&data[4], p.Y);
368}
369
370inline void writeV3F32(u8 *data, v3f p)
371{
372 writeF32(&data[0], p.X);
373 writeF32(&data[4], p.Y);
374 writeF32(&data[8], p.Z);
375}
376
380
381inline bool canRead(std::istream &is)
382{
383 return is.peek() != EOF;
384}
385
386// Assuming -O3 on GCC 14.2.0, this function results in 55% less machine code
387// generated for the `is.eof()` branch in `MAKE_STREAM_READ_FXN`.
389{
390 throw SerializationError("EOF");
391}
392
393#define MAKE_STREAM_READ_FXN(T, N, S) \
394 inline T read ## N(std::istream &is) \
395 { \
396 char buf[S] = {0}; \
397 is.read(buf, sizeof(buf)); \
398 if (is.eof()) \
399 serialize_throw_eof(); \
400 return read ## N((u8 *)buf); \
401 }
402
403#define MAKE_STREAM_WRITE_FXN(T, N, S) \
404 inline void write ## N(std::ostream &os, T val) \
405 { \
406 char buf[S]; \
407 write ## N((u8 *)buf, val); \
408 os.write(buf, sizeof(buf)); \
409 }
410
419MAKE_STREAM_READ_FXN(f32, F1000, 4);
428MAKE_STREAM_READ_FXN(video::SColor, ARGB8, 4);
429
447MAKE_STREAM_WRITE_FXN(video::SColor, ARGB8, 4);
448
452
453[[nodiscard]] inline float clampToF1000(float v)
454{
455 return core::clamp(v, F1000_MIN, F1000_MAX);
456}
457
458[[nodiscard]] inline v3f clampToF1000(v3f v)
459{
460 return {clampToF1000(v.X), clampToF1000(v.Y), clampToF1000(v.Z)};
461}
462
463// Creates a string with the length as the first two bytes
464std::string serializeString16(std::string_view plain);
465
466// Reads a string with the length as the first two bytes
467std::string deSerializeString16(std::istream &is);
468
469// Creates a string with the length as the first four bytes
470std::string serializeString32(std::string_view plain);
471
472// Reads a string with the length as the first four bytes
473std::string deSerializeString32(std::istream &is);
474
475// Creates a string encoded in JSON format (almost equivalent to a C string literal)
476std::string serializeJsonString(std::string_view plain);
477
478// Reads a string encoded in JSON format
479std::string deSerializeJsonString(std::istream &is);
480
481// If the string contains spaces, quotes or control characters, encodes as JSON.
482// Else returns the string unmodified.
483std::string serializeJsonStringIfNeeded(std::string_view s);
484
485// Parses a string serialized by serializeJsonStringIfNeeded.
486std::string deSerializeJsonStringIfNeeded(std::istream &is);
487
488// Serializes an array of strings (max 2^16 chars each)
489// Output is well suited for compression :)
490std::string serializeString16Array(const std::vector<std::string> &array);
491
492// Deserializes a string array
493std::vector<std::string> deserializeString16Array(std::istream &is);
Definition exceptions.h:51
u32 f32Tou32Slow(f32 f)
Definition ieee_float.cpp:64
FloatType getFloatSerializationType()
Definition ieee_float.cpp:95
f32 u32Tof32Slow(u32 i)
Definition ieee_float.cpp:35
FloatType
Definition ieee_float.h:10
@ FLOATTYPE_UNKNOWN
Definition ieee_float.h:11
@ FLOATTYPE_SLOW
Definition ieee_float.h:12
@ FLOATTYPE_SYSTEM
Definition ieee_float.h:13
core::vector2d< s32 > v2s32
Definition irr_v2d.h:13
core::vector2d< s16 > v2s16
Definition irr_v2d.h:12
core::vector2d< f32 > v2f
Definition irr_v2d.h:11
core::vector3d< s32 > v3s32
Definition irr_v3d.h:15
core::vector3d< s16 > v3s16
Definition irr_v3d.h:13
core::vector3df v3f
Definition irr_v3d.h:11
#define S32_MAX
Definition irrlichttypes.h:18
#define S32_MIN
Definition irrlichttypes.h:13
FloatType g_serialize_f32_type
Definition serialize.cpp:15
std::string serializeJsonStringIfNeeded(std::string_view s)
Definition serialize.cpp:313
v2s16 readV2S16(const u8 *data)
Definition serialize.h:216
void writeU16(u8 *data, u16 i)
Definition serialize.h:131
u32 readU32(const u8 *data)
Definition serialize.h:115
void writeV3S16(u8 *data, v3s16 p)
Definition serialize.h:337
std::string deSerializeJsonString(std::istream &is)
Definition serialize.cpp:282
v2s32 readV2S32(const u8 *data)
Definition serialize.h:233
void writeF1000(u8 *data, f32 i)
Definition serialize.h:303
void writeS16(u8 *data, s16 i)
Definition serialize.h:288
s64 readS64(const u8 *data)
Definition serialize.h:181
#define FIXEDPOINT_FACTOR
Definition serialize.h:43
void writeV2F32(u8 *data, v2f p)
Definition serialize.h:364
void writeF32(u8 *data, f32 i)
Definition serialize.h:309
std::string serializeString16Array(const std::vector< std::string > &array)
Definition serialize.cpp:112
std::vector< std::string > deserializeString16Array(std::istream &is)
Definition serialize.cpp:142
void writeU64(u8 *data, u64 i)
Definition serialize.h:145
static void serialize_throw_eof()
Definition serialize.h:388
s32 readS32(const u8 *data)
Definition serialize.h:176
std::string deSerializeString32(std::istream &is)
Definition serialize.cpp:81
u8 readU8(const u8 *data)
Definition serialize.h:161
void writeV2S32(u8 *data, v2s32 p)
Definition serialize.h:344
video::SColor readARGB8(const u8 *data)
Definition serialize.h:210
std::string deSerializeJsonStringIfNeeded(std::istream &is)
Definition serialize.cpp:322
v3f readV3F1000(const u8 *data)
Definition serialize.h:250
v3s16 readV3S16(const u8 *data)
Definition serialize.h:224
void writeV2S16(u8 *data, v2s16 p)
Definition serialize.h:331
f32 readF32(const u8 *data)
Definition serialize.h:191
f32 readF1000(const u8 *data)
Definition serialize.h:186
void writeARGB8(u8 *data, video::SColor p)
Definition serialize.h:326
std::string serializeJsonString(std::string_view plain)
Definition serialize.cpp:173
#define MAKE_STREAM_READ_FXN(T, N, S)
Definition serialize.h:393
u64 readU64(const u8 *data)
Definition serialize.h:122
void writeU32(u8 *data, u32 i)
Definition serialize.h:137
void writeV3F32(u8 *data, v3f p)
Definition serialize.h:370
bool canRead(std::istream &is)
Definition serialize.h:381
std::string serializeString16(std::string_view plain)
Definition serialize.cpp:22
void writeS8(u8 *data, s8 i)
Definition serialize.h:283
std::string deSerializeString16(std::istream &is)
Definition serialize.cpp:39
void writeV3S32(u8 *data, v3s32 p)
Definition serialize.h:350
static constexpr float F1000_MAX
Definition serialize.h:53
std::string serializeString32(std::string_view plain)
Definition serialize.cpp:65
u16 readU16(const u8 *data)
Definition serialize.h:109
v2f readV2F32(const u8 *data)
Definition serialize.h:259
float clampToF1000(float v)
Definition serialize.h:453
v3s32 readV3S32(const u8 *data)
Definition serialize.h:241
void writeV3F1000(u8 *data, v3f p)
Definition serialize.h:357
#define MAKE_STREAM_WRITE_FXN(T, N, S)
Definition serialize.h:403
void writeU8(u8 *data, u8 i)
Definition serialize.h:278
v3f readV3F32(const u8 *data)
Definition serialize.h:267
void writeS32(u8 *data, s32 i)
Definition serialize.h:293
s8 readS8(const u8 *data)
Definition serialize.h:166
s16 readS16(const u8 *data)
Definition serialize.h:171
static constexpr float F1000_MIN
Definition serialize.h:52
void writeS64(u8 *data, s64 i)
Definition serialize.h:298
static std::string p(std::string path)
Definition test_filesys.cpp:73