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