From: <man...@us...> - 2013-10-25 16:59:19
|
Revision: 3023 http://sourceforge.net/p/modplug/code/3023 Author: manxorist Date: 2013-10-25 16:59:10 +0000 (Fri, 25 Oct 2013) Log Message: ----------- [Ref] unarchiver: Factor out common code of different archive types and thus simplify each archive implementation. [Ref] unarchiver: Move best file heuristic to a single place in CUnarchiver. Modified Paths: -------------- trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/unarchiver/unarchiver.cpp trunk/OpenMPT/unarchiver/unarchiver.h trunk/OpenMPT/unarchiver/ungzip.cpp trunk/OpenMPT/unarchiver/ungzip.h trunk/OpenMPT/unarchiver/unlha.cpp trunk/OpenMPT/unarchiver/unlha.h trunk/OpenMPT/unarchiver/unzip.cpp trunk/OpenMPT/unarchiver/unzip.h Added Paths: ----------- trunk/OpenMPT/unarchiver/archive.h Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-10-25 16:59:10 UTC (rev 3023) @@ -1573,6 +1573,10 @@ Name="unarchiver" > <File + RelativePath="..\unarchiver\archive.h" + > + </File> + <File RelativePath="..\unarchiver\unarchiver.cpp" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-10-25 16:59:10 UTC (rev 3023) @@ -538,6 +538,7 @@ <ClInclude Include="..\soundlib\WindowedFIR.h" /> <ClInclude Include="..\soundlib\XMTools.h" /> <ClInclude Include="..\test\test.h" /> + <ClInclude Include="..\unarchiver\archive.h" /> <ClInclude Include="..\unarchiver\unarchiver.h" /> <ClInclude Include="..\unarchiver\ungzip.h" /> <ClInclude Include="..\unarchiver\unlha.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-10-25 16:59:10 UTC (rev 3023) @@ -957,6 +957,9 @@ <ClInclude Include="StreamEncoderFLAC.h"> <Filter>Header Files\mptrack</Filter> </ClInclude> + <ClInclude Include="..\unarchiver\archive.h"> + <Filter>Header Files\unarchiver</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-10-25 16:59:10 UTC (rev 3023) @@ -673,8 +673,8 @@ DWORD dwMemLength = file.GetLength(); #ifndef NO_ARCHIVE_SUPPORT - CUnarchiver unarchiver(file, GetSupportedExtensions(true)); - if(unarchiver.IsArchive() && unarchiver.ExtractFile()) + CUnarchiver unarchiver(file); + if(unarchiver.ExtractBestFile(GetSupportedExtensions(true))) { file = unarchiver.GetOutputFile(); lpStream = (LPCBYTE)file.GetRawData(); @@ -744,7 +744,7 @@ // Read archive comment if there is no song comment if(songMessage.empty()) { - songMessage.assign(unarchiver.GetComments()); + songMessage.assign(unarchiver.GetComment()); } #endif Added: trunk/OpenMPT/unarchiver/archive.h =================================================================== --- trunk/OpenMPT/unarchiver/archive.h (rev 0) +++ trunk/OpenMPT/unarchiver/archive.h 2013-10-25 16:59:10 UTC (rev 3023) @@ -0,0 +1,103 @@ +/* + * archive.h + * --------- + * Purpose: archive loader + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#pragma once + +#include "../soundlib/FileReader.h" +#include <string> +#include <vector> + +enum ArchiveFileType +{ + ArchiveFileInvalid, + ArchiveFileNormal, + ArchiveFileSpecial, +}; + +struct ArchiveFileInfo +{ + std::string name; + ArchiveFileType type; + uint64 size; + std::string comment; + uint64 cookie1; + uint64 cookie2; + ArchiveFileInfo() + : name(std::string()) + , type(ArchiveFileInvalid) + , size(0) + , comment(std::string()) + , cookie1(0) + , cookie2(0) + { + return; + } +}; + +//============ +class IArchive +//============ +{ +public: + typedef std::vector<ArchiveFileInfo>::const_iterator const_iterator; +protected: + IArchive() {} +public: + virtual ~IArchive() {}; +public: + virtual bool IsArchive() const = 0; + virtual std::string GetComment() const = 0; + virtual bool ExtractFile(std::size_t index) = 0; + virtual FileReader GetOutputFile() const = 0; + virtual std::size_t size() const = 0; + virtual IArchive::const_iterator begin() const = 0; + virtual IArchive::const_iterator end() const = 0; + virtual const ArchiveFileInfo & at(std::size_t index) const = 0; + virtual const ArchiveFileInfo & operator [] (std::size_t index) const = 0; +}; + +//================================= +class ArchiveBase : public IArchive +//================================= +{ +protected: + FileReader inFile; + std::string comment; + std::vector<ArchiveFileInfo> contents; + std::vector<char> data; +public: + ArchiveBase(const FileReader &inFile) + : inFile(inFile) + { + return; + } + virtual ~ArchiveBase() + { + return; + } + virtual bool ExtractFile(std::size_t index) { MPT_UNREFERENCED_PARAMETER(index); return false; } // overwrite this +public: + virtual bool IsArchive() const + { + return !contents.empty(); + } + virtual std::string GetComment() const + { + return comment; + } + virtual FileReader GetOutputFile() const + { + return FileReader(&data[0], data.size()); + } + virtual std::size_t size() const { return contents.size(); } + virtual IArchive::const_iterator begin() const { return contents.begin(); } + virtual IArchive::const_iterator end() const { return contents.end(); } + virtual const ArchiveFileInfo & at(std::size_t index) const { return contents.at(index); } + virtual const ArchiveFileInfo & operator [] (std::size_t index) const { return contents[index]; } +}; Property changes on: trunk/OpenMPT/unarchiver/archive.h ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/x-chdr \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Modified: trunk/OpenMPT/unarchiver/unarchiver.cpp =================================================================== --- trunk/OpenMPT/unarchiver/unarchiver.cpp 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unarchiver.cpp 2013-10-25 16:59:10 UTC (rev 3023) @@ -14,16 +14,38 @@ #include "unarchiver.h" #include "../soundlib/FileReader.h" -CUnarchiver::CUnarchiver(FileReader &file, const std::vector<const char *> &extensions) : -ext(extensions), -inFile(file), -zipArchive(inFile, ext), -rarArchive((LPBYTE)inFile.GetRawData(), inFile.GetLength()), -lhaArchive(inFile), -gzipArchive(inFile) -//--------------------------------------------------------------------------------- +CUnarchiver::CUnarchiver(FileReader &file) +//---------------------------------------- + : impl(nullptr) + , inFile(file) + , emptyArchive(inFile) +#ifdef ZIPPED_MOD_SUPPORT + , zipArchive(inFile) +#endif +#ifdef UNRAR_SUPPORT + , rarArchive(inFile) +#endif +#ifdef UNLHA_SUPPORT + , lhaArchive(inFile) +#endif +#ifdef UNGZIP_SUPPORT + , gzipArchive(inFile) +#endif { inFile.Rewind(); +#ifdef ZIPPED_MOD_SUPPORT + if(zipArchive.IsArchive()) { impl = &zipArchive; return; } +#endif +#ifdef UNRAR_SUPPORT + if(rarArchive.IsArchive()) { impl = &rarArchive; return; } +#endif +#ifdef UNLHA_SUPPORT + if(lhaArchive.IsArchive()) { impl = &lhaArchive; return; } +#endif +#ifdef UNGZIP_SUPPORT + if(gzipArchive.IsArchive()) { impl = &gzipArchive; return; } +#endif + impl = &emptyArchive; } @@ -34,73 +56,141 @@ } -bool CUnarchiver::IsArchive() const -//--------------------------------- +struct find_str { - return false -#ifdef ZIPPED_MOD_SUPPORT - || zipArchive.IsArchive() -#endif -#ifdef UNRAR_SUPPORT - || rarArchive.IsArchive() -#endif -#ifdef UNLHA_SUPPORT - || lhaArchive.IsArchive() -#endif -#ifdef UNGZIP_SUPPORT - || gzipArchive.IsArchive() -#endif - ; -} + find_str(const char *str): s1(str) { } + bool operator() (const char *s2) const + { + return !strcmp(s1, s2); + } + const char *s1; +}; -bool CUnarchiver::ExtractFile() -//----------------------------- +static inline std::string GetExtension(const std::string &filename) +//----------------------------------------------------------------- { -#ifdef ZIPPED_MOD_SUPPORT - if(zipArchive.IsArchive()) + if(filename.find_last_of(".") != std::string::npos) { - if(!zipArchive.ExtractFile()) return false; - outFile = zipArchive.GetOutputFile(); - return outFile.GetRawData()?true:false; + std::string ext = filename.substr(filename.find_last_of(".") + 1); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + return ext; } -#endif -#ifdef UNRAR_SUPPORT - if(rarArchive.IsArchive()) + return std::string(); +} + + +std::size_t CUnarchiver::FindBestFile(const std::vector<const char *> &extensions) +//-------------------------------------------------------------------------------- +{ + if(!IsArchive()) { - if(!rarArchive.ExtrFile()) return false; - outFile = FileReader(rarArchive.GetOutputFile(), rarArchive.GetOutputFileLength()); - return outFile.GetRawData()?true:false; + return failIndex; } -#endif -#ifdef UNLHA_SUPPORT - if(lhaArchive.IsArchive()) + uint64 biggestSize = 0; + std::size_t bestIndex = failIndex; + for(std::size_t i = 0; i < size(); ++i) { - if(!lhaArchive.ExtractFile()) return false; - outFile = lhaArchive.GetOutputFile(); - return outFile.GetRawData()?true:false; + if(at(i).type != ArchiveFileNormal) + { + continue; + } + const std::string ext = GetExtension(at(i).name); + + // Compare with list of preferred extensions + if(std::find_if(extensions.begin(), extensions.end(), find_str(ext.c_str())) != extensions.end()) + { + bestIndex = i; + break; + } + + if(ext == "diz" || ext == "nfo" || ext == "txt") + { + // we do not want these + continue; + } + + if(at(i).size >= biggestSize) + { + biggestSize = at(i).size; + bestIndex = i; + } } -#endif -#ifdef UNGZIP_SUPPORT - if(gzipArchive.IsArchive()) - { - if(!gzipArchive.ExtractFile()) return false; - outFile = gzipArchive.GetOutputFile(); - return outFile.GetRawData()?true:false; - } -#endif - return false; + return bestIndex; } -std::string CUnarchiver::GetComments() -//------------------------------------ +bool CUnarchiver::ExtractBestFile(const std::vector<const char *> &extensions) +//---------------------------------------------------------------------------- { -#ifdef ZIPPED_MOD_SUPPORT - if(zipArchive.IsArchive()) + std::size_t bestFile = FindBestFile(extensions); + if(bestFile == failIndex) { - return zipArchive.GetComments(); + return false; } -#endif - return ""; + return ExtractFile(bestFile); } + + +bool CUnarchiver::IsArchive() const +//--------------------------------- +{ + return impl->IsArchive(); +} + + +std::string CUnarchiver::GetComment() const +//----------------------------------------- +{ + return impl->GetComment(); +} + + +bool CUnarchiver::ExtractFile(std::size_t index) +//---------------------------------------------- +{ + return impl->ExtractFile(index); +} + + +FileReader CUnarchiver::GetOutputFile() const +//------------------------------------------- +{ + return impl->GetOutputFile(); +} + + +std::size_t CUnarchiver::size() const +//----------------------------------- +{ + return impl->size(); +} + + +IArchive::const_iterator CUnarchiver::begin() const +//------------------------------------------------- +{ + return impl->begin(); +} + + +IArchive::const_iterator CUnarchiver::end() const +//----------------------------------------------- +{ + return impl->end(); +} + + +const ArchiveFileInfo & CUnarchiver::at(std::size_t index) const +//-------------------------------------------------------------- +{ + return impl->at(index); +} + + +const ArchiveFileInfo & CUnarchiver::operator [] (std::size_t index) const +//------------------------------------------------------------------------ +{ + return impl->operator[](index); +} + Modified: trunk/OpenMPT/unarchiver/unarchiver.h =================================================================== --- trunk/OpenMPT/unarchiver/unarchiver.h 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unarchiver.h 2013-10-25 16:59:10 UTC (rev 3023) @@ -11,6 +11,8 @@ #include "../soundlib/FileReader.h" +#include "archive.h" + #define UNGZIP_SUPPORT #define UNLHA_SUPPORT #define UNRAR_SUPPORT @@ -29,30 +31,85 @@ #include "ungzip.h" #endif -//=============== -class CUnarchiver -//=============== +#ifdef UNRAR_SUPPORT +class CWrappedRarArchive : public IArchive { -protected: +private: FileReader inFile; - const std::vector<const char *> ext; + std::vector<ArchiveFileInfo> contents; + mutable CRarArchive rar; +public: + CWrappedRarArchive(FileReader &inFile) + : inFile(inFile) + , rar((LPBYTE)inFile.GetRawData(), inFile.GetLength()) + { + if(rar.IsArchive()) + { + ArchiveFileInfo info; + info.type = ArchiveFileNormal; + contents.push_back(info); + } + } + virtual ~CWrappedRarArchive() { return; } +public: + virtual bool IsArchive() const { return rar.IsArchive() == TRUE; } + virtual std::string GetComment() const { return std::string(); } + virtual bool ExtractFile(std::size_t index) { if(index >= contents.size()) { return false; } return rar.ExtrFile() == TRUE; } + virtual FileReader GetOutputFile() const { return FileReader(rar.GetOutputFile(), rar.GetOutputFileLength()); } + virtual std::size_t size() const { return contents.size(); } + virtual IArchive::const_iterator begin() const { return contents.begin(); } + virtual IArchive::const_iterator end() const { return contents.end(); } + virtual const ArchiveFileInfo & at(std::size_t index) const { return contents.at(index); } + virtual const ArchiveFileInfo & operator [] (std::size_t index) const { return contents[index]; } +}; +#endif + +//================================= +class CUnarchiver : public IArchive +//================================= +{ + private: + + IArchive *impl; + + FileReader inFile; + + ArchiveBase emptyArchive; +#ifdef ZIPPED_MOD_SUPPORT CZipArchive zipArchive; - mutable CRarArchive rarArchive; - mutable CLhaArchive lhaArchive; +#endif +#ifdef UNRAR_SUPPORT + CWrappedRarArchive rarArchive; +#endif +#ifdef UNLHA_SUPPORT + CLhaArchive lhaArchive; +#endif +#ifdef UNGZIP_SUPPORT CGzipArchive gzipArchive; +#endif -protected: - FileReader outFile; +public: + CUnarchiver(FileReader &file); + virtual ~CUnarchiver(); + + virtual bool IsArchive() const; + virtual std::string GetComment() const; + virtual bool ExtractFile(std::size_t index); + virtual FileReader GetOutputFile() const; + virtual std::size_t size() const; + virtual IArchive::const_iterator begin() const; + virtual IArchive::const_iterator end() const; + virtual const ArchiveFileInfo & at(std::size_t index) const; + virtual const ArchiveFileInfo & operator [] (std::size_t index) const; + public: - FileReader GetOutputFile() const { return outFile; } - bool IsArchive() const; - bool ExtractFile(); - std::string GetComments(); + static const std::size_t failIndex = (std::size_t)-1; - CUnarchiver(FileReader &file, const std::vector<const char *> &extensions); - ~CUnarchiver(); + std::size_t FindBestFile(const std::vector<const char *> &extensions); + bool ExtractBestFile(const std::vector<const char *> &extensions); + }; Modified: trunk/OpenMPT/unarchiver/ungzip.cpp =================================================================== --- trunk/OpenMPT/unarchiver/ungzip.cpp 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/ungzip.cpp 2013-10-25 16:59:10 UTC (rev 3023) @@ -20,42 +20,39 @@ #endif -CGzipArchive::CGzipArchive(FileReader &file) : inFile(file) -//--------------------------------------------------------- +CGzipArchive::CGzipArchive(FileReader &file) : ArchiveBase(file) +//-------------------------------------------------------------- { inFile.Rewind(); inFile.Read(header); + + // Check header data + file size + if(header.magic1 != GZ_HMAGIC1 || header.magic2 != GZ_HMAGIC2 || header.method != GZ_HMDEFLATE || (header.flags & GZ_FRESERVED) != 0 + || inFile.GetLength() <= sizeof(GZheader) + sizeof(GZtrailer)) + { + return; + } + ArchiveFileInfo info; + info.type = ArchiveFileNormal; + contents.push_back(info); } CGzipArchive::~CGzipArchive() //--------------------------- { - delete[] outFile.GetRawData(); + return; } -bool CGzipArchive::IsArchive() const -//---------------------------------- +bool CGzipArchive::ExtractFile(std::size_t index) +//----------------------------------------------- { - // Check header data + file size - if(header.magic1 != GZ_HMAGIC1 || header.magic2 != GZ_HMAGIC2 || header.method != GZ_HMDEFLATE || (header.flags & GZ_FRESERVED) != 0 - || inFile.GetLength() <= sizeof(GZheader) + sizeof(GZtrailer)) + if(index >= contents.size()) { return false; } - return true; -} - -bool CGzipArchive::ExtractFile() -//------------------------------ -{ - if(!IsArchive()) - { - return false; - } - // Read trailer GZtrailer trailer; inFile.Seek(inFile.GetLength() - sizeof(GZtrailer)); @@ -94,10 +91,9 @@ return false; } - delete[] outFile.GetRawData(); - - char *data = new (std::nothrow) char[trailer.isize]; - if(data == nullptr) + try { + data.resize(trailer.isize); + } catch(...) { return false; } @@ -114,21 +110,19 @@ return false; } strm.avail_out = trailer.isize; - strm.next_out = (Bytef *)data; + strm.next_out = (Bytef *)&data[0]; int retVal = inflate(&strm, Z_NO_FLUSH); inflateEnd(&strm); // Everything went OK? Check return code, number of written bytes and CRC32. - if(retVal == Z_STREAM_END && trailer.isize == strm.total_out && trailer.crc32_ == crc32(0, (Bytef *)data, trailer.isize)) + if(retVal == Z_STREAM_END && trailer.isize == strm.total_out && trailer.crc32_ == crc32(0, (Bytef *)&data[0], trailer.isize)) { // Success! :) - outFile = FileReader(data, trailer.isize); return true; } else { // Fail :( - delete[] outFile.GetRawData(); return false; } } Modified: trunk/OpenMPT/unarchiver/ungzip.h =================================================================== --- trunk/OpenMPT/unarchiver/ungzip.h 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/ungzip.h 2013-10-25 16:59:10 UTC (rev 3023) @@ -9,12 +9,13 @@ #pragma once -//================ -class CGzipArchive -//================ +#include "archive.h" + +//===================================== +class CGzipArchive : public ArchiveBase +//===================================== { protected: - FileReader inFile, outFile; #ifdef NEEDS_PRAGMA_PACK #pragma pack(push, 1) @@ -72,10 +73,8 @@ public: - FileReader GetOutputFile() const { return outFile; } - bool IsArchive() const; - bool ExtractFile(); + bool ExtractFile(std::size_t index); CGzipArchive(FileReader &file); - ~CGzipArchive(); + virtual ~CGzipArchive(); }; Modified: trunk/OpenMPT/unarchiver/unlha.cpp =================================================================== --- trunk/OpenMPT/unarchiver/unlha.cpp 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unlha.cpp 2013-10-25 16:59:10 UTC (rev 3023) @@ -45,20 +45,35 @@ LHAcloseFileReader }; -static inline std::string get_extension( std::string filename ) + +CLhaArchive::CLhaArchive(FileReader &file) : ArchiveBase(file), inputstream(nullptr), reader(nullptr), firstfile(nullptr) +//----------------------------------------------------------------------------------------------------------------------- { - if ( filename.find_last_of( "." ) != std::string::npos ) + OpenArchive(); + for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader)) { - return filename.substr( filename.find_last_of( "." ) + 1 ); + ArchiveFileInfo info; + info.name = fileheader->filename; + info.size = fileheader->length; + info.type = ArchiveFileNormal; + contents.push_back(info); } - return ""; + CloseArchive(); } -CLhaArchive::CLhaArchive(FileReader file_ ) : file(file_), inputstream(nullptr), reader(nullptr), firstfile(nullptr) -//------------------------------------------------------------------------------------------------------------------ +CLhaArchive::~CLhaArchive() +//------------------------- { - inputstream = lha_input_stream_new(&vtable, &file); + return; +} + + +void CLhaArchive::OpenArchive() +//----------------------------- +{ + inFile.Rewind(); + inputstream = lha_input_stream_new(&vtable, &inFile); if(inputstream) { reader = lha_reader_new(inputstream); @@ -71,8 +86,8 @@ } -CLhaArchive::~CLhaArchive() -//------------------------- +void CLhaArchive::CloseArchive() +//------------------------------ { if(reader) { @@ -87,79 +102,49 @@ } -bool CLhaArchive::IsArchive() -//--------------------------- +bool CLhaArchive::ExtractFile(std::size_t index) +//---------------------------------------------- { - return firstfile != nullptr; -} - - -bool CLhaArchive::ExtractFile() -//----------------------------- -{ + if(index >= contents.size()) + { + return false; + } + data.clear(); + OpenArchive(); const std::size_t bufSize = 4096; + std::size_t i = 0; for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader)) { - // get the biggest file - if(fileheader->length >= data.size()) + if(index == i) { data.clear(); std::size_t countRead = 0; do { - data.resize(data.size() + bufSize); + try + { + data.resize(data.size() + bufSize); + } catch(...) + { + CloseArchive(); + return false; + } countRead = lha_reader_read(reader, &data[data.size() - bufSize], bufSize); if(countRead < bufSize) { - data.resize(data.size() - (bufSize - countRead)); + try + { + data.resize(data.size() - (bufSize - countRead)); + } catch(...) + { + CloseArchive(); + return false; + } } } while(countRead > 0); } + ++i; } + CloseArchive(); return data.size() > 0; } - - -bool CLhaArchive::ExtractFile(const std::vector<const char *> &extensions) -//------------------------------------------------------------------------ -{ - const std::size_t bufSize = 4096; - for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader)) - { - if(fileheader->filename) - { - std::string ext = get_extension(fileheader->filename); - if(!ext.empty()) - { - std::transform(ext.begin(), ext.end(), ext.begin(), tolower); - if(std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) - { - data.clear(); - std::size_t countRead = 0; - do - { - data.resize(data.size() + bufSize); - countRead = lha_reader_read(reader, &data[data.size() - bufSize], bufSize); - if(countRead < bufSize) - { - data.resize(data.size() - (bufSize - countRead)); - } - } while(countRead > 0); - return true; - } - } - } - } - return false; -} - - -FileReader CLhaArchive::GetOutputFile() const -//------------------------------------------- -{ - if(data.size() == 0) - { - return FileReader(); - } - return FileReader(&data[0], data.size()); -} Modified: trunk/OpenMPT/unarchiver/unlha.h =================================================================== --- trunk/OpenMPT/unarchiver/unlha.h 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unlha.h 2013-10-25 16:59:10 UTC (rev 3023) @@ -9,28 +9,25 @@ #pragma once -#include "../soundlib/FileReader.h" +#include "archive.h" typedef struct _LHAInputStream LHAInputStream; typedef struct _LHAReader LHAReader; typedef struct _LHAFileHeader LHAFileHeader; -//=============== -class CLhaArchive -//=============== +//==================================== +class CLhaArchive : public ArchiveBase +//==================================== { private: - FileReader file; LHAInputStream *inputstream; LHAReader *reader; LHAFileHeader *firstfile; - std::vector<char> data; + void OpenArchive(); + void CloseArchive(); public: - CLhaArchive(FileReader file_); - ~CLhaArchive(); + CLhaArchive(FileReader &file); + virtual ~CLhaArchive(); public: - bool IsArchive(); - FileReader GetOutputFile() const; - bool ExtractFile(); - bool ExtractFile(const std::vector<const char *> &extensions); + virtual bool ExtractFile(std::size_t index); }; Modified: trunk/OpenMPT/unarchiver/unzip.cpp =================================================================== --- trunk/OpenMPT/unarchiver/unzip.cpp 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unzip.cpp 2013-10-25 16:59:10 UTC (rev 3023) @@ -10,10 +10,10 @@ #include "stdafx.h" #include "../soundlib/FileReader.h" -#include <vector> #include "unzip.h" #include "../common/misc_util.h" #include <algorithm> +#include <vector> #if !defined(NO_ZLIB) #include <contrib/minizip/unzip.h> @@ -97,8 +97,8 @@ }; -CZipArchive::CZipArchive(FileReader &file, const std::vector<const char *> &ext) : inFile(file), extensions(ext) -//-------------------------------------------------------------------------------------------------------------- +CZipArchive::CZipArchive(FileReader &file) : ArchiveBase(file) +//------------------------------------------------------------ { zlib_filefunc_def functions = { @@ -112,142 +112,113 @@ &inFile }; zipFile = unzOpen2(nullptr, &functions); -} + if(zipFile == nullptr) + { + return; + } -CZipArchive::~CZipArchive() -//------------------------- -{ - unzClose(zipFile); - delete[] outFile.GetRawData(); -} - - -bool CZipArchive::IsArchive() const -//--------------------------------- -{ - return (zipFile != nullptr); -} - - -struct find_str -{ - find_str(const char *str): s1(str) { } - - bool operator() (const char *s2) const + // read comment { - return !strcmp(s1, s2); + unz_global_info info; + if(unzGetGlobalInfo(zipFile, &info) == UNZ_OK) + { + if(info.size_comment > 0) + { + if(info.size_comment < Util::MaxValueOfType(info.size_comment)) + { + info.size_comment++; + } + std::vector<char> commentData(info.size_comment); + if(unzGetGlobalComment(zipFile, &commentData[0], info.size_comment) >= 0) + { + commentData[info.size_comment - 1] = '\0'; + comment = &commentData[0]; + } + } + } } - const char *s1; -}; - - -bool CZipArchive::ExtractFile() -//----------------------------- -{ + // read contents unz_file_pos bestFile; unz_file_info info; - uLong biggestFile = 0; int status = unzGoToFirstFile(zipFile); unzGetFilePos(zipFile, &bestFile); while(status == UNZ_OK) { + ArchiveFileInfo fileinfo; + + fileinfo.type = ArchiveFileNormal; + char name[256]; unzGetCurrentFileInfo(zipFile, &info, name, sizeof(name), nullptr, 0, nullptr, 0); + fileinfo.name = name; + fileinfo.size = info.uncompressed_size; - // Extract file extension - char *ext = name + info.size_filename; - while(ext > name) - { - ext--; - *ext = static_cast<char>(tolower(*ext)); - if(*ext == '.') - { - ext++; - break; - } - } + unzGetFilePos(zipFile, &bestFile); + fileinfo.cookie1 = bestFile.pos_in_zip_directory; + fileinfo.cookie2 = bestFile.num_of_file; - // Compare with list of preferred extensions - if(std::find_if(extensions.begin(), extensions.end(), find_str(ext)) != extensions.end()) - { - // File has a preferred extension: use it. - unzGetFilePos(zipFile, &bestFile); - break; - } + contents.push_back(fileinfo); - if(strcmp(ext, "diz") - && strcmp(ext, "nfo") - && strcmp(ext, "txt") - && info.uncompressed_size >= biggestFile) - { - // If this isn't some kind of info file, we should maybe pick it. - unzGetFilePos(zipFile, &bestFile); - biggestFile = info.uncompressed_size; - } - status = unzGoToNextFile(zipFile); } - if(unzGoToFilePos(zipFile, &bestFile) == UNZ_OK && unzOpenCurrentFile(zipFile) == UNZ_OK) - { - unzGetCurrentFileInfo(zipFile, &info, nullptr, 0, nullptr, 0, nullptr, 0); - - delete[] outFile.GetRawData(); - char *data = new (std::nothrow) char[info.uncompressed_size]; - if(data != nullptr) - { - unzReadCurrentFile(zipFile, data, info.uncompressed_size); - outFile = FileReader(data, info.uncompressed_size); - } - unzCloseCurrentFile(zipFile); +} - return (data != nullptr); - } - return false; +CZipArchive::~CZipArchive() +//------------------------- +{ + unzClose(zipFile); } -std::string CZipArchive::GetComments() -//------------------------------------ +bool CZipArchive::ExtractFile(std::size_t index) +//---------------------------------------------- { - unz_global_info info; - if(zipFile == nullptr || unzGetGlobalInfo(zipFile, &info) != UNZ_OK) + if(index >= contents.size()) { - return ""; + return false; } - if(info.size_comment > 0) + data.clear(); + + unz_file_pos bestFile; + unz_file_info info; + + bestFile.pos_in_zip_directory = static_cast<uLong>(contents[index].cookie1); + bestFile.num_of_file = static_cast<uLong>(contents[index].cookie2); + + if(unzGoToFilePos(zipFile, &bestFile) == UNZ_OK && unzOpenCurrentFile(zipFile) == UNZ_OK) { - if(info.size_comment < Util::MaxValueOfType(info.size_comment)) + unzGetCurrentFileInfo(zipFile, &info, nullptr, 0, nullptr, 0, nullptr, 0); + + try { - info.size_comment++; - } - char *comment = new (std::nothrow) char[info.size_comment]; - if(comment != nullptr && unzGetGlobalComment(zipFile, comment, info.size_comment) >= 0) + data.resize(info.uncompressed_size); + } catch(...) { - comment[info.size_comment - 1] = '\0'; - std::string result = comment; - delete[] comment; - return result; - } else - { - delete[] comment; + unzCloseCurrentFile(zipFile); + return false; } + unzReadCurrentFile(zipFile, &data[0], info.uncompressed_size); + unzCloseCurrentFile(zipFile); + + return true; } - return ""; + + return false; } #elif !defined(NO_MINIZ) -CZipArchive::CZipArchive(FileReader &file, const std::vector<const char *> &ext) : inFile(file), extensions(ext) -//-------------------------------------------------------------------------------------------------------------- +CZipArchive::CZipArchive(FileReader &file) : ArchiveBase(file) +//------------------------------------------------------------ { zipFile = new mz_zip_archive(); @@ -257,9 +228,37 @@ if(!mz_zip_reader_init_mem(zip, file.GetRawData(), file.GetLength(), 0)) { delete zip; + zip = nullptr; zipFile = nullptr; } + if(!zip) + { + return; + } + + for(mz_uint i = 0; i < mz_zip_reader_get_num_files(zip); ++i) + { + ArchiveFileInfo info; + info.type = ArchiveFileInvalid; + mz_zip_archive_file_stat stat; + MemsetZero(stat); + if(mz_zip_reader_file_stat(zip, i, &stat)) + { + info.type = ArchiveFileNormal; + info.name = stat.m_filename; + info.size = stat.m_uncomp_size; + } + if(mz_zip_reader_is_file_a_directory(zip, i)) + { + info.type = ArchiveFileSpecial; + } else if(mz_zip_reader_is_file_encrypted(zip, i)) + { + info.type = ArchiveFileSpecial; + } + contents.push_back(info); + } + } @@ -276,106 +275,42 @@ zipFile = nullptr; } - delete[] outFile.GetRawData(); } -bool CZipArchive::IsArchive() const -//--------------------------------- +bool CZipArchive::ExtractFile(std::size_t index) +//---------------------------------------------- { - return (zipFile != nullptr); -} + mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile); - -static inline std::string GetExtension(const std::string &filename) -//----------------------------------------------------------------- -{ - if(filename.find_last_of(".") != std::string::npos) + if(index >= contents.size()) { - return filename.substr(filename.find_last_of(".") + 1); + return false; } - return std::string(); -} + mz_uint bestFile = index; -bool CZipArchive::ExtractFile() -//----------------------------- -{ - mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile); - - if(!zip) + mz_zip_archive_file_stat stat; + MemsetZero(stat); + mz_zip_reader_file_stat(zip, bestFile, &stat); + if(stat.m_uncomp_size >= std::numeric_limits<std::size_t>::max()) { return false; } - - mz_uint bestFile = (mz_uint)-1; - mz_uint64 biggestFile = 0; - for(mz_uint i = 0; i < mz_zip_reader_get_num_files(zip); ++i) + try { - mz_zip_archive_file_stat stat; - MemsetZero(stat); - if(!mz_zip_reader_file_stat(zip, i, &stat)) - { - continue; - } - if(mz_zip_reader_is_file_a_directory(zip, i)) - { - continue; - } - if(mz_zip_reader_is_file_encrypted(zip, i)) - { - continue; - } - std::string ext = GetExtension(stat.m_filename); - if(std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) - { - // File has a preferred extension: use it. - bestFile = i; - break; - } - if(ext != "diz" && ext != "nfo" && ext != "txt" && stat.m_uncomp_size >= biggestFile) - { - // If this isn't some kind of info file, we should maybe pick it. - bestFile = i; - biggestFile = stat.m_uncomp_size; - } - } - if(bestFile == (mz_uint)-1) + data.resize(static_cast<std::size_t>(stat.m_uncomp_size)); + } catch(...) { return false; } - delete [] outFile.GetRawData(); - mz_zip_archive_file_stat stat; - MemsetZero(stat); - mz_zip_reader_file_stat(zip, bestFile, &stat); - char *data = new (std::nothrow) char[stat.m_uncomp_size]; - if(data != nullptr) + if(!mz_zip_reader_extract_to_mem(zip, bestFile, &data[0], static_cast<std::size_t>(stat.m_uncomp_size), 0)) { - if(!mz_zip_reader_extract_to_mem(zip, bestFile, data, stat.m_uncomp_size, 0)) - { - delete [] data; - return false; - } - outFile = FileReader(data, stat.m_uncomp_size); - comment = std::string(stat.m_comment, stat.m_comment + stat.m_comment_size); + return false; } - + comment = std::string(stat.m_comment, stat.m_comment + stat.m_comment_size); return true; } -std::string CZipArchive::GetComments() -//------------------------------------ -{ - mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile); - - if(!zip) - { - return ""; - } - - return comment; -} - - #endif // NO_ZLIB || NO_MINIZ Modified: trunk/OpenMPT/unarchiver/unzip.h =================================================================== --- trunk/OpenMPT/unarchiver/unzip.h 2013-10-25 16:31:52 UTC (rev 3022) +++ trunk/OpenMPT/unarchiver/unzip.h 2013-10-25 16:59:10 UTC (rev 3023) @@ -9,23 +9,17 @@ #pragma once -//=============== -class CZipArchive -//=============== +#include "archive.h" + +//==================================== +class CZipArchive : public ArchiveBase +//==================================== { protected: - FileReader inFile, outFile; void *zipFile; - const std::vector<const char *> &extensions; - std::string comment; - public: - - FileReader GetOutputFile() const { return outFile; } - bool IsArchive() const; - bool ExtractFile(); - std::string GetComments(); - - CZipArchive(FileReader &file, const std::vector<const char *> &ext); - ~CZipArchive(); + CZipArchive(FileReader &file); + virtual ~CZipArchive(); +public: + virtual bool ExtractFile(std::size_t index); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |