/* ** Copyright (C) 1999-2013 Erik de Castro Lopo ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU Lesser General Public License as published by ** the Free Software Foundation; either version 2.1 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef SFENDIAN_INCLUDED #define SFENDIAN_INCLUDED #include "sfconfig.h" #include #ifndef WIN32 #include #endif #if COMPILER_IS_GCC && CPU_IS_X86 static inline int16_t ENDSWAP_16 (int16_t x) { int16_t y ; __asm__ ("rorw $8, %w0" : "=r" (y) : "0" (x) : "cc") ; return y ; } /* ENDSWAP_16 */ static inline int32_t ENDSWAP_32 (int32_t x) { int32_t y ; __asm__ ("bswap %0" : "=r" (y) : "0" (x)) ; return y ; } /* ENDSWAP_32 */ #if CPU_IS_X86_64 static inline int64_t ENDSWAP_64X (int64_t x) { int64_t y ; __asm__ ("bswap %q0" : "=r" (y) : "0" (x)) ; return y ; } /* ENDSWAP_64X */ #define ENDSWAP_64 ENDSWAP_64X #endif #elif HAVE_BYTESWAP_H /* Linux, any CPU */ #include #define ENDSWAP_16(x) (bswap_16 (x)) #define ENDSWAP_32(x) (bswap_32 (x)) #define ENDSWAP_64(x) (bswap_64 (x)) #else #define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8)) #define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24)) #endif #ifndef ENDSWAP_64 static inline uint64_t ENDSWAP_64 (uint64_t x) { union { uint32_t parts [2] ; uint64_t whole ; } u ; uint32_t temp ; u.whole = x ; temp = u.parts [0] ; u.parts [0] = ENDSWAP_32 (u.parts [1]) ; u.parts [1] = ENDSWAP_32 (temp) ; return u.whole ; } #endif /* ** Many file types (ie WAV, AIFF) use sets of four consecutive bytes as a ** marker indicating different sections of the file. ** The following MAKE_MARKER macro allows th creation of integer constants ** for these markers. */ #if (CPU_IS_LITTLE_ENDIAN == 1) #define MAKE_MARKER(a, b, c, d) ((uint32_t) ((a) | ((b) << 8) | ((c) << 16) | (((uint32_t) (d)) << 24))) #elif (CPU_IS_BIG_ENDIAN == 1) #define MAKE_MARKER(a, b, c, d) ((uint32_t) ((((uint32_t) (a)) << 24) | ((b) << 16) | ((c) << 8) | (d))) #else #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" #endif /* ** Macros to handle reading of data of a specific endian-ness into host endian ** shorts and ints. The single input is an unsigned char* pointer to the start ** of the object. There are two versions of each macro as we need to deal with ** both big and little endian CPUs. */ #if (CPU_IS_LITTLE_ENDIAN == 1) #define LE2H_16(x) (x) #define LE2H_32(x) (x) #define BE2H_16(x) ENDSWAP_16 (x) #define BE2H_32(x) ENDSWAP_32 (x) #define BE2H_64(x) ENDSWAP_64 (x) #define H2BE_16(x) ENDSWAP_16 (x) #define H2BE_32(x) ENDSWAP_32 (x) #elif (CPU_IS_BIG_ENDIAN == 1) #define LE2H_16(x) ENDSWAP_16 (x) #define LE2H_32(x) ENDSWAP_32 (x) #define BE2H_16(x) (x) #define BE2H_32(x) (x) #define BE2H_64(x) (x) #define H2BE_16(x) (x) #define H2BE_32(x) (x) #define H2LE_16(x) ENDSWAP_16 (x) #define H2LE_32(x) ENDSWAP_32 (x) #else #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" #endif #define LET2H_16_PTR(x) ((x) [1] + ((x) [2] << 8)) #define LET2H_32_PTR(x) (((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24)) #define BET2H_16_PTR(x) (((x) [0] << 8) + (x) [1]) #define BET2H_32_PTR(x) (((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8)) static inline void psf_put_be64 (uint8_t *ptr, int offset, int64_t value) { ptr [offset] = value >> 56 ; ptr [offset + 1] = value >> 48 ; ptr [offset + 2] = value >> 40 ; ptr [offset + 3] = value >> 32 ; ptr [offset + 4] = value >> 24 ; ptr [offset + 5] = value >> 16 ; ptr [offset + 6] = value >> 8 ; ptr [offset + 7] = value ; } /* psf_put_be64 */ static inline void psf_put_be32 (uint8_t *ptr, int offset, int32_t value) { ptr [offset] = value >> 24 ; ptr [offset + 1] = value >> 16 ; ptr [offset + 2] = value >> 8 ; ptr [offset + 3] = value ; } /* psf_put_be32 */ static inline void psf_put_be16 (uint8_t *ptr, int offset, int16_t value) { ptr [offset] = value >> 8 ; ptr [offset + 1] = value ; } /* psf_put_be16 */ static inline int64_t psf_get_be64 (uint8_t *ptr, int offset) { int64_t value ; value = ptr [offset] << 24 ; value += ptr [offset + 1] << 16 ; value += ptr [offset + 2] << 8 ; value += ptr [offset + 3] ; value <<= 32 ; value += ptr [offset + 4] << 24 ; value += ptr [offset + 5] << 16 ; value += ptr [offset + 6] << 8 ; value += ptr [offset + 7] ; return value ; } /* psf_get_be64 */ static inline int32_t psf_get_be32 (uint8_t *ptr, int offset) { int32_t value ; value = ptr [offset] << 24 ; value += ptr [offset + 1] << 16 ; value += ptr [offset + 2] << 8 ; value += ptr [offset + 3] ; return value ; } /* psf_get_be32 */ static inline int16_t psf_get_be16 (uint8_t *ptr, int offset) { return (ptr [offset] << 8) + ptr [offset + 1] ; } /* psf_get_be16 */ /*----------------------------------------------------------------------------------------------- ** Generic functions for performing endian swapping on integer arrays. */ static inline void endswap_short_array (short *ptr, int len) { short temp ; while (--len >= 0) { temp = ptr [len] ; ptr [len] = ENDSWAP_16 (temp) ; } ; } /* endswap_short_array */ static inline void endswap_short_copy (short *dest, const short *src, int len) { while (--len >= 0) { dest [len] = ENDSWAP_16 (src [len]) ; } ; } /* endswap_short_copy */ static inline void endswap_int_array (int *ptr, int len) { int temp ; while (--len >= 0) { temp = ptr [len] ; ptr [len] = ENDSWAP_32 (temp) ; } ; } /* endswap_int_array */ static inline void endswap_int_copy (int *dest, const int *src, int len) { while (--len >= 0) { dest [len] = ENDSWAP_32 (src [len]) ; } ; } /* endswap_int_copy */ /*======================================================================================== */ static inline void endswap_int64_t_array (int64_t *ptr, int len) { int64_t value ; while (--len >= 0) { value = ptr [len] ; ptr [len] = ENDSWAP_64 (value) ; } ; } /* endswap_int64_t_array */ static inline void endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len) { int64_t value ; while (--len >= 0) { value = src [len] ; dest [len] = ENDSWAP_64 (value) ; } ; } /* endswap_int64_t_copy */ /* A couple of wrapper functions. */ static inline void endswap_float_array (float *ptr, int len) { endswap_int_array ((int *) ptr, len) ; } /* endswap_float_array */ static inline void endswap_double_array (double *ptr, int len) { endswap_int64_t_array ((int64_t *) ptr, len) ; } /* endswap_double_array */ static inline void endswap_float_copy (float *dest, const float *src, int len) { endswap_int_copy ((int *) dest, (const int *) src, len) ; } /* endswap_float_copy */ static inline void endswap_double_copy (double *dest, const double *src, int len) { endswap_int64_t_copy ((int64_t *) dest, (const int64_t *) src, len) ; } /* endswap_double_copy */ #endif /* SFENDIAN_INCLUDED */