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