xref: /third_party/libsnd/src/sfendian.h (revision b815c7f3)
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
48static inline int16_t
49ENDSWAP_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
55static inline int32_t
56ENDSWAP_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
69static inline int64_t
70ENDSWAP_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
98static inline uint64_t
99ENDSWAP_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
176static inline void
177psf_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
189static inline void
190psf_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
198static inline void
199psf_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
205static inline int64_t
206psf_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
223static inline int64_t
224psf_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
239static inline int32_t
240psf_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
248static inline int32_t
249psf_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
257static inline int32_t
258psf_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
265static inline int32_t
266psf_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
273static inline int16_t
274psf_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
282static inline void
283endswap_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
291static inline void
292endswap_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
299static inline void
300endswap_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
308static inline void
309endswap_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
319static inline void
320endswap_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
328static inline void
329endswap_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
339static inline void
340endswap_float_array (float *ptr, int len)
341{	endswap_int_array ((int *) ptr, len) ;
342} /* endswap_float_array */
343
344static inline void
345endswap_double_array (double *ptr, int len)
346{	endswap_int64_t_array ((int64_t *) ptr, len) ;
347} /* endswap_double_array */
348
349static inline void
350endswap_float_copy (float *dest, const float *src, int len)
351{	endswap_int_copy ((int *) dest, (const int *) src, len) ;
352} /* endswap_float_copy */
353
354static inline void
355endswap_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