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