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