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