Merge branch 'mr/build' into pu
[sox/ew.git] / src / sox-fmt.c
blobaad965cd12e27c4c2d022fbea0f45d9c878d2313
1 /* libSoX file format: SoX native (c) 2008 robs@users.sourceforge.net
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.
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.
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
18 #include "sox_i.h"
19 #include <string.h>
21 static char const magic[2][4] = {".SoX", "XoS."};
22 #define FIXED_HDR (4 + 8 + 8 + 4 + 4) /* Without magic */
24 static int startread(sox_format_t * ft)
26 char magic_[sizeof(magic[0])];
27 uint32_t headers_bytes, num_channels, comments_bytes;
28 uint64_t num_samples;
29 double rate;
31 if (lsx_readdw(ft, (uint32_t *)&magic_))
32 return SOX_EOF;
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;
39 ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
40 lsx_report("file is opposite endian");
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;
49 if (((headers_bytes + 4) & 7) || headers_bytes < FIXED_HDR + comments_bytes ||
50 (num_channels > 65535)) /* Reserve top 16 bits */ {
51 lsx_fail_errno(ft, SOX_EHDR, "invalid sox file format header");
52 return SOX_EOF;
55 if (comments_bytes) {
56 char * buf = lsx_calloc(1, (size_t)comments_bytes + 1); /* ensure nul-terminated */
57 if (lsx_readchars(ft, buf, (size_t)comments_bytes) != SOX_SUCCESS) {
58 free(buf);
59 return SOX_EOF;
61 sox_append_comments(&ft->oob.comments, buf);
62 free(buf);
65 /* Consume any bytes after the comments and before the start of the audio
66 * block. These may include comment padding up to a multiple of 8 bytes,
67 * and further header information that might be defined in future. */
68 lsx_seeki(ft, (off_t)(headers_bytes - FIXED_HDR - comments_bytes), SEEK_CUR);
70 return lsx_check_read_params(
71 ft, num_channels, rate, SOX_ENCODING_SIGN2, 32, num_samples, sox_true);
74 static int write_header(sox_format_t * ft)
76 char * comments = lsx_cat_comments(ft->oob.comments);
77 size_t comments_len = strlen(comments);
78 size_t comments_bytes = (comments_len + 7) & ~7u; /* Multiple of 8 bytes */
79 uint64_t size = ft->olength? ft->olength : ft->signal.length;
80 int error;
81 uint32_t header;
82 memcpy(&header, magic[MACHINE_IS_BIGENDIAN], sizeof(header));
83 error = 0
84 ||lsx_writedw(ft, header)
85 ||lsx_writedw(ft, FIXED_HDR + (unsigned)comments_bytes)
86 ||lsx_writeqw(ft, size)
87 ||lsx_writedf(ft, ft->signal.rate)
88 ||lsx_writedw(ft, ft->signal.channels)
89 ||lsx_writedw(ft, (unsigned)comments_len)
90 ||lsx_writechars(ft, comments, comments_len)
91 ||lsx_padbytes(ft, comments_bytes - comments_len);
92 free(comments);
93 return error? SOX_EOF: SOX_SUCCESS;
96 LSX_FORMAT_HANDLER(sox)
98 static char const * const names[] = {"sox", NULL};
99 static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 0, 0};
100 static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
101 "SoX native intermediate format", names, SOX_FILE_REWIND,
102 startread, lsx_rawread, NULL, write_header, lsx_rawwrite, NULL,
103 lsx_rawseek, write_encodings, NULL, 0
105 return &handler;