static FLAC__uint32 unpack32_(const FLAC__byte *b, foreign_block_type_t type) { if(type == FOREIGN_BLOCK_TYPE__AIFF) return unpack32be_(b); else return unpack32le_(b); }
static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error) { FLAC__byte buffer[12]; FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1; if((offset = ftello(f)) < 0) { if(error) *error = "ftello() error (001)"; return false; } if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) { if(error) *error = "unsupported RIFF layout (002)"; return false; } if(!memcmp(buffer, "RF64", 4)) fm->is_rf64 = true; if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) { if(error) *error = "RF64 is not supported on this compile (r00)"; return false; } if(!append_block_(fm, offset, 12, error)) return false; if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffffu) eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4); while(!feof(f)) { FLAC__uint32 size; if((offset = ftello(f)) < 0) { if(error) *error = "ftello() error (003)"; return false; } if((size = fread(buffer, 1, 8, f)) < 8) { if(size == 0 && feof(f)) break; if(error) *error = "invalid WAVE file (004)"; return false; } size = unpack32le_(buffer+4); /* check if pad byte needed */ if(size & 1) size++; if(!memcmp(buffer, "fmt ", 4)) { if(fm->format_block) { if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)"; return false; } if(fm->audio_block) { if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)"; return false; } fm->format_block = fm->num_blocks; } else if(!memcmp(buffer, "data", 4)) { if(fm->audio_block) { if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)"; return false; } if(!fm->format_block) { if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)"; return false; } fm->audio_block = fm->num_blocks; if(fm->is_rf64 && fm->num_blocks < 2) { if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)"; return false; } } if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error)) return false; /* parse ds64 chunk if necessary */ if(fm->is_rf64 && fm->num_blocks == 2) { FLAC__byte buffer2[7*4]; if(memcmp(buffer, "ds64", 4)) { if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)"; return false; } /* unpack the size again since we don't want the padding byte effect */ size = unpack32le_(buffer+4); if(size < sizeof(buffer2)) { if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)"; return false; } if(size > sizeof(buffer2)) { if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)"; return false; } if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) { if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)"; return false; } ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8); if(ds64_data_size == (FLAC__off_t)(-1)) { if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)"; return false; } /* check if pad byte needed */ if(ds64_data_size & 1) ds64_data_size++; /* @@@ [2^63 limit] */ if(ds64_data_size < 0) { if(error) *error = "RF64 file too large (r09)"; return false; } if(unpack32le_(buffer2+24)) { if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)"; return false; } eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2); /* @@@ [2^63 limit] */ if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) { if(error) *error = "RF64 file too large (r07)"; return false; } } else { /* skip to next chunk */ if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffffu) { if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) { if(error) *error = "invalid RF64 file: seek error (r10)"; return false; } } else { if(fseeko(f, size, SEEK_CUR) < 0) { if(error) *error = "invalid WAVE file: seek error (009)"; return false; } } } } if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) { if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)"; return false; } if(eof_offset != ftello(f)) { if(error) *error = "invalid WAVE file: unexpected EOF (010)"; return false; } if(!fm->format_block) { if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)"; return false; } if(!fm->audio_block) { if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)"; return false; } return true; }
int main(int argc, char *argv[]) { FILE *f; char buf[36]; foreign_metadata_t *fm; const char *fn, *error; size_t i; FLAC__uint32 size; if(argc != 2) { fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]); return 1; } fn = argv[1]; if(0 == (f = fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) { fprintf(stderr, "ERROR opening %s for reading\n", fn); return 1; } fclose(f); if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4) && memcmp(buf, "RF64", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) { fprintf(stderr, "ERROR: out of memory\n"); return 1; } if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) { if(!flac__foreign_metadata_read_from_aiff(fm, fn, &error)) { fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); return 1; } } else { if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) { fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); return 1; } } if(0 == (f = fopen(fn, "rb"))) { fprintf(stderr, "ERROR opening %s for reading\n", fn); return 1; } for(i = 0; i < fm->num_blocks; i++) { if(fseeko(f, fm->blocks[i].offset, SEEK_SET) < 0) { fprintf(stderr, "ERROR seeking in %s\n", fn); return 1; } if(fread(buf, 1, i==0?12:8, f) != (i==0?12:8)) { fprintf(stderr, "ERROR reading %s\n", fn); return 1; } size = unpack32_((const FLAC__byte*)buf+4, fm->type); printf("block:[%c%c%c%c] size=%08x=(%10u)", buf[0], buf[1], buf[2], buf[3], size, size); if(i == 0) printf(" type:[%c%c%c%c]", buf[8], buf[9], buf[10], buf[11]); else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && i == fm->audio_block) printf(" offset size=%08x=(%10u)", fm->ssnd_offset_size, fm->ssnd_offset_size); else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && i == 1 && !memcmp(buf, "ds64", 4)) { if(fread(buf+8, 1, 36-8, f) != 36-8) { fprintf(stderr, "ERROR reading %s\n", fn); return 1; } #ifdef _MSC_VER printf(" RIFF size=%016I64x=(%I64u)", unpack64le_(buf+8), unpack64le_(buf+8)); printf(" data size=%016I64x=(%I64u)", unpack64le_(buf+16), unpack64le_(buf+16)); printf(" sample count=%016I64x=(%I64u)", unpack64le_(buf+24), unpack64le_(buf+24)); #else printf(" RIFF size=%016llx=(%llu)", unpack64le_(buf+8), unpack64le_(buf+8)); printf(" data size=%016llx=(%llu)", unpack64le_(buf+16), unpack64le_(buf+16)); printf(" sample count=%016llx=(%llu)", unpack64le_(buf+24), unpack64le_(buf+24)); #endif printf(" table size=%08x=(%u)", unpack32le_(buf+32), unpack32le_(buf+32)); } printf("\n"); } fclose(f); flac__foreign_metadata_delete(fm); return 0; }