1 /*
2 ** Copyright (C) 1999-2018 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #ifndef SFENDIAN_INCLUDED
20 #define SFENDIAN_INCLUDED
21 
22 #include "sfconfig.h"
23 
24 #include <stdint.h>
25 #include <inttypes.h>
26 
27 #if HAVE_BYTESWAP_H			/* Linux, any CPU */
28 #include <byteswap.h>
29 
30 #define	ENDSWAP_16(x)		(bswap_16 (x))
31 #define	ENDSWAP_32(x)		(bswap_32 (x))
32 #define	ENDSWAP_64(x)		(bswap_64 (x))
33 
34 #elif defined __has_builtin
35 
36 #if __has_builtin (__builtin_bswap16)
37 #define ENDSWAP_16(x) ((int16_t) __builtin_bswap16 ((uint16_t) x))
38 #endif
39 
40 #if __has_builtin (__builtin_bswap32)
41 #define ENDSWAP_32(x) ((int32_t) __builtin_bswap32 ((uint32_t) x))
42 #endif
43 
44 #if __has_builtin (__builtin_bswap64)
45 #define ENDSWAP_64(x) ((int64_t) __builtin_bswap64 ((uint64_t) x))
46 #endif
47 
48 #elif COMPILER_IS_GCC
49 
50 #if CPU_IS_X86
51 
52 static inline int16_t
ENDSWAP_16X(int16_t x)53 ENDSWAP_16X (int16_t x)
54 {	int16_t y ;
55 	__asm__ ("rorw $8, %w0" : "=r" (y) : "0" (x) : "cc") ;
56 	return y ;
57 } /* ENDSWAP_16 */
58 
59 static inline int32_t
ENDSWAP_32X(int32_t x)60 ENDSWAP_32X (int32_t x)
61 {	int32_t y ;
62 	__asm__ ("bswap %0" : "=r" (y) : "0" (x)) ;
63 	return y ;
64 } /* ENDSWAP_32 */
65 
66 #define ENDSWAP_16 ENDSWAP_16X
67 #define ENDSWAP_32 ENDSWAP_32X
68 
69 #endif
70 
71 #if CPU_IS_X86_64
72 
73 static inline int64_t
ENDSWAP_64X(int64_t x)74 ENDSWAP_64X (int64_t x)
75 {	int64_t y ;
76 	__asm__ ("bswap %q0" : "=r" (y) : "0" (x)) ;
77 	return y ;
78 } /* ENDSWAP_64X */
79 
80 #define ENDSWAP_64 ENDSWAP_64X
81 
82 #endif
83 
84 #elif defined _MSC_VER
85 #include <stdlib.h>
86 
87 #define	ENDSWAP_16(x)		(_byteswap_ushort (x))
88 #define	ENDSWAP_32(x)		(_byteswap_ulong (x))
89 #define	ENDSWAP_64(x)		(_byteswap_uint64 (x))
90 
91 #endif
92 
93 #ifndef ENDSWAP_16
94 #define	ENDSWAP_16(x)		((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8))
95 #endif
96 
97 #ifndef ENDSWAP_32
98 #define	ENDSWAP_32(x)		((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24))
99 #endif
100 
101 #ifndef ENDSWAP_64
102 static inline uint64_t
ENDSWAP_64(uint64_t x)103 ENDSWAP_64 (uint64_t x)
104 {	union
105 	{	uint32_t parts [2] ;
106 		uint64_t whole ;
107 	} u ;
108 	uint32_t temp ;
109 
110 	u.whole = x ;
111 	temp = u.parts [0] ;
112 	u.parts [0] = ENDSWAP_32 (u.parts [1]) ;
113 	u.parts [1] = ENDSWAP_32 (temp) ;
114 	return u.whole ;
115 }
116 #endif
117 
118 /*
119 ** Many file types (ie WAV, AIFF) use sets of four consecutive bytes as a
120 ** marker indicating different sections of the file.
121 ** The following MAKE_MARKER macro allows th creation of integer constants
122 ** for these markers.
123 */
124 
125 #if (CPU_IS_LITTLE_ENDIAN == 1)
126 	#define	MAKE_MARKER(a, b, c, d)		((uint32_t) ((a) | ((b) << 8) | ((c) << 16) | (((uint32_t) (d)) << 24)))
127 #elif (CPU_IS_BIG_ENDIAN == 1)
128 	#define	MAKE_MARKER(a, b, c, d)		((uint32_t) ((((uint32_t) (a)) << 24) | ((b) << 16) | ((c) << 8) | (d)))
129 #else
130 	#error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h"
131 #endif
132 
133 /*
134 ** Macros to handle reading of data of a specific endian-ness into host endian
135 ** shorts and ints. The single input is an unsigned char* pointer to the start
136 ** of the object. There are two versions of each macro as we need to deal with
137 ** both big and little endian CPUs.
138 */
139 
140 #if (CPU_IS_LITTLE_ENDIAN == 1)
141 	#define LE2H_16(x)			(x)
142 	#define LE2H_32(x)			(x)
143 
144 	#define BE2H_16(x)			ENDSWAP_16 (x)
145 	#define BE2H_32(x)			ENDSWAP_32 (x)
146 	#define BE2H_64(x)			ENDSWAP_64 (x)
147 
148 	#define H2BE_16(x)			ENDSWAP_16 (x)
149 	#define H2BE_32(x)			ENDSWAP_32 (x)
150 
151 	#define H2LE_16(x)			(x)
152 	#define H2LE_32(x)			(x)
153 
154 #elif (CPU_IS_BIG_ENDIAN == 1)
155 	#define LE2H_16(x)			ENDSWAP_16 (x)
156 	#define LE2H_32(x)			ENDSWAP_32 (x)
157 
158 	#define BE2H_16(x)			(x)
159 	#define BE2H_32(x)			(x)
160 	#define	BE2H_64(x)			(x)
161 
162 	#define H2BE_16(x)			(x)
163 	#define H2BE_32(x)			(x)
164 
165 	#define H2LE_16(x)			ENDSWAP_16 (x)
166 	#define H2LE_32(x)			ENDSWAP_32 (x)
167 
168 #else
169 	#error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h"
170 #endif
171 
172 #define LE2H_32_PTR(x)			(((x) [0]) + ((x) [1] << 8) + ((x) [2] << 16) + ((x) [3] << 24))
173 
174 #define LET2H_16_PTR(x)			((x) [1] + ((x) [2] << 8))
175 #define LET2H_32_PTR(x)			(((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24))
176 
177 #define BET2H_16_PTR(x)			(((x) [0] << 8) + (x) [1])
178 #define BET2H_32_PTR(x)			(((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8))
179 
180 static inline void
psf_put_be64(uint8_t * ptr,int offset,int64_t value)181 psf_put_be64 (uint8_t *ptr, int offset, int64_t value)
182 {
183 	ptr [offset] = (uint8_t) (value >> 56) ;
184 	ptr [offset + 1] = (uint8_t) (value >> 48) ;
185 	ptr [offset + 2] = (uint8_t) (value >> 40) ;
186 	ptr [offset + 3] = (uint8_t) (value >> 32) ;
187 	ptr [offset + 4] = (uint8_t) (value >> 24) ;
188 	ptr [offset + 5] = (uint8_t) (value >> 16) ;
189 	ptr [offset + 6] = (uint8_t) (value >> 8) ;
190 	ptr [offset + 7] = (uint8_t) value ;
191 } /* psf_put_be64 */
192 
193 static inline void
psf_put_be32(uint8_t * ptr,int offset,int32_t value)194 psf_put_be32 (uint8_t *ptr, int offset, int32_t value)
195 {
196 	ptr [offset] = (uint8_t) (value >> 24) ;
197 	ptr [offset + 1] = (uint8_t) (value >> 16) ;
198 	ptr [offset + 2] = (uint8_t) (value >> 8) ;
199 	ptr [offset + 3] = (uint8_t) value ;
200 } /* psf_put_be32 */
201 
202 static inline void
psf_put_be16(uint8_t * ptr,int offset,int16_t value)203 psf_put_be16 (uint8_t *ptr, int offset, int16_t value)
204 {
205 	ptr [offset] = (uint8_t) (value >> 8) ;
206 	ptr [offset + 1] = (uint8_t) value ;
207 } /* psf_put_be16 */
208 
209 static inline int64_t
psf_get_be64(const uint8_t * ptr,int offset)210 psf_get_be64 (const uint8_t *ptr, int offset)
211 {	int64_t value ;
212 
213 	value = ((uint32_t) ptr [offset]) << 24 ;
214 	value += ptr [offset + 1] << 16 ;
215 	value += ptr [offset + 2] << 8 ;
216 	value += ptr [offset + 3] ;
217 
218 	value = (int64_t) (((uint64_t) value) << 32) ;
219 
220 	value += ((uint32_t) ptr [offset + 4]) << 24 ;
221 	value += ptr [offset + 5] << 16 ;
222 	value += ptr [offset + 6] << 8 ;
223 	value += ptr [offset + 7] ;
224 	return value ;
225 } /* psf_get_be64 */
226 
227 static inline int64_t
psf_get_le64(const uint8_t * ptr,int offset)228 psf_get_le64 (const uint8_t *ptr, int offset)
229 {	int64_t value ;
230 
231 	value = ((uint32_t) ptr [offset + 7]) << 24 ;
232 	value += ptr [offset + 6] << 16 ;
233 	value += ptr [offset + 5] << 8 ;
234 	value += ptr [offset + 4] ;
235 
236 	value = (int64_t) (((uint64_t) value) << 32) ;
237 
238 	value += ((uint32_t) ptr [offset + 3]) << 24 ;
239 	value += ptr [offset + 2] << 16 ;
240 	value += ptr [offset + 1] << 8 ;
241 	value += ptr [offset] ;
242 	return value ;
243 } /* psf_get_le64 */
244 
245 static inline int32_t
psf_get_be32(const uint8_t * ptr,int offset)246 psf_get_be32 (const uint8_t *ptr, int offset)
247 {	int32_t value ;
248 
249 	value = ((uint32_t) ptr [offset]) << 24 ;
250 	value += ptr [offset + 1] << 16 ;
251 	value += ptr [offset + 2] << 8 ;
252 	value += ptr [offset + 3] ;
253 	return value ;
254 } /* psf_get_be32 */
255 
256 static inline int32_t
psf_get_le32(const uint8_t * ptr,int offset)257 psf_get_le32 (const uint8_t *ptr, int offset)
258 {	int32_t value ;
259 
260 	value = ((uint32_t) ptr [offset + 3]) << 24 ;
261 	value += ptr [offset + 2] << 16 ;
262 	value += ptr [offset + 1] << 8 ;
263 	value += ptr [offset] ;
264 	return value ;
265 } /* psf_get_le32 */
266 
267 static inline int32_t
psf_get_be24(const uint8_t * ptr,int offset)268 psf_get_be24 (const uint8_t *ptr, int offset)
269 {	int32_t value ;
270 
271 	value = ((uint32_t) ptr [offset]) << 24 ;
272 	value += ptr [offset + 1] << 16 ;
273 	value += ptr [offset + 2] << 8 ;
274 	return value ;
275 } /* psf_get_be24 */
276 
277 static inline int32_t
psf_get_le24(const uint8_t * ptr,int offset)278 psf_get_le24 (const uint8_t *ptr, int offset)
279 {	int32_t value ;
280 
281 	value = ((uint32_t) ptr [offset + 2]) << 24 ;
282 	value += ptr [offset + 1] << 16 ;
283 	value += ptr [offset] << 8 ;
284 	return value ;
285 } /* psf_get_le24 */
286 
287 static inline int16_t
psf_get_be16(const uint8_t * ptr,int offset)288 psf_get_be16 (const uint8_t *ptr, int offset)
289 {	return (int16_t) (ptr [offset] << 8) + ptr [offset + 1] ;
290 } /* psf_get_be16 */
291 
292 /*-----------------------------------------------------------------------------------------------
293 ** Generic functions for performing endian swapping on integer arrays.
294 */
295 
296 static inline void
endswap_short_array(short * ptr,int len)297 endswap_short_array (short *ptr, int len)
298 {	short	temp ;
299 
300 	while (--len >= 0)
301 	{	temp = ptr [len] ;
302 		ptr [len] = ENDSWAP_16 (temp) ;
303 		} ;
304 } /* endswap_short_array */
305 
306 static inline void
endswap_short_copy(short * dest,const short * src,int len)307 endswap_short_copy (short *dest, const short *src, int len)
308 {
309 	while (--len >= 0)
310 	{	dest [len] = ENDSWAP_16 (src [len]) ;
311 		} ;
312 } /* endswap_short_copy */
313 
314 static inline void
endswap_int_array(int * ptr,int len)315 endswap_int_array (int *ptr, int len)
316 {	int temp ;
317 
318 	while (--len >= 0)
319 	{	temp = ptr [len] ;
320 		ptr [len] = ENDSWAP_32 (temp) ;
321 		} ;
322 } /* endswap_int_array */
323 
324 static inline void
endswap_int_copy(int * dest,const int * src,int len)325 endswap_int_copy (int *dest, const int *src, int len)
326 {
327 	while (--len >= 0)
328 	{	dest [len] = ENDSWAP_32 (src [len]) ;
329 		} ;
330 } /* endswap_int_copy */
331 
332 /*========================================================================================
333 */
334 
335 static inline void
endswap_int64_t_array(int64_t * ptr,int len)336 endswap_int64_t_array (int64_t *ptr, int len)
337 {	int64_t value ;
338 
339 	while (--len >= 0)
340 	{	value = ptr [len] ;
341 		ptr [len] = ENDSWAP_64 (value) ;
342 		} ;
343 } /* endswap_int64_t_array */
344 
345 static inline void
endswap_int64_t_copy(int64_t * dest,const int64_t * src,int len)346 endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len)
347 {	int64_t value ;
348 
349 	while (--len >= 0)
350 	{	value = src [len] ;
351 		dest [len] = ENDSWAP_64 (value) ;
352 		} ;
353 } /* endswap_int64_t_copy */
354 
355 /* A couple of wrapper functions. */
356 
357 static inline void
endswap_float_array(float * ptr,int len)358 endswap_float_array (float *ptr, int len)
359 {	endswap_int_array ((int *) ptr, len) ;
360 } /* endswap_float_array */
361 
362 static inline void
endswap_double_array(double * ptr,int len)363 endswap_double_array (double *ptr, int len)
364 {	endswap_int64_t_array ((int64_t *) ptr, len) ;
365 } /* endswap_double_array */
366 
367 static inline void
endswap_float_copy(float * dest,const float * src,int len)368 endswap_float_copy (float *dest, const float *src, int len)
369 {	endswap_int_copy ((int *) dest, (const int *) src, len) ;
370 } /* endswap_float_copy */
371 
372 static inline void
endswap_double_copy(double * dest,const double * src,int len)373 endswap_double_copy (double *dest, const double *src, int len)
374 {	endswap_int64_t_copy ((int64_t *) dest, (const int64_t *) src, len) ;
375 } /* endswap_double_copy */
376 
377 #endif /* SFENDIAN_INCLUDED */
378 
379