diff options
Diffstat (limited to '')
-rw-r--r-- | Tools/MCADefrag/CMakeLists.txt | 8 | ||||
-rw-r--r-- | Tools/MCADefrag/Globals.cpp | 10 | ||||
-rw-r--r-- | Tools/MCADefrag/Globals.h | 174 | ||||
-rw-r--r-- | Tools/MCADefrag/MCADefrag.cpp | 84 | ||||
-rw-r--r-- | Tools/MCADefrag/MCADefrag.h | 17 |
5 files changed, 68 insertions, 225 deletions
diff --git a/Tools/MCADefrag/CMakeLists.txt b/Tools/MCADefrag/CMakeLists.txt index 6ad894390..86a16b98a 100644 --- a/Tools/MCADefrag/CMakeLists.txt +++ b/Tools/MCADefrag/CMakeLists.txt @@ -17,10 +17,6 @@ function(flatten_files arg1) endfunction() -# Include the libraries: - -add_subdirectory(../../lib/zlib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/lib/zlib) - # Include the shared files: set(SHARED_SRC ../../src/StringCompression.cpp @@ -66,11 +62,9 @@ source_group("Shared\\OSSupport" FILES ${SHARED_OSS_SRC} ${SHARED_OSS_HDR}) # Include the main source files: set(SOURCES MCADefrag.cpp - Globals.cpp ) set(HEADERS MCADefrag.h - Globals.h ) source_group("" FILES ${SOURCES} ${HEADERS}) @@ -84,7 +78,7 @@ add_executable(MCADefrag ${SHARED_OSS_HDR} ) -target_link_libraries(MCADefrag zlib fmt::fmt Threads::Threads) +target_link_libraries(MCADefrag fmt::fmt libdeflate Threads::Threads) include(../../SetFlags.cmake) set_exe_flags(MCADefrag) diff --git a/Tools/MCADefrag/Globals.cpp b/Tools/MCADefrag/Globals.cpp deleted file mode 100644 index 13c6ae709..000000000 --- a/Tools/MCADefrag/Globals.cpp +++ /dev/null @@ -1,10 +0,0 @@ - -// Globals.cpp - -// This file is used for precompiled header generation in MSVC environments - -#include "Globals.h" - - - - diff --git a/Tools/MCADefrag/Globals.h b/Tools/MCADefrag/Globals.h deleted file mode 100644 index def1fbdb9..000000000 --- a/Tools/MCADefrag/Globals.h +++ /dev/null @@ -1,174 +0,0 @@ - -// Globals.h - -// This file gets included from every module in the project, so that global symbols may be introduced easily -// Also used for precompiled header generation in MSVC environments - - - - - -// Compiler-dependent stuff: -#if defined(_MSC_VER) - // MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether - #pragma warning(disable:4481) - - // Disable some warnings that we don't care about: - #pragma warning(disable:4100) - -#elif defined(__GNUC__) - - // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? - #define abstract - -#else - - #error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler" - -#endif - - - - - -// Integral types with predefined sizes: -typedef long long Int64; -typedef int Int32; -typedef short Int16; - -typedef unsigned long long UInt64; -typedef unsigned int UInt32; -typedef unsigned short UInt16; - -typedef unsigned char Byte; - - - - - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for any class that shouldn't allow copying itself -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &); \ - void operator=(const TypeName &) - -// A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc -#define UNUSED(X) (void)(X) - - - - -// OS-dependent stuff: -#ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #include <Windows.h> - #include <winsock2.h> - #include <ws2tcpip.h> - - // Windows SDK defines min and max macros, messing up with our std::min and std::max usage - #undef min - #undef max - - // Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant - #ifdef GetFreeSpace - #undef GetFreeSpace - #endif // GetFreeSpace - - #define SocketError WSAGetLastError() -#else - #include <sys/types.h> - #include <sys/stat.h> // for mkdir - #include <sys/time.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <arpa/inet.h> - #include <netdb.h> - #include <dirent.h> - #include <iostream> - #include <unistd.h> - - #include <cstring> - #include <pthread.h> - #include <semaphore.h> - #include <cerrno> - #include <fcntl.h> - - typedef int SOCKET; - enum - { - INVALID_SOCKET = -1, - }; - #define closesocket close - #define SocketError errno -#endif - - - - - -// CRT stuff: -#include <cassert> -#include <cstdio> -#include <cmath> -#include <cstdarg> -#include <ctime> - - - - - -// STL stuff: -#include <vector> -#include <list> -#include <deque> -#include <string> -#include <map> -#include <algorithm> -#include <memory> -#include <atomic> -#include <mutex> -#include <thread> -#include <condition_variable> - - - - -// Common headers (without macros): -#include "fmt.h" -#include "LoggerSimple.h" -#include "StringUtils.h" -#include "OSSupport/CriticalSection.h" -#include "OSSupport/Event.h" -#include "OSSupport/IsThread.h" -#include "OSSupport/File.h" - - - - - -// Common definitions: - -/** Evaluates to the number of elements in an array (compile-time!) */ -#define ARRAYCOUNT(X) (sizeof(X) / sizeof(*(X))) - -/** Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it, "(32 KiB)") */ -#define KiB * 1024 -#define MiB * 1024 * 1024 - -/** Faster than (int)floorf((float)x / (float)div) */ -#define FAST_FLOOR_DIV(x, div) ((x) < 0 ? (((int)x / div) - 1) : ((int)x / div)) - -// Own version of assert() that writes failed assertions to the log for review -#ifdef NDEBUG - #define ASSERT(x) ((void)0) -#else - #define ASSERT assert -#endif - -// Pretty much the same as ASSERT() but stays in Release builds -#define VERIFY(x) (!!(x) || (LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__), exit(1), 0)) - - - - - diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index c7886da35..d11505d45 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -8,7 +8,6 @@ #include "Logger.h" #include "LoggerSimple.h" #include "LoggerListeners.h" -#include "zlib/zlib.h" @@ -129,7 +128,8 @@ AString cMCADefrag::GetNextFileName(void) cMCADefrag::cThread::cThread(cMCADefrag & a_Parent) : super("MCADefrag thread"), m_Parent(a_Parent), - m_IsChunkUncompressed(false) + m_IsChunkUncompressed(false), + m_Compressor(12) // Set the highest compression factor { } @@ -384,27 +384,33 @@ bool cMCADefrag::cThread::UncompressChunkGzip(void) bool cMCADefrag::cThread::UncompressChunkZlib(void) { - // Uncompress the data: - z_stream strm; - strm.zalloc = nullptr; - strm.zfree = nullptr; - strm.opaque = nullptr; - inflateInit(&strm); - strm.next_out = m_RawChunkData; - strm.avail_out = sizeof(m_RawChunkData); - strm.next_in = m_CompressedChunkData + 1; // The first byte is the compression method, skip it - strm.avail_in = static_cast<uInt>(m_CompressedChunkDataSize); - int res = inflate(&strm, Z_FINISH); - inflateEnd(&strm); - if (res != Z_STREAM_END) + try { - LOGWARNING("Failed to uncompress chunk data: %s", strm.msg); + // Uncompress the data + + const auto ExtractedData = m_Extractor.ExtractZLib( + { + reinterpret_cast<const std::byte *>(m_CompressedChunkData + 1), // The first byte is the compression method, skip it + static_cast<size_t>(m_CompressedChunkDataSize - 1) + }); + const auto Extracted = ExtractedData.GetView(); + + if (Extracted.size() > MAX_RAW_CHUNK_DATA_SIZE) + { + LOGINFO("Too much data for the internal decompression buffer!"); + return false; + } + + std::copy(Extracted.begin(), Extracted.end(), reinterpret_cast<std::byte *>(m_RawChunkData)); + m_RawChunkDataSize = static_cast<int>(Extracted.size()); + + return true; + } + catch (const std::exception & Oops) + { + LOGWARNING("Failed to uncompress chunk data. %s", Oops.what()); return false; } - ASSERT(strm.total_out < static_cast<uLong>(std::numeric_limits<int>::max())); - m_RawChunkDataSize = static_cast<int>(strm.total_out); - - return true; } @@ -413,23 +419,33 @@ bool cMCADefrag::cThread::UncompressChunkZlib(void) bool cMCADefrag::cThread::CompressChunk(void) { - // Check that the compressed data can fit: - uLongf CompressedSize = compressBound(static_cast<uLong>(m_RawChunkDataSize)); - if (CompressedSize > sizeof(m_CompressedChunkData)) + try { - LOGINFO("Too much data for the internal compression buffer!"); - return false; - } + // Compress the data (using the highest compression factor, as set in the constructor) + + const auto CompressedData = m_Compressor.CompressZLib( + { + reinterpret_cast<const std::byte *>(m_RawChunkData), + static_cast<size_t>(m_RawChunkDataSize) + }); + const auto Compressed = CompressedData.GetView(); + + // Check that the compressed data can fit: + if (Compressed.size() > MAX_COMPRESSED_CHUNK_DATA_SIZE) + { + LOGINFO("Too much data for the internal compression buffer!"); + return false; + } + + m_CompressedChunkData[0] = COMPRESSION_ZLIB; + std::copy(Compressed.begin(), Compressed.end(), reinterpret_cast<std::byte *>(m_CompressedChunkData + 1)); + m_CompressedChunkDataSize = static_cast<int>(Compressed.size()) + 1; - // Compress the data using the highest compression factor: - int errorcode = compress2(m_CompressedChunkData + 1, &CompressedSize, m_RawChunkData, static_cast<uLong>(m_RawChunkDataSize), Z_BEST_COMPRESSION); - if (errorcode != Z_OK) + return true; + } + catch (const std::exception & Oops) { - LOGINFO("Recompression failed: %d", errorcode); + LOGWARNING("Recompression failed. %s", Oops.what()); return false; } - m_CompressedChunkData[0] = COMPRESSION_ZLIB; - ASSERT(CompressedSize < static_cast<uLong>(std::numeric_limits<int>::max())); - m_CompressedChunkDataSize = static_cast<int>(CompressedSize + 1); - return true; } diff --git a/Tools/MCADefrag/MCADefrag.h b/Tools/MCADefrag/MCADefrag.h index cddaef625..cc151d032 100644 --- a/Tools/MCADefrag/MCADefrag.h +++ b/Tools/MCADefrag/MCADefrag.h @@ -13,10 +13,18 @@ +#include "OSSupport/IsThread.h" +#include "StringCompression.h" + + + + + class cMCADefrag { public: + enum { MAX_COMPRESSED_CHUNK_DATA_SIZE = (1 MiB), @@ -33,6 +41,7 @@ public: void Run(void); protected: + /** A single thread processing MCA files from the queue */ class cThread : public cIsThread @@ -40,9 +49,11 @@ protected: typedef cIsThread super; public: + cThread(cMCADefrag & a_Parent); protected: + /** The compression methods, as specified by the MCA compression method byte. */ enum { @@ -75,6 +86,12 @@ protected: WriteChunk() tests this flag to decide whether to call Compress(). */ bool m_IsChunkUncompressed; + /** An instance of the compressor. */ + Compression::Compressor m_Compressor; + + /** An instance of the extractor. */ + Compression::Extractor m_Extractor; + /** Processes the specified file. */ void ProcessFile(const AString & a_FileName); |