diff --git a/Project/GNU/CLI/Makefile.am b/Project/GNU/CLI/Makefile.am index 0f2d6755..2656c348 100644 --- a/Project/GNU/CLI/Makefile.am +++ b/Project/GNU/CLI/Makefile.am @@ -32,6 +32,7 @@ bwfmetaedit_SOURCES = \ ../../../Source/Riff/Riff_Chunks_WAVE_CSET.cpp \ ../../../Source/Riff/Riff_Handler.cpp \ ../../../Source/TinyXml2/tinyxml2.cpp \ + ../../../Source/FLACwrapper/File.cpp \ ../../../Source/ZenLib/Conf.cpp \ ../../../Source/ZenLib/CriticalSection.cpp \ ../../../Source/ZenLib/Dir.cpp \ diff --git a/Project/GNU/CLI/configure.ac b/Project/GNU/CLI/configure.ac index 10088447..c479c629 100644 --- a/Project/GNU/CLI/configure.ac +++ b/Project/GNU/CLI/configure.ac @@ -64,6 +64,11 @@ dnl CXXFLAGS="$CXXFLAGS -pthread" LDFLAGS="$LDFLAGS -lpthread -pthread" +dnl ------------------------------------------------------------------------- +dnl Use dlopen +dnl +LIBS="$LIBS -ldl" + dnl ------------------------------------------------------------------------- dnl Large files dnl diff --git a/Source/Common/Core.cpp b/Source/Common/Core.cpp index e23d1027..7ed055ac 100644 --- a/Source/Common/Core.cpp +++ b/Source/Common/Core.cpp @@ -17,7 +17,7 @@ #include "Common/Core.h" #include "ZenLib/ZtringListList.h" #include "ZenLib/Ztring.h" -#include "ZenLib/File.h" +#include "FLACwrapper/File.h" #include "ZenLib/Dir.h" #include "ZenLib/OS_Utils.h" #include "Common/Common_About.h" @@ -456,7 +456,7 @@ float Core::Menu_File_Open_Files_Finish_Middle () File_Name=Ztring().From_UTF8(Handler->second.In_cue__FileName); Ztring Value; - File F; + FLACwrapper::File F; int64u F_Size; if (!F.Open(File_Name)) @@ -734,7 +734,7 @@ string Core::Menu_File_Undo_ListModifiedFiles(size_t Pos) Ztring FileName=BackupFiles[Pos]; //Opening the file - File F; + FLACwrapper::File F; if (!F.Open(FileName)) return string(); int64u F_Size=F.Size_Get(); @@ -976,7 +976,7 @@ int Core::Menu_File_Import_Core(const string &FileName) try { //Checking if file exists - File In_Bext_File; + FLACwrapper::File In_Bext_File; if (!In_Bext_File.Open(Ztring().From_UTF8(FileName))) throw "--in-core=: file does not exist"; int64u File_Size=In_Bext_File.Size_Get(); @@ -1603,7 +1603,7 @@ void Core::Batch_Finish() { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Out_XML_FileName))) throw "--out-XML: error during file creation"; if (!F.Write(Ztring().From_UTF8(Out_XML_Buf))) @@ -1896,7 +1896,7 @@ void Core::Batch_Launch_PMX(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Handler->second.Riff->FileName_Get())+__T(".XMP.xml"))) throw "--out-XMP-XML: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -1913,7 +1913,7 @@ void Core::Batch_Launch_PMX(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Out__PMX_FileName.c_str()))) throw "--out-XMP=: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -1959,7 +1959,7 @@ void Core::Batch_Launch_aXML(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Handler->second.Riff->FileName_Get())+__T(".aXML.xml"))) throw "--out-aXML-XML: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -1976,7 +1976,7 @@ void Core::Batch_Launch_aXML(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Out_aXML_FileName.c_str()))) throw "--out-aXML=: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -2020,7 +2020,7 @@ void Core::Batch_Launch_iXML(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Handler->second.Riff->FileName_Get())+__T(".iXML.xml"))) throw "--out-iXML-XML: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -2037,7 +2037,7 @@ void Core::Batch_Launch_iXML(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Out_iXML_FileName.c_str()))) throw "--out-iXML=: error during file creation"; if (!F.Write(Ztring().From_UTF8(Content))) @@ -2082,7 +2082,7 @@ void Core::Batch_Launch_cue_(handlers::iterator &Handler) //Saving file try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Handler->second.Riff->FileName_Get())+__T(".cue.xml"))) throw "--out-cue-XML: error during file creation"; if (!F.Write(Content)) @@ -2099,7 +2099,7 @@ void Core::Batch_Launch_cue_(handlers::iterator &Handler) { try { - File F; + FLACwrapper::File F; if (!F.Create(Ztring().From_UTF8(Out_cue__FileName.c_str()))) throw "--out-cue=: error during file creation"; if (!F.Write(Content)) @@ -2210,7 +2210,7 @@ void Core::StdAll(handlers::iterator &Handler) Data+=TimeS; Data+=__T(" "); Data+=Ztring().From_UTF8(Handler->second.Riff->Information.str()); - File F(LogFile, File::Access_Write_Append); + FLACwrapper::File F(LogFile, File::Access_Write_Append); F.Write(Data); } Handler->second.Riff->Information.str(string()); @@ -2225,7 +2225,7 @@ void Core::StdAll(handlers::iterator &Handler) Data+=TimeS; Data+=__T(" "); Data+=Ztring().From_UTF8(Handler->second.Riff->Warnings.str()); - File F(LogFile, File::Access_Write_Append); + FLACwrapper::File F(LogFile, File::Access_Write_Append); F.Write(Data); } Handler->second.Riff->Warnings.str(string()); @@ -2240,7 +2240,7 @@ void Core::StdAll(handlers::iterator &Handler) Data+=TimeS; Data+=__T(" "); Data+=Ztring().From_UTF8(Handler->second.Riff->Errors.str()); - File F(LogFile, File::Access_Write_Append); + FLACwrapper::File F(LogFile, File::Access_Write_Append); F.Write(Data); } Handler->second.Riff->Errors.str(string()); @@ -2266,7 +2266,7 @@ void Core::StdOut(string Text) Data+=__T(" "); Data+=Ztring().From_UTF8(Text); Data+=EOL; - File F(LogFile, File::Access_Write_Append); + FLACwrapper::File F(LogFile, File::Access_Write_Append); F.Write(Data); } } diff --git a/Source/FLACwrapper/File.cpp b/Source/FLACwrapper/File.cpp new file mode 100644 index 00000000..05f1bb0d --- /dev/null +++ b/Source/FLACwrapper/File.cpp @@ -0,0 +1,403 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a zlib-style license that can + * be found in the License.txt file in the root of the source tree. + */ + +#include "FLACwrapper/File.h" +#include +//--------------------------------------------------------------------------- + +namespace FLACwrapper +{ + + +#define PREPARE_FUNCTION_POINTERS \ + FLAC_available = false; \ + FLAChandle = dlopen("libFLAC.so",RTLD_LAZY); \ + if(!FLAChandle) { \ + fprintf(stderr,"Failed to open libFLAC\n"); \ + } \ + else { \ + FLACversion = (const char **) dlsym(FLAChandle, "FLAC__VERSION_STRING"); \ + local_FLAC_stream_decoder_new = (FLAC__StreamDecoder * (*)()) dlsym(FLAChandle, "FLAC__stream_decoder_new"); \ + local_FLAC_stream_decoder_set_metadata_ignore_all = (FLAC__bool (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_set_metadata_ignore_all"); \ + local_FLAC_stream_decoder_set_metadata_respond_application = (FLAC__bool (*)(FLAC__StreamDecoder *, const FLAC__byte *)) dlsym(FLAChandle, "FLAC__stream_decoder_set_metadata_respond_application"); \ + local_FLAC_stream_decoder_init_file = (FLAC__StreamDecoderInitStatus (*)(FLAC__StreamDecoder *, const char *, FLAC__StreamDecoderWriteCallback, FLAC__StreamDecoderMetadataCallback, FLAC__StreamDecoderErrorCallback, void *)) dlsym(FLAChandle, "FLAC__stream_decoder_init_file"); \ + local_FLAC_stream_decoder_process_until_end_of_metadata = (FLAC__bool (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_process_until_end_of_metadata"); \ + local_FLAC_stream_decoder_process_single = (FLAC__bool (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_process_single"); \ + local_FLAC_stream_decoder_finish = (FLAC__bool (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_finish"); \ + local_FLAC_stream_decoder_reset = (FLAC__bool (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_reset"); \ + local_FLAC_stream_decoder_delete = (void (*)(FLAC__StreamDecoder *)) dlsym(FLAChandle, "FLAC__stream_decoder_delete"); \ + local_FLAC_metadata_object_delete = (void (*)(FLAC__StreamMetadata *)) dlsym(FLAChandle, "FLAC__metadata_object_delete"); \ + if(dlerror() == NULL) { \ + FLAC_decoder = local_FLAC_stream_decoder_new(); \ + if(FLAC_decoder != NULL) \ + FLAC_available = true; \ + } \ + } + +// *************************************************************************** +// Constructor/Destructor +// *************************************************************************** + +//--------------------------------------------------------------------------- +File::File() +{ + File_Handle = ZenLib::File(); + PREPARE_FUNCTION_POINTERS +} + +File::File(ZenLib::Ztring File_Name, ZenLib::File::access_t Access) +{ + File_Handle = ZenLib::File(File_Name, Access); + PREPARE_FUNCTION_POINTERS +} + + +//--------------------------------------------------------------------------- +File::~File() +{ + if(callbackdata.chunkbuffer != NULL) + free(callbackdata.chunkbuffer); + dlclose(FLAChandle); +} + +// *************************************************************************** +// Open/Close +// *************************************************************************** + +//--------------------------------------------------------------------------- +bool File::Open (const ZenLib::tstring &File_Name_, ZenLib::File::access_t Access) +{ + ZenLib::FileName filename = File_Name_; + if(filename.Extension_Get() == ZenLib::Ztring("flac")) { + /* FLAC parsing */ + FLAC__byte rifftag[4] = {'r','i','f','f'}; + + if(!FLAC_available) + return false; + if(!local_FLAC_stream_decoder_set_metadata_ignore_all(FLAC_decoder)) + return false; + if(!local_FLAC_stream_decoder_set_metadata_respond_application(FLAC_decoder,rifftag)) + return false; + if(local_FLAC_stream_decoder_init_file(FLAC_decoder, ZenLib::Ztring(File_Name_).To_UTF8().c_str(), FLAC_WriteCallback, FLAC_MetadataCallback, FLAC_ErrorCallback, (void*)&callbackdata) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return false; + if(!local_FLAC_stream_decoder_process_until_end_of_metadata(FLAC_decoder)) + return false; + if(callbackdata.chunkbuffer == NULL || callbackdata.chunkbuffer_data_location == 0){ + // Haven't found data chunk, or any chunks at all + return false; + } + return true; + } + else + return File_Handle.Open(File_Name_, Access); +} +//--------------------------------------------------------------------------- +bool File::Create (const ZenLib::Ztring &File_Name_, bool OverWrite) +{ + return File_Handle.Create(File_Name_, OverWrite); +} + +//--------------------------------------------------------------------------- +void File::Close () +{ + File_Handle.Close(); +} + +// *************************************************************************** +// Read/Write +// *************************************************************************** + +//--------------------------------------------------------------------------- +size_t File::Read (ZenLib::int8u* Buffer, size_t Buffer_Size_Max) +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Read(Buffer, Buffer_Size_Max); + + if(callbackdata.chunkbuffer_readpointer < callbackdata.chunkbuffer_data_location) { + // Data to be read is all in front of audio + size_t read_size = callbackdata.chunkbuffer_data_location - callbackdata.chunkbuffer_readpointer; + if(read_size > Buffer_Size_Max) + read_size = Buffer_Size_Max; + + memcpy(Buffer, callbackdata.chunkbuffer + callbackdata.chunkbuffer_readpointer, read_size); + callbackdata.chunkbuffer_readpointer += read_size; + return read_size; + } + else if(callbackdata.chunkbuffer_readpointer < callbackdata.chunkbuffer_data_location + callbackdata.chunkbuffer_data_length) { + // Data to be read is audio + size_t read_size = callbackdata.chunkbuffer_data_location + callbackdata.chunkbuffer_data_length - callbackdata.chunkbuffer_readpointer; + if(read_size > Buffer_Size_Max) + read_size = Buffer_Size_Max; + if(callbackdata.got_error) + return 0; + if(callbackdata.audiobuffer_readpointer == 0) { + if(!local_FLAC_stream_decoder_process_single(FLAC_decoder)) { + callbackdata.got_error = true; + return 0; + } + } + if(read_size <= callbackdata.audiobuffer_sizeinuse - callbackdata.audiobuffer_readpointer) { + read_size = callbackdata.audiobuffer_sizeinuse - callbackdata.audiobuffer_readpointer; + memcpy(Buffer, callbackdata.audiobuffer + callbackdata.audiobuffer_readpointer, read_size); + callbackdata.audiobuffer_readpointer = 0; + return read_size; + } + else { + memcpy(Buffer, callbackdata.audiobuffer + callbackdata.audiobuffer_readpointer, read_size); + callbackdata.audiobuffer_readpointer += read_size; + return read_size; + } + } + else { + // Data to be read is behind audio + size_t read_size = callbackdata.chunkbuffer_size + callbackdata.chunkbuffer_data_length - callbackdata.chunkbuffer_readpointer; + if(read_size > Buffer_Size_Max) + read_size = Buffer_Size_Max; + + memcpy(Buffer, callbackdata.chunkbuffer + callbackdata.chunkbuffer_readpointer - callbackdata.chunkbuffer_data_length, read_size); + callbackdata.chunkbuffer_readpointer += read_size; + return read_size; + } +} + +//--------------------------------------------------------------------------- +size_t File::Write (const ZenLib::int8u* Buffer, size_t Buffer_Size) +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Write(Buffer, Buffer_Size); + return false; +} + +//--------------------------------------------------------------------------- +bool File::Truncate (ZenLib::int64u Offset) +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Truncate(Offset); + return false; +} + +//--------------------------------------------------------------------------- +size_t File::Write (const ZenLib::Ztring &ToWrite) +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Write(ToWrite); + return false; +} + +// *************************************************************************** +// Moving +// *************************************************************************** + +//--------------------------------------------------------------------------- +bool File::GoTo (ZenLib::int64s Position_ToMove, ZenLib::File::move_t MoveMethod) +{ + ZenLib::int64u position; + if(callbackdata.chunkbuffer == NULL) + return File_Handle.GoTo(Position_ToMove, MoveMethod); + + if(MoveMethod == ZenLib::File::move_t::FromBegin) + position = Position_ToMove; + else if(MoveMethod == ZenLib::File::move_t::FromCurrent) + callbackdata.chunkbuffer_readpointer += Position_ToMove; + else //if(MoveMethod == ZenLib::File::move_t::FromEnd) + callbackdata.chunkbuffer_readpointer = (ZenLib::File::move_t)callbackdata.chunkbuffer_data_length + Position_ToMove; + + // Seeks halfway audio data are not supported + if(position > callbackdata.chunkbuffer_data_location && position < (callbackdata.chunkbuffer_data_location + callbackdata.chunkbuffer_data_length)) + return false; + else if(position > (callbackdata.chunkbuffer_data_length + callbackdata.chunkbuffer_size)) + return false; + callbackdata.chunkbuffer_readpointer = position; + return true; +} + +//--------------------------------------------------------------------------- +ZenLib::int64u File::Position_Get () +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Position_Get(); + + return callbackdata.chunkbuffer_readpointer; +} + +// *************************************************************************** +// Attributes +// *************************************************************************** + +//--------------------------------------------------------------------------- +ZenLib::int64u File::Size_Get() +{ + if(callbackdata.chunkbuffer == NULL) + return File_Handle.Size_Get(); + return callbackdata.chunkbuffer_size + callbackdata.chunkbuffer_data_length; +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Created_Get() +{ + return File_Handle.Created_Get(); +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Created_Local_Get() +{ + return File_Handle.Created_Local_Get(); +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Modified_Get() +{ + return File_Handle.Modified_Get(); +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Modified_Local_Get() +{ + return File_Handle.Modified_Local_Get(); +} + +//--------------------------------------------------------------------------- +bool File::Opened_Get() +{ + return File_Handle.Opened_Get(); +} + +//*************************************************************************** +// Helpers +//*************************************************************************** + +//--------------------------------------------------------------------------- +ZenLib::int64u File::Size_Get(const ZenLib::Ztring &File_Name) +{ + ZenLib::File F(File_Name); + return F.Size_Get(); +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Created_Get(const ZenLib::Ztring &File_Name) +{ + ZenLib::File F(File_Name); + return F.Created_Get(File_Name); +} + +//--------------------------------------------------------------------------- +ZenLib::Ztring File::Modified_Get(const ZenLib::Ztring &File_Name) +{ + ZenLib::File F(File_Name); + return F.Modified_Get(File_Name); +} + +//--------------------------------------------------------------------------- +bool File::Exists(const ZenLib::Ztring &File_Name) +{ + ZenLib::File F(File_Name); + return F.Exists(File_Name); +} + +//--------------------------------------------------------------------------- +bool File::Copy(const ZenLib::Ztring &Source, const ZenLib::Ztring &Destination, bool OverWrite) +{ + return ZenLib::File::Copy(Source, Destination, OverWrite); +} + +//--------------------------------------------------------------------------- +bool File::Move(const ZenLib::Ztring &Source, const ZenLib::Ztring &Destination, bool OverWrite) +{ + return ZenLib::File::Move(Source, Destination, OverWrite); +} + +//--------------------------------------------------------------------------- +bool File::Delete(const ZenLib::Ztring &File_Name) +{ + return ZenLib::File::Delete(File_Name); +} + +//*************************************************************************** +// +//*************************************************************************** +void FLAC_MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + File::clientdata_t * callbackdata = (File::clientdata_t *)(client_data); + void * temp_ptr = realloc(callbackdata->chunkbuffer,callbackdata->chunkbuffer_size + metadata->length - 4); + (void) decoder; + + if(temp_ptr == NULL) { + callbackdata->got_error = true; + return; + } + callbackdata->chunkbuffer = (char *)temp_ptr; + memcpy(callbackdata->chunkbuffer + callbackdata->chunkbuffer_size, metadata->data.application.data,metadata->length - 4); + callbackdata->chunkbuffer_size += metadata->length - 4; + if(callbackdata->chunkbuffer_data_location == 0) + // Check whether this is the data chunk + if(memcmp(metadata->data.application.data,"data",4) == 0) { + callbackdata->chunkbuffer_data_location = callbackdata->chunkbuffer_size; + callbackdata->chunkbuffer_data_length = (ZenLib::int64u)(metadata->data.application.data[4]) + + ((ZenLib::int64u)(metadata->data.application.data[5]) << 8) + + ((ZenLib::int64u)(metadata->data.application.data[6]) << 16) + + ((ZenLib::int64u)(metadata->data.application.data[7]) << 24); + } +} + +void FLAC_ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + File::clientdata_t * callbackdata = (File::clientdata_t *)(client_data); + (void) decoder; + (void) status; + + callbackdata->got_error = true; +} + +FLAC__StreamDecoderWriteStatus FLAC_WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) +{ + File::clientdata_t * callbackdata = (File::clientdata_t *)(client_data); + ZenLib::int64u channels = frame->header.channels; + ZenLib::int64u bps = frame->header.bits_per_sample; + ZenLib::int64u blocksize = frame->header.blocksize; + (void) decoder; + if(callbackdata->audiobuffer_channels == 0 && callbackdata->audiobuffer_bps == 0) { + // First frame + callbackdata->audiobuffer_channels = channels; + callbackdata->audiobuffer_bps = bps; + } + else if(callbackdata->audiobuffer_channels != channels || callbackdata->audiobuffer_bps == bps) { + // Change of parameters mid-stream, which we don't handle + callbackdata->got_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if(blocksize * channels * (bps / 8) > callbackdata->audiobuffer_size) { + void * temp_ptr = realloc(callbackdata->audiobuffer, blocksize * channels * (bps / 8)); + if(temp_ptr == NULL) { + callbackdata->got_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + callbackdata->audiobuffer = (char *)temp_ptr; + callbackdata->audiobuffer_size = blocksize * channels * (bps / 8); + } + + { + char * audiobuffer = callbackdata->audiobuffer; + if(bps > 8) { + for(ZenLib::int64u i = 0; i < blocksize; i++) + for(ZenLib::int64u j = 0; j < channels; j++) { + memcpy(audiobuffer, &buffer[j][i], (bps / 8)); + audiobuffer += (bps/8); + } + } + else { + for(ZenLib::int64u i = 0; i < blocksize; i++) + for(ZenLib::int64u j = 0; j < channels; j++) { + int tmp = buffer[j][i] + (1 << (bps-1)); + memcpy(audiobuffer, &tmp, (bps / 8)); + audiobuffer += (bps/8); + } + } + } + callbackdata->audiobuffer_sizeinuse = blocksize * channels * (bps / 8); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +} //namespace diff --git a/Source/FLACwrapper/File.h b/Source/FLACwrapper/File.h new file mode 100644 index 00000000..69ac696e --- /dev/null +++ b/Source/FLACwrapper/File.h @@ -0,0 +1,119 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a zlib-style license that can + * be found in the License.txt file in the root of the source tree. + */ + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// File functions +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//--------------------------------------------------------------------------- +#ifndef FLACwrapper_FileH +#define FLACwrapper_FileH +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +#include "ZenLib/Ztring.h" +#include "ZenLib/File.h" +#include "ZenLib/FileName.h" +#include "FLAC/metadata.h" +#include "FLAC/stream_decoder.h" +//--------------------------------------------------------------------------- + +namespace FLACwrapper +{ + +//*************************************************************************** +/// @brief File manipulation +//*************************************************************************** + +class File +{ +public : + //Constructor/Destructor + File (); + File (ZenLib::Ztring File_Name, ZenLib::File::access_t Access=ZenLib::File::Access_Read); + ~File (); + + //Open/close + bool Open (const ZenLib::tstring &File_Name, ZenLib::File::access_t Access=ZenLib::File::Access_Read); + bool Create(const ZenLib::Ztring &File_Name, bool OverWrite=true); + void Close (); + + //Read/Write + size_t Read (ZenLib::int8u* Buffer, size_t Buffer_Size); + size_t Write (const ZenLib::int8u* Buffer, size_t Buffer_Size); + size_t Write (const ZenLib::Ztring &ToWrite); + bool Truncate (ZenLib::int64u Offset=(ZenLib::int64u)-1); + + //Moving + bool GoTo (ZenLib::int64s Position, ZenLib::File::move_t MoveMethod=ZenLib::File::FromBegin); + ZenLib::int64u Position_Get (); + + //Attributes + ZenLib::int64u Size_Get(); + ZenLib::Ztring Created_Get(); + ZenLib::Ztring Created_Local_Get(); + ZenLib::Ztring Modified_Get(); + ZenLib::Ztring Modified_Local_Get(); + bool Opened_Get(); + + //Helpers + static ZenLib::int64u Size_Get(const ZenLib::Ztring &File_Name); + static ZenLib::Ztring Created_Get(const ZenLib::Ztring &File_Name); + static ZenLib::Ztring Modified_Get(const ZenLib::Ztring &File_Name); + static bool Exists(const ZenLib::Ztring &File_Name); + static bool Copy(const ZenLib::Ztring &Source, const ZenLib::Ztring &Destination, bool OverWrite=false); + static bool Move(const ZenLib::Ztring &Source, const ZenLib::Ztring &Destination, bool OverWrite=false); + static bool Delete(const ZenLib::Ztring &File_Name); + + //Callback client_data + struct clientdata_t { + char * chunkbuffer; + ZenLib::int64u chunkbuffer_size; + ZenLib::int64u chunkbuffer_readpointer; + ZenLib::int64u chunkbuffer_data_location; + ZenLib::int64u chunkbuffer_data_length; + bool chunkbuffer_complete; + char * audiobuffer; + ZenLib::int64u audiobuffer_size; + ZenLib::int64u audiobuffer_sizeinuse; + ZenLib::int64u audiobuffer_readpointer; + ZenLib::int64u audiobuffer_channels; + ZenLib::int64u audiobuffer_bps; + bool got_error; + }; + +private: + ZenLib::File File_Handle; + clientdata_t callbackdata = {NULL, 0, 0, 0, 0, false, NULL, 0, 0, 0, 0, 0, false}; + FLAC__StreamDecoder * FLAC_decoder = NULL; + bool FLAC_available; + + // Function pointers + void * FLAChandle; + const char ** FLACversion; + FLAC__StreamDecoder * (*local_FLAC_stream_decoder_new)(); + FLAC__bool (*local_FLAC_stream_decoder_set_metadata_ignore_all)(FLAC__StreamDecoder *); + FLAC__bool (*local_FLAC_stream_decoder_set_metadata_respond_application)(FLAC__StreamDecoder *, const FLAC__byte *); + FLAC__StreamDecoderInitStatus (*local_FLAC_stream_decoder_init_file)(FLAC__StreamDecoder *, const char *, FLAC__StreamDecoderWriteCallback, FLAC__StreamDecoderMetadataCallback, FLAC__StreamDecoderErrorCallback, void *); + FLAC__bool (*local_FLAC_stream_decoder_process_until_end_of_metadata)(FLAC__StreamDecoder *); + FLAC__bool (*local_FLAC_stream_decoder_process_single)(FLAC__StreamDecoder *); + FLAC__bool (*local_FLAC_stream_decoder_finish)(FLAC__StreamDecoder *); + FLAC__bool (*local_FLAC_stream_decoder_reset)(FLAC__StreamDecoder *); + void (*local_FLAC_stream_decoder_delete)(FLAC__StreamDecoder *); + void (*local_FLAC_metadata_object_delete)(FLAC__StreamMetadata *); +}; + +// Callback functions + +FLAC__StreamDecoderWriteStatus FLAC_WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data); +void FLAC_MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +void FLAC_ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +} //NameSpace + +#endif diff --git a/Source/Riff/Riff_Base.h b/Source/Riff/Riff_Base.h index d763aa70..09a9f74b 100644 --- a/Source/Riff/Riff_Base.h +++ b/Source/Riff/Riff_Base.h @@ -15,7 +15,7 @@ //--------------------------------------------------------------------------- #include "ZenLib/ZtringList.h" #include "ZenLib/Ztring.h" -#include "ZenLib/File.h" +#include "FLACwrapper/File.h" #include "ZenLib/CriticalSection.h" #include #include @@ -362,8 +362,8 @@ class Riff_Base } }; - File In; - File Out; + FLACwrapper::File In; + FLACwrapper::File Out; buffer Out_Buffer_Begin; buffer Out_Buffer_End; bool Out_Buffer_WriteAtEnd; diff --git a/Source/Riff/Riff_Handler.cpp b/Source/Riff/Riff_Handler.cpp index 1fa8a2bf..84f9b085 100644 --- a/Source/Riff/Riff_Handler.cpp +++ b/Source/Riff/Riff_Handler.cpp @@ -15,7 +15,7 @@ #include #include #include "ZenLib/ZtringListList.h" -#include "ZenLib/File.h" +#include "FLACwrapper/File.h" #include "ZenLib/Dir.h" #include "TinyXml2/tinyxml2.h" @@ -394,7 +394,7 @@ bool Riff_Handler::Open_Internal(const string &FileName) Chunks->Global->In.Close(); //ReadOnly check - if (!File().Open(Ztring().From_UTF8(FileName), File::Access_Write)) + if (!FLACwrapper::File().Open(Ztring().From_UTF8(FileName), File::Access_Write)) { Chunks->Global->Read_Only=true; Information<Global->File_Name.To_UTF8()<<": Is read only"<Global->File_Name).Extension_Get() == ZenLib::Ztring("flac")) + { + Errors<Global->File_Name.To_UTF8()<<": Writing to FLAC is not yet supported"<Global->File_Name.To_UTF8()<<": Malformed input ("< #include @@ -176,8 +176,8 @@ class Riff_Handler //--------------------------------------------------------------------------- //Internal - ZenLib::File In; - ZenLib::File Out; + FLACwrapper::File In; + FLACwrapper::File Out; Ztring Core_FromFile; Riff* Chunks; bool File_IsValid;