summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/port/win/xpress_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rocksdb/port/win/xpress_win.cc')
-rw-r--r--src/rocksdb/port/win/xpress_win.cc226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/rocksdb/port/win/xpress_win.cc b/src/rocksdb/port/win/xpress_win.cc
new file mode 100644
index 000000000..bcc106534
--- /dev/null
+++ b/src/rocksdb/port/win/xpress_win.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
+// This source code is licensed under both the GPLv2 (found in the
+// COPYING file in the root directory) and Apache 2.0 License
+// (found in the LICENSE.Apache file in the root directory).
+//
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include "port/win/xpress_win.h"
+#include <windows.h>
+
+#include <cassert>
+#include <memory>
+#include <limits>
+#include <iostream>
+
+#ifdef XPRESS
+
+// Put this under ifdef so windows systems w/o this
+// can still build
+#include <compressapi.h>
+
+namespace ROCKSDB_NAMESPACE {
+namespace port {
+namespace xpress {
+
+// Helpers
+namespace {
+
+auto CloseCompressorFun = [](void* h) {
+ if (NULL != h) {
+ ::CloseCompressor(reinterpret_cast<COMPRESSOR_HANDLE>(h));
+ }
+};
+
+auto CloseDecompressorFun = [](void* h) {
+ if (NULL != h) {
+ ::CloseDecompressor(reinterpret_cast<DECOMPRESSOR_HANDLE>(h));
+ }
+};
+}
+
+bool Compress(const char* input, size_t length, std::string* output) {
+
+ assert(input != nullptr);
+ assert(output != nullptr);
+
+ if (length == 0) {
+ output->clear();
+ return true;
+ }
+
+ COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
+
+ COMPRESSOR_HANDLE compressor = NULL;
+
+ BOOL success = CreateCompressor(
+ COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
+ allocRoutinesPtr, // Optional allocation routine
+ &compressor); // Handle
+
+ if (!success) {
+#ifdef _DEBUG
+ std::cerr << "XPRESS: Failed to create Compressor LastError: " <<
+ GetLastError() << std::endl;
+#endif
+ return false;
+ }
+
+ std::unique_ptr<void, decltype(CloseCompressorFun)>
+ compressorGuard(compressor, CloseCompressorFun);
+
+ SIZE_T compressedBufferSize = 0;
+
+ // Query compressed buffer size.
+ success = ::Compress(
+ compressor, // Compressor Handle
+ const_cast<char*>(input), // Input buffer
+ length, // Uncompressed data size
+ NULL, // Compressed Buffer
+ 0, // Compressed Buffer size
+ &compressedBufferSize); // Compressed Data size
+
+ if (!success) {
+
+ auto lastError = GetLastError();
+
+ if (lastError != ERROR_INSUFFICIENT_BUFFER) {
+#ifdef _DEBUG
+ std::cerr <<
+ "XPRESS: Failed to estimate compressed buffer size LastError " <<
+ lastError << std::endl;
+#endif
+ return false;
+ }
+ }
+
+ assert(compressedBufferSize > 0);
+
+ std::string result;
+ result.resize(compressedBufferSize);
+
+ SIZE_T compressedDataSize = 0;
+
+ // Compress
+ success = ::Compress(
+ compressor, // Compressor Handle
+ const_cast<char*>(input), // Input buffer
+ length, // Uncompressed data size
+ &result[0], // Compressed Buffer
+ compressedBufferSize, // Compressed Buffer size
+ &compressedDataSize); // Compressed Data size
+
+ if (!success) {
+#ifdef _DEBUG
+ std::cerr << "XPRESS: Failed to compress LastError " <<
+ GetLastError() << std::endl;
+#endif
+ return false;
+ }
+
+ result.resize(compressedDataSize);
+ output->swap(result);
+
+ return true;
+}
+
+char* Decompress(const char* input_data, size_t input_length,
+ int* decompress_size) {
+
+ assert(input_data != nullptr);
+ assert(decompress_size != nullptr);
+
+ if (input_length == 0) {
+ return nullptr;
+ }
+
+ COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
+
+ DECOMPRESSOR_HANDLE decompressor = NULL;
+
+ BOOL success = CreateDecompressor(
+ COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
+ allocRoutinesPtr, // Optional allocation routine
+ &decompressor); // Handle
+
+
+ if (!success) {
+#ifdef _DEBUG
+ std::cerr << "XPRESS: Failed to create Decompressor LastError "
+ << GetLastError() << std::endl;
+#endif
+ return nullptr;
+ }
+
+ std::unique_ptr<void, decltype(CloseDecompressorFun)>
+ compressorGuard(decompressor, CloseDecompressorFun);
+
+ SIZE_T decompressedBufferSize = 0;
+
+ success = ::Decompress(
+ decompressor, // Compressor Handle
+ const_cast<char*>(input_data), // Compressed data
+ input_length, // Compressed data size
+ NULL, // Buffer set to NULL
+ 0, // Buffer size set to 0
+ &decompressedBufferSize); // Decompressed Data size
+
+ if (!success) {
+
+ auto lastError = GetLastError();
+
+ if (lastError != ERROR_INSUFFICIENT_BUFFER) {
+#ifdef _DEBUG
+ std::cerr
+ << "XPRESS: Failed to estimate decompressed buffer size LastError "
+ << lastError << std::endl;
+#endif
+ return nullptr;
+ }
+ }
+
+ assert(decompressedBufferSize > 0);
+
+ // On Windows we are limited to a 32-bit int for the
+ // output data size argument
+ // so we hopefully never get here
+ if (decompressedBufferSize > std::numeric_limits<int>::max()) {
+ assert(false);
+ return nullptr;
+ }
+
+ // The callers are deallocating using delete[]
+ // thus we must allocate with new[]
+ std::unique_ptr<char[]> outputBuffer(new char[decompressedBufferSize]);
+
+ SIZE_T decompressedDataSize = 0;
+
+ success = ::Decompress(
+ decompressor,
+ const_cast<char*>(input_data),
+ input_length,
+ outputBuffer.get(),
+ decompressedBufferSize,
+ &decompressedDataSize);
+
+ if (!success) {
+#ifdef _DEBUG
+ std::cerr <<
+ "XPRESS: Failed to decompress LastError " <<
+ GetLastError() << std::endl;
+#endif
+ return nullptr;
+ }
+
+ *decompress_size = static_cast<int>(decompressedDataSize);
+
+ // Return the raw buffer to the caller supporting the tradition
+ return outputBuffer.release();
+}
+}
+}
+} // namespace ROCKSDB_NAMESPACE
+
+#endif