various bugfixes

- don't parse -X option because such an option doesn't exist
- allow argument for --sleep-min option
- fix handling of .voc magic string
- fix handling of .voc files on big-endian machines
- remove superfluous "size" parameter from check_wavefile_space macro
- reallocate buffer only if needed in check_wavefile_space
- fix playback of >2GB .wav files
- skip over padding bytes in .wav files
- fix memory leak when playing .voc silence blocks
- fix file length when recording >2GB .wav files
- fix recording of >4GB files
This commit is contained in:
Clemens Ladisch 2004-09-13 07:04:53 +00:00
parent dfec58eb7e
commit 72ae8b1e79
2 changed files with 35 additions and 33 deletions

View file

@ -305,7 +305,7 @@ enum {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int option_index; int option_index;
char *short_options = "hlLD:qt:c:f:r:d:s:MNF:A:X:R:T:B:vIPC"; char *short_options = "hlLD:qt:c:f:r:d:s:MNF:A:R:T:B:vIPC";
static struct option long_options[] = { static struct option long_options[] = {
{"help", 0, 0, 'h'}, {"help", 0, 0, 'h'},
{"version", 0, 0, OPT_VERSION}, {"version", 0, 0, OPT_VERSION},
@ -318,7 +318,7 @@ int main(int argc, char *argv[])
{"format", 1, 0, 'f'}, {"format", 1, 0, 'f'},
{"rate", 1, 0, 'r'}, {"rate", 1, 0, 'r'},
{"duration", 1, 0 ,'d'}, {"duration", 1, 0 ,'d'},
{"sleep-min", 0, 0, 's'}, {"sleep-min", 1, 0, 's'},
{"mmap", 0, 0, 'M'}, {"mmap", 0, 0, 'M'},
{"nonblock", 0, 0, 'N'}, {"nonblock", 0, 0, 'N'},
{"period-time", 1, 0, 'F'}, {"period-time", 1, 0, 'F'},
@ -602,12 +602,12 @@ static int test_vocfile(void *buffer)
{ {
VocHeader *vp = buffer; VocHeader *vp = buffer;
if (strstr(vp->magic, VOC_MAGIC_STRING)) { if (!memcmp(vp->magic, VOC_MAGIC_STRING, 20)) {
vocminor = vp->version & 0xFF; vocminor = LE_SHORT(vp->version) & 0xFF;
vocmajor = vp->version / 256; vocmajor = LE_SHORT(vp->version) / 256;
if (vp->version != (0x1233 - vp->coded_ver)) if (LE_SHORT(vp->version) != (0x1233 - LE_SHORT(vp->coded_ver)))
return -2; /* coded version mismatch */ return -2; /* coded version mismatch */
return vp->headerlen - sizeof(VocHeader); /* 0 mostly */ return LE_SHORT(vp->headerlen) - sizeof(VocHeader); /* 0 mostly */
} }
return -1; /* magic string fail */ return -1; /* magic string fail */
} }
@ -627,12 +627,13 @@ size_t test_wavefile_read(int fd, char *buffer, size_t *size, size_t reqsize, in
return *size = reqsize; return *size = reqsize;
} }
#define check_wavefile_space(buffer, size, len, blimit) \ #define check_wavefile_space(buffer, len, blimit) \
if (size + len > blimit) \ if (len > blimit) { \
blimit = size + len; \ blimit = len; \
if ((buffer = realloc(buffer, blimit)) == NULL) { \ if ((buffer = realloc(buffer, blimit)) == NULL) { \
error("not enough memory"); \ error("not enough memory"); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \
} }
/* /*
@ -654,22 +655,23 @@ static ssize_t test_wavefile(int fd, char *_buffer, size_t size)
if (h->magic != WAV_RIFF || h->type != WAV_WAVE) if (h->magic != WAV_RIFF || h->type != WAV_WAVE)
return -1; return -1;
if (size > sizeof(WaveHeader)) { if (size > sizeof(WaveHeader)) {
check_wavefile_space(buffer, size, size - sizeof(WaveHeader), blimit); check_wavefile_space(buffer, size - sizeof(WaveHeader), blimit);
memcpy(buffer, _buffer + sizeof(WaveHeader), size - sizeof(WaveHeader)); memcpy(buffer, _buffer + sizeof(WaveHeader), size - sizeof(WaveHeader));
} }
size -= sizeof(WaveHeader); size -= sizeof(WaveHeader);
while (1) { while (1) {
check_wavefile_space(buffer, size, sizeof(WaveChunkHeader), blimit); check_wavefile_space(buffer, sizeof(WaveChunkHeader), blimit);
test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__);
c = (WaveChunkHeader*)buffer; c = (WaveChunkHeader*)buffer;
type = c->type; type = c->type;
len = LE_INT(c->length); len = LE_INT(c->length);
len += len % 2;
if (size > sizeof(WaveChunkHeader)) if (size > sizeof(WaveChunkHeader))
memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader));
size -= sizeof(WaveChunkHeader); size -= sizeof(WaveChunkHeader);
if (type == WAV_FMT) if (type == WAV_FMT)
break; break;
check_wavefile_space(buffer, size, len, blimit); check_wavefile_space(buffer, len, blimit);
test_wavefile_read(fd, buffer, &size, len, __LINE__); test_wavefile_read(fd, buffer, &size, len, __LINE__);
if (size > len) if (size > len)
memmove(buffer, buffer + len, size - len); memmove(buffer, buffer + len, size - len);
@ -680,7 +682,7 @@ static ssize_t test_wavefile(int fd, char *_buffer, size_t size)
error("unknown length of 'fmt ' chunk (read %u, should be %u at least)", len, (u_int)sizeof(WaveFmtBody)); error("unknown length of 'fmt ' chunk (read %u, should be %u at least)", len, (u_int)sizeof(WaveFmtBody));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
check_wavefile_space(buffer, size, len, blimit); check_wavefile_space(buffer, len, blimit);
test_wavefile_read(fd, buffer, &size, len, __LINE__); test_wavefile_read(fd, buffer, &size, len, __LINE__);
f = (WaveFmtBody*) buffer; f = (WaveFmtBody*) buffer;
if (LE_SHORT(f->format) != WAV_PCM_CODE) { if (LE_SHORT(f->format) != WAV_PCM_CODE) {
@ -740,7 +742,7 @@ static ssize_t test_wavefile(int fd, char *_buffer, size_t size)
while (1) { while (1) {
u_int type, len; u_int type, len;
check_wavefile_space(buffer, size, sizeof(WaveChunkHeader), blimit); check_wavefile_space(buffer, sizeof(WaveChunkHeader), blimit);
test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__);
c = (WaveChunkHeader*)buffer; c = (WaveChunkHeader*)buffer;
type = c->type; type = c->type;
@ -749,14 +751,15 @@ static ssize_t test_wavefile(int fd, char *_buffer, size_t size)
memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader));
size -= sizeof(WaveChunkHeader); size -= sizeof(WaveChunkHeader);
if (type == WAV_DATA) { if (type == WAV_DATA) {
if (len < pbrec_count) if (len < pbrec_count && len < 0x7ffffffe)
pbrec_count = len; pbrec_count = len;
if (size > 0) if (size > 0)
memcpy(_buffer, buffer, size); memcpy(_buffer, buffer, size);
free(buffer); free(buffer);
return size; return size;
} }
check_wavefile_space(buffer, size, len, blimit); len += len % 2;
check_wavefile_space(buffer, len, blimit);
test_wavefile_read(fd, buffer, &size, len, __LINE__); test_wavefile_read(fd, buffer, &size, len, __LINE__);
if (size > len) if (size > len)
memmove(buffer, buffer + len, size - len); memmove(buffer, buffer + len, size - len);
@ -1294,6 +1297,7 @@ static void voc_write_silence(unsigned x)
} }
x -= l; x -= l;
} }
free(buf);
} }
static void voc_pcm_flush(void) static void voc_pcm_flush(void)
@ -1562,11 +1566,10 @@ static void begin_voc(int fd, size_t cnt)
VocVoiceData vd; VocVoiceData vd;
VocExtBlock eb; VocExtBlock eb;
strncpy(vh.magic, VOC_MAGIC_STRING, 20); memcpy(vh.magic, VOC_MAGIC_STRING, 20);
vh.magic[19] = 0x1A; vh.headerlen = LE_SHORT(sizeof(VocHeader));
vh.headerlen = sizeof(VocHeader); vh.version = LE_SHORT(VOC_ACTUAL_VERSION);
vh.version = VOC_ACTUAL_VERSION; vh.coded_ver = LE_SHORT(0x1233 - VOC_ACTUAL_VERSION);
vh.coded_ver = 0x1233 - VOC_ACTUAL_VERSION;
if (write(fd, &vh, sizeof(VocHeader)) != sizeof(VocHeader)) { if (write(fd, &vh, sizeof(VocHeader)) != sizeof(VocHeader)) {
error("write error"); error("write error");
@ -1581,7 +1584,7 @@ static void begin_voc(int fd, size_t cnt)
error("write error"); error("write error");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
eb.tc = (u_short) (65536 - 256000000L / (hwparams.rate << 1)); eb.tc = LE_SHORT(65536 - 256000000L / (hwparams.rate << 1));
eb.pack = 0; eb.pack = 0;
eb.mode = 1; eb.mode = 1;
if (write(fd, &eb, sizeof(VocExtBlock)) != sizeof(VocExtBlock)) { if (write(fd, &eb, sizeof(VocExtBlock)) != sizeof(VocExtBlock)) {
@ -1743,15 +1746,16 @@ static void end_wave(int fd)
{ /* only close output */ { /* only close output */
WaveChunkHeader cd; WaveChunkHeader cd;
off64_t length_seek; off64_t length_seek;
off64_t filelen;
u_int rifflen; u_int rifflen;
length_seek = sizeof(WaveHeader) + length_seek = sizeof(WaveHeader) +
sizeof(WaveChunkHeader) + sizeof(WaveChunkHeader) +
sizeof(WaveFmtBody); sizeof(WaveFmtBody);
cd.type = WAV_DATA; cd.type = WAV_DATA;
cd.length = fdcount > 0x7fffffff ? 0x7fffffff : LE_INT(fdcount); cd.length = fdcount > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(fdcount);
rifflen = fdcount + 2*sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + 4; filelen = fdcount + 2*sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + 4;
rifflen = rifflen > 0x7fffffff ? 0x7fffffff : LE_INT(rifflen); rifflen = filelen > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(filelen);
if (lseek64(fd, 4, SEEK_SET) == 4) if (lseek64(fd, 4, SEEK_SET) == 4)
write(fd, &rifflen, 4); write(fd, &rifflen, 4);
if (lseek64(fd, length_seek, SEEK_SET) == length_seek) if (lseek64(fd, length_seek, SEEK_SET) == length_seek)
@ -1856,9 +1860,7 @@ void capture_go(int fd, off64_t count, int rtype, char *name)
do { do {
for (cur = count; cur > 0; cur -= r) { for (cur = count; cur > 0; cur -= r) {
c = cur; c = (cur <= chunk_bytes) ? cur : chunk_bytes;
if (c > chunk_bytes)
c = chunk_bytes;
c = c * 8 / bits_per_frame; c = c * 8 / bits_per_frame;
if ((size_t)(r = pcm_read(audiobuf, c)) != c) if ((size_t)(r = pcm_read(audiobuf, c)) != c)
break; break;

View file

@ -6,7 +6,7 @@
/* Definitions for .VOC files */ /* Definitions for .VOC files */
#define VOC_MAGIC_STRING "Creative Voice File\0x1A" #define VOC_MAGIC_STRING "Creative Voice File\x1A"
#define VOC_ACTUAL_VERSION 0x010A #define VOC_ACTUAL_VERSION 0x010A
#define VOC_SAMPLESIZE 8 #define VOC_SAMPLESIZE 8