1 /* libSoX file format: SoX native   (c) 2008 robs@users.sourceforge.net
2  *
3  * This library is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2.1 of the License, or (at
6  * your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17 
18 #include "sox_i.h"
19 #include <string.h>
20 
21 static char const magic[2][4] = {".SoX", "XoS."};
22 #define FIXED_HDR     (4 + 8 + 8 + 4 + 4) /* Without magic */
23 
startread(sox_format_t * ft)24 static int startread(sox_format_t * ft)
25 {
26   char     magic_[sizeof(magic[0])];
27   uint32_t headers_bytes, num_channels, comments_bytes;
28   uint64_t num_samples;
29   double   rate;
30 
31   if (lsx_readdw(ft, (uint32_t *)&magic_))
32     return SOX_EOF;
33 
34   if (memcmp(magic[MACHINE_IS_BIGENDIAN], magic_, sizeof(magic_))) {
35     if (memcmp(magic[MACHINE_IS_LITTLEENDIAN], magic_, sizeof(magic_))) {
36       lsx_fail_errno(ft, SOX_EHDR, "can't find sox file format identifier");
37       return SOX_EOF;
38     }
39     ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
40     lsx_report("file is opposite endian");
41   }
42   if (lsx_readdw(ft, &headers_bytes) ||
43       lsx_readqw(ft, &num_samples) ||
44       lsx_readdf(ft, &rate) ||
45       lsx_readdw(ft, &num_channels) ||
46       lsx_readdw(ft, &comments_bytes))
47     return SOX_EOF;
48 
49   if (((headers_bytes + 4) & 7) ||
50       comments_bytes > 0x40000000 || /* max 1 GB */
51       headers_bytes < FIXED_HDR + comments_bytes ||
52       (num_channels > 65535)) /* Reserve top 16 bits */ {
53     lsx_fail_errno(ft, SOX_EHDR, "invalid sox file format header");
54     return SOX_EOF;
55   }
56 
57   if (comments_bytes) {
58     char * buf = lsx_calloc(1, (size_t)comments_bytes + 1); /* ensure nul-terminated */
59     if (lsx_readchars(ft, buf, (size_t)comments_bytes) != SOX_SUCCESS) {
60       free(buf);
61       return SOX_EOF;
62     }
63     sox_append_comments(&ft->oob.comments, buf);
64     free(buf);
65   }
66 
67   /* Consume any bytes after the comments and before the start of the audio
68    * block.  These may include comment padding up to a multiple of 8 bytes,
69    * and further header information that might be defined in future. */
70   lsx_seeki(ft, (off_t)(headers_bytes - FIXED_HDR - comments_bytes), SEEK_CUR);
71 
72   return lsx_check_read_params(
73       ft, num_channels, rate, SOX_ENCODING_SIGN2, 32, num_samples, sox_true);
74 }
75 
write_header(sox_format_t * ft)76 static int write_header(sox_format_t * ft)
77 {
78   char * comments  = lsx_cat_comments(ft->oob.comments);
79   size_t comments_len = strlen(comments);
80   size_t comments_bytes = (comments_len + 7) & ~7u; /* Multiple of 8 bytes */
81   uint64_t size   = ft->olength? ft->olength : ft->signal.length;
82   int error;
83   uint32_t header;
84   memcpy(&header, magic[MACHINE_IS_BIGENDIAN], sizeof(header));
85   error = 0
86   ||lsx_writedw(ft, header)
87   ||lsx_writedw(ft, FIXED_HDR + (unsigned)comments_bytes)
88   ||lsx_writeqw(ft, size)
89   ||lsx_writedf(ft, ft->signal.rate)
90   ||lsx_writedw(ft, ft->signal.channels)
91   ||lsx_writedw(ft, (unsigned)comments_len)
92   ||lsx_writechars(ft, comments, comments_len)
93   ||lsx_padbytes(ft, comments_bytes - comments_len);
94   free(comments);
95   return error? SOX_EOF: SOX_SUCCESS;
96 }
97 
LSX_FORMAT_HANDLER(sox)98 LSX_FORMAT_HANDLER(sox)
99 {
100   static char const * const names[] = {"sox", NULL};
101   static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 0, 0};
102   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
103     "SoX native intermediate format", names, SOX_FILE_REWIND,
104     startread, lsx_rawread, NULL, write_header, lsx_rawwrite, NULL,
105     lsx_rawseek, write_encodings, NULL, 0
106   };
107   return &handler;
108 }
109