1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5 
6 #ifndef LIB_JXL_BASE_BYTE_ORDER_H_
7 #define LIB_JXL_BASE_BYTE_ORDER_H_
8 
9 #include <stdint.h>
10 #include <string.h>  // memcpy
11 
12 #include "lib/jxl/base/compiler_specific.h"
13 
14 #if JXL_COMPILER_MSVC
15 #include <intrin.h>  // _byteswap_*
16 #endif
17 
18 #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
19 #define JXL_BYTE_ORDER_LITTLE 1
20 #else
21 // This means that we don't know that the byte order is little endian, in
22 // this case we use endian-neutral code that works for both little- and
23 // big-endian.
24 #define JXL_BYTE_ORDER_LITTLE 0
25 #endif
26 
27 // Returns whether the system is little-endian (least-significant byte first).
28 #if JXL_BYTE_ORDER_LITTLE
IsLittleEndian()29 static constexpr bool IsLittleEndian() { return true; }
30 #else
IsLittleEndian()31 static inline bool IsLittleEndian() {
32   const uint32_t multibyte = 1;
33   uint8_t byte;
34   memcpy(&byte, &multibyte, 1);
35   return byte == 1;
36 }
37 #endif
38 
39 #if JXL_COMPILER_MSVC
40 #define JXL_BSWAP32(x) _byteswap_ulong(x)
41 #define JXL_BSWAP64(x) _byteswap_uint64(x)
42 #else
43 #define JXL_BSWAP32(x) __builtin_bswap32(x)
44 #define JXL_BSWAP64(x) __builtin_bswap64(x)
45 #endif
46 
LoadBE16(const uint8_t * p)47 static JXL_INLINE uint32_t LoadBE16(const uint8_t* p) {
48   const uint32_t byte1 = p[0];
49   const uint32_t byte0 = p[1];
50   return (byte1 << 8) | byte0;
51 }
52 
LoadLE16(const uint8_t * p)53 static JXL_INLINE uint32_t LoadLE16(const uint8_t* p) {
54   const uint32_t byte0 = p[0];
55   const uint32_t byte1 = p[1];
56   return (byte1 << 8) | byte0;
57 }
58 
LoadBE24(const uint8_t * p)59 static JXL_INLINE uint32_t LoadBE24(const uint8_t* p) {
60   const uint32_t byte2 = p[0];
61   const uint32_t byte1 = p[1];
62   const uint32_t byte0 = p[2];
63   return (byte2 << 16) | (byte1 << 8) | byte0;
64 }
65 
LoadLE24(const uint8_t * p)66 static JXL_INLINE uint32_t LoadLE24(const uint8_t* p) {
67   const uint32_t byte0 = p[0];
68   const uint32_t byte1 = p[1];
69   const uint32_t byte2 = p[2];
70   return (byte2 << 16) | (byte1 << 8) | byte0;
71 }
72 
LoadBE32(const uint8_t * p)73 static JXL_INLINE uint32_t LoadBE32(const uint8_t* p) {
74 #if JXL_BYTE_ORDER_LITTLE
75   uint32_t big;
76   memcpy(&big, p, 4);
77   return JXL_BSWAP32(big);
78 #else
79   // Byte-order-independent - can't assume this machine is big endian.
80   const uint32_t byte3 = p[0];
81   const uint32_t byte2 = p[1];
82   const uint32_t byte1 = p[2];
83   const uint32_t byte0 = p[3];
84   return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
85 #endif
86 }
87 
LoadBE64(const uint8_t * p)88 static JXL_INLINE uint64_t LoadBE64(const uint8_t* p) {
89 #if JXL_BYTE_ORDER_LITTLE
90   uint64_t big;
91   memcpy(&big, p, 8);
92   return JXL_BSWAP64(big);
93 #else
94   // Byte-order-independent - can't assume this machine is big endian.
95   const uint64_t byte7 = p[0];
96   const uint64_t byte6 = p[1];
97   const uint64_t byte5 = p[2];
98   const uint64_t byte4 = p[3];
99   const uint64_t byte3 = p[4];
100   const uint64_t byte2 = p[5];
101   const uint64_t byte1 = p[6];
102   const uint64_t byte0 = p[7];
103   return (byte7 << 56ull) | (byte6 << 48ull) | (byte5 << 40ull) |
104          (byte4 << 32ull) | (byte3 << 24ull) | (byte2 << 16ull) |
105          (byte1 << 8ull) | byte0;
106 #endif
107 }
108 
LoadLE32(const uint8_t * p)109 static JXL_INLINE uint32_t LoadLE32(const uint8_t* p) {
110 #if JXL_BYTE_ORDER_LITTLE
111   uint32_t little;
112   memcpy(&little, p, 4);
113   return little;
114 #else
115   // Byte-order-independent - can't assume this machine is big endian.
116   const uint32_t byte0 = p[0];
117   const uint32_t byte1 = p[1];
118   const uint32_t byte2 = p[2];
119   const uint32_t byte3 = p[3];
120   return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
121 #endif
122 }
123 
LoadLE64(const uint8_t * p)124 static JXL_INLINE uint64_t LoadLE64(const uint8_t* p) {
125 #if JXL_BYTE_ORDER_LITTLE
126   uint64_t little;
127   memcpy(&little, p, 8);
128   return little;
129 #else
130   // Byte-order-independent - can't assume this machine is big endian.
131   const uint64_t byte0 = p[0];
132   const uint64_t byte1 = p[1];
133   const uint64_t byte2 = p[2];
134   const uint64_t byte3 = p[3];
135   const uint64_t byte4 = p[4];
136   const uint64_t byte5 = p[5];
137   const uint64_t byte6 = p[6];
138   const uint64_t byte7 = p[7];
139   return (byte7 << 56) | (byte6 << 48) | (byte5 << 40) | (byte4 << 32) |
140          (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
141 #endif
142 }
143 
StoreBE16(const uint32_t native,uint8_t * p)144 static JXL_INLINE void StoreBE16(const uint32_t native, uint8_t* p) {
145   p[0] = (native >> 8) & 0xFF;
146   p[1] = native & 0xFF;
147 }
148 
StoreLE16(const uint32_t native,uint8_t * p)149 static JXL_INLINE void StoreLE16(const uint32_t native, uint8_t* p) {
150   p[1] = (native >> 8) & 0xFF;
151   p[0] = native & 0xFF;
152 }
153 
StoreBE24(const uint32_t native,uint8_t * p)154 static JXL_INLINE void StoreBE24(const uint32_t native, uint8_t* p) {
155   p[0] = (native >> 16) & 0xFF;
156   p[1] = (native >> 8) & 0xFF;
157   p[2] = native & 0xFF;
158 }
159 
StoreLE24(const uint32_t native,uint8_t * p)160 static JXL_INLINE void StoreLE24(const uint32_t native, uint8_t* p) {
161   p[2] = (native >> 24) & 0xFF;
162   p[1] = (native >> 8) & 0xFF;
163   p[0] = native & 0xFF;
164 }
165 
StoreBE32(const uint32_t native,uint8_t * p)166 static JXL_INLINE void StoreBE32(const uint32_t native, uint8_t* p) {
167 #if JXL_BYTE_ORDER_LITTLE
168   const uint32_t big = JXL_BSWAP32(native);
169   memcpy(p, &big, 4);
170 #else
171   // Byte-order-independent - can't assume this machine is big endian.
172   p[0] = native >> 24;
173   p[1] = (native >> 16) & 0xFF;
174   p[2] = (native >> 8) & 0xFF;
175   p[3] = native & 0xFF;
176 #endif
177 }
178 
StoreBE64(const uint64_t native,uint8_t * p)179 static JXL_INLINE void StoreBE64(const uint64_t native, uint8_t* p) {
180 #if JXL_BYTE_ORDER_LITTLE
181   const uint64_t big = JXL_BSWAP64(native);
182   memcpy(p, &big, 8);
183 #else
184   // Byte-order-independent - can't assume this machine is big endian.
185   p[0] = native >> 56ull;
186   p[1] = (native >> 48ull) & 0xFF;
187   p[2] = (native >> 40ull) & 0xFF;
188   p[3] = (native >> 32ull) & 0xFF;
189   p[4] = (native >> 24ull) & 0xFF;
190   p[5] = (native >> 16ull) & 0xFF;
191   p[6] = (native >> 8ull) & 0xFF;
192   p[7] = native & 0xFF;
193 #endif
194 }
195 
StoreLE32(const uint32_t native,uint8_t * p)196 static JXL_INLINE void StoreLE32(const uint32_t native, uint8_t* p) {
197 #if JXL_BYTE_ORDER_LITTLE
198   const uint32_t little = native;
199   memcpy(p, &little, 4);
200 #else
201   // Byte-order-independent - can't assume this machine is big endian.
202   p[3] = native >> 24;
203   p[2] = (native >> 16) & 0xFF;
204   p[1] = (native >> 8) & 0xFF;
205   p[0] = native & 0xFF;
206 #endif
207 }
208 
StoreLE64(const uint64_t native,uint8_t * p)209 static JXL_INLINE void StoreLE64(const uint64_t native, uint8_t* p) {
210 #if JXL_BYTE_ORDER_LITTLE
211   const uint64_t little = native;
212   memcpy(p, &little, 8);
213 #else
214   // Byte-order-independent - can't assume this machine is big endian.
215   p[7] = native >> 56;
216   p[6] = (native >> 48) & 0xFF;
217   p[5] = (native >> 40) & 0xFF;
218   p[4] = (native >> 32) & 0xFF;
219   p[3] = (native >> 24) & 0xFF;
220   p[2] = (native >> 16) & 0xFF;
221   p[1] = (native >> 8) & 0xFF;
222   p[0] = native & 0xFF;
223 #endif
224 }
225 
226 // Big/Little Endian order.
227 struct OrderBE {};
228 struct OrderLE {};
229 
230 // Wrappers for calling from generic code.
Store16(OrderBE,const uint32_t native,uint8_t * p)231 static JXL_INLINE void Store16(OrderBE /*tag*/, const uint32_t native,
232                                uint8_t* p) {
233   return StoreBE16(native, p);
234 }
235 
Store16(OrderLE,const uint32_t native,uint8_t * p)236 static JXL_INLINE void Store16(OrderLE /*tag*/, const uint32_t native,
237                                uint8_t* p) {
238   return StoreLE16(native, p);
239 }
240 
Store24(OrderBE,const uint32_t native,uint8_t * p)241 static JXL_INLINE void Store24(OrderBE /*tag*/, const uint32_t native,
242                                uint8_t* p) {
243   return StoreBE24(native, p);
244 }
245 
Store24(OrderLE,const uint32_t native,uint8_t * p)246 static JXL_INLINE void Store24(OrderLE /*tag*/, const uint32_t native,
247                                uint8_t* p) {
248   return StoreLE24(native, p);
249 }
Store32(OrderBE,const uint32_t native,uint8_t * p)250 static JXL_INLINE void Store32(OrderBE /*tag*/, const uint32_t native,
251                                uint8_t* p) {
252   return StoreBE32(native, p);
253 }
254 
Store32(OrderLE,const uint32_t native,uint8_t * p)255 static JXL_INLINE void Store32(OrderLE /*tag*/, const uint32_t native,
256                                uint8_t* p) {
257   return StoreLE32(native, p);
258 }
259 
Load16(OrderBE,const uint8_t * p)260 static JXL_INLINE uint32_t Load16(OrderBE /*tag*/, const uint8_t* p) {
261   return LoadBE16(p);
262 }
263 
Load16(OrderLE,const uint8_t * p)264 static JXL_INLINE uint32_t Load16(OrderLE /*tag*/, const uint8_t* p) {
265   return LoadLE16(p);
266 }
267 
Load24(OrderBE,const uint8_t * p)268 static JXL_INLINE uint32_t Load24(OrderBE /*tag*/, const uint8_t* p) {
269   return LoadBE24(p);
270 }
271 
Load24(OrderLE,const uint8_t * p)272 static JXL_INLINE uint32_t Load24(OrderLE /*tag*/, const uint8_t* p) {
273   return LoadLE24(p);
274 }
Load32(OrderBE,const uint8_t * p)275 static JXL_INLINE uint32_t Load32(OrderBE /*tag*/, const uint8_t* p) {
276   return LoadBE32(p);
277 }
278 
Load32(OrderLE,const uint8_t * p)279 static JXL_INLINE uint32_t Load32(OrderLE /*tag*/, const uint8_t* p) {
280   return LoadLE32(p);
281 }
282 
283 #endif  // LIB_JXL_BASE_BYTE_ORDER_H_
284