ScummVM API documentation
endian.h
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 modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (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, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef COMMON_ENDIAN_H
23#define COMMON_ENDIAN_H
24
25#include "common/scummsys.h"
26
27
51// Sanity check
52#if !defined(SCUMM_LITTLE_ENDIAN) && !defined(SCUMM_BIG_ENDIAN)
53# error No endianness defined
54#endif
55
60#define SWAP_CONSTANT_64(a) \
61 ((uint64)((((a) >> 56) & 0x000000FF) | \
62 (((a) >> 40) & 0x0000FF00) | \
63 (((a) >> 24) & 0x00FF0000) | \
64 (((a) >> 8) & 0xFF000000) | \
65 (((a) & 0xFF000000) << 8) | \
66 (((a) & 0x00FF0000) << 24) | \
67 (((a) & 0x0000FF00) << 40) | \
68 (((a) & 0x000000FF) << 56) ))
69
74#define SWAP_CONSTANT_32(a) \
75 ((uint32)((((a) >> 24) & 0x00FF) | \
76 (((a) >> 8) & 0xFF00) | \
77 (((a) & 0xFF00) << 8) | \
78 (((a) & 0x00FF) << 24) ))
79
84#define SWAP_CONSTANT_16(a) \
85 ((uint16)((((a) >> 8) & 0x00FF) | \
86 (((a) << 8) & 0xFF00) ))
87
88
89
95// compiler-specific variants come first, fallback last
96#if GCC_ATLEAST(4, 8) || defined(__clang__)
97
98 FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
99 return __builtin_bswap16(a);
100 }
101
102#elif defined(_MSC_VER)
103
104 FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
105 return _byteswap_ushort(a);
106 }
107
108#else
109
110 inline uint16 SWAP_BYTES_16(const uint16 a) {
111 return (a >> 8) | (a << 8);
112 }
113#endif
114
115
116
122// compiler-specific variants come first, fallback last
123#if defined(__GNUC__)
124
125 FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
126 return __builtin_bswap32(a);
127 }
128
129#elif defined(_MSC_VER)
130
131 FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
132 return _byteswap_ulong(a);
133 }
134
135// generic fallback
136#else
137
138 inline uint32 SWAP_BYTES_32(uint32 a) {
139 const uint16 low = (uint16)a, high = (uint16)(a >> 16);
140 return ((uint32)(uint16)((low >> 8) | (low << 8)) << 16)
141 | (uint16)((high >> 8) | (high << 8));
142 }
143#endif
144
150// compiler-specific variants come first, fallback last
151#if defined(__GNUC__)
152
153 FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) {
154 return __builtin_bswap64(a);
155 }
156
157#elif defined(_MSC_VER)
158
159 FORCEINLINE uint64 SWAP_BYTES_64(uint64 a) {
160 return _byteswap_uint64(a);
161 }
162
163// generic fallback
164#else
165
166 inline uint64 SWAP_BYTES_64(uint64 a) {
167 uint32 low = (uint32)a, high = (uint32)(a >> 32);
168 uint16 lowLow = (uint16)low, lowHigh = (uint16)(low >> 16),
169 highLow = (uint16)high, highHigh = (uint16)(high >> 16);
170
171 return ((uint64)(((uint32)(uint16)((lowLow >> 8) | (lowLow << 8)) << 16) |
172 (uint16)((lowHigh >> 8) | (lowHigh << 8))) << 32) |
173 (((uint32)(uint16)((highLow >> 8) | (highLow << 8)) << 16) |
174 (uint16)((highHigh >> 8) | (highHigh << 8)));
175 }
176#endif
177
178
179
188#define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
189
194#define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8)))
195
202// Test for GCC and compatible. These implementations will automatically use
203// CPU-specific instructions for unaligned data when they are available (eg.
204// MIPS).
205#if defined(__GNUC__)
206
207 FORCEINLINE uint16 READ_UINT16(const void *ptr) {
208 struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
209 return ((const Unaligned16 *)ptr)->val;
210 }
211
212 FORCEINLINE uint32 READ_UINT32(const void *ptr) {
213 struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
214 return ((const Unaligned32 *)ptr)->val;
215 }
216
217 FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
218 struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
219 ((Unaligned16 *)ptr)->val = value;
220 }
221
222 FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
223 struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
224 ((Unaligned32 *)ptr)->val = value;
225 }
226
227 FORCEINLINE uint64 READ_UINT64(const void *ptr) {
228 struct Unaligned64 { uint64 val; } __attribute__ ((__packed__, __may_alias__));
229 return ((const Unaligned64 *)ptr)->val;
230 }
231
232 FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
233 struct Unaligned64 { uint64 val; } __attribute__((__packed__, __may_alias__));
234 ((Unaligned64 *)ptr)->val = value;
235 }
236
237#elif !defined(SCUMM_NEED_ALIGNMENT)
238
239 FORCEINLINE uint16 READ_UINT16(const void *ptr) {
240 return *(const uint16 *)(ptr);
241 }
242
243 FORCEINLINE uint32 READ_UINT32(const void *ptr) {
244 return *(const uint32 *)(ptr);
245 }
246
247 FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
248 *(uint16 *)(ptr) = value;
249 }
250
251 FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
252 *(uint32 *)(ptr) = value;
253 }
254
255 FORCEINLINE uint64 READ_UINT64(const void *ptr) {
256 return *(const uint64 *)(ptr);
257 }
258
259 FORCEINLINE void WRITE_UINT64(void *ptr, uint64 value) {
260 *(uint64 *)(ptr) = value;
261 }
262
263
264// use software fallback by loading each byte explicitely
265#else
266
267# if defined(SCUMM_LITTLE_ENDIAN)
268
269 inline uint16 READ_UINT16(const void *ptr) {
270 const uint8 *b = (const uint8 *)ptr;
271 return (b[1] << 8) | b[0];
272 }
273 inline uint32 READ_UINT32(const void *ptr) {
274 const uint8 *b = (const uint8 *)ptr;
275 return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
276 }
277 inline void WRITE_UINT16(void *ptr, uint16 value) {
278 uint8 *b = (uint8 *)ptr;
279 b[0] = (uint8)(value >> 0);
280 b[1] = (uint8)(value >> 8);
281 }
282 inline void WRITE_UINT32(void *ptr, uint32 value) {
283 uint8 *b = (uint8 *)ptr;
284 b[0] = (uint8)(value >> 0);
285 b[1] = (uint8)(value >> 8);
286 b[2] = (uint8)(value >> 16);
287 b[3] = (uint8)(value >> 24);
288 }
289 inline uint64 READ_UINT64(const void *ptr) {
290 const uint8 *b = (const uint8 *)ptr;
291 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]);
292 }
293 inline void WRITE_UINT64(void *ptr, uint64 value) {
294 uint8 *b = (uint8 *)ptr;
295 b[0] = (uint8)(value >> 0);
296 b[1] = (uint8)(value >> 8);
297 b[2] = (uint8)(value >> 16);
298 b[3] = (uint8)(value >> 24);
299 b[4] = (uint8)(value >> 32);
300 b[5] = (uint8)(value >> 40);
301 b[6] = (uint8)(value >> 48);
302 b[7] = (uint8)(value >> 56);
303 }
304
305# elif defined(SCUMM_BIG_ENDIAN)
306
307 inline uint16 READ_UINT16(const void *ptr) {
308 const uint8 *b = (const uint8 *)ptr;
309 return (b[0] << 8) | b[1];
310 }
311 inline uint32 READ_UINT32(const void *ptr) {
312 const uint8 *b = (const uint8 *)ptr;
313 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
314 }
315 inline void WRITE_UINT16(void *ptr, uint16 value) {
316 uint8 *b = (uint8 *)ptr;
317 b[0] = (uint8)(value >> 8);
318 b[1] = (uint8)(value >> 0);
319 }
320 inline void WRITE_UINT32(void *ptr, uint32 value) {
321 uint8 *b = (uint8 *)ptr;
322 b[0] = (uint8)(value >> 24);
323 b[1] = (uint8)(value >> 16);
324 b[2] = (uint8)(value >> 8);
325 b[3] = (uint8)(value >> 0);
326 }
327 inline uint64 READ_UINT64(const void *ptr) {
328 const uint8 *b = (const uint8 *)ptr;
329 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]);
330 }
331 inline void WRITE_UINT64(void *ptr, uint64 value) {
332 uint8 *b = (uint8 *)ptr;
333 b[0] = (uint8)(value >> 56);
334 b[1] = (uint8)(value >> 48);
335 b[2] = (uint8)(value >> 40);
336 b[3] = (uint8)(value >> 32);
337 b[4] = (uint8)(value >> 24);
338 b[5] = (uint8)(value >> 16);
339 b[6] = (uint8)(value >> 8);
340 b[7] = (uint8)(value >> 0);
341 }
342
343# endif
345#endif
346
347
352#if defined(SCUMM_LITTLE_ENDIAN)
353
354 #define READ_LE_UINT16(a) READ_UINT16(a)
355 #define READ_LE_UINT32(a) READ_UINT32(a)
356
357 #define WRITE_LE_UINT16(a, v) WRITE_UINT16(a, v)
358 #define WRITE_LE_UINT32(a, v) WRITE_UINT32(a, v)
359
360 #define FROM_LE_32(a) ((uint32)(a))
361 #define FROM_LE_16(a) ((uint16)(a))
362
363 #define FROM_BE_32(a) SWAP_BYTES_32(a)
364 #define FROM_BE_16(a) SWAP_BYTES_16(a)
365
366 #define TO_LE_32(a) ((uint32)(a))
367 #define TO_LE_16(a) ((uint16)(a))
368
369 #define TO_BE_32(a) SWAP_BYTES_32(a)
370 #define TO_BE_16(a) SWAP_BYTES_16(a)
371
372 #define CONSTANT_LE_32(a) ((uint32)(a))
373 #define CONSTANT_LE_16(a) ((uint16)(a))
374
375 #define CONSTANT_BE_32(a) SWAP_CONSTANT_32(a)
376 #define CONSTANT_BE_16(a) SWAP_CONSTANT_16(a)
377
378 #define READ_LE_UINT64(a) READ_UINT64(a)
379 #define WRITE_LE_UINT64(a, v) WRITE_UINT64(a, v)
380 #define FROM_LE_64(a) ((uint64)(a))
381 #define FROM_BE_64(a) SWAP_BYTES_64(a)
382 #define TO_LE_64(a) ((uint64)(a))
383 #define TO_BE_64(a) SWAP_BYTES_64(a)
384 #define CONSTANT_LE_64(a) ((uint64)(a))
385 #define CONSTANT_BE_64(a) SWAP_CONSTANT_64(a)
393# if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__)
394
395 inline uint16 READ_BE_UINT16(const void *ptr) {
396 const uint8 *b = (const uint8 *)ptr;
397 return (b[0] << 8) | b[1];
398 }
399 inline uint32 READ_BE_UINT32(const void *ptr) {
400 const uint8 *b = (const uint8 *)ptr;
401 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
402 }
403 inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
404 uint8 *b = (uint8 *)ptr;
405 b[0] = (uint8)(value >> 8);
406 b[1] = (uint8)(value >> 0);
407 }
408 inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
409 uint8 *b = (uint8 *)ptr;
410 b[0] = (uint8)(value >> 24);
411 b[1] = (uint8)(value >> 16);
412 b[2] = (uint8)(value >> 8);
413 b[3] = (uint8)(value >> 0);
414 }
415 inline uint64 READ_BE_UINT64(const void *ptr) {
416 const uint8 *b = (const uint8 *)ptr;
417 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]);
418 }
419 inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
420 uint8 *b = (uint8 *)ptr;
421 b[0] = (uint8)(value >> 56);
422 b[1] = (uint8)(value >> 48);
423 b[2] = (uint8)(value >> 40);
424 b[3] = (uint8)(value >> 32);
425 b[4] = (uint8)(value >> 24);
426 b[5] = (uint8)(value >> 16);
427 b[6] = (uint8)(value >> 8);
428 b[7] = (uint8)(value >> 0);
429 }
430
431# else
432
433 inline uint16 READ_BE_UINT16(const void *ptr) {
434 return SWAP_BYTES_16(READ_UINT16(ptr));
435 }
436 inline uint32 READ_BE_UINT32(const void *ptr) {
437 return SWAP_BYTES_32(READ_UINT32(ptr));
438 }
439 inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
440 WRITE_UINT16(ptr, SWAP_BYTES_16(value));
441 }
442 inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
443 WRITE_UINT32(ptr, SWAP_BYTES_32(value));
444 }
445 inline uint64 READ_BE_UINT64(const void *ptr) {
446 return SWAP_BYTES_64(READ_UINT64(ptr));
447 }
448 inline void WRITE_BE_UINT64(void *ptr, uint64 value) {
449 WRITE_UINT64(ptr, SWAP_BYTES_64(value));
450 }
451
452# endif // if defined(SCUMM_NEED_ALIGNMENT)
453
454#elif defined(SCUMM_BIG_ENDIAN)
455
456 #define READ_BE_UINT16(a) READ_UINT16(a)
457 #define READ_BE_UINT32(a) READ_UINT32(a)
458
459 #define WRITE_BE_UINT16(a, v) WRITE_UINT16(a, v)
460 #define WRITE_BE_UINT32(a, v) WRITE_UINT32(a, v)
461
462 #define FROM_LE_32(a) SWAP_BYTES_32(a)
463 #define FROM_LE_16(a) SWAP_BYTES_16(a)
464
465 #define FROM_BE_32(a) ((uint32)(a))
466 #define FROM_BE_16(a) ((uint16)(a))
467
468 #define TO_LE_32(a) SWAP_BYTES_32(a)
469 #define TO_LE_16(a) SWAP_BYTES_16(a)
470
471 #define TO_BE_32(a) ((uint32)(a))
472 #define TO_BE_16(a) ((uint16)(a))
473
474 #define CONSTANT_LE_32(a) SWAP_CONSTANT_32(a)
475 #define CONSTANT_LE_16(a) SWAP_CONSTANT_16(a)
476
477 #define CONSTANT_BE_32(a) ((uint32)(a))
478 #define CONSTANT_BE_16(a) ((uint16)(a))
479
480 #define READ_BE_UINT64(a) READ_UINT64(a)
481 #define WRITE_BE_UINT64(a, v) WRITE_UINT64(a, v)
482 #define FROM_LE_64(a) SWAP_BYTES_64(a)
483 #define FROM_BE_64(a) ((uint64)(a))
484 #define TO_LE_64(a) SWAP_BYTES_64(a)
485 #define TO_BE_64(a) ((uint64)(a))
486 #define CONSTANT_LE_64(a) SWAP_CONSTANT_64(a)
487 #define CONSTANT_BE_64(a) ((uint64)(a))
488
489// if the unaligned load and the byteswap take a lot of instructions its better to directly read and invert
490# if defined(SCUMM_NEED_ALIGNMENT) && !defined(__mips__)
491
492 inline uint16 READ_LE_UINT16(const void *ptr) {
493 const uint8 *b = (const uint8 *)ptr;
494 return (b[1] << 8) | b[0];
495 }
496 inline uint32 READ_LE_UINT32(const void *ptr) {
497 const uint8 *b = (const uint8 *)ptr;
498 return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
499 }
500 inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
501 uint8 *b = (uint8 *)ptr;
502 b[0] = (uint8)(value >> 0);
503 b[1] = (uint8)(value >> 8);
504 }
505 inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
506 uint8 *b = (uint8 *)ptr;
507 b[0] = (uint8)(value >> 0);
508 b[1] = (uint8)(value >> 8);
509 b[2] = (uint8)(value >> 16);
510 b[3] = (uint8)(value >> 24);
511 }
512
513 inline uint64 READ_LE_UINT64(const void *ptr) {
514 const uint8 *b = (const uint8 *)ptr;
515 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]);
516 }
517 inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
518 uint8 *b = (uint8 *)ptr;
519 b[0] = (uint8)(value >> 0);
520 b[1] = (uint8)(value >> 8);
521 b[2] = (uint8)(value >> 16);
522 b[3] = (uint8)(value >> 24);
523 b[4] = (uint8)(value >> 32);
524 b[5] = (uint8)(value >> 40);
525 b[6] = (uint8)(value >> 48);
526 b[7] = (uint8)(value >> 56);
527 }
528
529# else
530
531 inline uint16 READ_LE_UINT16(const void *ptr) {
532 return SWAP_BYTES_16(READ_UINT16(ptr));
533 }
534 inline uint32 READ_LE_UINT32(const void *ptr) {
535 return SWAP_BYTES_32(READ_UINT32(ptr));
536 }
537 inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
538 WRITE_UINT16(ptr, SWAP_BYTES_16(value));
539 }
540 inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
541 WRITE_UINT32(ptr, SWAP_BYTES_32(value));
542 }
543 inline uint64 READ_LE_UINT64(const void *ptr) {
544 return SWAP_BYTES_64(READ_UINT64(ptr));
545 }
546 inline void WRITE_LE_UINT64(void *ptr, uint64 value) {
547 WRITE_UINT64(ptr, SWAP_BYTES_64(value));
548 }
549
550# endif // if defined(SCUMM_NEED_ALIGNMENT)
551
552#endif // if defined(SCUMM_LITTLE_ENDIAN)
553
554inline uint32 READ_LE_UINT24(const void *ptr) {
555 const uint8 *b = (const uint8 *)ptr;
556 return (b[2] << 16) | (b[1] << 8) | (b[0]);
557}
558
559inline void WRITE_LE_UINT24(void *ptr, uint32 value) {
560 uint8 *b = (uint8 *)ptr;
561 b[0] = (uint8)(value >> 0);
562 b[1] = (uint8)(value >> 8);
563 b[2] = (uint8)(value >> 16);
564}
565
566inline uint32 READ_BE_UINT24(const void *ptr) {
567 const uint8 *b = (const uint8 *)ptr;
568 return (b[0] << 16) | (b[1] << 8) | (b[2]);
569}
570
571inline void WRITE_BE_UINT24(void *ptr, uint32 value) {
572 uint8 *b = (uint8 *)ptr;
573 b[0] = (uint8)(value >> 16);
574 b[1] = (uint8)(value >> 8);
575 b[2] = (uint8)(value >> 0);
576}
577
578#ifdef SCUMM_LITTLE_ENDIAN
579#define READ_UINT24(a) READ_LE_UINT24(a)
580#define WRITE_UINT24(a,b) WRITE_LE_UINT24(a,b)
581#else
582#define READ_UINT24(a) READ_BE_UINT24(a)
583#define WRITE_UINT24(a,b) WRITE_BE_UINT24(a,b)
584#endif
585
587 float f;
588 uint32 u32;
589};
590
591static_assert(sizeof(float) == sizeof(uint32), "Unexpected size of float");
592
593inline float READ_LE_FLOAT32(const void *ptr) {
594 SwapFloat swap;
595 swap.u32 = READ_LE_UINT32(ptr);
596 return swap.f;
597}
598
599inline void WRITE_LE_FLOAT32(void *ptr, float value) {
600 SwapFloat swap;
601 swap.f = value;
602 WRITE_LE_UINT32(ptr, swap.u32);
603}
604
605inline float READ_BE_FLOAT32(const void *ptr) {
606 SwapFloat swap;
607 swap.u32 = READ_BE_UINT32(ptr);
608 return swap.f;
609}
610
611inline void WRITE_BE_FLOAT32(void *ptr, float value) {
612 SwapFloat swap;
613 swap.f = value;
614 WRITE_BE_UINT32(ptr, swap.u32);
615}
616
617#ifdef SCUMM_LITTLE_ENDIAN
618#define READ_FLOAT32(a) READ_LE_FLOAT32(a)
619#define WRITE_FLOAT32(a,b) WRITE_LE_FLOAT32(a,b)
620#else
621#define READ_FLOAT32(a) READ_BE_FLOAT32(a)
622#define WRITE_FLOAT32(a,b) WRITE_BE_FLOAT32(a,b)
623#endif
624
625#ifdef SCUMM_FLOAT_WORD_LITTLE_ENDIAN
626union SwapDouble {
627 double d;
628 uint64 u64;
629 struct {
630 uint32 low, high;
631 } u32;
632};
633#else
635 double d;
636 uint64 u64;
637 struct {
638 uint32 high, low;
639 } u32;
640};
641#endif
642
643static_assert(sizeof(double) == sizeof(uint64) || sizeof(double) == sizeof(uint32), "Unexpected size of double");
644
645template<size_t n> inline double READ_DOUBLE(const SwapDouble& sw);
646template<size_t n> inline void WRITE_DOUBLE(SwapDouble &sw, double d);
647
648// 64-bit double
649template<> inline double READ_DOUBLE<sizeof(uint64)>(const SwapDouble& sd)
650{
651 return sd.d;
652}
653
654template<> inline void WRITE_DOUBLE<sizeof(uint64)>(SwapDouble &sd, double d)
655{
656 sd.d = d;
657}
658
659// 32-bit double
660template<> inline double READ_DOUBLE<sizeof(uint32)>(const SwapDouble& sd)
661{
662 SwapFloat sf;
663 uint32 e = (sd.u32.high >> 20) & 0x7ff;
664 if (e <= 896) {
665 // Too small for normalized, create a zero with the correct sign
666 // (FIXME: Create denormalized numbers instead when possible?)
667 sf.u32 = (sd.u32.high & 0x80000000U); // sign bit
668 return sf.f;
669 } else if(e >= 1151) {
670 // Overflow, infinity or NaN
671 if (e < 2047) {
672 // Overflow; make sure result is infinity and not NaN
673 sf.u32 = (sd.u32.high & 0x80000000U) | // sign bit
674 (255 << 23); // exponent
675 return sf.f;
676 }
677 e = 255;
678 } else
679 e -= 896;
680 sf.u32 = (sd.u32.high & 0x80000000U) | // sign bit
681 (e << 23) | // exponent
682 ((sd.u32.high & 0xfffff) << 3) | (sd.u32.low >> 29); // mantissa
683 return sf.f;
684}
685
686template<> inline void WRITE_DOUBLE<sizeof(uint32)>(SwapDouble &sd, double d)
687{
688 SwapFloat sf;
689 sf.f = d;
690 uint32 e = (sf.u32 >> 23) & 0xff;
691 if (!e) {
692 // Denormalized or zero, create a zero with the correct sign
693 // (FIXME: Convert denormalized 32-bit to normalized 64-bit?)
694 sd.u32.high = (sf.u32 & 0x80000000U); // sign bit
695 sd.u32.low = 0;
696 return;
697 } else if (e == 255) {
698 // Infinity or NaN
699 e = 2047;
700 } else
701 e += 896;
702 sd.u32.high = (sf.u32 & 0x80000000U) | // sign bit
703 (e << 20) | // exponent
704 ((sf.u32 >> 3) & 0xfffff); // mantissa
705 sd.u32.low = sf.u32 << 29;
706}
707
708inline double READ_LE_FLOAT64(const void *ptr) {
709 SwapDouble swap;
710 const uint8 *b = (const uint8 *)ptr;
711 swap.u32.low = READ_LE_UINT32(b);
712 swap.u32.high = READ_LE_UINT32(b + 4);
713 return READ_DOUBLE<sizeof(double)>(swap);
714}
715
716inline void WRITE_LE_FLOAT64(void *ptr, double value) {
717 SwapDouble swap;
718 WRITE_DOUBLE<sizeof(double)>(swap, value);
719 uint8 *b = (uint8 *)ptr;
720 WRITE_LE_UINT32(b, swap.u32.low);
721 WRITE_LE_UINT32(b + 4, swap.u32.high);
722}
723
724inline double READ_BE_FLOAT64(const void *ptr) {
725 SwapDouble swap;
726 const uint8 *b = (const uint8 *)ptr;
727 swap.u32.high = READ_BE_UINT32(b);
728 swap.u32.low = READ_BE_UINT32(b + 4);
729 return READ_DOUBLE<sizeof(double)>(swap);
730}
731
732inline void WRITE_BE_FLOAT64(void *ptr, double value) {
733 SwapDouble swap;
734 WRITE_DOUBLE<sizeof(double)>(swap, value);
735 uint8 *b = (uint8 *)ptr;
736 WRITE_BE_UINT32(b, swap.u32.high);
737 WRITE_BE_UINT32(b + 4, swap.u32.low);
738}
739
740inline double READ_FPA_FLOAT64(const void *ptr) {
741 SwapDouble swap;
742 const uint8 *b = (const uint8 *)ptr;
743 swap.u32.high = READ_LE_UINT32(b);
744 swap.u32.low = READ_LE_UINT32(b + 4);
745 return READ_DOUBLE<sizeof(double)>(swap);
746}
747
748inline void WRITE_FPA_FLOAT64(void *ptr, double value) {
749 SwapDouble swap;
750 WRITE_DOUBLE<sizeof(double)>(swap, value);
751 uint8 *b = (uint8 *)ptr;
752 WRITE_LE_UINT32(b, swap.u32.high);
753 WRITE_LE_UINT32(b + 4, swap.u32.low);
754}
755
756inline double READ_FLOAT64(const void *ptr) {
757 SwapDouble swap;
758 swap.u64 = READ_UINT64(ptr);
759 return READ_DOUBLE<sizeof(double)>(swap);
760}
761
762inline void WRITE_FLOAT64(void *ptr, double value) {
763 SwapDouble swap;
764 WRITE_DOUBLE<sizeof(double)>(swap, value);
765 WRITE_UINT64(ptr, swap.u64);
766}
767
768inline int16 READ_LE_INT16(const void *ptr) {
769 return static_cast<int16>(READ_LE_UINT16(ptr));
770}
771
772inline void WRITE_LE_INT16(void *ptr, int16 value) {
773 WRITE_LE_UINT16(ptr, static_cast<uint16>(value));
774}
775
776inline int16 READ_BE_INT16(const void *ptr) {
777 return static_cast<int16>(READ_BE_UINT16(ptr));
778}
779
780inline void WRITE_BE_INT16(void *ptr, int16 value) {
781 WRITE_BE_UINT16(ptr, static_cast<uint16>(value));
782}
783
784inline int32 READ_LE_INT32(const void *ptr) {
785 return static_cast<int32>(READ_LE_UINT32(ptr));
786}
787
788inline void WRITE_LE_INT32(void *ptr, int32 value) {
789 WRITE_LE_UINT32(ptr, static_cast<uint32>(value));
790}
791
792inline int32 READ_BE_INT32(const void *ptr) {
793 return static_cast<int32>(READ_BE_UINT32(ptr));
794}
795
796inline void WRITE_BE_INT32(void *ptr, int32 value) {
797 WRITE_BE_UINT32(ptr, static_cast<uint32>(value));
798}
802#endif
uint16 SWAP_BYTES_16(const uint16 a)
Definition: endian.h:110
uint32 SWAP_BYTES_32(uint32 a)
Definition: endian.h:138
uint64 SWAP_BYTES_64(uint64 a)
Definition: endian.h:166
Definition: endian.h:634
Definition: endian.h:586