| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // 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
|