diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 1671cecc8a..b97a33b90e 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -369,7 +369,7 @@ public: if (!File::Exists(_rFilename)) return false; - // Check file size + // Check file size - most probably it can't compress THAT well. const u64 fileSize = File::GetSize(_rFilename); static const u64 headerSize = sizeof(SChunkHeader); if (fileSize < headerSize) @@ -378,7 +378,7 @@ public: return false; } - File::IOFile pFile(_rFilename, "rb"); + File::IOFile pFile(_rFilename, "rb", File::METHOD_GZIP); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); @@ -402,11 +402,11 @@ public: } // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) + const int sz = header.ExpectedSize; + if (sz > 128 * 1024 * 1024) { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); + ERROR_LOG(COMMON,"ChunkReader: File too large, got %d bytes", + header.ExpectedSize); return false; } @@ -432,7 +432,7 @@ public: static bool Save(const std::string& _rFilename, int _Revision, T& _class) { INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - File::IOFile pFile(_rFilename, "wb"); + File::IOFile pFile(_rFilename, "wb9", File::METHOD_GZIP); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 8ba82fa901..47207e00a7 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -767,17 +767,17 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) } IOFile::IOFile() - : m_file(NULL), m_good(true) + : m_file(NULL), m_zFile(NULL), m_good(true) {} IOFile::IOFile(std::FILE* file) - : m_file(file), m_good(true) + : m_file(file), m_zFile(NULL), m_good(true) {} -IOFile::IOFile(const std::string& filename, const char openmode[]) - : m_file(NULL), m_good(true) +IOFile::IOFile(const std::string& filename, const char openmode[], IOFileMethod method) + : m_file(NULL), m_zFile(NULL), m_good(true), m_method(method) { - Open(filename, openmode); + Open(filename, openmode, method); } IOFile::~IOFile() @@ -785,14 +785,21 @@ IOFile::~IOFile() Close(); } -bool IOFile::Open(const std::string& filename, const char openmode[]) +bool IOFile::Open(const std::string& filename, const char openmode[], IOFileMethod method) { Close(); + + m_method = method; + if (0 != (m_method & METHOD_GZIP)) + m_zFile = gzopen(filename.c_str(), openmode); + else + { #ifdef _WIN32 - fopen_s(&m_file, filename.c_str(), openmode); + fopen_s(&m_file, filename.c_str(), openmode); #else - m_file = fopen(filename.c_str(), openmode); + m_file = fopen(filename.c_str(), openmode); #endif + } m_good = IsOpen(); return m_good; @@ -800,10 +807,19 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) bool IOFile::Close() { - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; + if (0 != (m_method & METHOD_GZIP)) + { + if (Z_OK != gzclose(m_zFile)) + m_good = false; + m_zFile = NULL; + } + else + { + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; + m_file = NULL; + } - m_file = NULL; return m_good; } @@ -819,19 +835,32 @@ void IOFile::SetHandle(std::FILE* file) Close(); Clear(); m_file = file; + m_method = METHOD_STANDARD; } u64 IOFile::GetSize() { if (IsOpen()) + { + // Not supported. + if (0 != (m_method & METHOD_GZIP)) + return 0; return File::GetSize(m_file); + } else return 0; } bool IOFile::Seek(s64 off, int origin) { - if (!IsOpen() || 0 != fseeko(m_file, off, origin)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (-1 == gzseek(m_zFile, (z_off_t) off, origin)) + m_good = false; + } + else if (0 != fseeko(m_file, off, origin)) m_good = false; return m_good; @@ -840,14 +869,26 @@ bool IOFile::Seek(s64 off, int origin) u64 IOFile::Tell() { if (IsOpen()) + { + if (0 != (m_method & METHOD_GZIP)) + return gztell(m_zFile); + return ftello(m_file); + } else return -1; } bool IOFile::Flush() { - if (!IsOpen() || 0 != std::fflush(m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (-1 == gzflush(m_zFile, Z_PARTIAL_FLUSH)) + m_good = false; + } + else if (0 != std::fflush(m_file)) m_good = false; return m_good; @@ -855,7 +896,15 @@ bool IOFile::Flush() bool IOFile::Resize(u64 size) { - if (!IsOpen() || 0 != + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + // gzseek() adds nulls to the seeked location. + if (-1 == gzseek(m_zFile, (z_off_t) size, SEEK_SET)) + m_good = false; + } + else if (0 != #ifdef _WIN32 // ector: _chsize sucks, not 64-bit safe // F|RES: changed to _chsize_s. i think it is 64-bit safe diff --git a/Common/FileUtil.h b/Common/FileUtil.h index 4c9a86f5cf..12a79ea730 100644 --- a/Common/FileUtil.h +++ b/Common/FileUtil.h @@ -25,6 +25,7 @@ #include #include "Common.h" +#include "../ext/zlib/zlib.h" // User directory indices for GetUserPath enum { @@ -124,6 +125,13 @@ std::string &GetExeDirectory(); bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); bool ReadFileToString(bool text_file, const char *filename, std::string &str); +enum IOFileMethod +{ + METHOD_STANDARD = 0x00, + // Warning: may not be 64-bit safe. + METHOD_GZIP = 0x01, +}; + // simple wrapper for cstdlib file functions to // hopefully will make error checking easier // and make forgetting an fclose() harder @@ -132,17 +140,24 @@ class IOFile : NonCopyable public: IOFile(); IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); + IOFile(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); ~IOFile(); - bool Open(const std::string& filename, const char openmode[]); + bool Open(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); bool Close(); template bool ReadArray(T* data, size_t length) { - if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (sizeof(T) * length != gzread(m_zFile, data, sizeof(T) * length)) + m_good = false; + } + else if (length != std::fread(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -151,7 +166,14 @@ public: template bool WriteArray(const T* data, size_t length) { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (sizeof(T) * length != gzwrite(m_zFile, data, sizeof(T) * length)) + m_good = false; + } + else if (length != std::fwrite(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -167,11 +189,11 @@ public: return WriteArray(reinterpret_cast(data), length); } - bool IsOpen() { return NULL != m_file; } + bool IsOpen() { return NULL != m_file || NULL != m_zFile; } // m_good is set to false when a read, write or other function fails bool IsGood() { return m_good; } - operator void*() { return m_good ? m_file : NULL; } + operator void*() { return m_good ? (NULL != m_file ? m_file : m_zFile) : NULL; } std::FILE* ReleaseHandle(); @@ -189,13 +211,18 @@ public: void Clear() { m_good = true; #undef clearerr - std::clearerr(m_file); + if (NULL != m_file) + std::clearerr(m_file); + if (NULL != m_zFile) + gzclearerr(m_zFile); } private: IOFile& operator=(const IOFile&) /*= delete*/; std::FILE* m_file; + gzFile m_zFile; + IOFileMethod m_method; bool m_good; };