1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program 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 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program 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 this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifndef COMMON_ENDIAN_H
24 #define COMMON_ENDIAN_H
25
26 #include "common/scummsys.h"
27
28
29 /**
30 * @defgroup common_endian Endian conversions
31 * @ingroup common
32 *
33 * @brief Functions and macros for endian conversions and byteswap conversions.
34 *
35 * @details
36 * - SWAP_BYTES_??(a) - Reverse byte order
37 * - SWAP_CONSTANT_??(a) - Reverse byte order, implemented as a macro.
38 * Use with compile-time constants only, the result will be a compile-time constant as well.
39 * Unlike most other functions, these can be used for e.g. switch-case labels.
40 * - READ_UINT??(a) - Read native value from pointer @p a.
41 * - READ_??_UINT??(a) - Read LE/BE value from pointer @p a and convert it to native.
42 * - WRITE_??_UINT??(a, v) - Write a native value @p v to pointer @p a with LE/BE encoding.
43 * - TO_??_??(a) - Convert native value @p v to LE/BE.
44 * - FROM_??_??(a) - Convert LE/BE value @p v to native.
45 * - CONSTANT_??_??(a) - Convert LE/BE value @p v to native, implemented as a macro.
46 * Use with compile-time constants only, the result will be a compile-time constant as well.
47 * Unlike most other functions these, can be used for e.g. switch-case labels.
48 *
49 * @{
50 */
51
52 // Sanity check
53 #if !defined(SCUMM_LITTLE_ENDIAN) && !defined(SCUMM_BIG_ENDIAN)
54 # error No endianness defined
55 #endif
56
57 /**
58 * Swap the bytes in a 64-bit word in order to convert LE encoded data to BE
59 * and vice versa. Use with compile-time constants only.
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 /**
72 * Swap the bytes in a 32-bit word in order to convert LE encoded data to BE
73 * and vice versa. Use with compile-time constants only.
74 */
75 #define SWAP_CONSTANT_32(a) \
76 ((uint32)((((a) >> 24) & 0x00FF) | \
77 (((a) >> 8) & 0xFF00) | \
78 (((a) & 0xFF00) << 8) | \
79 (((a) & 0x00FF) << 24) ))
80
81 /**
82 * Swap the bytes in a 16-bit word in order to convert LE encoded data to BE
83 * and vice versa. Use with compile-time constants only.
84 */
85 #define SWAP_CONSTANT_16(a) \
86 ((uint16)((((a) >> 8) & 0x00FF) | \
87 (((a) << 8) & 0xFF00) ))
88
89
90
91 /**
92 * Swap the bytes in a 16-bit word in order to convert LE encoded data to BE
93 * and vice versa.
94 */
95
96 // compilerspecific variants come first, fallback last
97
98 // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does)
99 #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2))
100
SWAP_BYTES_16(const uint16 a)101 FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) {
102 if (__builtin_constant_p(a)) {
103 return SWAP_CONSTANT_16(a);
104 } else {
105 uint16 result;
106 __asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a));
107 return result;
108 }
109 }
110 #else
111
SWAP_BYTES_16(const uint16 a)112 inline uint16 SWAP_BYTES_16(const uint16 a) {
113 return (a >> 8) | (a << 8);
114 }
115 #endif
116
117
118
119 /**
120 * Swap the bytes in a 32-bit word in order to convert LE encoded data to BE
121 * and vice versa.
122 */
123
124 // machine/compiler-specific variants come first, fallback last
125
126 // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does)
127 #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2))
128
SWAP_BYTES_32(const uint32 a)129 FORCEINLINE uint32 SWAP_BYTES_32(const uint32 a) {
130 if (__builtin_constant_p(a)) {
131 return SWAP_CONSTANT_32(a);
132 } else {
133 uint32 result;
134 # if defined(__psp__)
135 // use special allegrex instruction
136 __asm__ ("wsbw %0,%1" : "=r" (result) : "r" (a));
137 # else
138 __asm__ ("wsbh %0,%1\n"
139 "rotr %0,%0,16" : "=r" (result) : "r" (a));
140 # endif
141 return result;
142 }
143 }
144
145 // Test for GCC >= 4.3.0 as this version added the bswap builtin
146 #elif GCC_ATLEAST(4, 3)
147
SWAP_BYTES_32(uint32 a)148 FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
149 return __builtin_bswap32(a);
150 }
151
152 #elif defined(_MSC_VER)
153
SWAP_BYTES_32(uint32 a)154 FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
155 return _byteswap_ulong(a);
156 }
157
158 // generic fallback
159 #else
160
SWAP_BYTES_32(uint32 a)161 inline uint32 SWAP_BYTES_32(uint32 a) {
162 const uint16 low = (uint16)a, high = (uint16)(a >> 16);
163 return ((uint32)(uint16)((low >> 8) | (low << 8)) << 16)
164 | (uint16)((high >> 8) | (high << 8));
165 }
166 #endif
167
168 /**
169 * Swap the bytes in a 64-bit word in order to convert LE encoded data to BE
170 * and vice versa.
171 */
172
173 // machine/compiler-specific variants come first, fallback last
174
175 // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does)
176 //
177 #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2))
178
SWAP_BYTES_64(const uint64 a)179 FORCEINLINE uint64 SWAP_BYTES_64(const uint64 a) {
180 if (__builtin_constant_p(a)) {
181 return SWAP_CONSTANT_64(a);
182 } else {
183 uint32 low = (uint32)a, high = (uint32)(a >> 32);
184 low = SWAP_BYTES_32(low);
185 high = SWAP_BYTES_32(high);
186
187 return (((uint64)low) << 32) | high;
188 }
189 }
190
191 // Test for GCC >= 4.3.0 as this version added the bswap builtin
192 #elif GCC_ATLEAST(4, 3)
193
SWAP_BYTES_64(uint64 a)194 FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) {
195 return __builtin_bswap64(a);
196 }
197
198 #elif defined(_MSC_VER)
199
SWAP_BYTES_64(uint64 a)200 FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) {
201 return _byteswap_uint64(a);
202 }
203
204 // generic fallback
205 #else
206
SWAP_BYTES_64(uint64 a)207 inline uint64 SWAP_BYTES_64(uint64 a) {
208 uint32 low = (uint32)a, high = (uint32)(a >> 32);
209 uint16 lowLow = (uint16)low, lowHigh = (uint16)(low >> 16),
210 highLow = (uint16)high, highHigh = (uint16)(high >> 16);
211
212 return ((uint64)(((uint32)(uint16)((lowLow >> 8) | (lowLow << 8)) << 16) |
213 (uint16)((lowHigh >> 8) | (lowHigh << 8))) << 32) |
214 (((uint32)(uint16)((highLow >> 8) | (highLow << 8)) << 16) |
215 (uint16)((highHigh >> 8) | (highHigh << 8)));
216 }
217 #endif
218
219
220
221 /**
222 * A wrapper macro used around four character constants, like 'DATA', to
223 * ensure portability. Typical usage: MKTAG('D','A','T','A').
224 *
225 * This is required because the C/C++ standard does not define the endianess to
226 * be used for character constants. Hence, if one uses multi-byte character
227 * constants, a potential portability problem opens up.
228 */
229 #define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
230
231 /**
232 * A wrapper macro used around two character constants, like 'wb', to
233 * ensure portability. Typical usage: MKTAG16('w','b').
234 */
235 #define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8)))
236
237 /** @name Functions for reading and writing native integers
238 * @brief Functions for reading and writing native integer values.
239 * They also transparently handle the need for alignment.
240 * @{
241 */
242
243 // Test for GCC >= 4.0. These implementations will automatically use
244 // CPU-specific instructions for unaligned data when they are available (eg.
245 // MIPS). See also this email thread on scummvm-devel for details:
246 // <http://thread.gmane.org/gmane.games.devel.scummvm/8063>
247 //
248 // Moreover, we activate this code for GCC >= 3.3 but *only* if unaligned access
249 // is allowed.
250 #if GCC_ATLEAST(4, 0) || (GCC_ATLEAST(3, 3) && !defined(SCUMM_NEED_ALIGNMENT))
251
READ_UINT16(const void * ptr)252 FORCEINLINE uint16 READ_UINT16(const void *ptr) {
253 struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
254 return ((const Unaligned16 *)ptr)->val;
255 }
256
READ_UINT32(const void * ptr)257 FORCEINLINE uint32 READ_UINT32(const void *ptr) {
258 struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
259 return ((const Unaligned32 *)ptr)->val;
260 }
261
WRITE_UINT16(void * ptr,uint16 value)262 FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
263 struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
264 ((Unaligned16 *)ptr)->val = value;
265 }
266
WRITE_UINT32(void * ptr,uint32 value)267 FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
268 struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
269 ((Unaligned32 *)ptr)->val = value;
270 }
271
READ_UINT64(const void * ptr)272 FORCEINLINE uint64 READ_UINT64(const void *ptr) {
273 struct Unaligned64 { uint64 val; } __attribute__ ((__packed__, __may_alias__));
274 return ((const Unaligned64 *)ptr)->val;
275 }
276
WRITE_UINT64(void * ptr,uint64 value)277 FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
278 struct Unaligned64 { uint64 val; } __attribute__((__packed__, __may_alias__));
279 ((Unaligned64 *)ptr)->val = value;
280 }
281
282 #elif !defined(SCUMM_NEED_ALIGNMENT)
283
READ_UINT16(const void * ptr)284 FORCEINLINE uint16 READ_UINT16(const void *ptr) {
285 return *(const uint16 *)(ptr);
286 }
287
READ_UINT32(const void * ptr)288 FORCEINLINE uint32 READ_UINT32(const void *ptr) {
289 return *(const uint32 *)(ptr);
290 }
291
WRITE_UINT16(void * ptr,uint16 value)292 FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
293 *(uint16 *)(ptr) = value;
294 }
295
WRITE_UINT32(void * ptr,uint32 value)296 FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
297 *(uint32 *)(ptr) = value;
298 }
299
READ_UINT64(const void * ptr)300 FORCEINLINE uint64 READ_UINT64(const void *ptr) {
301 return *(const uint64 *)(ptr);
302 }
303
WRITE_UINT64(void * ptr,uint64 value)304 FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
305 *(uint64 *)(ptr) = value;
306 }
307
308
309 // use software fallback by loading each byte explicitely
310 #else
311
312 # if defined(SCUMM_LITTLE_ENDIAN)
313
READ_UINT16(const void * ptr)314 inline uint16 READ_UINT16(const void *ptr) {
315 const uint8 *b = (const uint8 *)ptr;
316 return (b[1] << 8) | b[0];
317 }
READ_UINT32(const void * ptr)318 inline uint32 READ_UINT32(const void *ptr) {
319 const uint8 *b = (const uint8 *)ptr;
320 return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
321 }
WRITE_UINT16(void * ptr,uint16 value)322 inline void WRITE_UINT16(void *ptr, uint16 value) {
323 uint8 *b = (uint8 *)ptr;
324 b[0] = (uint8)(value >> 0);
325 b[1] = (uint8)(value >> 8);
326 }
WRITE_UINT32(void * ptr,uint32 value)327 inline void WRITE_UINT32(void *ptr, uint32 value) {
328 uint8 *b = (uint8 *)ptr;
329 b[0] = (uint8)(value >> 0);
330 b[1] = (uint8)(value >> 8);
331 b[2] = (uint8)(value >> 16);
332 b[3] = (uint8)(value >> 24);
333 }
READ_UINT64(const void * ptr)334 inline uint64 READ_UINT64(const void *ptr) {
335 const uint8 *b = (const uint8 *)ptr;
336 return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) | ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]);
337 }
WRITE_UINT64(void * ptr,uint64 value)338 inline void WRITE_UINT64(void *ptr, uint64 value) {
339 uint8 *b = (uint8 *)ptr;
340 b[0] = (uint8)(value >> 0);
341 b[1] = (uint8)(value >> 8);
342 b[2] = (uint8)(value >> 16);
343 b[3] = (uint8)(value >> 24);
344 b[4] = (uint8)(value >> 32);
345 b[5] = (uint8)(value >> 40);
346 b[6] = (uint8)(value >> 48);
347 b[7] = (uint8)(value >> 56);
348 }
349
350 # elif defined(SCUMM_BIG_ENDIAN)
351
READ_UINT16(const void * ptr)352 inline uint16 READ_UINT16(const void *ptr) {
353 const uint8 *b = (const uint8 *)ptr;
354 return (b[0] << 8) | b[1];
355 }
READ_UINT32(const void * ptr)356 inline uint32 READ_UINT32(const void *ptr) {
357 const uint8 *b = (const uint8 *)ptr;
358 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
359 }
WRITE_UINT16(void * ptr,uint16 value)360 inline void WRITE_UINT16(void *ptr, uint16 value) {
361 uint8 *b = (uint8 *)ptr;
362 b[0] = (uint8)(value >> 8);
363 b[1] = (uint8)(value >> 0);
364 }
WRITE_UINT32(void * ptr,uint32 value)365 inline void WRITE_UINT32(void *ptr, uint32 value) {
366 uint8 *b = (uint8 *)ptr;
367 b[0] = (uint8)(value >> 24);
368 b[1] = (uint8)(value >> 16);
369 b[2] = (uint8)(value >> 8);
370 b[3] = (uint8)(value >> 0);
371 }
READ_UINT64(const void * ptr)372 inline uint64 READ_UINT64(const void *ptr) {
373 const uint8 *b = (const uint8 *)ptr;
374 return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) | ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]);
375 }
WRITE_UINT64(void * ptr,uint64 value)376 inline void WRITE_UINT64(void *ptr, uint64 value) {
377 uint8 *b = (uint8 *)ptr;
378 b[0] = (uint8)(value >> 56);
379 b[1] = (uint8)(value >> 48);
380 b[2] = (uint8)(value >> 40);
381 b[3] = (uint8)(value >> 32);
382 b[4] = (uint8)(value >> 24);
383 b[5] = (uint8)(value >> 16);
384 b[6] = (uint8)(value >> 8);
385 b[7] = (uint8)(value >> 0);
386 }
387
388 # endif
389 /** @} */
390 #endif
391
392
393 /** @name Map functions for reading/writing BE/LE integers depending on native endianess
394 * @{
395 */
396
397 #if defined(SCUMM_LITTLE_ENDIAN)
398
399 #define READ_LE_UINT16(a) READ_UINT16(a)
400 #define READ_LE_UINT32(a) READ_UINT32(a)
401
402 #define WRITE_LE_UINT16(a, v) WRITE_UINT16(a, v)
403 #define WRITE_LE_UINT32(a, v) WRITE_UINT32(a, v)
404
405 #define FROM_LE_32(a) ((uint32)(a))
406 #define FROM_LE_16(a) ((uint16)(a))
407
408 #define FROM_BE_32(a) SWAP_BYTES_32(a)
409 #define FROM_BE_16(a) SWAP_BYTES_16(a)
410
411 #define TO_LE_32(a) ((uint32)(a))
412 #define TO_LE_16(a) ((uint16)(a))
413
414 #define TO_BE_32(a) SWAP_BYTES_32(a)
415 #define TO_BE_16(a) SWAP_BYTES_16(a)
416
417 #define CONSTANT_LE_32(a) ((uint32)(a))
418 #define CONSTANT_LE_16(a) ((uint16)(a))
419
420 #define CONSTANT_BE_32(a) SWAP_CONSTANT_32(a)
421 #define CONSTANT_BE_16(a) SWAP_CONSTANT_16(a)
422
423 #define READ_LE_UINT64(a) READ_UINT64(a)
424 #define WRITE_LE_UINT64(a, v) WRITE_UINT64(a, v)
425 #define FROM_LE_64(a) ((uint64)(a))
426 #define FROM_BE_64(a) SWAP_BYTES_64(a)
427 #define TO_LE_64(a) ((uint64)(a))
428 #define TO_BE_64(a) SWAP_BYTES_64(a)
429 #define CONSTANT_LE_64(a) ((uint64)(a))
430 #define CONSTANT_BE_64(a) SWAP_CONSTANT_64(a)
431 /** @} */
432
433 /** @name Functions for directly reading/writing and inverting
434 * @brief Use these in case the unaligned load and byteswap take
435 * a lot of instructions.
436 * @{
437 */
438 # if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__)
439
READ_BE_UINT16(const void * ptr)440 inline uint16 READ_BE_UINT16(const void *ptr) {
441 const uint8 *b = (const uint8 *)ptr;
442 return (b[0] << 8) | b[1];
443 }
READ_BE_UINT32(const void * ptr)444 inline uint32 READ_BE_UINT32(const void *ptr) {
445 const uint8 *b = (const uint8 *)ptr;
446 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
447 }
WRITE_BE_UINT16(void * ptr,uint16 value)448 inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
449 uint8 *b = (uint8 *)ptr;
450 b[0] = (uint8)(value >> 8);
451 b[1] = (uint8)(value >> 0);
452 }
WRITE_BE_UINT32(void * ptr,uint32 value)453 inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
454 uint8 *b = (uint8 *)ptr;
455 b[0] = (uint8)(value >> 24);
456 b[1] = (uint8)(value >> 16);
457 b[2] = (uint8)(value >> 8);
458 b[3] = (uint8)(value >> 0);
459 }
READ_BE_UINT64(const void * ptr)460 inline uint64 READ_BE_UINT64(const void *ptr) {
461 const uint8 *b = (const uint8 *)ptr;
462 return ((uint64)b[0] << 56) | ((uint64)b[1] << 48) | ((uint64)b[2] << 40) | ((uint64)b[3] << 32) | ((uint64)b[4] << 24) | ((uint64)b[5] << 16) | ((uint64)b[6] << 8) | ((uint64)b[7]);
463 }
WRITE_BE_UINT64(void * ptr,uint64 value)464 inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
465 uint8 *b = (uint8 *)ptr;
466 b[0] = (uint8)(value >> 56);
467 b[1] = (uint8)(value >> 48);
468 b[2] = (uint8)(value >> 40);
469 b[3] = (uint8)(value >> 32);
470 b[4] = (uint8)(value >> 24);
471 b[5] = (uint8)(value >> 16);
472 b[6] = (uint8)(value >> 8);
473 b[7] = (uint8)(value >> 0);
474 }
475
476 # else
477
READ_BE_UINT16(const void * ptr)478 inline uint16 READ_BE_UINT16(const void *ptr) {
479 return SWAP_BYTES_16(READ_UINT16(ptr));
480 }
READ_BE_UINT32(const void * ptr)481 inline uint32 READ_BE_UINT32(const void *ptr) {
482 return SWAP_BYTES_32(READ_UINT32(ptr));
483 }
WRITE_BE_UINT16(void * ptr,uint16 value)484 inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
485 WRITE_UINT16(ptr, SWAP_BYTES_16(value));
486 }
WRITE_BE_UINT32(void * ptr,uint32 value)487 inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
488 WRITE_UINT32(ptr, SWAP_BYTES_32(value));
489 }
READ_BE_UINT64(const void * ptr)490 inline uint64 READ_BE_UINT64(const void *ptr) {
491 return SWAP_BYTES_64(READ_UINT64(ptr));
492 }
WRITE_BE_UINT64(void * ptr,uint64 value)493 inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
494 WRITE_UINT64(ptr, SWAP_BYTES_64(value));
495 }
496
497 # endif // if defined(SCUMM_NEED_ALIGNMENT)
498
499 #elif defined(SCUMM_BIG_ENDIAN)
500
501 #define READ_BE_UINT16(a) READ_UINT16(a)
502 #define READ_BE_UINT32(a) READ_UINT32(a)
503
504 #define WRITE_BE_UINT16(a, v) WRITE_UINT16(a, v)
505 #define WRITE_BE_UINT32(a, v) WRITE_UINT32(a, v)
506
507 #define FROM_LE_32(a) SWAP_BYTES_32(a)
508 #define FROM_LE_16(a) SWAP_BYTES_16(a)
509
510 #define FROM_BE_32(a) ((uint32)(a))
511 #define FROM_BE_16(a) ((uint16)(a))
512
513 #define TO_LE_32(a) SWAP_BYTES_32(a)
514 #define TO_LE_16(a) SWAP_BYTES_16(a)
515
516 #define TO_BE_32(a) ((uint32)(a))
517 #define TO_BE_16(a) ((uint16)(a))
518
519 #define CONSTANT_LE_32(a) SWAP_CONSTANT_32(a)
520 #define CONSTANT_LE_16(a) SWAP_CONSTANT_16(a)
521
522 #define CONSTANT_BE_32(a) ((uint32)(a))
523 #define CONSTANT_BE_16(a) ((uint16)(a))
524
525 #define READ_BE_UINT64(a) READ_UINT64(a)
526 #define WRITE_BE_UINT64(a, v) WRITE_UINT64(a, v)
527 #define FROM_LE_64(a) SWAP_BYTES_64(a)
528 #define FROM_BE_64(a) ((uint64)(a))
529 #define TO_LE_64(a) SWAP_BYTES_64(a)
530 #define TO_BE_64(a) ((uint64)(a))
531 #define CONSTANT_LE_64(a) SWAP_CONSTANT_64(a)
532 #define CONSTANT_BE_64(a) ((uint64)(a))
533
534 // if the unaligned load and the byteswap take alot instructions its better to directly read and invert
535 # if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__)
536
READ_LE_UINT16(const void * ptr)537 inline uint16 READ_LE_UINT16(const void *ptr) {
538 const uint8 *b = (const uint8 *)ptr;
539 return (b[1] << 8) | b[0];
540 }
READ_LE_UINT32(const void * ptr)541 inline uint32 READ_LE_UINT32(const void *ptr) {
542 const uint8 *b = (const uint8 *)ptr;
543 return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
544 }
WRITE_LE_UINT16(void * ptr,uint16 value)545 inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
546 uint8 *b = (uint8 *)ptr;
547 b[0] = (uint8)(value >> 0);
548 b[1] = (uint8)(value >> 8);
549 }
WRITE_LE_UINT32(void * ptr,uint32 value)550 inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
551 uint8 *b = (uint8 *)ptr;
552 b[0] = (uint8)(value >> 0);
553 b[1] = (uint8)(value >> 8);
554 b[2] = (uint8)(value >> 16);
555 b[3] = (uint8)(value >> 24);
556 }
557
READ_LE_UINT64(const void * ptr)558 inline uint64 READ_LE_UINT64(const void *ptr) {
559 const uint8 *b = (const uint8 *)ptr;
560 return ((uint64)b[7] << 56) | ((uint64)b[6] << 48) | ((uint64)b[5] << 40) | ((uint64)b[4] << 32) | ((uint64)b[3] << 24) | ((uint64)b[2] << 16) | ((uint64)b[1] << 8) | ((uint64)b[0]);
561 }
WRITE_LE_UINT64(void * ptr,uint64 value)562 inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
563 uint8 *b = (uint8 *)ptr;
564 b[0] = (uint8)(value >> 0);
565 b[1] = (uint8)(value >> 8);
566 b[2] = (uint8)(value >> 16);
567 b[3] = (uint8)(value >> 24);
568 b[4] = (uint8)(value >> 32);
569 b[5] = (uint8)(value >> 40);
570 b[6] = (uint8)(value >> 48);
571 b[7] = (uint8)(value >> 56);
572 }
573
574 # else
575
READ_LE_UINT16(const void * ptr)576 inline uint16 READ_LE_UINT16(const void *ptr) {
577 return SWAP_BYTES_16(READ_UINT16(ptr));
578 }
READ_LE_UINT32(const void * ptr)579 inline uint32 READ_LE_UINT32(const void *ptr) {
580 return SWAP_BYTES_32(READ_UINT32(ptr));
581 }
WRITE_LE_UINT16(void * ptr,uint16 value)582 inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
583 WRITE_UINT16(ptr, SWAP_BYTES_16(value));
584 }
WRITE_LE_UINT32(void * ptr,uint32 value)585 inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
586 WRITE_UINT32(ptr, SWAP_BYTES_32(value));
587 }
READ_LE_UINT64(const void * ptr)588 inline uint64 READ_LE_UINT64(const void *ptr) {
589 return SWAP_BYTES_64(READ_UINT64(ptr));
590 }
WRITE_LE_UINT64(void * ptr,uint64 value)591 inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
592 WRITE_UINT64(ptr, SWAP_BYTES_64(value));
593 }
594
595 # endif // if defined(SCUMM_NEED_ALIGNMENT)
596
597 #endif // if defined(SCUMM_LITTLE_ENDIAN)
598
READ_LE_UINT24(const void * ptr)599 inline uint32 READ_LE_UINT24(const void *ptr) {
600 const uint8 *b = (const uint8 *)ptr;
601 return (b[2] << 16) | (b[1] << 8) | (b[0]);
602 }
603
WRITE_LE_UINT24(void * ptr,uint32 value)604 inline void WRITE_LE_UINT24(void *ptr, uint32 value) {
605 uint8 *b = (uint8 *)ptr;
606 b[0] = (uint8)(value >> 0);
607 b[1] = (uint8)(value >> 8);
608 b[2] = (uint8)(value >> 16);
609 }
610
READ_BE_UINT24(const void * ptr)611 inline uint32 READ_BE_UINT24(const void *ptr) {
612 const uint8 *b = (const uint8 *)ptr;
613 return (b[0] << 16) | (b[1] << 8) | (b[2]);
614 }
615
WRITE_BE_UINT24(void * ptr,uint32 value)616 inline void WRITE_BE_UINT24(void *ptr, uint32 value) {
617 uint8 *b = (uint8 *)ptr;
618 b[0] = (uint8)(value >> 16);
619 b[1] = (uint8)(value >> 8);
620 b[2] = (uint8)(value >> 0);
621 }
622
623 #ifdef SCUMM_LITTLE_ENDIAN
624 #define READ_UINT24(a) READ_LE_UINT24(a)
625 #define WRITE_UINT24(a,b) WRITE_LE_UINT24(a,b)
626 #else
627 #define READ_UINT24(a) READ_BE_UINT24(a)
628 #define WRITE_UINT24(a,b) WRITE_BE_UINT24(a,b)
629 #endif
630
READ_LE_INT16(const void * ptr)631 inline int16 READ_LE_INT16(const void *ptr) {
632 return static_cast<int16>(READ_LE_UINT16(ptr));
633 }
634
WRITE_LE_INT16(void * ptr,int16 value)635 inline void WRITE_LE_INT16(void *ptr, int16 value) {
636 WRITE_LE_UINT16(ptr, static_cast<uint16>(value));
637 }
638
READ_BE_INT16(const void * ptr)639 inline int16 READ_BE_INT16(const void *ptr) {
640 return static_cast<int16>(READ_BE_UINT16(ptr));
641 }
642
WRITE_BE_INT16(void * ptr,int16 value)643 inline void WRITE_BE_INT16(void *ptr, int16 value) {
644 WRITE_BE_UINT16(ptr, static_cast<uint16>(value));
645 }
646
READ_LE_INT32(const void * ptr)647 inline int32 READ_LE_INT32(const void *ptr) {
648 return static_cast<int32>(READ_LE_UINT32(ptr));
649 }
650
WRITE_LE_INT32(void * ptr,int32 value)651 inline void WRITE_LE_INT32(void *ptr, int32 value) {
652 WRITE_LE_UINT32(ptr, static_cast<uint32>(value));
653 }
654
READ_BE_INT32(const void * ptr)655 inline int32 READ_BE_INT32(const void *ptr) {
656 return static_cast<int32>(READ_BE_UINT32(ptr));
657 }
658
WRITE_BE_INT32(void * ptr,int32 value)659 inline void WRITE_BE_INT32(void *ptr, int32 value) {
660 WRITE_BE_UINT32(ptr, static_cast<uint32>(value));
661 }
662 /** @} */
663 /** @} */
664
665 #endif
666