From eeb63b8901a9c049f1bb594abb9ce9b4a9c47620 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 11 Jan 2021 16:39:43 +0000 Subject: zlib -> libdeflate (#5085) + Use libdeflate + Use std::byte * Fix passing temporary to string_view + Emulate make_unique_for_overwrite --- src/OSSupport/File.cpp | 67 +++++++++++++++++++++++++++----- src/OSSupport/File.h | 27 +++++++------ src/OSSupport/GZipFile.cpp | 96 ++++------------------------------------------ src/OSSupport/GZipFile.h | 41 ++++---------------- 4 files changed, 88 insertions(+), 143 deletions(-) (limited to 'src/OSSupport') diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 8c5eb92a4..618463bd6 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -157,19 +157,18 @@ int cFile::Read (void * a_Buffer, size_t a_NumBytes) -AString cFile::Read(size_t a_NumBytes) +ContiguousByteBuffer cFile::Read(size_t a_NumBytes) { ASSERT(IsOpen()); if (!IsOpen()) { - return AString(); + return {}; } - // HACK: This depends on the knowledge that AString::data() returns the internal buffer, rather than a copy of it. - AString res; - res.resize(a_NumBytes); - auto newSize = fread(const_cast(res.data()), 1, a_NumBytes, m_File); + ContiguousByteBuffer res; + res.resize(a_NumBytes); // TODO: investigate if worth hacking around std::string internals to avoid initialisation + auto newSize = fread(res.data(), sizeof(std::byte), a_NumBytes, m_File); res.resize(newSize); return res; } @@ -284,9 +283,8 @@ int cFile::ReadRestOfFile(AString & a_Contents) auto DataSize = static_cast(TotalSize - Position); - // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly - a_Contents.assign(DataSize, '\0'); - return Read(static_cast(const_cast(a_Contents.data())), DataSize); + a_Contents.resize(DataSize); // TODO: investigate if worth hacking around std::string internals to avoid initialisation + return Read(a_Contents.data(), DataSize); } @@ -709,3 +707,54 @@ void cFile::Flush(void) { fflush(m_File); } + + + + + +template +FileStream::FileStream(const std::string & Path) +{ + // Except on failbit, which is what open sets on failure: + FileStream::exceptions(FileStream::failbit | FileStream::badbit); + + // Open the file: + FileStream::open(Path); + + // Only subsequently except on serious errors, and not on conditions like EOF or malformed input: + FileStream::exceptions(FileStream::badbit); +} + + + + + +template +FileStream::FileStream(const std::string & Path, const typename FileStream::openmode Mode) +{ + // Except on failbit, which is what open sets on failure: + FileStream::exceptions(FileStream::failbit | FileStream::badbit); + + // Open the file: + FileStream::open(Path, Mode); + + // Only subsequently except on serious errors, and not on conditions like EOF or malformed input: + FileStream::exceptions(FileStream::badbit); +} + + + + + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-template-vtables" // http://bugs.llvm.org/show_bug.cgi?id=18733 +#endif + +// Instantiate the templated wrapper for input and output: +template class FileStream; +template class FileStream; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index 59f3a5558..7a3333483 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -75,7 +75,7 @@ public: int Read(void * a_Buffer, size_t a_NumBytes); /** Reads up to a_NumBytes bytes, returns the bytes actually read, or empty string on failure; asserts if not open */ - AString Read(size_t a_NumBytes); + std::basic_string Read(size_t a_NumBytes); /** Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */ int Write(const void * a_Buffer, size_t a_NumBytes); @@ -192,17 +192,8 @@ class FileStream final : public StreamType { public: - FileStream(const std::string & Path) - { - // Except on failbit, which is what open sets on failure: - FileStream::exceptions(FileStream::failbit | FileStream::badbit); - - // Open the file: - FileStream::open(Path); - - // Only subsequently except on serious errors, and not on conditions like EOF or malformed input: - FileStream::exceptions(FileStream::badbit); - } + FileStream(const std::string & Path); + FileStream(const std::string & Path, const typename FileStream::openmode Mode); }; @@ -211,3 +202,15 @@ public: using InputFileStream = FileStream; using OutputFileStream = FileStream; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-template-vtables" // http://bugs.llvm.org/show_bug.cgi?id=18733 +#endif + +extern template class FileStream; +extern template class FileStream; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index e83d42583..0bf26dfed 100644 --- a/src/OSSupport/GZipFile.cpp +++ b/src/OSSupport/GZipFile.cpp @@ -4,107 +4,27 @@ // Implements the cGZipFile class representing a RAII wrapper over zlib's GZip file routines #include "Globals.h" +#include "File.h" #include "GZipFile.h" -cGZipFile::cGZipFile(void) : - m_File(nullptr), m_Mode(fmRead) +Compression::Result GZipFile::ReadRestOfFile(const std::string & a_FileName) { -} - - - - - -cGZipFile::~cGZipFile() -{ - Close(); -} - + InputFileStream File(a_FileName, InputFileStream::binary); + const std::string Input{ std::istreambuf_iterator(File), std::istreambuf_iterator() }; + const ContiguousByteBufferView Data{ reinterpret_cast(Input.data()), Input.size() }; - - - -bool cGZipFile::Open(const AString & a_FileName, eMode a_Mode) -{ - if (m_File != nullptr) - { - ASSERT(!"A file is already open in this object"); - return false; - } - m_File = gzopen(a_FileName.c_str(), (a_Mode == fmRead) ? "r" : "w"); - m_Mode = a_Mode; - return (m_File != nullptr); + return Compression::Extractor().ExtractGZip(Data); } -void cGZipFile::Close(void) +void GZipFile::Write(const std::string & a_FileName, ContiguousByteBufferView a_Contents) { - if (m_File != nullptr) - { - gzclose(m_File); - m_File = nullptr; - } + OutputFileStream(a_FileName, OutputFileStream::binary) << Compression::Compressor().CompressGZip(a_Contents).GetStringView(); } - - - - - -int cGZipFile::ReadRestOfFile(AString & a_Contents) -{ - if (m_File == nullptr) - { - ASSERT(!"No file has been opened"); - return -1; - } - - if (m_Mode != fmRead) - { - ASSERT(!"Bad file mode, cannot read"); - return -1; - } - - // Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck! - int NumBytesRead = 0; - int TotalBytes = 0; - char Buffer[64 KiB]; - while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0) - { - TotalBytes += NumBytesRead; - a_Contents.append(Buffer, static_cast(NumBytesRead)); - } - // NumBytesRead is < 0 on error - return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead; -} - - - - - -bool cGZipFile::Write(const char * a_Contents, int a_Size) -{ - if (m_File == nullptr) - { - ASSERT(!"No file has been opened"); - return false; - } - - if (m_Mode != fmWrite) - { - ASSERT(!"Bad file mode, cannot write"); - return false; - } - - return (gzwrite(m_File, a_Contents, static_cast(a_Size)) != 0); -} - - - - diff --git a/src/OSSupport/GZipFile.h b/src/OSSupport/GZipFile.h index 00a2fd717..dd4999339 100644 --- a/src/OSSupport/GZipFile.h +++ b/src/OSSupport/GZipFile.h @@ -1,7 +1,7 @@ // GZipFile.h -// Declares the cGZipFile class representing a RAII wrapper over zlib's GZip file routines +// Declares the GZipFile namespace representing a wrapper over a file stream that can read and write to GZip'd files @@ -9,44 +9,17 @@ #pragma once -#include "zlib/zlib.h" +#include "StringCompression.h" -class cGZipFile +namespace GZipFile { -public: - enum eMode - { - fmRead, // Read-only. If the file doesn't exist, object will not be valid - fmWrite, // Write-only. If the file already exists, it will be overwritten - } ; + /** Reads the rest of the file and returns the decompressed contents. */ + Compression::Result ReadRestOfFile(const std::string & a_FileName); - cGZipFile(void); - ~cGZipFile(); - - /** Opens the file. Returns true if successful. Fails if a file has already been opened through this object. */ - bool Open(const AString & a_FileName, eMode a_Mode); - - /** Closes the file, flushing all buffers. This object may be then reused for a different file and / or mode */ - void Close(void); - - /** Reads the rest of the file and decompresses it into a_Contents. Returns the number of decompressed bytes, <0 for error */ - int ReadRestOfFile(AString & a_Contents); - - /** Writes a_Contents into file, compressing it along the way. Returns true if successful. Multiple writes are supported. */ - bool Write(const AString & a_Contents) { return Write(a_Contents.data(), static_cast(a_Contents.size())); } - - bool Write(const char * a_Data, int a_Size); - -protected: - gzFile m_File; - eMode m_Mode; + /** Writes a_Contents into file, compressing it along the way. */ + void Write(const std::string & a_FileName, ContiguousByteBufferView a_Contents); } ; - - - - - -- cgit v1.2.3