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