Endian.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifndef Endian_H
  16. #define Endian_H
  17. #include <stdint.h>
  18. #ifdef linux
  19. #include <byteswap.h>
  20. #endif
  21. #ifdef darwin
  22. #include <libkern/OSByteOrder.h>
  23. #endif
  24. #ifdef freebsd
  25. #include <sys/endian.h>
  26. #endif
  27. static inline int Endian_isBigEndian()
  28. {
  29. union {
  30. uint32_t i;
  31. char c[4];
  32. } bint = {0x01020304};
  33. return bint.c[0] == 1;
  34. }
  35. #ifdef __BYTE_ORDER__
  36. #if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
  37. #define Endian_isBigEndian() 0
  38. #define Endian_LITTLE
  39. #endif
  40. #if defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  41. #define Endian_isBigEndian() 1
  42. #define Endian_BIG
  43. #endif
  44. #endif
  45. #define Endian_rotateAndMask(mask, rotateBits) \
  46. ((input >> rotateBits) & mask) | ((input & mask) << rotateBits)
  47. // Portable
  48. static inline uint16_t Endian_byteSwap16_manual(uint16_t input)
  49. {
  50. return (input << 8) | (input >> 8);
  51. }
  52. #define Endian_byteSwapNoCast16(x) Endian_byteSwap16_manual(x)
  53. #define Endian_byteSwap16_uses "Endian_byteSwap16_manual"
  54. static inline uint32_t Endian_byteSwap32_manual(uint32_t input)
  55. {
  56. input = Endian_rotateAndMask(0x00FF00FF, 8);
  57. return Endian_rotateAndMask(0x0000FFFF, 16);
  58. }
  59. #define Endian_byteSwapNoCast32(x) Endian_byteSwap32_manual(x)
  60. #define Endian_byteSwap32_uses "Endian_byteSwap32_manual"
  61. static inline uint64_t Endian_byteSwap64_manual(uint64_t input)
  62. {
  63. input = Endian_rotateAndMask(0x00FF00FF00FF00FFull, 8);
  64. input = Endian_rotateAndMask(0x0000FFFF0000FFFFull, 16);
  65. return Endian_rotateAndMask(0x00000000FFFFFFFFull, 32);
  66. }
  67. #define Endian_byteSwapNoCast64(x) Endian_byteSwap64_manual(x)
  68. #define Endian_byteSwap64_uses "Endian_byteSwap64_manual"
  69. // Linux
  70. #ifdef bswap_16
  71. #undef Endian_byteSwapNoCast16
  72. #undef Endian_byteSwap16_uses
  73. #define Endian_byteSwapNoCast16(x) bswap_16(x)
  74. #define Endian_byteSwap16_uses "bswap_16"
  75. #endif
  76. #ifdef bswap_32
  77. #undef Endian_byteSwapNoCast32
  78. #undef Endian_byteSwap32_uses
  79. #define Endian_byteSwapNoCast32(x) bswap_32(x)
  80. #define Endian_byteSwap32_uses "bswap_32"
  81. #endif
  82. #ifdef bswap_64
  83. #undef Endian_byteSwapNoCast64
  84. #undef Endian_byteSwap64_uses
  85. #define Endian_byteSwapNoCast64(x) bswap_64(x)
  86. #define Endian_byteSwap64_uses "bswap_64"
  87. #endif
  88. // BSD
  89. #ifdef bswap16
  90. #undef Endian_byteSwapNoCast16
  91. #undef Endian_byteSwap16_uses
  92. #define Endian_byteSwapNoCast16(x) bswap16(x)
  93. #define Endian_byteSwap16_uses "bswap16"
  94. #endif
  95. #ifdef bswap32
  96. #undef Endian_byteSwapNoCast32
  97. #undef Endian_byteSwap32_uses
  98. #define Endian_byteSwapNoCast32(x) bswap32(x)
  99. #define Endian_byteSwap32_uses "bswap32"
  100. #endif
  101. #ifdef bswap64
  102. #undef Endian_byteSwapNoCast64
  103. #undef Endian_byteSwap64_uses
  104. #define Endian_byteSwapNoCast64(x) bswap64(x)
  105. #define Endian_byteSwap64_uses "bswap64"
  106. #endif
  107. // Apple
  108. #ifdef OSSwapInt16
  109. #undef Endian_byteSwapNoCast16
  110. #undef Endian_byteSwap16_uses
  111. #define Endian_byteSwapNoCast16(x) OSSwapInt16(x)
  112. #define Endian_byteSwap16_uses "OSSwapInt16"
  113. #endif
  114. #ifdef OSSwapInt32
  115. #undef Endian_byteSwapNoCast32
  116. #undef Endian_byteSwap32_uses
  117. #define Endian_byteSwapNoCast32(x) OSSwapInt32(x)
  118. #define Endian_byteSwap32_uses "OSSwapInt32"
  119. #endif
  120. #ifdef OSSwapInt64
  121. #undef Endian_byteSwapNoCast64
  122. #undef Endian_byteSwap64_uses
  123. #define Endian_byteSwapNoCast64(x) OSSwapInt64(x)
  124. #define Endian_byteSwap64_uses "OSSwapInt64"
  125. #endif
  126. // Make sure the size is right.
  127. #define Endian_byteSwap16(x) ((uint16_t)Endian_byteSwapNoCast16(((uint16_t)(x))))
  128. #define Endian_byteSwap32(x) ((uint32_t)Endian_byteSwapNoCast32(((uint32_t)(x))))
  129. #define Endian_byteSwap64(x) ((uint64_t)Endian_byteSwapNoCast64(((uint64_t)(x))))
  130. #if defined(Endian_BIG)
  131. #define Endian_hostToLittleEndian16(input) Endian_byteSwap16(input)
  132. #define Endian_hostToBigEndian16(input) (input)
  133. #define Endian_hostToLittleEndian32(input) Endian_byteSwap32(input)
  134. #define Endian_hostToBigEndian32(input) (input)
  135. #define Endian_hostToLittleEndian64(input) Endian_byteSwap64(input)
  136. #define Endian_hostToBigEndian64(input) (input)
  137. #elif defined(Endian_LITTLE)
  138. #define Endian_hostToLittleEndian16(input) (input)
  139. #define Endian_hostToBigEndian16(input) Endian_byteSwap16(input)
  140. #define Endian_hostToLittleEndian32(input) (input)
  141. #define Endian_hostToBigEndian32(input) Endian_byteSwap32(input)
  142. #define Endian_hostToLittleEndian64(input) (input)
  143. #define Endian_hostToBigEndian64(input) Endian_byteSwap64(input)
  144. #else
  145. #define Endian_hostToLittleEndian16(input) \
  146. ((!Endian_isBigEndian()) ? (input) : Endian_byteSwap16(input))
  147. #define Endian_hostToBigEndian16(input) \
  148. ((Endian_isBigEndian()) ? (input) : Endian_byteSwap16(input))
  149. #define Endian_hostToLittleEndian32(input) \
  150. ((!Endian_isBigEndian()) ? (input) : Endian_byteSwap32(input))
  151. #define Endian_hostToBigEndian32(input) \
  152. ((Endian_isBigEndian()) ? (input) : Endian_byteSwap32(input))
  153. #define Endian_hostToLittleEndian64(input) \
  154. ((!Endian_isBigEndian()) ? (input) : Endian_byteSwap64(input))
  155. #define Endian_hostToBigEndian64(input) \
  156. ((Endian_isBigEndian()) ? (input) : Endian_byteSwap64(input))
  157. #endif
  158. // looks silly but some macros want to be able to do generic swapping for any common int type.
  159. #define Endian_littleEndianToHost8(x) (x)
  160. #define Endian_bigEndianToHost8(x) (x)
  161. #define Endian_hostToLittleEndian8(x) (x)
  162. #define Endian_hostToBigEndian8(x) (x)
  163. #define Endian_littleEndianToHost16(x) Endian_hostToLittleEndian16(x)
  164. #define Endian_bigEndianToHost16(x) Endian_hostToBigEndian16(x)
  165. #define Endian_littleEndianToHost32(x) Endian_hostToLittleEndian32(x)
  166. #define Endian_bigEndianToHost32(x) Endian_hostToBigEndian32(x)
  167. #define Endian_littleEndianToHost64(x) Endian_hostToLittleEndian64(x)
  168. #define Endian_bigEndianToHost64(x) Endian_hostToBigEndian64(x)
  169. // These are not guaranteed to exist.
  170. #undef Endian_LITTLE
  171. #undef Endian_BIG
  172. #endif