1 /* Implements a libSoX internal interface for use in implementing file formats. 2 * All public functions & data are prefixed with lsx_ . 3 * 4 * (c) 2005-8 Chris Bagwell and SoX contributors 5 * 6 * This library is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation; either version 2.1 of the License, or (at 9 * your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with this library; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #include "sox_i.h" 22 #include <string.h> 23 #include <sys/stat.h> 24 #include <stdarg.h> 25 26 void lsx_fail_errno(sox_format_t * ft, int sox_errno, const char *fmt, ...) 27 { 28 va_list args; 29 30 ft->sox_errno = sox_errno; 31 32 va_start(args, fmt); 33 #ifdef HAVE_VSNPRINTF 34 vsnprintf(ft->sox_errstr, sizeof(ft->sox_errstr), fmt, args); 35 #else 36 vsprintf(ft->sox_errstr, fmt, args); 37 #endif 38 va_end(args); 39 ft->sox_errstr[255] = '\0'; 40 } 41 42 void lsx_set_signal_defaults(sox_format_t * ft) 43 { 44 if (!ft->signal.rate ) ft->signal.rate = SOX_DEFAULT_RATE; 45 if (!ft->signal.precision) ft->signal.precision = SOX_DEFAULT_PRECISION; 46 if (!ft->signal.channels ) ft->signal.channels = SOX_DEFAULT_CHANNELS; 47 48 if (!ft->encoding.bits_per_sample) 49 ft->encoding.bits_per_sample = ft->signal.precision; 50 if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) 51 ft->encoding.encoding = SOX_ENCODING_SIGN2; 52 } 53 54 int lsx_check_read_params(sox_format_t * ft, unsigned channels, 55 sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, 56 uint64_t num_samples, sox_bool check_length) 57 { 58 ft->signal.length = ft->signal.length == SOX_IGNORE_LENGTH? SOX_UNSPEC : num_samples; 59 60 if (ft->seekable) 61 ft->data_start = lsx_tell(ft); 62 63 if (channels && ft->signal.channels && ft->signal.channels != channels) 64 lsx_warn("`%s': overriding number of channels", ft->filename); 65 else ft->signal.channels = channels; 66 67 if (rate && ft->signal.rate && ft->signal.rate != rate) 68 lsx_warn("`%s': overriding sample rate", ft->filename); 69 else ft->signal.rate = rate; 70 71 if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding) 72 lsx_warn("`%s': overriding encoding type", ft->filename); 73 else ft->encoding.encoding = encoding; 74 75 if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample) 76 lsx_warn("`%s': overriding encoding size", ft->filename); 77 ft->encoding.bits_per_sample = bits_per_sample; 78 79 if (check_length && ft->encoding.bits_per_sample && lsx_filelength(ft)) { 80 uint64_t calculated_length = div_bits(lsx_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample); 81 if (!ft->signal.length) 82 ft->signal.length = calculated_length; 83 else if (num_samples != calculated_length) 84 lsx_warn("`%s': file header gives the total number of samples as %" PRIu64 " but file length indicates the number is in fact %" PRIu64, ft->filename, num_samples, calculated_length); 85 } 86 87 if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample)) 88 return SOX_SUCCESS; 89 lsx_fail_errno(ft, EINVAL, "invalid format for this file type"); 90 return SOX_EOF; 91 } 92 93 /* Read in a buffer of data of length len bytes. 94 * Returns number of bytes read. 95 */ 96 size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len) 97 { 98 size_t ret = fread(buf, (size_t) 1, len, (FILE*)ft->fp); 99 if (ret != len && ferror((FILE*)ft->fp)) 100 lsx_fail_errno(ft, errno, "lsx_readbuf"); 101 ft->tell_off += ret; 102 return ret; 103 } 104 105 /* Skip input without seeking. */ 106 int lsx_skipbytes(sox_format_t * ft, size_t n) 107 { 108 unsigned char trash; 109 110 while (n--) 111 if (lsx_readb(ft, &trash) == SOX_EOF) 112 return (SOX_EOF); 113 114 return (SOX_SUCCESS); 115 } 116 117 /* Pad output. */ 118 int lsx_padbytes(sox_format_t * ft, size_t n) 119 { 120 while (n--) 121 if (lsx_writeb(ft, '\0') == SOX_EOF) 122 return (SOX_EOF); 123 124 return (SOX_SUCCESS); 125 } 126 127 /* Write a buffer of data of length bytes. 128 * Returns number of bytes written. 129 */ 130 size_t lsx_writebuf(sox_format_t * ft, void const * buf, size_t len) 131 { 132 size_t ret = fwrite(buf, (size_t) 1, len, (FILE*)ft->fp); 133 if (ret != len) { 134 lsx_fail_errno(ft, errno, "error writing output file"); 135 clearerr((FILE*)ft->fp); /* Allows us to seek back to write header */ 136 } 137 ft->tell_off += ret; 138 return ret; 139 } 140 141 sox_uint64_t lsx_filelength(sox_format_t * ft) 142 { 143 struct stat st; 144 int ret = ft->fp ? fstat(fileno((FILE*)ft->fp), &st) : 0; 145 146 return (!ret && (st.st_mode & S_IFREG))? (uint64_t)st.st_size : 0; 147 } 148 149 int lsx_flush(sox_format_t * ft) 150 { 151 return fflush((FILE*)ft->fp); 152 } 153 154 off_t lsx_tell(sox_format_t * ft) 155 { 156 return ft->seekable? (off_t)ftello((FILE*)ft->fp) : (off_t)ft->tell_off; 157 } 158 159 int lsx_eof(sox_format_t * ft) 160 { 161 return feof((FILE*)ft->fp); 162 } 163 164 int lsx_error(sox_format_t * ft) 165 { 166 return ferror((FILE*)ft->fp); 167 } 168 169 void lsx_rewind(sox_format_t * ft) 170 { 171 rewind((FILE*)ft->fp); 172 ft->tell_off = 0; 173 } 174 175 void lsx_clearerr(sox_format_t * ft) 176 { 177 clearerr((FILE*)ft->fp); 178 ft->sox_errno = 0; 179 } 180 181 int lsx_unreadb(sox_format_t * ft, unsigned b) 182 { 183 return ungetc((int)b, ft->fp); 184 } 185 186 /* Implements traditional fseek() behavior. Meant to abstract out 187 * file operations so that they could one day also work on memory 188 * buffers. 189 * 190 * N.B. Can only seek forwards on non-seekable streams! 191 */ 192 int lsx_seeki(sox_format_t * ft, off_t offset, int whence) 193 { 194 if (ft->seekable == 0) { 195 /* If a stream peel off chars else EPERM */ 196 if (whence == SEEK_CUR) { 197 while (offset > 0 && !feof((FILE*)ft->fp)) { 198 getc((FILE*)ft->fp); 199 offset--; 200 ++ft->tell_off; 201 } 202 if (offset) 203 lsx_fail_errno(ft,SOX_EOF, "offset past EOF"); 204 else 205 ft->sox_errno = SOX_SUCCESS; 206 } else 207 lsx_fail_errno(ft,SOX_EPERM, "file not seekable"); 208 } else { 209 if (fseeko((FILE*)ft->fp, offset, whence) == -1) 210 lsx_fail_errno(ft,errno, "%s", strerror(errno)); 211 else 212 ft->sox_errno = SOX_SUCCESS; 213 } 214 return ft->sox_errno; 215 } 216 217 int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample) 218 { 219 double wide_sample = to_sample - (to_sample % ft->signal.channels); 220 double to_d = wide_sample * ft->encoding.bits_per_sample / 8; 221 off_t to = to_d; 222 return (to != to_d)? SOX_EOF : lsx_seeki(ft, (byte_offset + to), SEEK_SET); 223 } 224 225 /* Read and write known datatypes in "machine format". Swap if indicated. 226 * They all return SOX_EOF on error and SOX_SUCCESS on success. 227 */ 228 /* Read n-char string (and possibly null-terminating). 229 * Stop reading and null-terminate string if either a 0 or \n is reached. 230 */ 231 int lsx_reads(sox_format_t * ft, char *c, size_t len) 232 { 233 char *sc; 234 char in; 235 236 sc = c; 237 do 238 { 239 if (lsx_readbuf(ft, &in, (size_t)1) != 1) 240 { 241 *sc = 0; 242 return (SOX_EOF); 243 } 244 if (in == 0 || in == '\n') 245 break; 246 247 *sc = in; 248 sc++; 249 } while (sc - c < (ptrdiff_t)len); 250 *sc = 0; 251 return(SOX_SUCCESS); 252 } 253 254 /* Write null-terminated string (without \0). */ 255 int lsx_writes(sox_format_t * ft, char const * c) 256 { 257 if (lsx_writebuf(ft, c, strlen(c)) != strlen(c)) 258 return(SOX_EOF); 259 return(SOX_SUCCESS); 260 } 261 262 /* return swapped 32-bit float */ 263 static void lsx_swapf(float * f) 264 { 265 union { 266 uint32_t dw; 267 float f; 268 } u; 269 270 u.f= *f; 271 u.dw= (u.dw>>24) | ((u.dw>>8)&0xff00) | ((u.dw<<8)&0xff0000) | (u.dw<<24); 272 *f = u.f; 273 } 274 275 static void swap(void * data, size_t len) 276 { 277 uint8_t * bytes = (uint8_t *)data; 278 size_t i; 279 280 for (i = 0; i < len / 2; ++i) { 281 char tmp = bytes[i]; 282 bytes[i] = bytes[len - 1 - i]; 283 bytes[len - 1 - i] = tmp; 284 } 285 } 286 287 static double lsx_swapdf(double data) 288 { 289 swap(&data, sizeof(data)); 290 return data; 291 } 292 293 static uint64_t lsx_swapqw(uint64_t data) 294 { 295 swap(&data, sizeof(data)); 296 return data; 297 } 298 299 /* Lookup table to reverse the bit order of a byte. ie MSB become LSB */ 300 static uint8_t const cswap[256] = { 301 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 302 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 303 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 304 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 305 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 306 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 307 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 308 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 309 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 310 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 311 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 312 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 313 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 314 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 315 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 316 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 317 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 318 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 319 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 320 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 321 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 322 0x3F, 0xBF, 0x7F, 0xFF 323 }; 324 325 /* Utilities to byte-swap values, use libc optimized macros if possible */ 326 #define TWIDDLE_BYTE(ub, type) \ 327 do { \ 328 if (ft->encoding.reverse_bits) \ 329 ub = cswap[ub]; \ 330 if (ft->encoding.reverse_nibbles) \ 331 ub = ((ub & 15) << 4) | (ub >> 4); \ 332 } while (0); 333 334 #define TWIDDLE_WORD(uw, type) \ 335 if (ft->encoding.reverse_bytes) \ 336 uw = lsx_swap ## type(uw); 337 338 #define TWIDDLE_FLOAT(f, type) \ 339 if (ft->encoding.reverse_bytes) \ 340 lsx_swapf(&f); 341 342 /* N.B. This macro doesn't work for unaligned types (e.g. 3-byte 343 types). */ 344 #define READ_FUNC(type, size, ctype, twiddle) \ 345 size_t lsx_read_ ## type ## _buf( \ 346 sox_format_t * ft, ctype *buf, size_t len) \ 347 { \ 348 size_t n, nread; \ 349 nread = lsx_readbuf(ft, buf, len * size) / size; \ 350 for (n = 0; n < nread; n++) \ 351 twiddle(buf[n], type); \ 352 return nread; \ 353 } 354 355 /* Unpack a 3-byte value from a uint8_t * */ 356 #define sox_unpack3(p) (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? \ 357 ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) : \ 358 ((p)[2] | ((p)[1] << 8) | ((p)[0] << 16))) 359 360 /* This (slower) macro works for unaligned types (e.g. 3-byte types) 361 that need to be unpacked. */ 362 #define READ_FUNC_UNPACK(type, size, ctype, twiddle) \ 363 size_t lsx_read_ ## type ## _buf( \ 364 sox_format_t * ft, ctype *buf, size_t len) \ 365 { \ 366 size_t n, nread; \ 367 uint8_t *data = lsx_malloc(size * len); \ 368 nread = lsx_readbuf(ft, data, len * size) / size; \ 369 for (n = 0; n < nread; n++) \ 370 buf[n] = sox_unpack ## size(data + n * size); \ 371 free(data); \ 372 return n; \ 373 } 374 375 READ_FUNC(b, 1, uint8_t, TWIDDLE_BYTE) 376 READ_FUNC(w, 2, uint16_t, TWIDDLE_WORD) 377 READ_FUNC_UNPACK(3, 3, sox_uint24_t, TWIDDLE_WORD) 378 READ_FUNC(dw, 4, uint32_t, TWIDDLE_WORD) 379 READ_FUNC(qw, 8, uint64_t, TWIDDLE_WORD) 380 READ_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT) 381 READ_FUNC(df, sizeof(double), double, TWIDDLE_WORD) 382 383 #define READ1_FUNC(type, ctype) \ 384 int lsx_read ## type(sox_format_t * ft, ctype * datum) { \ 385 if (lsx_read_ ## type ## _buf(ft, datum, (size_t)1) == 1) \ 386 return SOX_SUCCESS; \ 387 if (!lsx_error(ft)) \ 388 lsx_fail_errno(ft, errno, premature_eof); \ 389 return SOX_EOF; \ 390 } 391 392 static char const premature_eof[] = "premature EOF"; 393 394 READ1_FUNC(b, uint8_t) 395 READ1_FUNC(w, uint16_t) 396 READ1_FUNC(3, sox_uint24_t) 397 READ1_FUNC(dw, uint32_t) 398 READ1_FUNC(qw, uint64_t) 399 READ1_FUNC(f, float) 400 READ1_FUNC(df, double) 401 402 int lsx_readchars(sox_format_t * ft, char * chars, size_t len) 403 { 404 size_t ret = lsx_readbuf(ft, chars, len); 405 if (ret == len) 406 return SOX_SUCCESS; 407 if (!lsx_error(ft)) 408 lsx_fail_errno(ft, errno, premature_eof); 409 return SOX_EOF; 410 } 411 412 /* N.B. This macro doesn't work for unaligned types (e.g. 3-byte 413 types). */ 414 #define WRITE_FUNC(type, size, ctype, twiddle) \ 415 size_t lsx_write_ ## type ## _buf( \ 416 sox_format_t * ft, ctype *buf, size_t len) \ 417 { \ 418 size_t n, nwritten; \ 419 for (n = 0; n < len; n++) \ 420 twiddle(buf[n], type); \ 421 nwritten = lsx_writebuf(ft, buf, len * size); \ 422 return nwritten / size; \ 423 } 424 425 /* Pack a 3-byte value to a uint8_t * */ 426 #define sox_pack3(p, v) do {if (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN)\ 427 {(p)[0] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[2] = (v >> 16) & 0xff;} else \ 428 {(p)[2] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[0] = (v >> 16) & 0xff;} \ 429 } while (0) 430 431 /* This (slower) macro works for unaligned types (e.g. 3-byte types) 432 that need to be packed. */ 433 #define WRITE_FUNC_PACK(type, size, ctype, twiddle) \ 434 size_t lsx_write_ ## type ## _buf( \ 435 sox_format_t * ft, ctype *buf, size_t len) \ 436 { \ 437 size_t n, nwritten; \ 438 uint8_t *data = lsx_malloc(size * len); \ 439 for (n = 0; n < len; n++) \ 440 sox_pack ## size(data + n * size, buf[n]); \ 441 nwritten = lsx_writebuf(ft, data, len * size); \ 442 free(data); \ 443 return nwritten / size; \ 444 } 445 446 WRITE_FUNC(b, 1, uint8_t, TWIDDLE_BYTE) 447 WRITE_FUNC(w, 2, uint16_t, TWIDDLE_WORD) 448 WRITE_FUNC_PACK(3, 3, sox_uint24_t, TWIDDLE_WORD) 449 WRITE_FUNC(dw, 4, uint32_t, TWIDDLE_WORD) 450 WRITE_FUNC(qw, 8, uint64_t, TWIDDLE_WORD) 451 WRITE_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT) 452 WRITE_FUNC(df, sizeof(double), double, TWIDDLE_WORD) 453 454 #define WRITE1U_FUNC(type, ctype) \ 455 int lsx_write ## type(sox_format_t * ft, unsigned d) \ 456 { ctype datum = (ctype)d; \ 457 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ 458 } 459 460 #define WRITE1S_FUNC(type, ctype) \ 461 int lsx_writes ## type(sox_format_t * ft, signed d) \ 462 { ctype datum = (ctype)d; \ 463 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ 464 } 465 466 #define WRITE1_FUNC(type, ctype) \ 467 int lsx_write ## type(sox_format_t * ft, ctype datum) \ 468 { \ 469 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ 470 } 471 472 WRITE1U_FUNC(b, uint8_t) 473 WRITE1U_FUNC(w, uint16_t) 474 WRITE1U_FUNC(3, sox_uint24_t) 475 WRITE1U_FUNC(dw, uint32_t) 476 WRITE1_FUNC(qw, uint64_t) 477 WRITE1S_FUNC(b, uint8_t) 478 WRITE1S_FUNC(w, uint16_t) 479 WRITE1_FUNC(df, double) 480 481 int lsx_writef(sox_format_t * ft, double datum) 482 { 483 float f = datum; 484 return lsx_write_f_buf(ft, &f, (size_t) 1) == 1 ? SOX_SUCCESS : SOX_EOF; 485 } 486