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
344 
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)
386 
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 
554 inline 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 
559 inline 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 
566 inline 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 
571 inline 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 
586 union SwapFloat {
587  float f;
588  uint32 u32;
589 };
590 
591 STATIC_ASSERT(sizeof(float) == sizeof(uint32), Unexpected_size_of_float);
592 
593 inline float READ_LE_FLOAT32(const void *ptr) {
594  SwapFloat swap;
595  swap.u32 = READ_LE_UINT32(ptr);
596  return swap.f;
597 }
598 
599 inline void WRITE_LE_FLOAT32(void *ptr, float value) {
600  SwapFloat swap;
601  swap.f = value;
602  WRITE_LE_UINT32(ptr, swap.u32);
603 }
604 
605 inline float READ_BE_FLOAT32(const void *ptr) {
606  SwapFloat swap;
607  swap.u32 = READ_BE_UINT32(ptr);
608  return swap.f;
609 }
610 
611 inline 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
626 union SwapDouble {
627  double d;
628  uint64 u64;
629  struct {
630  uint32 low, high;
631  } u32;
632 };
633 #else
634 union SwapDouble {
635  double d;
636  uint64 u64;
637  struct {
638  uint32 high, low;
639  } u32;
640 };
641 #endif
642 
643 STATIC_ASSERT(sizeof(double) == sizeof(uint64) || sizeof(double) == sizeof(uint32), Unexpected_size_of_double);
644 
645 template<size_t n> inline double READ_DOUBLE(const SwapDouble& sw);
646 template<size_t n> inline void WRITE_DOUBLE(SwapDouble &sw, double d);
647 
648 // 64-bit double
649 template<> inline double READ_DOUBLE<sizeof(uint64)>(const SwapDouble& sd)
650 {
651  return sd.d;
652 }
653 
654 template<> inline void WRITE_DOUBLE<sizeof(uint64)>(SwapDouble &sd, double d)
655 {
656  sd.d = d;
657 }
658 
659 // 32-bit double
660 template<> 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 
686 template<> 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 
708 inline 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 
716 inline 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 
724 inline 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 
732 inline 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 
740 inline 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 
748 inline 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 
756 inline double READ_FLOAT64(const void *ptr) {
757  SwapDouble swap;
758  swap.u64 = READ_UINT64(ptr);
759  return READ_DOUBLE<sizeof(double)>(swap);
760 }
761 
762 inline 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 
768 inline int16 READ_LE_INT16(const void *ptr) {
769  return static_cast<int16>(READ_LE_UINT16(ptr));
770 }
771 
772 inline void WRITE_LE_INT16(void *ptr, int16 value) {
773  WRITE_LE_UINT16(ptr, static_cast<uint16>(value));
774 }
775 
776 inline int16 READ_BE_INT16(const void *ptr) {
777  return static_cast<int16>(READ_BE_UINT16(ptr));
778 }
779 
780 inline void WRITE_BE_INT16(void *ptr, int16 value) {
781  WRITE_BE_UINT16(ptr, static_cast<uint16>(value));
782 }
783 
784 inline int32 READ_LE_INT32(const void *ptr) {
785  return static_cast<int32>(READ_LE_UINT32(ptr));
786 }
787 
788 inline void WRITE_LE_INT32(void *ptr, int32 value) {
789  WRITE_LE_UINT32(ptr, static_cast<uint32>(value));
790 }
791 
792 inline int32 READ_BE_INT32(const void *ptr) {
793  return static_cast<int32>(READ_BE_UINT32(ptr));
794 }
795 
796 inline void WRITE_BE_INT32(void *ptr, int32 value) {
797  WRITE_BE_UINT32(ptr, static_cast<uint32>(value));
798 }
802 #endif
Definition: endian.h:586
Definition: endian.h:634
uint64 SWAP_BYTES_64(uint64 a)
Definition: endian.h:166
uint32 SWAP_BYTES_32(uint32 a)
Definition: endian.h:138
uint16 SWAP_BYTES_16(const uint16 a)
Definition: endian.h:110