| /* | |
| ** Copyright (C) 1999-2018 Erik de Castro Lopo <erikd@mega-nerd.com> | |
| ** | |
| ** 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 <stdint.h> | |
| #include <inttypes.h> | |
| #ifndef __has_builtin | |
| #define __has_builtin(x) 0 | |
| #endif | |
| #if HAVE_BYTESWAP_H /* Linux, any CPU */ | |
| #include <byteswap.h> | |
| #define ENDSWAP_16(x) (bswap_16 (x)) | |
| #define ENDSWAP_32(x) (bswap_32 (x)) | |
| #define ENDSWAP_64(x) (bswap_64 (x)) | |
| #elif __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) | |
| #define ENDSWAP_16(x) ((int16_t) __builtin_bswap16 ((uint16_t) x)) | |
| #define ENDSWAP_32(x) ((int32_t) __builtin_bswap32 ((uint32_t) x)) | |
| #define ENDSWAP_64(x) ((int64_t) __builtin_bswap64 ((uint64_t) x)) | |
| #elif COMPILER_IS_GCC | |
| #if CPU_IS_X86 | |
| static inline int16_t | |
| ENDSWAP_16X (int16_t x) | |
| { int16_t y ; | |
| __asm__ ("rorw $8, %w0" : "=r" (y) : "0" (x) : "cc") ; | |
| return y ; | |
| } /* ENDSWAP_16 */ | |
| static inline int32_t | |
| ENDSWAP_32X (int32_t x) | |
| { int32_t y ; | |
| __asm__ ("bswap %0" : "=r" (y) : "0" (x)) ; | |
| return y ; | |
| } /* ENDSWAP_32 */ | |
| #define ENDSWAP_16 ENDSWAP_16X | |
| #define ENDSWAP_32 ENDSWAP_32X | |
| #endif | |
| #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 defined _MSC_VER | |
| #include <stdlib.h> | |
| #define ENDSWAP_16(x) (_byteswap_ushort (x)) | |
| #define ENDSWAP_32(x) (_byteswap_ulong (x)) | |
| #define ENDSWAP_64(x) (_byteswap_uint64 (x)) | |
| #endif | |
| #ifndef ENDSWAP_16 | |
| #define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8)) | |
| #endif | |
| #ifndef ENDSWAP_32 | |
| #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) | |
| #define H2LE_16(x) (x) | |
| #define H2LE_32(x) (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 LE2H_32_PTR(x) (((x) [0]) + ((x) [1] << 8) + ((x) [2] << 16) + ((x) [3] << 24)) | |
| #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] = (uint8_t) (value >> 56) ; | |
| ptr [offset + 1] = (uint8_t) (value >> 48) ; | |
| ptr [offset + 2] = (uint8_t) (value >> 40) ; | |
| ptr [offset + 3] = (uint8_t) (value >> 32) ; | |
| ptr [offset + 4] = (uint8_t) (value >> 24) ; | |
| ptr [offset + 5] = (uint8_t) (value >> 16) ; | |
| ptr [offset + 6] = (uint8_t) (value >> 8) ; | |
| ptr [offset + 7] = (uint8_t) value ; | |
| } /* psf_put_be64 */ | |
| static inline void | |
| psf_put_be32 (uint8_t *ptr, int offset, int32_t value) | |
| { | |
| ptr [offset] = (uint8_t) (value >> 24) ; | |
| ptr [offset + 1] = (uint8_t) (value >> 16) ; | |
| ptr [offset + 2] = (uint8_t) (value >> 8) ; | |
| ptr [offset + 3] = (uint8_t) value ; | |
| } /* psf_put_be32 */ | |
| static inline void | |
| psf_put_be16 (uint8_t *ptr, int offset, int16_t value) | |
| { | |
| ptr [offset] = (uint8_t) (value >> 8) ; | |
| ptr [offset + 1] = (uint8_t) value ; | |
| } /* psf_put_be16 */ | |
| static inline int64_t | |
| psf_get_be64 (const uint8_t *ptr, int offset) | |
| { int64_t value ; | |
| value = (int64_t) ((uint64_t) ptr [offset] << 24) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 1] << 16) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 2] << 8) ; | |
| value += ptr [offset + 3] ; | |
| value = (int64_t) (((uint64_t) value) << 32) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 4] << 24) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 5] << 16) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 6] << 8) ; | |
| value += ptr [offset + 7] ; | |
| return value ; | |
| } /* psf_get_be64 */ | |
| static inline int64_t | |
| psf_get_le64 (const uint8_t *ptr, int offset) | |
| { int64_t value = (int64_t) ((uint64_t) ptr [offset + 7] << 24) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 6] << 16) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 5] << 8) ; | |
| value += ptr [offset + 4] ; | |
| value = (int64_t) (((uint64_t) value) << 32) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 3] << 24) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 2] << 16) ; | |
| value += (int64_t) ((uint64_t) ptr [offset + 1] << 8) ; | |
| value += ptr [offset] ; | |
| return value ; | |
| } /* psf_get_le64 */ | |
| static inline int32_t | |
| psf_get_be32 (const uint8_t *ptr, int offset) | |
| { int32_t value = ((uint32_t) ptr [offset]) << 24 ; | |
| value += ptr [offset + 1] << 16 ; | |
| value += ptr [offset + 2] << 8 ; | |
| value += ptr [offset + 3] ; | |
| return value ; | |
| } /* psf_get_be32 */ | |
| static inline int32_t | |
| psf_get_le32 (const uint8_t *ptr, int offset) | |
| { int32_t value = ((uint32_t) ptr [offset + 3]) << 24 ; | |
| value += ptr [offset + 2] << 16 ; | |
| value += ptr [offset + 1] << 8 ; | |
| value += ptr [offset] ; | |
| return value ; | |
| } /* psf_get_le32 */ | |
| static inline int32_t | |
| psf_get_be24 (const uint8_t *ptr, int offset) | |
| { int32_t value = ((uint32_t) ptr [offset]) << 24 ; | |
| value += ptr [offset + 1] << 16 ; | |
| value += ptr [offset + 2] << 8 ; | |
| return value ; | |
| } /* psf_get_be24 */ | |
| static inline int32_t | |
| psf_get_le24 (const uint8_t *ptr, int offset) | |
| { int32_t value = ((uint32_t) ptr [offset + 2]) << 24 ; | |
| value += ptr [offset + 1] << 16 ; | |
| value += ptr [offset] << 8 ; | |
| return value ; | |
| } /* psf_get_le24 */ | |
| static inline int16_t | |
| psf_get_be16 (const uint8_t *ptr, int offset) | |
| { return (int16_t) (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) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { short temp = ptr [i] ; | |
| ptr [i] = ENDSWAP_16 (temp) ; | |
| } ; | |
| } /* endswap_short_array */ | |
| static inline void | |
| endswap_short_copy (short *dest, const short *src, int len) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { dest [i] = ENDSWAP_16 (src [i]) ; | |
| } ; | |
| } /* endswap_short_copy */ | |
| static inline void | |
| endswap_int_array (int *ptr, int len) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { int temp = ptr [i] ; | |
| ptr [i] = ENDSWAP_32 (temp) ; | |
| } ; | |
| } /* endswap_int_array */ | |
| static inline void | |
| endswap_int_copy (int *dest, const int *src, int len) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { dest [i] = ENDSWAP_32 (src [i]) ; | |
| } ; | |
| } /* endswap_int_copy */ | |
| /*======================================================================================== | |
| */ | |
| static inline void | |
| endswap_int64_t_array (int64_t *ptr, int len) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { int64_t value = ptr [i] ; | |
| ptr [i] = ENDSWAP_64 (value) ; | |
| } ; | |
| } /* endswap_int64_t_array */ | |
| static inline void | |
| endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len) | |
| { | |
| for (int i = 0 ; i < len ; i++) | |
| { int64_t value = src [i] ; | |
| dest [i] = 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 */ | |