/* libFLAC - Free Lossless Audio Codec library * Copyright (C) 2000,2001 Josh Coalson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include /* for malloc() */ #include /* for strcmp() */ #include /* for stat() */ #include "FLAC/assert.h" #include "protected/file_decoder.h" #include "protected/seekable_stream_decoder.h" #include "private/md5.h" /*********************************************************************** * * Private class method prototypes * ***********************************************************************/ static FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); static FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); static FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data); static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data); static void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); /*********************************************************************** * * Private class data * ***********************************************************************/ typedef struct FLAC__FileDecoderPrivate { FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data); void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); void *client_data; FILE *file; char *filename; /* == NULL if stdin */ FLAC__SeekableStreamDecoder *seekable_stream_decoder; struct { FLAC__bool md5_checking; } init_values_for_superclass; } FLAC__FileDecoderPrivate; /*********************************************************************** * * Public static class data * ***********************************************************************/ const char *FLAC__FileDecoderStateString[] = { "FLAC__FILE_DECODER_OK", "FLAC__FILE_DECODER_SEEKING", "FLAC__FILE_DECODER_END_OF_FILE", "FLAC__FILE_DECODER_ERROR_OPENING_FILE", "FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR", "FLAC__FILE_DECODER_SEEK_ERROR", "FLAC__FILE_DECODER_STREAM_ERROR", "FLAC__FILE_DECODER_STREAM_DECODER_ERROR", "FLAC__FILE_DECODER_ALREADY_INITIALIZED", "FLAC__FILE_DECODER_INVALID_CALLBACK", "FLAC__FILE_DECODER_UNINITIALIZED" }; /*********************************************************************** * * Class constructor/destructor * ***********************************************************************/ FLAC__FileDecoder *FLAC__file_decoder_new() { FLAC__FileDecoder *decoder; FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ decoder = (FLAC__FileDecoder*)malloc(sizeof(FLAC__FileDecoder)); if(decoder == 0) { return 0; } decoder->protected_ = (FLAC__FileDecoderProtected*)malloc(sizeof(FLAC__FileDecoderProtected)); if(decoder->protected_ == 0) { free(decoder); return 0; } decoder->private_ = (FLAC__FileDecoderPrivate*)malloc(sizeof(FLAC__FileDecoderPrivate)); if(decoder->private_ == 0) { free(decoder->protected_); free(decoder); return 0; } decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; decoder->private_->filename = 0; decoder->private_->write_callback = 0; decoder->private_->metadata_callback = 0; decoder->private_->error_callback = 0; decoder->private_->client_data = 0; decoder->private_->init_values_for_superclass.md5_checking = false; return decoder; } void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder) { FLAC__ASSERT(decoder != 0); FLAC__ASSERT(decoder->protected_ != 0); FLAC__ASSERT(decoder->private_ != 0); free(decoder->private_); free(decoder->protected_); free(decoder); } /*********************************************************************** * * Public class methods * ***********************************************************************/ FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder) { FLAC__ASSERT(decoder != 0); if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return decoder->protected_->state = FLAC__FILE_DECODER_ALREADY_INITIALIZED; decoder->protected_->state = FLAC__FILE_DECODER_OK; if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) return decoder->protected_->state = FLAC__FILE_DECODER_INVALID_CALLBACK; decoder->private_->file = 0; decoder->private_->seekable_stream_decoder = 0; if(0 == decoder->private_->filename) decoder->private_->file = stdin; else decoder->private_->file = fopen(decoder->private_->filename, "rb"); if(decoder->private_->file == 0) return decoder->protected_->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE; decoder->private_->seekable_stream_decoder = FLAC__seekable_stream_decoder_new(); if(0 == decoder->private_->seekable_stream_decoder) return decoder->protected_->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; FLAC__seekable_stream_decoder_set_read_callback(decoder->private_->seekable_stream_decoder, read_callback_); FLAC__seekable_stream_decoder_set_seek_callback(decoder->private_->seekable_stream_decoder, seek_callback_); FLAC__seekable_stream_decoder_set_tell_callback(decoder->private_->seekable_stream_decoder, tell_callback_); FLAC__seekable_stream_decoder_set_length_callback(decoder->private_->seekable_stream_decoder, length_callback_); FLAC__seekable_stream_decoder_set_eof_callback(decoder->private_->seekable_stream_decoder, eof_callback_); FLAC__seekable_stream_decoder_set_write_callback(decoder->private_->seekable_stream_decoder, write_callback_); FLAC__seekable_stream_decoder_set_metadata_callback(decoder->private_->seekable_stream_decoder, metadata_callback_); FLAC__seekable_stream_decoder_set_error_callback(decoder->private_->seekable_stream_decoder, error_callback_); FLAC__seekable_stream_decoder_set_client_data(decoder->private_->seekable_stream_decoder, decoder); /* * Unfortunately, because of the "_new() ... _set_() ... _init()" order of * decoder initialization, settings that are 'inherited' from the superclass * have to be passed up this way, because the superclass has not even been * created yet when the value is set in the subclass. */ (void)FLAC__seekable_stream_decoder_set_md5_checking(decoder->private_->seekable_stream_decoder, decoder->private_->init_values_for_superclass.md5_checking); if(FLAC__seekable_stream_decoder_init(decoder->private_->seekable_stream_decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) return decoder->protected_->state = FLAC__FILE_DECODER_STREAM_DECODER_ERROR; /*@@@ change this to FLAC__FILE_DECODER_SEEKABLE_STREAM_ERROR in next minor-revision */ return decoder->protected_->state; } FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder) { FLAC__bool ok = true; FLAC__ASSERT(decoder != 0); if(decoder->protected_->state == FLAC__FILE_DECODER_UNINITIALIZED) return true; if(decoder->private_->file != 0 && decoder->private_->file != stdin) fclose(decoder->private_->file); if(0 != decoder->private_->filename) { free(decoder->private_->filename); decoder->private_->filename = 0; } if(decoder->private_->seekable_stream_decoder != 0) { ok = FLAC__seekable_stream_decoder_finish(decoder->private_->seekable_stream_decoder); FLAC__seekable_stream_decoder_delete(decoder->private_->seekable_stream_decoder); } decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; return ok; } FLAC__bool FLAC__file_decoder_set_md5_checking(const FLAC__FileDecoder *decoder, FLAC__bool value) { if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; decoder->private_->init_values_for_superclass.md5_checking = value; return true; } FLAC__bool FLAC__file_decoder_set_filename(const FLAC__FileDecoder *decoder, const char *value) { FLAC__ASSERT(value != 0); if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; if(0 != decoder->private_->filename) { free(decoder->private_->filename); decoder->private_->filename = 0; } if(0 != strcmp(value, "-")) { if(0 == (decoder->private_->filename = (char*)malloc(strlen(value)+1))) { decoder->protected_->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; return false; } strcpy(decoder->private_->filename, value); } return true; } FLAC__bool FLAC__file_decoder_set_write_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderWriteStatus (*value)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)) { if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; decoder->private_->write_callback = value; return true; } FLAC__bool FLAC__file_decoder_set_metadata_callback(const FLAC__FileDecoder *decoder, void (*value)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)) { if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; decoder->private_->metadata_callback = value; return true; } FLAC__bool FLAC__file_decoder_set_error_callback(const FLAC__FileDecoder *decoder, void (*value)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)) { if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; decoder->private_->error_callback = value; return true; } FLAC__bool FLAC__file_decoder_set_client_data(const FLAC__FileDecoder *decoder, void *value) { if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) return false; decoder->private_->client_data = value; return true; } FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder) { return decoder->protected_->state; } FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder) { return FLAC__seekable_stream_decoder_get_md5_checking(decoder->private_->seekable_stream_decoder); } FLAC__bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder) { FLAC__bool ret; FLAC__ASSERT(decoder != 0); if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) return true; FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); ret = FLAC__seekable_stream_decoder_process_whole_stream(decoder->private_->seekable_stream_decoder); if(!ret) decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_ERROR; return ret; } FLAC__bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder) { FLAC__bool ret; FLAC__ASSERT(decoder != 0); if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) return true; FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); ret = FLAC__seekable_stream_decoder_process_metadata(decoder->private_->seekable_stream_decoder); if(!ret) decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_ERROR; return ret; } FLAC__bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder) { FLAC__bool ret; FLAC__ASSERT(decoder != 0); if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) return true; FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); ret = FLAC__seekable_stream_decoder_process_one_frame(decoder->private_->seekable_stream_decoder); if(!ret) decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_ERROR; return ret; } FLAC__bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder) { FLAC__bool ret; FLAC__ASSERT(decoder != 0); if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) return true; FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); ret = FLAC__seekable_stream_decoder_process_remaining_frames(decoder->private_->seekable_stream_decoder); if(!ret) decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_ERROR; return ret; } /*********************************************************************** * * Private class methods * ***********************************************************************/ FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample) { FLAC__ASSERT(decoder != 0); FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); if(decoder->private_->filename == 0) { /* means the file is stdin... */ decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; return false; } if(!FLAC__seekable_stream_decoder_seek_absolute(decoder->private_->seekable_stream_decoder, sample)) { decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; return false; } else return true; } FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; if(*bytes > 0) { size_t bytes_read = fread(buffer, sizeof(FLAC__byte), *bytes, file_decoder->private_->file); if(bytes_read == 0 && !feof(file_decoder->private_->file)) { return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; } else { *bytes = (unsigned)bytes_read; return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; } } else return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */ } FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; if(fseek(file_decoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0) return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; else return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; } FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; long pos; (void)decoder; if((pos = ftell(file_decoder->private_->file)) < 0) return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR; else { *absolute_byte_offset = (FLAC__uint64)pos; return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; } } FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; struct stat filestats; (void)decoder; if(0 == file_decoder->private_->filename || stat(file_decoder->private_->filename, &filestats) != 0) return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR; else { *stream_length = (FLAC__uint64)filestats.st_size; return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; } } FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; return feof(file_decoder->private_->file); } FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; return file_decoder->private_->write_callback(file_decoder, frame, buffer, file_decoder->private_->client_data); } void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; file_decoder->private_->metadata_callback(file_decoder, metadata, file_decoder->private_->client_data); } void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; (void)decoder; file_decoder->private_->error_callback(file_decoder, status, file_decoder->private_->client_data); }