From 3ac4048b0dcbb88d429879fca7d318e27fac8df1 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Thu, 10 May 2007 06:24:50 +0000 Subject: [PATCH] Fix wav scanner to allow both 16 and 18 byte 'fmt ' chunks, also allow for out-of-order WAVE chunks --- src/scan-wav.c | 115 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 29 deletions(-) diff --git a/src/scan-wav.c b/src/scan-wav.c index 530d05bd..91c33018 100644 --- a/src/scan-wav.c +++ b/src/scan-wav.c @@ -34,13 +34,13 @@ #include "err.h" #include "mp3-scanner.h" -#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \ - (((unsigned long)((p)[2])) << 16) | \ - (((unsigned long)((p)[1])) << 8) | \ - (((unsigned long)((p)[0])))) +#define GET_WAV_INT32(p) ((((uint32_t)((p)[3])) << 24) | \ + (((uint32_t)((p)[2])) << 16) | \ + (((uint32_t)((p)[1])) << 8) | \ + (((uint32_t)((p)[0])))) -#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \ - (((unsigned long)((p)[0])))) +#define GET_WAV_INT16(p) ((((uint32_t)((p)[1])) << 8) | \ + (((uint32_t)((p)[0])))) /** * Get info from the actual wav headers. Since there is no @@ -54,16 +54,23 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) { FILE *infile; size_t rl; - unsigned char hdr[44]; - unsigned long chunk_data_length; - unsigned long format_data_length; - unsigned long compression_code; - unsigned long channel_count; - unsigned long sample_rate; - unsigned long sample_bit_length; - unsigned long bit_rate; - unsigned long data_length; - unsigned long sec, ms; + unsigned char hdr[12]; + unsigned char fmt[16]; + uint32_t chunk_data_length; + uint32_t format_data_length = 0; + uint32_t compression_code = 0; + uint32_t channel_count = 0; + uint32_t sample_rate = 0; + uint32_t sample_bit_length = 0; + uint32_t bit_rate; + uint32_t data_length = 0; + uint32_t sec, ms; + + uint32_t current_offset; + uint32_t block_len; + + int found_fmt = 0; + int found_data = 0; DPRINTF(E_DBG,L_SCAN,"Getting WAV file info\n"); @@ -72,30 +79,80 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) { return FALSE; } - rl = fread(hdr, 1, 44, infile); - fclose(infile); - if (rl != 44) { + rl = fread(hdr, 1, 12, infile); + if (rl != 12) { DPRINTF(E_WARN,L_SCAN,"Could not read wav header from %s\n",filename); + fclose(infile); return FALSE; } + /* I've found some wav files that have INFO tags + * in them... */ if (strncmp((char*)hdr + 0, "RIFF", 4) || - strncmp((char*)hdr + 8, "WAVE", 4) || - strncmp((char*)hdr + 12, "fmt ", 4) || - strncmp((char*)hdr + 36, "data", 4)) { + strncmp((char*)hdr + 8, "WAVE", 4)) { DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename); + fclose(infile); return FALSE; } chunk_data_length = GET_WAV_INT32(hdr + 4); - format_data_length = GET_WAV_INT32(hdr + 16); - compression_code = GET_WAV_INT16(hdr + 20); - channel_count = GET_WAV_INT16(hdr + 22); - sample_rate = GET_WAV_INT32(hdr + 24); - sample_bit_length = GET_WAV_INT16(hdr + 34); - data_length = GET_WAV_INT32(hdr + 40); - if ((format_data_length != 16) || + /* now, walk through the chunks */ + current_offset = 12; + + while(!found_fmt && !found_data) { + rl = fread(hdr, 1, 8, infile); + if (rl != 8) { + fclose(infile); + DPRINTF(E_WARN,L_SCAN,"Error reading block: %s\n",filename); + return FALSE; + } + + block_len = GET_WAV_INT32(hdr + 4); + + DPRINTF(E_DBG,L_SCAN,"Read block %02x%02x%02x%02x (%c%c%c%c) of " + "size %08x\n",hdr[0],hdr[1],hdr[2],hdr[3], + hdr[0],hdr[1],hdr[2],hdr[3],block_len); + + if(block_len < 0) { + fclose(infile); + DPRINTF(E_WARN,L_SCAN,"Bad block len: %s\n",filename); + return FALSE; + } + + if(strncmp((char*)&hdr,"fmt ",4) == 0) { + found_fmt = TRUE; + DPRINTF(E_DBG,L_SCAN,"Found 'fmt ' header\n"); + rl = fread(fmt,1,16,infile); + if(rl != 16) { + fclose(infile); + DPRINTF(E_WARN,L_SCAN,"Bad .wav file: can't read fmt: %s\n", + filename); + return FALSE; + } + + format_data_length = block_len; + compression_code = GET_WAV_INT16(fmt); + channel_count = GET_WAV_INT16(fmt+2); + sample_rate = GET_WAV_INT32(fmt + 4); + sample_bit_length = GET_WAV_INT16(hdr + 14); + DPRINTF(E_DBG,L_SCAN,"Compression code: %d\n",compression_code); + DPRINTF(E_DBG,L_SCAN,"Channel count: %d\n",channel_count); + DPRINTF(E_DBG,L_SCAN,"Sample Rate: %d\n",sample_rate); + DPRINTF(E_DBG,L_SCAN,"Sample bit length %d\n",sample_bit_length); + + } else if (strncmp((char*)&hdr,"data",4) == 0) { + DPRINTF(E_DBG,L_SCAN,"Found 'data' header\n"); + data_length = block_len; + found_data = TRUE; + } + + fseek(infile,current_offset + block_len + 8,SEEK_SET); + current_offset += block_len; + } + + fclose(infile); + if (((format_data_length != 16) && (format_data_length != 18)) || (compression_code != 1) || (channel_count < 1)) { DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);