xoreos  0.0.5
endianness.h
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on ScummVM (<http://scummvm.org>) code, which is released
26  * under the terms of version 2 or later of the GNU General Public
27  * License.
28  *
29  * The original copyright note in ScummVM reads as follows:
30  *
31  * ScummVM is the legal property of its developers, whose names
32  * are too numerous to list here. Please refer to the COPYRIGHT
33  * file distributed with this source distribution.
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
48  */
49 
50 #ifndef COMMON_ENDIAN_H
51 #define COMMON_ENDIAN_H
52 
53 #include "src/common/system.h"
54 #include "src/common/types.h"
55 
56 // Sanity check
57 #if !defined(XOREOS_LITTLE_ENDIAN) && !defined(XOREOS_BIG_ENDIAN)
58  #error No endianness defined
59 #endif
60 
61 #define SWAP_CONSTANT_64(a) \
62  ((uint64)((((a) >> 56) & 0x000000FF) | \
63  (((a) >> 40) & 0x0000FF00) | \
64  (((a) >> 24) & 0x00FF0000) | \
65  (((a) >> 8) & 0xFF000000) | \
66  (((a) & 0xFF000000) << 8) | \
67  (((a) & 0x00FF0000) << 24) | \
68  (((a) & 0x0000FF00) << 40) | \
69  (((a) & 0x000000FF) << 56) ))
70 
71 #define SWAP_CONSTANT_32(a) \
72  ((uint32)((((a) >> 24) & 0x00FF) | \
73  (((a) >> 8) & 0xFF00) | \
74  (((a) & 0xFF00) << 8) | \
75  (((a) & 0x00FF) << 24) ))
76 
77 #define SWAP_CONSTANT_16(a) \
78  ((uint16)((((a) >> 8) & 0x00FF) | \
79  (((a) << 8) & 0xFF00) ))
80 
81 // Test for GCC >= 4.3.0 as this version added the bswap builtin
82 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
83 
85  return __builtin_bswap64(a);
86  }
87 
89  return __builtin_bswap32(a);
90  }
91 
92 // test for MSVC 7 or newer
93 #elif defined(_MSC_VER) && _MSC_VER >= 1300
94 
95  #include <cstdlib>
96 
98  return _byteswap_uint64(a);
99  }
100 
102  return _byteswap_ulong(a);
103  }
104 
105 // generic fallback
106 #else
107 
108  static inline uint64 SWAP_BYTES_64(uint64 a) {
109  const uint16 lowlow = (uint16) a;
110  const uint16 low = (uint16) (a >> 16);
111  const uint16 high = (uint16) (a >> 32);
112  const uint16 highhigh = (uint16) (a >> 48);
113 
114  return (((uint64)(((uint32)(uint16)((lowlow >> 8) | (lowlow << 8)) << 16)
115  | (uint16)((low >> 8) | (low << 8)))) << 32)
116  | ((uint32)(uint16)((high >> 8) | (high << 8)) << 16)
117  | (uint16)((highhigh >> 8) | (highhigh << 8));
118  }
119 
120  static inline uint32 SWAP_BYTES_32(uint32 a) {
121  const uint16 low = (uint16)a, high = (uint16)(a >> 16);
122  return ((uint32)(uint16)((low >> 8) | (low << 8)) << 16)
123  | (uint16)((high >> 8) | (high << 8));
124  }
125 
126 #endif
127 
128 static inline uint16 SWAP_BYTES_16(const uint16 a) {
129  return (a >> 8) | (a << 8);
130 }
131 
140 #define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
141 
143 #define MKTAG_16(a0,a1) ((uint16)((a1) | ((a0) << 8)))
144 
145 // Functions for reading/writing native Integers,
146 // this transparently handles the need for alignment
147 
148 #if !defined(XOREOS_NEED_ALIGNMENT)
149 
150  FORCEINLINE uint16 READ_UINT16(const void *ptr) {
151  return *(static_cast<const uint16 *>(ptr));
152  }
153 
154  FORCEINLINE uint32 READ_UINT32(const void *ptr) {
155  return *(static_cast<const uint32 *>(ptr));
156  }
157 
158  FORCEINLINE uint64 READ_UINT64(const void *ptr) {
159  return *(static_cast<const uint64 *>(ptr));
160  }
161 
162  FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
163  *static_cast<uint16 *>(ptr) = value;
164  }
165 
166  FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
167  *static_cast<uint32 *>(ptr) = value;
168  }
169 
170  FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
171  *static_cast<uint64 *>(ptr) = value;
172  }
173 
174 // test for GCC >= 4.0. these implementations will automatically use CPU-specific
175 // instructions for unaligned data when they are available (eg. MIPS)
176 #elif defined(__GNUC__) && (__GNUC__ >= 4)
177 
178  FORCEINLINE uint16 READ_UINT16(const void *ptr) {
179  struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
180  return static_cast<const Unaligned16 *>(ptr)->val;
181  }
182 
183  FORCEINLINE uint32 READ_UINT32(const void *ptr) {
184  struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
185  return static_cast<const Unaligned32 *>(ptr)->val;
186  }
187 
188  FORCEINLINE uint64 READ_UINT64(const void *ptr) {
189  struct Unaligned64 { uint64 val; } __attribute__ ((__packed__));
190  return static_cast<const Unaligned64 *>(ptr)->val;
191  }
192 
193  FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
194  struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
195  static_cast<Unaligned16 *>(ptr)->val = value;
196  }
197 
198  FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
199  struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
200  static_cast<Unaligned32 *>(ptr)->val = value;
201  }
202 
203  FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
204  struct Unaligned64 { uint64 val; } __attribute__ ((__packed__));
205  static_cast<Unaligned64 *>(ptr)->val = value;
206  }
207 
208 // use software fallback by loading each byte explicitly
209 #else
210 
211  #if defined(XOREOS_LITTLE_ENDIAN)
212 
213  static inline uint16 READ_UINT16(const void *ptr) {
214  const uint8 *b = static_cast<const uint8 *>(ptr);
215  return ((uint16)b[1] << 8) | (uint16)b[0];
216  }
217  static inline uint32 READ_UINT32(const void *ptr) {
218  const uint8 *b = static_cast<const uint8 *>(ptr);
219  return ((uint32)b[3] << 24) | (uint32)(b[2] << 16) | (uint32)(b[1] << 8) | (uint32)(b[0]);
220  }
221  static inline uint64 READ_UINT64(const void *ptr) {
222  const uint8 *b = static_cast<const uint8 *>(ptr);
223  return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) |
224  ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]);
225  }
226  static inline void WRITE_UINT16(void *ptr, uint16 value) {
227  uint8 *b = static_cast<uint8 *>(ptr);
228  b[0] = (uint8)(value >> 0);
229  b[1] = (uint8)(value >> 8);
230  }
231  static inline void WRITE_UINT32(void *ptr, uint32 value) {
232  uint8 *b = static_cast<uint8 *>(ptr);
233  b[0] = (uint8)(value >> 0);
234  b[1] = (uint8)(value >> 8);
235  b[2] = (uint8)(value >> 16);
236  b[3] = (uint8)(value >> 24);
237  }
238  static inline void WRITE_UINT64(void *ptr, uint64 value) {
239  uint8 *b = static_cast<uint8 *>(ptr);
240  b[0] = (uint8)(value >> 0);
241  b[1] = (uint8)(value >> 8);
242  b[2] = (uint8)(value >> 16);
243  b[3] = (uint8)(value >> 24);
244  b[4] = (uint8)(value >> 32);
245  b[5] = (uint8)(value >> 40);
246  b[6] = (uint8)(value >> 48);
247  b[7] = (uint8)(value >> 56);
248  }
249 
250  #elif defined(XOREOS_BIG_ENDIAN)
251 
252  static inline uint16 READ_UINT16(const void *ptr) {
253  const uint8 *b = static_cast<const uint8 *>(ptr);
254  return ((uint16)b[0] << 8) | (uint16)b[1];
255  }
256  static inline uint32 READ_UINT32(const void *ptr) {
257  const uint8 *b = static_cast<const uint8 *>(ptr);
258  return ((uint32)b[0] << 24) | ((uint32)b[1] << 16) | ((uint32)b[2] << 8) | ((uint32)b[3]);
259  }
260  static inline uint64 READ_UINT64(const void *ptr) {
261  const uint8 *b = static_cast<const uint8 *>(ptr);
262  return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) |
263  ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]);
264  }
265  static inline void WRITE_UINT16(void *ptr, uint16 value) {
266  uint8 *b = static_cast<uint8 *>(ptr);
267  b[0] = (uint8)(value >> 8);
268  b[1] = (uint8)(value >> 0);
269  }
270  static inline void WRITE_UINT32(void *ptr, uint32 value) {
271  uint8 *b = static_cast<uint8 *>(ptr);
272  b[0] = (uint8)(value >> 24);
273  b[1] = (uint8)(value >> 16);
274  b[2] = (uint8)(value >> 8);
275  b[3] = (uint8)(value >> 0);
276  }
277  static inline void WRITE_UINT64(void *ptr, uint64 value) {
278  uint8 *b = static_cast<uint8 *>(ptr);
279  b[0] = (uint8)(value >> 56);
280  b[1] = (uint8)(value >> 48);
281  b[2] = (uint8)(value >> 40);
282  b[3] = (uint8)(value >> 32);
283  b[4] = (uint8)(value >> 24);
284  b[5] = (uint8)(value >> 16);
285  b[6] = (uint8)(value >> 8);
286  b[7] = (uint8)(value >> 0);
287  }
288 
289  #endif
290 
291 #endif
292 
293 // Map Functions for reading/writing BE/LE integers depending on native endianness
294 #if defined(XOREOS_LITTLE_ENDIAN)
295 
296  #define READ_LE_UINT16(a) READ_UINT16(a)
297  #define READ_LE_UINT32(a) READ_UINT32(a)
298  #define READ_LE_UINT64(a) READ_UINT64(a)
299 
300  #define WRITE_LE_UINT16(a, v) WRITE_UINT16(a, v)
301  #define WRITE_LE_UINT32(a, v) WRITE_UINT32(a, v)
302  #define WRITE_LE_UINT64(a, v) WRITE_UINT64(a, v)
303 
304  #define FROM_LE_16(a) ((uint16)(a))
305  #define FROM_LE_32(a) ((uint32)(a))
306  #define FROM_LE_64(a) ((uint64)(a))
307 
308  #define FROM_BE_16(a) SWAP_BYTES_16(a)
309  #define FROM_BE_32(a) SWAP_BYTES_32(a)
310  #define FROM_BE_64(a) SWAP_BYTES_64(a)
311 
312  #define TO_LE_16(a) ((uint16)(a))
313  #define TO_LE_32(a) ((uint32)(a))
314  #define TO_LE_64(a) ((uint64)(a))
315 
316  #define TO_BE_16(a) SWAP_BYTES_16(a)
317  #define TO_BE_32(a) SWAP_BYTES_32(a)
318  #define TO_BE_64(a) SWAP_BYTES_64(a)
319 
320  #define CONSTANT_LE_16(a) ((uint16)(a))
321  #define CONSTANT_LE_32(a) ((uint32)(a))
322  #define CONSTANT_LE_64(a) ((uint64)(a))
323 
324  #define CONSTANT_BE_16(a) SWAP_CONSTANT_16(a)
325  #define CONSTANT_BE_32(a) SWAP_CONSTANT_32(a)
326  #define CONSTANT_BE_64(a) SWAP_CONSTANT_64(a)
327 
328 // if the unaligned load and the byteswap take a lot instructions its better to directly read and invert
329  #if defined(XOREOS_NEED_ALIGNMENT) && !defined(__mips__)
330 
331  static inline uint16 READ_BE_UINT16(const void *ptr) {
332  const uint8 *b = static_cast<const uint8 *>(ptr);
333  return ((uint16)b[0] << 8) | (uint16)b[1];
334  }
335  static inline uint32 READ_BE_UINT32(const void *ptr) {
336  const uint8 *b = static_cast<const uint8 *>(ptr);
337  return ((uint32)b[0] << 24) | ((uint32)b[1] << 16) | ((uint32)b[2] << 8) | ((uint32)b[3]);
338  }
339  static inline uint32 READ_BE_UINT64(const void *ptr) {
340  const uint8 *b = static_cast<const uint8 *>(ptr);
341  return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) |
342  ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]);
343  }
344  static inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
345  uint8 *b = static_cast<uint8 *>(ptr);
346  b[0] = (uint8)(value >> 8);
347  b[1] = (uint8)(value >> 0);
348  }
349  static inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
350  uint8 *b = static_cast<uint8 *>(ptr);
351  b[0] = (uint8)(value >> 24);
352  b[1] = (uint8)(value >> 16);
353  b[2] = (uint8)(value >> 8);
354  b[3] = (uint8)(value >> 0);
355  }
356  static inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
357  uint8 *b = static_cast<uint8 *>(ptr);
358  b[0] = (uint8)(value >> 56);
359  b[1] = (uint8)(value >> 48);
360  b[2] = (uint8)(value >> 40);
361  b[3] = (uint8)(value >> 32);
362  b[4] = (uint8)(value >> 24);
363  b[5] = (uint8)(value >> 16);
364  b[6] = (uint8)(value >> 8);
365  b[7] = (uint8)(value >> 0);
366  }
367 
368  #else
369 
370  static inline uint16 READ_BE_UINT16(const void *ptr) {
371  return SWAP_BYTES_16(READ_UINT16(ptr));
372  }
373  static inline uint32 READ_BE_UINT32(const void *ptr) {
374  return SWAP_BYTES_32(READ_UINT32(ptr));
375  }
376  static inline uint64 READ_BE_UINT64(const void *ptr) {
377  return SWAP_BYTES_64(READ_UINT64(ptr));
378  }
379  static inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
380  WRITE_UINT16(ptr, SWAP_BYTES_16(value));
381  }
382  static inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
383  WRITE_UINT32(ptr, SWAP_BYTES_32(value));
384  }
385  static inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
386  WRITE_UINT64(ptr, SWAP_BYTES_64(value));
387  }
388 
389  #endif // if defined(XOREOS_NEED_ALIGNMENT)
390 
391 #elif defined(XOREOS_BIG_ENDIAN)
392 
393  #define READ_BE_UINT16(a) READ_UINT16(a)
394  #define READ_BE_UINT32(a) READ_UINT32(a)
395  #define READ_BE_UINT64(a) READ_UINT64(a)
396 
397  #define WRITE_BE_UINT16(a, v) WRITE_UINT16(a, v)
398  #define WRITE_BE_UINT32(a, v) WRITE_UINT32(a, v)
399  #define WRITE_BE_UINT64(a, v) WRITE_UINT64(a, v)
400 
401  #define FROM_LE_16(a) SWAP_BYTES_16(a)
402  #define FROM_LE_32(a) SWAP_BYTES_32(a)
403  #define FROM_LE_64(a) SWAP_BYTES_64(a)
404 
405  #define FROM_BE_16(a) ((uint16)(a))
406  #define FROM_BE_32(a) ((uint32)(a))
407  #define FROM_BE_64(a) ((uint64)(a))
408 
409  #define TO_LE_16(a) SWAP_BYTES_16(a)
410  #define TO_LE_32(a) SWAP_BYTES_32(a)
411  #define TO_LE_64(a) SWAP_BYTES_64(a)
412 
413  #define TO_BE_16(a) ((uint16)(a))
414  #define TO_BE_32(a) ((uint32)(a))
415  #define TO_BE_64(a) ((uint64)(a))
416 
417  #define CONSTANT_LE_16(a) SWAP_CONSTANT_16(a)
418  #define CONSTANT_LE_32(a) SWAP_CONSTANT_32(a)
419  #define CONSTANT_LE_64(a) SWAP_CONSTANT_64(a)
420 
421  #define CONSTANT_BE_16(a) ((uint16)(a))
422  #define CONSTANT_BE_32(a) ((uint32)(a))
423  #define CONSTANT_BE_64(a) ((uint64)(a))
424 
425  // if the unaligned load and the byteswap take a lot instructions its better to directly read and invert
426  #if defined(XOREOS_NEED_ALIGNMENT) && !defined(__mips__)
427 
428  static inline uint16 READ_LE_UINT16(const void *ptr) {
429  const uint8 *b = static_cast<const uint8 *>(ptr);
430  return ((uint16)b[1] << 8) | (uint16)b[0];
431  }
432  static inline uint32 READ_LE_UINT32(const void *ptr) {
433  const uint8 *b = static_cast<const uint8 *>(ptr);
434  return ((uint32)b[3] << 24) | ((uint32)b[2] << 16) | ((uint32)b[1] << 8) | ((uint32)b[0]);
435  }
436  static inline uint64 READ_LE_UINT64(const void *ptr) {
437  const uint8 *b = static_cast<const uint8 *>(ptr);
438  return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) |
439  ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]);
440  }
441  static inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
442  uint8 *b = static_cast<uint8 *>(ptr);
443  b[0] = (uint8)(value >> 0);
444  b[1] = (uint8)(value >> 8);
445  }
446  static inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
447  uint8 *b = static_cast<uint8 *>(ptr);
448  b[0] = (uint8)(value >> 0);
449  b[1] = (uint8)(value >> 8);
450  b[2] = (uint8)(value >> 16);
451  b[3] = (uint8)(value >> 24);
452  }
453  static inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
454  uint8 *b = static_cast<uint8 *>(ptr);
455  b[0] = (uint8)(value >> 0);
456  b[1] = (uint8)(value >> 8);
457  b[2] = (uint8)(value >> 16);
458  b[3] = (uint8)(value >> 24);
459  b[4] = (uint8)(value >> 32);
460  b[5] = (uint8)(value >> 40);
461  b[6] = (uint8)(value >> 48);
462  b[7] = (uint8)(value >> 56);
463  }
464 
465  #else
466 
467  static inline uint16 READ_LE_UINT16(const void *ptr) {
468  return SWAP_BYTES_16(READ_UINT16(ptr));
469  }
470  static inline uint32 READ_LE_UINT32(const void *ptr) {
471  return SWAP_BYTES_32(READ_UINT32(ptr));
472  }
473  static inline uint64 READ_LE_UINT64(const void *ptr) {
474  return SWAP_BYTES_64(READ_UINT64(ptr));
475  }
476  static inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
477  WRITE_UINT16(ptr, SWAP_BYTES_16(value));
478  }
479  static inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
480  WRITE_UINT32(ptr, SWAP_BYTES_32(value));
481  }
482  static inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
483  WRITE_UINT64(ptr, SWAP_BYTES_64(value));
484  }
485 
486  #endif // if defined(XOREOS_NEED_ALIGNMENT)
487 
488 #endif // if defined(XOREOS_LITTLE_ENDIAN)
489 
490 #endif // COMMON_ENDIAN_H
uint64_t uint64
Definition: types.h:206
uint8_t uint8
Definition: types.h:200
FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value)
Definition: endianness.h:170
FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value)
Definition: endianness.h:166
FORCEINLINE uint16 READ_UINT16(const void *ptr)
Definition: endianness.h:150
FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value)
Definition: endianness.h:162
uint16_t uint16
Definition: types.h:202
Low-level type definitions to handle fixed width types portably.
static uint16 SWAP_BYTES_16(const uint16 a)
Definition: endianness.h:128
static uint32 SWAP_BYTES_32(uint32 a)
Definition: endianness.h:120
static uint64 SWAP_BYTES_64(uint64 a)
Definition: endianness.h:108
uint32_t uint32
Definition: types.h:204
Low-level detection of architecture/system properties.
#define FORCEINLINE
Definition: system.h:411
FORCEINLINE uint32 READ_UINT32(const void *ptr)
Definition: endianness.h:154
FORCEINLINE uint64 READ_UINT64(const void *ptr)
Definition: endianness.h:158