X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/e775f23a10c4ba37fc1a762299f52cd0d71593b7..f1f94803668061f90a5ce88bf06ee72bba8e41a5:/interpretor/lib/src/libsndfile-1.0.25/src/common.c diff --git a/interpretor/lib/src/libsndfile-1.0.25/src/common.c b/interpretor/lib/src/libsndfile-1.0.25/src/common.c new file mode 100644 index 0000000..8aadbab --- /dev/null +++ b/interpretor/lib/src/libsndfile-1.0.25/src/common.c @@ -0,0 +1,1465 @@ +/* +** Copyright (C) 1999-2011 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. +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*----------------------------------------------------------------------------------------------- +** psf_log_printf allows libsndfile internal functions to print to an internal logbuffer which +** can later be displayed. +** The format specifiers are as for printf but without the field width and other modifiers. +** Printing is performed to the logbuffer char array of the SF_PRIVATE struct. +** Printing is done in such a way as to guarantee that the log never overflows the end of the +** logbuffer array. +*/ + +static inline void +log_putchar (SF_PRIVATE *psf, char ch) +{ if (psf->logindex < SIGNED_SIZEOF (psf->logbuffer) - 1) + { psf->logbuffer [psf->logindex++] = ch ; + psf->logbuffer [psf->logindex] = 0 ; + } ; + return ; +} /* log_putchar */ + +void +psf_log_printf (SF_PRIVATE *psf, const char *format, ...) +{ va_list ap ; + unsigned int u ; + int d, tens, shift, width, width_specifier, left_align ; + char c, *strptr, istr [5], lead_char, sign_char ; + + va_start (ap, format) ; + + while ((c = *format++)) + { if (c != '%') + { log_putchar (psf, c) ; + continue ; + } ; + + if (format [0] == '%') /* Handle %% */ + { log_putchar (psf, '%') ; + format ++ ; + continue ; + } ; + + sign_char = 0 ; + left_align = SF_FALSE ; + while (1) + { switch (format [0]) + { case ' ' : + case '+' : + sign_char = format [0] ; + format ++ ; + continue ; + + case '-' : + left_align = SF_TRUE ; + format ++ ; + continue ; + + default : break ; + } ; + + break ; + } ; + + if (format [0] == 0) + break ; + + lead_char = ' ' ; + if (format [0] == '0') + lead_char = '0' ; + + width_specifier = 0 ; + while ((c = *format++) && isdigit (c)) + width_specifier = width_specifier * 10 + (c - '0') ; + + switch (c) + { case 0 : /* NULL character. */ + va_end (ap) ; + return ; + + case 's': /* string */ + strptr = va_arg (ap, char *) ; + if (strptr == NULL) + break ; + width_specifier -= strlen (strptr) ; + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, ' ') ; + while (*strptr) + log_putchar (psf, *strptr++) ; + while (width_specifier -- > 0) + log_putchar (psf, ' ') ; + break ; + + case 'd': /* int */ + d = va_arg (ap, int) ; + + if (d < 0) + { d = -d ; + sign_char = '-' ; + if (lead_char != '0' && left_align == SF_FALSE) + width_specifier -- ; + } ; + + tens = 1 ; + width = 1 ; + while (d / tens >= 10) + { tens *= 10 ; + width ++ ; + } ; + + width_specifier -= width ; + + if (sign_char == ' ') + { log_putchar (psf, ' ') ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE && lead_char != '0') + { if (sign_char == '+') + width_specifier -- ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + } ; + + if (sign_char == '+' || sign_char == '-') + { log_putchar (psf, sign_char) ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + + while (tens > 0) + { log_putchar (psf, '0' + d / tens) ; + d %= tens ; + tens /= 10 ; + } ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + break ; + + case 'D': /* sf_count_t */ + { sf_count_t D, Tens ; + + D = va_arg (ap, sf_count_t) ; + + if (D == 0) + { while (-- width_specifier > 0) + log_putchar (psf, lead_char) ; + log_putchar (psf, '0') ; + break ; + } + if (D < 0) + { log_putchar (psf, '-') ; + D = -D ; + } ; + Tens = 1 ; + width = 1 ; + while (D / Tens >= 10) + { Tens *= 10 ; + width ++ ; + } ; + + while (width_specifier > width) + { log_putchar (psf, lead_char) ; + width_specifier-- ; + } ; + + while (Tens > 0) + { log_putchar (psf, '0' + D / Tens) ; + D %= Tens ; + Tens /= 10 ; + } ; + } ; + break ; + + case 'u': /* unsigned int */ + u = va_arg (ap, unsigned int) ; + + tens = 1 ; + width = 1 ; + while (u / tens >= 10) + { tens *= 10 ; + width ++ ; + } ; + + width_specifier -= width ; + + if (sign_char == ' ') + { log_putchar (psf, ' ') ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE && lead_char != '0') + { if (sign_char == '+') + width_specifier -- ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + } ; + + if (sign_char == '+' || sign_char == '-') + { log_putchar (psf, sign_char) ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + + while (tens > 0) + { log_putchar (psf, '0' + u / tens) ; + u %= tens ; + tens /= 10 ; + } ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + break ; + + case 'c': /* char */ + c = va_arg (ap, int) & 0xFF ; + log_putchar (psf, c) ; + break ; + + case 'x': /* hex */ + case 'X': /* hex */ + d = va_arg (ap, int) ; + + if (d == 0) + { while (--width_specifier > 0) + log_putchar (psf, lead_char) ; + log_putchar (psf, '0') ; + break ; + } ; + shift = 28 ; + width = (width_specifier < 8) ? 8 : width_specifier ; + while (! ((0xF << shift) & d)) + { shift -= 4 ; + width -- ; + } ; + + while (width > 0 && width_specifier > width) + { log_putchar (psf, lead_char) ; + width_specifier-- ; + } ; + + while (shift >= 0) + { c = (d >> shift) & 0xF ; + log_putchar (psf, (c > 9) ? c + 'A' - 10 : c + '0') ; + shift -= 4 ; + } ; + break ; + + case 'M': /* int2str */ + d = va_arg (ap, int) ; + if (CPU_IS_LITTLE_ENDIAN) + { istr [0] = d & 0xFF ; + istr [1] = (d >> 8) & 0xFF ; + istr [2] = (d >> 16) & 0xFF ; + istr [3] = (d >> 24) & 0xFF ; + } + else + { istr [3] = d & 0xFF ; + istr [2] = (d >> 8) & 0xFF ; + istr [1] = (d >> 16) & 0xFF ; + istr [0] = (d >> 24) & 0xFF ; + } ; + istr [4] = 0 ; + strptr = istr ; + while (*strptr) + { c = *strptr++ ; + log_putchar (psf, c) ; + } ; + break ; + + default : + log_putchar (psf, '*') ; + log_putchar (psf, c) ; + log_putchar (psf, '*') ; + break ; + } /* switch */ + } /* while */ + + va_end (ap) ; + return ; +} /* psf_log_printf */ + +/*----------------------------------------------------------------------------------------------- +** ASCII header printf functions. +** Some formats (ie NIST) use ascii text in their headers. +** Format specifiers are the same as the standard printf specifiers (uses vsnprintf). +** If this generates a compile error on any system, the author should be notified +** so an alternative vsnprintf can be provided. +*/ + +void +psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) +{ va_list argptr ; + int maxlen ; + char *start ; + + maxlen = strlen ((char*) psf->header) ; + start = ((char*) psf->header) + maxlen ; + maxlen = sizeof (psf->header) - maxlen ; + + va_start (argptr, format) ; + vsnprintf (start, maxlen, format, argptr) ; + va_end (argptr) ; + + /* Make sure the string is properly terminated. */ + start [maxlen - 1] = 0 ; + + psf->headindex = strlen ((char*) psf->header) ; + + return ; +} /* psf_asciiheader_printf */ + +/*----------------------------------------------------------------------------------------------- +** Binary header writing functions. Returns number of bytes written. +** +** Format specifiers for psf_binheader_writef are as follows +** m - marker - four bytes - no endian manipulation +** +** e - all following numerical values will be little endian +** E - all following numerical values will be big endian +** +** t - all following O types will be truncated to 4 bytes +** T - switch off truncation of all following O types +** +** 1 - single byte value +** 2 - two byte value +** 3 - three byte value +** 4 - four byte value +** 8 - eight byte value (sometimes written as 4 bytes) +** +** s - string preceded by a four byte length +** S - string including null terminator +** f - floating point data +** d - double precision floating point data +** h - 16 binary bytes value +** +** b - binary data (see below) +** z - zero bytes (ses below) +** j - jump forwards or backwards +** +** To write a word followed by an int (both little endian) use: +** psf_binheader_writef ("e24", wordval, longval) ; +** +** To write binary data use: +** psf_binheader_writef ("b", &bindata, sizeof (bindata)) ; +** +** To write N zero bytes use: +** NOTE: due to platform issues (ie x86-64) you should cast the +** argument to size_t or ensure the variable type is size_t. +** psf_binheader_writef ("z", N) ; +*/ + +/* These macros may seem a bit messy but do prevent problems with processors which +** seg. fault when asked to write an int or short to a non-int/short aligned address. +*/ + +static inline void +header_put_byte (SF_PRIVATE *psf, char x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 1) + psf->header [psf->headindex++] = x ; +} /* header_put_byte */ + +#if (CPU_IS_BIG_ENDIAN == 1) +static inline void +header_put_marker (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) + { psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_marker */ + +#elif (CPU_IS_LITTLE_ENDIAN == 1) +static inline void +header_put_marker (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 24) ; + } ; +} /* header_put_marker */ + +#else +# error "Cannot determine endian-ness of processor." +#endif + + +static inline void +header_put_be_short (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2) + { psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_be_short */ + +static inline void +header_put_le_short (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + } ; +} /* header_put_le_short */ + +static inline void +header_put_be_3byte (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3) + { psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_be_3byte */ + +static inline void +header_put_le_3byte (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = (x >> 16) ; + } ; +} /* header_put_le_3byte */ + +static inline void +header_put_be_int (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) + { psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_be_int */ + +static inline void +header_put_le_int (SF_PRIVATE *psf, int x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 24) ; + } ; +} /* header_put_le_int */ + +#if (SIZEOF_SF_COUNT_T == 4) + +static inline void +header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) + { psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_be_8byte */ + +static inline void +header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + psf->header [psf->headindex++] = 0 ; + } ; +} /* header_put_le_8byte */ + +#elif (SIZEOF_SF_COUNT_T == 8) + +static inline void +header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) + { psf->header [psf->headindex++] = (x >> 56) ; + psf->header [psf->headindex++] = (x >> 48) ; + psf->header [psf->headindex++] = (x >> 40) ; + psf->header [psf->headindex++] = (x >> 32) ; + psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = x ; + } ; +} /* header_put_be_8byte */ + +static inline void +header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x) +{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) + { psf->header [psf->headindex++] = x ; + psf->header [psf->headindex++] = (x >> 8) ; + psf->header [psf->headindex++] = (x >> 16) ; + psf->header [psf->headindex++] = (x >> 24) ; + psf->header [psf->headindex++] = (x >> 32) ; + psf->header [psf->headindex++] = (x >> 40) ; + psf->header [psf->headindex++] = (x >> 48) ; + psf->header [psf->headindex++] = (x >> 56) ; + } ; +} /* header_put_le_8byte */ + +#else +#error "SIZEOF_SF_COUNT_T is not defined." +#endif + +int +psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) +{ va_list argptr ; + sf_count_t countdata ; + unsigned long longdata ; + unsigned int data ; + float floatdata ; + double doubledata ; + void *bindata ; + size_t size ; + char c, *strptr ; + int count = 0, trunc_8to4 ; + + trunc_8to4 = SF_FALSE ; + + va_start (argptr, format) ; + + while ((c = *format++)) + { switch (c) + { case ' ' : /* Do nothing. Just used to space out format string. */ + break ; + + case 'e' : /* All conversions are now from LE to host. */ + psf->rwf_endian = SF_ENDIAN_LITTLE ; + break ; + + case 'E' : /* All conversions are now from BE to host. */ + psf->rwf_endian = SF_ENDIAN_BIG ; + break ; + + case 't' : /* All 8 byte values now get written as 4 bytes. */ + trunc_8to4 = SF_TRUE ; + break ; + + case 'T' : /* All 8 byte values now get written as 8 bytes. */ + trunc_8to4 = SF_FALSE ; + break ; + + case 'm' : + data = va_arg (argptr, unsigned int) ; + header_put_marker (psf, data) ; + count += 4 ; + break ; + + case '1' : + data = va_arg (argptr, unsigned int) ; + header_put_byte (psf, data) ; + count += 1 ; + break ; + + case '2' : + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_short (psf, data) ; + } + else + { header_put_le_short (psf, data) ; + } ; + count += 2 ; + break ; + + case '3' : /* tribyte */ + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_3byte (psf, data) ; + } + else + { header_put_le_3byte (psf, data) ; + } ; + count += 3 ; + break ; + + case '4' : + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_int (psf, data) ; + } + else + { header_put_le_int (psf, data) ; + } ; + count += 4 ; + break ; + + case '8' : + countdata = va_arg (argptr, sf_count_t) ; + if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_FALSE) + { header_put_be_8byte (psf, countdata) ; + count += 8 ; + } + else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_FALSE) + { header_put_le_8byte (psf, countdata) ; + count += 8 ; + } + else if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_TRUE) + { longdata = countdata & 0xFFFFFFFF ; + header_put_be_int (psf, longdata) ; + count += 4 ; + } + else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_TRUE) + { longdata = countdata & 0xFFFFFFFF ; + header_put_le_int (psf, longdata) ; + count += 4 ; + } + break ; + + case 'f' : + /* Floats are passed as doubles. Is this always true? */ + floatdata = (float) va_arg (argptr, double) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + float32_be_write (floatdata, psf->header + psf->headindex) ; + else + float32_le_write (floatdata, psf->header + psf->headindex) ; + psf->headindex += 4 ; + count += 4 ; + break ; + + case 'd' : + doubledata = va_arg (argptr, double) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + double64_be_write (doubledata, psf->header + psf->headindex) ; + else + double64_le_write (doubledata, psf->header + psf->headindex) ; + psf->headindex += 8 ; + count += 8 ; + break ; + + case 's' : + /* Write a C string (guaranteed to have a zero terminator). */ + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) + 1 ; + size += (size & 1) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + header_put_be_int (psf, size) ; + else + header_put_le_int (psf, size) ; + memcpy (&(psf->header [psf->headindex]), strptr, size) ; + psf->headindex += size ; + psf->header [psf->headindex - 1] = 0 ; + count += 4 + size ; + break ; + + case 'S' : + /* + ** Write an AIFF style string (no zero terminator but possibly + ** an extra pad byte if the string length is odd). + */ + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + header_put_be_int (psf, size) ; + else + header_put_le_int (psf, size) ; + memcpy (&(psf->header [psf->headindex]), strptr, size + 1) ; + size += (size & 1) ; + psf->headindex += size ; + psf->header [psf->headindex] = 0 ; + count += 4 + size ; + break ; + + case 'b' : + bindata = va_arg (argptr, void *) ; + size = va_arg (argptr, size_t) ; + memcpy (&(psf->header [psf->headindex]), bindata, size) ; + psf->headindex += size ; + count += size ; + break ; + + case 'z' : + size = va_arg (argptr, size_t) ; + count += size ; + while (size) + { psf->header [psf->headindex] = 0 ; + psf->headindex ++ ; + size -- ; + } ; + break ; + + case 'h' : + bindata = va_arg (argptr, void *) ; + memcpy (&(psf->header [psf->headindex]), bindata, 16) ; + psf->headindex += 16 ; + count += 16 ; + break ; + + case 'j' : + size = va_arg (argptr, size_t) ; + psf->headindex += size ; + count = size ; + break ; + + default : + psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; + psf->error = SFE_INTERNAL ; + break ; + } ; + } ; + + va_end (argptr) ; + return count ; +} /* psf_binheader_writef */ + +/*----------------------------------------------------------------------------------------------- +** Binary header reading functions. Returns number of bytes read. +** +** Format specifiers are the same as for header write function above with the following +** additions: +** +** p - jump a given number of position from start of file. +** +** If format is NULL, psf_binheader_readf returns the current offset. +*/ + +#if (CPU_IS_BIG_ENDIAN == 1) +#define GET_MARKER(ptr) ( ((ptr) [0] << 24) | ((ptr) [1] << 16) | \ + ((ptr) [2] << 8) | ((ptr) [3]) ) + +#elif (CPU_IS_LITTLE_ENDIAN == 1) +#define GET_MARKER(ptr) ( ((ptr) [0]) | ((ptr) [1] << 8) | \ + ((ptr) [2] << 16) | ((ptr) [3] << 24) ) + +#else +# error "Cannot determine endian-ness of processor." +#endif + +#define GET_LE_SHORT(ptr) ( ((ptr) [1] << 8) | ((ptr) [0]) ) +#define GET_BE_SHORT(ptr) ( ((ptr) [0] << 8) | ((ptr) [1]) ) + +#define GET_LE_3BYTE(ptr) ( ((ptr) [2] << 16) | ((ptr) [1] << 8) | ((ptr) [0]) ) +#define GET_BE_3BYTE(ptr) ( ((ptr) [0] << 16) | ((ptr) [1] << 8) | ((ptr) [2]) ) + +#define GET_LE_INT(ptr) ( ((ptr) [3] << 24) | ((ptr) [2] << 16) | \ + ((ptr) [1] << 8) | ((ptr) [0]) ) + +#define GET_BE_INT(ptr) ( ((ptr) [0] << 24) | ((ptr) [1] << 16) | \ + ((ptr) [2] << 8) | ((ptr) [3]) ) + +#define GET_LE_8BYTE(ptr) ( (((sf_count_t) (ptr) [7]) << 56) | (((sf_count_t) (ptr) [6]) << 48) | \ + (((sf_count_t) (ptr) [5]) << 40) | (((sf_count_t) (ptr) [4]) << 32) | \ + (((sf_count_t) (ptr) [3]) << 24) | (((sf_count_t) (ptr) [2]) << 16) | \ + (((sf_count_t) (ptr) [1]) << 8 ) | ((ptr) [0])) + +#define GET_BE_8BYTE(ptr) ( (((sf_count_t) (ptr) [0]) << 56) | (((sf_count_t) (ptr) [1]) << 48) | \ + (((sf_count_t) (ptr) [2]) << 40) | (((sf_count_t) (ptr) [3]) << 32) | \ + (((sf_count_t) (ptr) [4]) << 24) | (((sf_count_t) (ptr) [5]) << 16) | \ + (((sf_count_t) (ptr) [6]) << 8 ) | ((ptr) [7])) + + + +static int +header_read (SF_PRIVATE *psf, void *ptr, int bytes) +{ int count = 0 ; + + if (psf->headindex >= SIGNED_SIZEOF (psf->header)) + { memset (ptr, 0, SIGNED_SIZEOF (psf->header) - psf->headindex) ; + + /* This is the best that we can do. */ + psf_fseek (psf, bytes, SEEK_CUR) ; + return bytes ; + } ; + + if (psf->headindex + bytes > SIGNED_SIZEOF (psf->header)) + { int most ; + + most = SIGNED_SIZEOF (psf->header) - psf->headindex ; + psf_fread (psf->header + psf->headend, 1, most, psf) ; + memset ((char *) ptr + most, 0, bytes - most) ; + + psf_fseek (psf, bytes - most, SEEK_CUR) ; + return bytes ; + } ; + + if (psf->headindex + bytes > psf->headend) + { count = psf_fread (psf->header + psf->headend, 1, bytes - (psf->headend - psf->headindex), psf) ; + if (count != bytes - (int) (psf->headend - psf->headindex)) + { psf_log_printf (psf, "Error : psf_fread returned short count.\n") ; + return 0 ; + } ; + psf->headend += count ; + } ; + + memcpy (ptr, psf->header + psf->headindex, bytes) ; + psf->headindex += bytes ; + + return bytes ; +} /* header_read */ + +static void +header_seek (SF_PRIVATE *psf, sf_count_t position, int whence) +{ + + switch (whence) + { case SEEK_SET : + if (position > SIGNED_SIZEOF (psf->header)) + { /* Too much header to cache so just seek instead. */ + psf_fseek (psf, position, whence) ; + return ; + } ; + if (position > psf->headend) + psf->headend += psf_fread (psf->header + psf->headend, 1, position - psf->headend, psf) ; + psf->headindex = position ; + break ; + + case SEEK_CUR : + if (psf->headindex + position < 0) + break ; + + if (psf->headindex >= SIGNED_SIZEOF (psf->header)) + { psf_fseek (psf, position, whence) ; + return ; + } ; + + if (psf->headindex + position <= psf->headend) + { psf->headindex += position ; + break ; + } ; + + if (psf->headindex + position > SIGNED_SIZEOF (psf->header)) + { /* Need to jump this without caching it. */ + psf->headindex = psf->headend ; + psf_fseek (psf, position, SEEK_CUR) ; + break ; + } ; + + psf->headend += psf_fread (psf->header + psf->headend, 1, position - (psf->headend - psf->headindex), psf) ; + psf->headindex = psf->headend ; + break ; + + case SEEK_END : + default : + psf_log_printf (psf, "Bad whence param in header_seek().\n") ; + break ; + } ; + + return ; +} /* header_seek */ + +static int +header_gets (SF_PRIVATE *psf, char *ptr, int bufsize) +{ + int k ; + + for (k = 0 ; k < bufsize - 1 ; k++) + { if (psf->headindex < psf->headend) + { ptr [k] = psf->header [psf->headindex] ; + psf->headindex ++ ; + } + else + { psf->headend += psf_fread (psf->header + psf->headend, 1, 1, psf) ; + ptr [k] = psf->header [psf->headindex] ; + psf->headindex = psf->headend ; + } ; + + if (ptr [k] == '\n') + break ; + } ; + + ptr [k] = 0 ; + + return k ; +} /* header_gets */ + +int +psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) +{ va_list argptr ; + sf_count_t *countptr, countdata ; + unsigned char *ucptr, sixteen_bytes [16] ; + unsigned int *intptr, intdata ; + unsigned short *shortptr ; + char *charptr ; + float *floatptr ; + double *doubleptr ; + char c ; + int byte_count = 0, count ; + + if (! format) + return psf_ftell (psf) ; + + va_start (argptr, format) ; + + while ((c = *format++)) + { switch (c) + { case 'e' : /* All conversions are now from LE to host. */ + psf->rwf_endian = SF_ENDIAN_LITTLE ; + break ; + + case 'E' : /* All conversions are now from BE to host. */ + psf->rwf_endian = SF_ENDIAN_BIG ; + break ; + + case 'm' : + intptr = va_arg (argptr, unsigned int*) ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, ucptr, sizeof (int)) ; + *intptr = GET_MARKER (ucptr) ; + break ; + + case 'h' : + intptr = va_arg (argptr, unsigned int*) ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ; + { int k ; + intdata = 0 ; + for (k = 0 ; k < 16 ; k++) + intdata ^= sixteen_bytes [k] << k ; + } + *intptr = intdata ; + break ; + + case '1' : + charptr = va_arg (argptr, char*) ; + *charptr = 0 ; + byte_count += header_read (psf, charptr, sizeof (char)) ; + break ; + + case '2' : + shortptr = va_arg (argptr, unsigned short*) ; + *shortptr = 0 ; + ucptr = (unsigned char*) shortptr ; + byte_count += header_read (psf, ucptr, sizeof (short)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *shortptr = GET_BE_SHORT (ucptr) ; + else + *shortptr = GET_LE_SHORT (ucptr) ; + break ; + + case '3' : + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + byte_count += header_read (psf, sixteen_bytes, 3) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *intptr = GET_BE_3BYTE (sixteen_bytes) ; + else + *intptr = GET_LE_3BYTE (sixteen_bytes) ; + break ; + + case '4' : + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, ucptr, sizeof (int)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *intptr = GET_BE_INT (ucptr) ; + else + *intptr = GET_LE_INT (ucptr) ; + break ; + + case '8' : + countptr = va_arg (argptr, sf_count_t *) ; + *countptr = 0 ; + byte_count += header_read (psf, sixteen_bytes, 8) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + countdata = GET_BE_8BYTE (sixteen_bytes) ; + else + countdata = GET_LE_8BYTE (sixteen_bytes) ; + *countptr = countdata ; + break ; + + case 'f' : /* Float conversion */ + floatptr = va_arg (argptr, float *) ; + *floatptr = 0.0 ; + byte_count += header_read (psf, floatptr, sizeof (float)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *floatptr = float32_be_read ((unsigned char*) floatptr) ; + else + *floatptr = float32_le_read ((unsigned char*) floatptr) ; + break ; + + case 'd' : /* double conversion */ + doubleptr = va_arg (argptr, double *) ; + *doubleptr = 0.0 ; + byte_count += header_read (psf, doubleptr, sizeof (double)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *doubleptr = double64_be_read ((unsigned char*) doubleptr) ; + else + *doubleptr = double64_le_read ((unsigned char*) doubleptr) ; + break ; + + case 's' : + psf_log_printf (psf, "Format conversion 's' not implemented yet.\n") ; + /* + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) + 1 ; + size += (size & 1) ; + longdata = H2LE_INT (size) ; + get_int (psf, longdata) ; + memcpy (&(psf->header [psf->headindex]), strptr, size) ; + psf->headindex += size ; + */ + break ; + + case 'b' : + charptr = va_arg (argptr, char*) ; + count = va_arg (argptr, size_t) ; + if (count > 0) + byte_count += header_read (psf, charptr, count) ; + break ; + + case 'G' : + charptr = va_arg (argptr, char*) ; + count = va_arg (argptr, size_t) ; + if (count > 0) + byte_count += header_gets (psf, charptr, count) ; + break ; + + case 'z' : + psf_log_printf (psf, "Format conversion 'z' not implemented yet.\n") ; + /* + size = va_arg (argptr, size_t) ; + while (size) + { psf->header [psf->headindex] = 0 ; + psf->headindex ++ ; + size -- ; + } ; + */ + break ; + + case 'p' : + /* Get the seek position first. */ + count = va_arg (argptr, size_t) ; + header_seek (psf, count, SEEK_SET) ; + byte_count = count ; + break ; + + case 'j' : + /* Get the seek position first. */ + count = va_arg (argptr, size_t) ; + header_seek (psf, count, SEEK_CUR) ; + byte_count += count ; + break ; + + default : + psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; + psf->error = SFE_INTERNAL ; + break ; + } ; + } ; + + va_end (argptr) ; + + return byte_count ; +} /* psf_binheader_readf */ + +/*----------------------------------------------------------------------------------------------- +*/ + +sf_count_t +psf_default_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t samples_from_start) +{ sf_count_t position, retval ; + + if (! (psf->blockwidth && psf->dataoffset >= 0)) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (! psf->sf.seekable) + { psf->error = SFE_NOT_SEEKABLE ; + return PSF_SEEK_ERROR ; + } ; + + position = psf->dataoffset + psf->blockwidth * samples_from_start ; + + if ((retval = psf_fseek (psf, position, SEEK_SET)) != position) + { psf->error = SFE_SEEK_FAILED ; + return PSF_SEEK_ERROR ; + } ; + + return samples_from_start ; +} /* psf_default_seek */ + +/*----------------------------------------------------------------------------------------------- +*/ + +void +psf_hexdump (const void *ptr, int len) +{ const char *data ; + char ascii [17] ; + int k, m ; + + if ((data = ptr) == NULL) + return ; + if (len <= 0) + return ; + + puts ("") ; + for (k = 0 ; k < len ; k += 16) + { memset (ascii, ' ', sizeof (ascii)) ; + + printf ("%08X: ", k) ; + for (m = 0 ; m < 16 && k + m < len ; m++) + { printf (m == 8 ? " %02X " : "%02X ", data [k + m] & 0xFF) ; + ascii [m] = psf_isprint (data [k + m]) ? data [k + m] : '.' ; + } ; + + if (m <= 8) printf (" ") ; + for ( ; m < 16 ; m++) printf (" ") ; + + ascii [16] = 0 ; + printf (" %s\n", ascii) ; + } ; + + puts ("") ; +} /* psf_hexdump */ + +void +psf_log_SF_INFO (SF_PRIVATE *psf) +{ psf_log_printf (psf, "---------------------------------\n") ; + + psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ; + psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; + psf_log_printf (psf, " Channels : %d\n", psf->sf.channels) ; + + psf_log_printf (psf, " Format : 0x%X\n", psf->sf.format) ; + psf_log_printf (psf, " Sections : %d\n", psf->sf.sections) ; + psf_log_printf (psf, " Seekable : %s\n", psf->sf.seekable ? "TRUE" : "FALSE") ; + + psf_log_printf (psf, "---------------------------------\n") ; +} /* psf_dump_SFINFO */ + +/*======================================================================================== +*/ + +void* +psf_memset (void *s, int c, sf_count_t len) +{ char *ptr ; + int setcount ; + + ptr = (char *) s ; + + while (len > 0) + { setcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + memset (ptr, c, setcount) ; + + ptr += setcount ; + len -= setcount ; + } ; + + return s ; +} /* psf_memset */ + +SF_INSTRUMENT * +psf_instrument_alloc (void) +{ SF_INSTRUMENT *instr ; + + instr = calloc (1, sizeof (SF_INSTRUMENT)) ; + + if (instr == NULL) + return NULL ; + + /* Set non-zero default values. */ + instr->basenote = -1 ; + instr->velocity_lo = -1 ; + instr->velocity_hi = -1 ; + instr->key_lo = -1 ; + instr->key_hi = -1 ; + + return instr ; +} /* psf_instrument_alloc */ + +void +psf_sanitize_string (char * cptr, int len) +{ + do + { + len -- ; + cptr [len] = psf_isprint (cptr [len]) ? cptr [len] : '.' ; + } + while (len > 0) ; +} /* psf_sanitize_string */ + +void +psf_get_date_str (char *str, int maxlen) +{ time_t current ; + struct tm timedata, *tmptr ; + + time (¤t) ; + +#if defined (HAVE_GMTIME_R) + /* If the re-entrant version is available, use it. */ + tmptr = gmtime_r (¤t, &timedata) ; +#elif defined (HAVE_GMTIME) + /* Otherwise use the standard one and copy the data to local storage. */ + tmptr = gmtime (¤t) ; + memcpy (&timedata, tmptr, sizeof (timedata)) ; +#else + tmptr = NULL ; +#endif + + if (tmptr) + snprintf (str, maxlen, "%4d-%02d-%02d %02d:%02d:%02d UTC", + 1900 + timedata.tm_year, timedata.tm_mon, timedata.tm_mday, + timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ; + else + snprintf (str, maxlen, "Unknown date") ; + + return ; +} /* psf_get_date_str */ + +int +subformat_to_bytewidth (int format) +{ + switch (format) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + return 1 ; + case SF_FORMAT_PCM_16 : + return 2 ; + case SF_FORMAT_PCM_24 : + return 3 ; + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + return 4 ; + case SF_FORMAT_DOUBLE : + return 8 ; + } ; + + return 0 ; +} /* subformat_to_bytewidth */ + +int +s_bitwidth_to_subformat (int bits) +{ static int array [] = + { SF_FORMAT_PCM_S8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 + } ; + + if (bits < 8 || bits > 32) + return 0 ; + + return array [((bits + 7) / 8) - 1] ; +} /* bitwidth_to_subformat */ + +int +u_bitwidth_to_subformat (int bits) +{ static int array [] = + { SF_FORMAT_PCM_U8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 + } ; + + if (bits < 8 || bits > 32) + return 0 ; + + return array [((bits + 7) / 8) - 1] ; +} /* bitwidth_to_subformat */ + +/* +** psf_rand_int32 : Not crypto quality, but more than adequate for things +** like stream serial numbers in Ogg files or the unique_id field of the +** SF_PRIVATE struct. +*/ + +int32_t +psf_rand_int32 (void) +{ static int32_t value = -1 ; + int k, count ; + + if (value == -1) + { +#if HAVE_GETTIMEOFDAY + struct timeval tv ; + gettimeofday (&tv, NULL) ; + value = tv.tv_sec + tv.tv_usec ; +#else + value = time (NULL) ; +#endif + } ; + + count = 4 + (value & 7) ; + for (k = 0 ; k < count ; k++) + value = 11117 * value + 211231 ; + + return value ; +} /* psf_rand_int32 */ + +void +append_snprintf (char * dest, size_t maxlen, const char * fmt, ...) +{ size_t len = strlen (dest) ; + + if (len < maxlen) + { va_list ap ; + + va_start (ap, fmt) ; + vsnprintf (dest + len, maxlen - len, fmt, ap) ; + va_end (ap) ; + } ; + + return ; +} /* append_snprintf */ + + +void +psf_strlcpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) +{ /* Must be minus 2 so it can still expand a single trailing '\n' or '\r'. */ + char * destend = dest + destmax - 2 ; + const char * srcend = src + srcmax ; + + while (dest < destend && src < srcend) + { if ((src [0] == '\r' && src [1] == '\n') || (src [0] == '\n' && src [1] == '\r')) + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 2 ; + continue ; + } ; + + if (src [0] == '\r') + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 1 ; + continue ; + } ; + + if (src [0] == '\n') + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 1 ; + continue ; + } ; + + *dest++ = *src++ ; + } ; + + /* Make sure dest is terminated. */ + *dest = 0 ; +} /* psf_strlcpy_crlf */ + +/*============================================================================== +*/ + +#define CASE_NAME(x) case x : return #x ; break ; + +const char * +str_of_major_format (int format) +{ switch (SF_CONTAINER (format)) + { CASE_NAME (SF_FORMAT_WAV) ; + CASE_NAME (SF_FORMAT_AIFF) ; + CASE_NAME (SF_FORMAT_AU) ; + CASE_NAME (SF_FORMAT_RAW) ; + CASE_NAME (SF_FORMAT_PAF) ; + CASE_NAME (SF_FORMAT_SVX) ; + CASE_NAME (SF_FORMAT_NIST) ; + CASE_NAME (SF_FORMAT_VOC) ; + CASE_NAME (SF_FORMAT_IRCAM) ; + CASE_NAME (SF_FORMAT_W64) ; + CASE_NAME (SF_FORMAT_MAT4) ; + CASE_NAME (SF_FORMAT_MAT5) ; + CASE_NAME (SF_FORMAT_PVF) ; + CASE_NAME (SF_FORMAT_XI) ; + CASE_NAME (SF_FORMAT_HTK) ; + CASE_NAME (SF_FORMAT_SDS) ; + CASE_NAME (SF_FORMAT_AVR) ; + CASE_NAME (SF_FORMAT_WAVEX) ; + CASE_NAME (SF_FORMAT_SD2) ; + CASE_NAME (SF_FORMAT_FLAC) ; + CASE_NAME (SF_FORMAT_CAF) ; + CASE_NAME (SF_FORMAT_WVE) ; + CASE_NAME (SF_FORMAT_OGG) ; + default : + break ; + } ; + + return "BAD_MAJOR_FORMAT" ; +} /* str_of_major_format */ + +const char * +str_of_minor_format (int format) +{ switch (SF_CODEC (format)) + { CASE_NAME (SF_FORMAT_PCM_S8) ; + CASE_NAME (SF_FORMAT_PCM_16) ; + CASE_NAME (SF_FORMAT_PCM_24) ; + CASE_NAME (SF_FORMAT_PCM_32) ; + CASE_NAME (SF_FORMAT_PCM_U8) ; + CASE_NAME (SF_FORMAT_FLOAT) ; + CASE_NAME (SF_FORMAT_DOUBLE) ; + CASE_NAME (SF_FORMAT_ULAW) ; + CASE_NAME (SF_FORMAT_ALAW) ; + CASE_NAME (SF_FORMAT_IMA_ADPCM) ; + CASE_NAME (SF_FORMAT_MS_ADPCM) ; + CASE_NAME (SF_FORMAT_GSM610) ; + CASE_NAME (SF_FORMAT_VOX_ADPCM) ; + CASE_NAME (SF_FORMAT_G721_32) ; + CASE_NAME (SF_FORMAT_G723_24) ; + CASE_NAME (SF_FORMAT_G723_40) ; + CASE_NAME (SF_FORMAT_DWVW_12) ; + CASE_NAME (SF_FORMAT_DWVW_16) ; + CASE_NAME (SF_FORMAT_DWVW_24) ; + CASE_NAME (SF_FORMAT_DWVW_N) ; + CASE_NAME (SF_FORMAT_DPCM_8) ; + CASE_NAME (SF_FORMAT_DPCM_16) ; + CASE_NAME (SF_FORMAT_VORBIS) ; + default : + break ; + } ; + + return "BAD_MINOR_FORMAT" ; +} /* str_of_minor_format */ + +const char * +str_of_open_mode (int mode) +{ switch (mode) + { CASE_NAME (SFM_READ) ; + CASE_NAME (SFM_WRITE) ; + CASE_NAME (SFM_RDWR) ; + + default : + break ; + } ; + + return "BAD_MODE" ; +} /* str_of_open_mode */ + +const char * +str_of_endianness (int end) +{ switch (end) + { CASE_NAME (SF_ENDIAN_BIG) ; + CASE_NAME (SF_ENDIAN_LITTLE) ; + CASE_NAME (SF_ENDIAN_CPU) ; + default : + break ; + } ; + + /* Zero length string for SF_ENDIAN_FILE. */ + return "" ; +} /* str_of_endianness */