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
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
;
31 if (lsx_readdw(ft
, (uint32_t *)&magic_
))
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");
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
))
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");
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
) {
63 sox_append_comments(&ft
->oob
.comments
, buf
);
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
);
72 return lsx_check_read_params(
73 ft
, num_channels
, rate
, SOX_ENCODING_SIGN2
, 32, num_samples
, sox_true
);
76 static int write_header(sox_format_t
* ft
)
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
;
84 memcpy(&header
, magic
[MACHINE_IS_BIGENDIAN
], sizeof(header
));
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
);
95 return error
? SOX_EOF
: SOX_SUCCESS
;
98 LSX_FORMAT_HANDLER(sox
)
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