1 #ifndef LOADSAVEDATA_H 2 #define LOADSAVEDATA_H 3 4 #include "Types.h" 5 #include "IEncodingCorrector.h" 6 7 #include <string_theory/string> 8 9 #include <algorithm> 10 #include <type_traits> 11 12 13 //////////////////////////////////////////////////////////////////////////// 14 // DataWriter 15 //////////////////////////////////////////////////////////////////////////// 16 17 18 /** Class for serializing data. 19 * Assumes the endianess is correct. */ 20 class DataWriter 21 { 22 private: 23 DataWriter(const DataWriter&) = delete; // no copy 24 DataWriter& operator=(const DataWriter&) = delete; // no assign 25 public: 26 /** Constructor. 27 * @param buf Pointer to the buffer for writing data. */ 28 explicit DataWriter(uint8_t* buf); 29 30 /** Write UTF-8 encoded string. 31 * @param str String to write 32 * @param numChars Number of `char` characters to write. */ 33 void writeUTF8(const ST::string& str, size_t numChars); 34 35 /** Write UTF-16 encoded string. 36 * @param str String to write 37 * @param numChars Number of `char16_t` characters to write. */ 38 void writeUTF16(const ST::string& str, size_t numChars); 39 40 /** Write UTF-32 encoded string. 41 * @param str String to write 42 * @param numChars Number of `char32_t` characters to write. */ 43 void writeUTF32(const ST::string& str, size_t numChars); 44 45 void writeU8 (uint8_t value); /**< Write uint8_t */ 46 void writeU16(uint16_t value); /**< Write uint16_t */ 47 void writeU32(uint32_t value); /**< Write uint32_t */ 48 49 /* Write a value. */ 50 template<typename T> write(const T & value)51 void write(const T& value) 52 { 53 static_assert(std::is_trivially_copyable<T>::value, "memcpy requires a trivially copyable type"); 54 size_t numBytes = sizeof(T); 55 memcpy(m_buf, &value, numBytes); 56 move(numBytes); 57 } 58 59 /* Write an array of values. */ 60 template<typename T> writeArray(const T * arr,size_t len)61 void writeArray(const T* arr, size_t len) 62 { 63 static_assert(std::is_trivially_copyable<T>::value, "memcpy requires a trivially copyable type"); 64 size_t numBytes = len * sizeof(T); 65 memcpy(m_buf, arr, numBytes); 66 move(numBytes); 67 } 68 69 /* Write zeroed bytes. */ 70 void skip(size_t numBytes); 71 72 /** Get number of the consumed bytes during writing. */ 73 size_t getConsumed() const; 74 75 protected: 76 uint8_t* m_buf; 77 uint8_t* m_original; 78 79 /** Move pointer to \a numBytes bytes forward. */ 80 void move(size_t numBytes); 81 }; 82 83 84 //////////////////////////////////////////////////////////////////////////// 85 // DataReader 86 //////////////////////////////////////////////////////////////////////////// 87 88 89 /** Class for reading serializing data. 90 * Assumes the endianess is correct. */ 91 class DataReader 92 { 93 private: 94 DataReader(const DataReader&) = delete; // no copy 95 DataReader& operator=(const DataReader&) = delete; // no assign 96 public: 97 /** Constructor. 98 * @param buf Pointer to the buffer for writing data. */ 99 explicit DataReader(const uint8_t* buf); 100 101 /** Read UTF-8 encoded string. 102 * @param numChars Number of `char` characters to read. 103 * @param validation What happens with invalid character sequences. */ 104 ST::string readUTF8(size_t numChars, ST::utf_validation_t validation = ST_DEFAULT_VALIDATION); 105 106 /** Read UTF-16 encoded string. 107 * @param numChars Number of `char16_t` characters to read. 108 * @param fixer Optional encoding corrector. It is used for fixing incorrectly encoded text. 109 * @param validation What happens with invalid character sequences. */ 110 ST::string readUTF16(size_t numChars, const IEncodingCorrector* fixer = nullptr, ST::utf_validation_t validation = ST_DEFAULT_VALIDATION); 111 112 /** Read UTF-32 encoded string. 113 * @param numChars Number of `char32_t` characters to read. 114 * @param validation What happens with invalid character sequences. */ 115 ST::string readUTF32(size_t numChars, ST::utf_validation_t validation = ST_DEFAULT_VALIDATION); 116 117 uint8_t readU8(); /**< Read uint8_t */ 118 uint16_t readU16(); /**< Read uint16_t */ 119 uint32_t readU32(); /**< Read uint32_t */ 120 121 /* Read raw bytes. */ 122 void readBytes(uint8_t* bytes, size_t numBytes); 123 124 /* Read a value. */ 125 template<typename T> read()126 T read() 127 { 128 static_assert(std::is_trivially_copyable<T>::value, "memcpy requires a trivially copyable type"); 129 size_t numBytes = sizeof(T); 130 T value; 131 memcpy(&value, m_buf, numBytes); 132 move(numBytes); 133 return value; 134 } 135 136 /* Read an array of values. */ 137 template<typename T> readArray(T * arr,size_t len)138 void readArray(T* arr, size_t len) 139 { 140 static_assert(std::is_trivially_copyable<T>::value, "memcpy requires a trivially copyable type"); 141 size_t numBytes = len * sizeof(T); 142 memcpy(arr, m_buf, numBytes); 143 move(numBytes); 144 } 145 146 /* Read and discard bytes. */ 147 void skip(size_t numBytes); 148 149 /** Get number of the consumed bytes during reading. */ 150 size_t getConsumed() const; 151 152 protected: 153 const uint8_t* m_buf; 154 const uint8_t* m_original; 155 156 /** Move pointer to \a numBytes bytes forward. */ 157 void move(size_t numBytes); 158 }; 159 160 161 #define INJ_STR(D, S, Size) (D).writeArray<char>((S), (Size)); 162 #define INJ_BOOLA(D, S, Size) (D).writeArray<BOOLEAN>((S), (Size)); 163 #define INJ_I8A(D, S, Size) (D).writeArray<INT8>((S), (Size)); 164 #define INJ_U8A(D, S, Size) (D).writeArray<UINT8>((S), (Size)); 165 #define INJ_I16A(D, S, Size) (D).writeArray<INT16>((S), (Size)); 166 #define INJ_U16A(D, S, Size) (D).writeArray<UINT16>((S), (Size)); 167 #define INJ_I32A(D, S, Size) (D).writeArray<INT32>((S), (Size)); 168 #define INJ_BOOL(D, S) (D).write<BOOLEAN>((S)); 169 #define INJ_BYTE(D, S) (D).write<BYTE>((S)); 170 #define INJ_I8(D, S) (D).write<INT8>((S)); 171 #define INJ_U8(D, S) (D).write<UINT8>((S)); 172 #define INJ_I16(D, S) (D).write<INT16>((S)); 173 #define INJ_U16(D, S) (D).write<UINT16>((S)); 174 #define INJ_I32(D, S) (D).write<INT32>((S)); 175 #define INJ_U32(D, S) (D).write<UINT32>((S)); 176 #define INJ_FLOAT(D, S) (D).write<FLOAT>((S)); 177 #define INJ_DOUBLE(D, S) (D).write<DOUBLE>((S)); 178 #define INJ_PTR(D, S) INJ_SKIP(D, 4) 179 #define INJ_SKIP(D, Size) (D).skip((Size)); 180 #define INJ_SKIP_I16(D) (D).skip(2); 181 #define INJ_SKIP_I32(D) (D).skip(4); 182 #define INJ_SKIP_U8(D) (D).skip(1); 183 #define INJ_SOLDIER(D, S) (D).write<SoldierID>(Soldier2ID((S))); 184 #define INJ_VEC3(D, S) INJ_FLOAT(D, (S).x); INJ_FLOAT(D, (S).y); INJ_FLOAT(D, (S).z); 185 186 #define EXTR_STR(S, D, Size) (S).readArray<char>((D), (Size)); 187 #define EXTR_BOOLA(S, D, Size) (S).readArray<BOOLEAN>((D), (Size)); 188 #define EXTR_I8A(S, D, Size) (S).readArray<INT8>((D), (Size)); 189 #define EXTR_U8A(S, D, Size) (S).readArray<UINT8>((D), (Size)); 190 #define EXTR_I16A(S, D, Size) (S).readArray<INT16>((D), (Size)); 191 #define EXTR_U16A(S, D, Size) (S).readArray<UINT16>((D), (Size)); 192 #define EXTR_I32A(S, D, Size) (S).readArray<INT32>((D), (Size)); 193 #define EXTR_BOOL(S, D) (D) = (S).read<BOOLEAN>(); 194 #define EXTR_BYTE(S, D) (D) = (S).read<BYTE>(); 195 #define EXTR_I8(S, D) (D) = (S).read<INT8>(); 196 #define EXTR_U8(S, D) (D) = (S).read<UINT8>(); 197 #define EXTR_I16(S, D) (D) = (S).read<INT16>(); 198 #define EXTR_U16(S, D) (D) = (S).read<UINT16>(); 199 #define EXTR_I32(S, D) (D) = (S).read<INT32>(); 200 #define EXTR_U32(S, D) (D) = (S).read<UINT32>(); 201 #define EXTR_FLOAT(S, D) (D) = (S).read<FLOAT>(); 202 #define EXTR_DOUBLE(S, D) (D) = (S).read<DOUBLE>(); 203 #define EXTR_PTR(S, D) (D) = NULL; (S).skip(4); 204 #define EXTR_SKIP(S, Size) (S).skip((Size)); 205 #define EXTR_SKIP_I16(S) (S).skip(2); 206 #define EXTR_SKIP_I32(S) (S).skip(4); 207 #define EXTR_SKIP_U8(S) (S).skip(1); 208 #define EXTR_SOLDIER(S, D) (D) = ID2Soldier((S).read<SoldierID>()); 209 #define EXTR_VEC3(S, D) EXTR_FLOAT(S, (D).x); EXTR_FLOAT(S, (D).y); EXTR_FLOAT(S, (D).z); 210 211 #endif 212