README.osx wasn't easily readable in Finder. Revert back to
[sox.git] / src / formats_i.c
blob2400770b75486bcc63a811b46171742c590fd74f
1 /* Implements a libSoX internal interface for use in implementing file formats.
2 * All public functions & data are prefixed with lsx_ .
4 * (c) 2005-8 Chris Bagwell and SoX contributors
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.
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.
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
21 #include "sox_i.h"
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <stdarg.h>
26 void lsx_fail_errno(sox_format_t * ft, int sox_errno, const char *fmt, ...)
28 va_list args;
30 ft->sox_errno = sox_errno;
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';
42 void lsx_set_signal_defaults(sox_format_t * ft)
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;
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;
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 off_t num_samples, sox_bool check_length)
58 ft->signal.length = ft->signal.length == SOX_IGNORE_LENGTH? SOX_UNSPEC : num_samples;
60 if (ft->seekable)
61 ft->data_start = lsx_tell(ft);
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;
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;
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;
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;
79 if (check_length && ft->encoding.bits_per_sample && lsx_filelength(ft)) {
80 off_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 %u but file length indicates the number is in fact %u", ft->filename, (unsigned)num_samples, (unsigned)calculated_length); /* FIXME: casts */
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;
93 /* Read in a buffer of data of length len bytes.
94 * Returns number of bytes read.
96 size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len)
98 size_t ret = fread(buf, (size_t) 1, len, ft->fp);
99 if (ret != len && ferror(ft->fp))
100 lsx_fail_errno(ft, errno, "lsx_readbuf");
101 ft->tell_off += ret;
102 return ret;
105 /* Skip input without seeking. */
106 int lsx_skipbytes(sox_format_t * ft, size_t n)
108 unsigned char trash;
110 while (n--)
111 if (lsx_readb(ft, &trash) == SOX_EOF)
112 return (SOX_EOF);
114 return (SOX_SUCCESS);
117 /* Pad output. */
118 int lsx_padbytes(sox_format_t * ft, size_t n)
120 while (n--)
121 if (lsx_writeb(ft, '\0') == SOX_EOF)
122 return (SOX_EOF);
124 return (SOX_SUCCESS);
127 /* Write a buffer of data of length bytes.
128 * Returns number of bytes written.
130 size_t lsx_writebuf(sox_format_t * ft, void const * buf, size_t len)
132 size_t ret = fwrite(buf, (size_t) 1, len, ft->fp);
133 if (ret != len) {
134 lsx_fail_errno(ft, errno, "error writing output file");
135 clearerr(ft->fp); /* Allows us to seek back to write header */
137 ft->tell_off += ret;
138 return ret;
141 size_t lsx_filelength(sox_format_t * ft)
143 struct stat st;
144 int ret = fstat(fileno(ft->fp), &st);
146 return (!ret && (st.st_mode & S_IFREG))? (size_t)st.st_size : 0;
149 int lsx_flush(sox_format_t * ft)
151 return fflush(ft->fp);
154 off_t lsx_tell(sox_format_t * ft)
156 return ft->seekable? (ptrdiff_t)ftello(ft->fp) : ft->tell_off;
159 int lsx_eof(sox_format_t * ft)
161 return feof(ft->fp);
164 int lsx_error(sox_format_t * ft)
166 return ferror(ft->fp);
169 void lsx_rewind(sox_format_t * ft)
171 rewind(ft->fp);
172 ft->tell_off = 0;
175 void lsx_clearerr(sox_format_t * ft)
177 clearerr(ft->fp);
178 ft->sox_errno = 0;
181 int lsx_unreadb(sox_format_t * ft, unsigned b)
183 return ungetc((int)b, ft->fp);
186 /* Implements traditional fseek() behavior. Meant to abstract out
187 * file operations so that they could one day also work on memory
188 * buffers.
190 * N.B. Can only seek forwards on non-seekable streams!
192 int lsx_seeki(sox_format_t * ft, off_t offset, int whence)
194 if (ft->seekable == 0) {
195 /* If a stream peel off chars else EPERM */
196 if (whence == SEEK_CUR) {
197 while (offset > 0 && !feof(ft->fp)) {
198 getc(ft->fp);
199 offset--;
200 ++ft->tell_off;
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(ft->fp, offset, whence) == -1)
210 lsx_fail_errno(ft,errno, "%s", strerror(errno));
211 else
212 ft->sox_errno = SOX_SUCCESS;
214 return ft->sox_errno;
217 int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample)
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);
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.
228 /* Read n-char string (and possibly null-terminating).
229 * Stop reading and null-terminate string if either a 0 or \n is reached.
231 int lsx_reads(sox_format_t * ft, char *c, size_t len)
233 char *sc;
234 char in;
236 sc = c;
239 if (lsx_readbuf(ft, &in, (size_t)1) != 1)
241 *sc = 0;
242 return (SOX_EOF);
244 if (in == 0 || in == '\n')
245 break;
247 *sc = in;
248 sc++;
249 } while (sc - c < (ptrdiff_t)len);
250 *sc = 0;
251 return(SOX_SUCCESS);
254 /* Write null-terminated string (without \0). */
255 int lsx_writes(sox_format_t * ft, char const * c)
257 if (lsx_writebuf(ft, c, strlen(c)) != strlen(c))
258 return(SOX_EOF);
259 return(SOX_SUCCESS);
262 /* return swapped 32-bit float */
263 static void lsx_swapf(float * f)
265 union {
266 uint32_t dw;
267 float f;
268 } u;
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;
275 static void swap(void * data, size_t len)
277 uint8_t * bytes = (uint8_t *)data;
278 size_t i;
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;
287 static double lsx_swapdf(double data)
289 swap(&data, sizeof(data));
290 return data;
293 static uint64_t lsx_swapqw(uint64_t data)
295 swap(&data, sizeof(data));
296 return data;
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
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);
334 #define TWIDDLE_WORD(uw, type) \
335 if (ft->encoding.reverse_bytes) \
336 uw = lsx_swap ## type(uw);
338 #define TWIDDLE_FLOAT(f, type) \
339 if (ft->encoding.reverse_bytes) \
340 lsx_swapf(&f);
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) \
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; \
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)))
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) \
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; \
375 READ_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
376 READ_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
377 READ_FUNC_UNPACK(3, 3, 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)
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; \
392 static char const premature_eof[] = "premature EOF";
394 READ1_FUNC(b, uint8_t)
395 READ1_FUNC(w, uint16_t)
396 READ1_FUNC(3, uint24_t)
397 READ1_FUNC(dw, uint32_t)
398 READ1_FUNC(qw, uint64_t)
399 READ1_FUNC(f, float)
400 READ1_FUNC(df, double)
402 int lsx_readchars(sox_format_t * ft, char * chars, size_t len)
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;
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) \
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; \
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)
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) \
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; \
446 WRITE_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
447 WRITE_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
448 WRITE_FUNC_PACK(3, 3, 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)
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; \
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; \
466 #define WRITE1_FUNC(type, ctype) \
467 int lsx_write ## type(sox_format_t * ft, ctype datum) \
469 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
472 WRITE1U_FUNC(b, uint8_t)
473 WRITE1U_FUNC(w, uint16_t)
474 WRITE1U_FUNC(3, 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)
481 int lsx_writef(sox_format_t * ft, double datum)
483 float f = datum;
484 return lsx_write_f_buf(ft, &f, (size_t) 1) == 1 ? SOX_SUCCESS : SOX_EOF;