xpress_win.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include "port/win/xpress_win.h"
  10. #include <windows.h>
  11. #include <cassert>
  12. #include <memory>
  13. #include <limits>
  14. #include <iostream>
  15. #ifdef XPRESS
  16. // Put this under ifdef so windows systems w/o this
  17. // can still build
  18. #include <compressapi.h>
  19. namespace ROCKSDB_NAMESPACE {
  20. namespace port {
  21. namespace xpress {
  22. // Helpers
  23. namespace {
  24. auto CloseCompressorFun = [](void* h) {
  25. if (NULL != h) {
  26. ::CloseCompressor(reinterpret_cast<COMPRESSOR_HANDLE>(h));
  27. }
  28. };
  29. auto CloseDecompressorFun = [](void* h) {
  30. if (NULL != h) {
  31. ::CloseDecompressor(reinterpret_cast<DECOMPRESSOR_HANDLE>(h));
  32. }
  33. };
  34. }
  35. bool Compress(const char* input, size_t length, std::string* output) {
  36. assert(input != nullptr);
  37. assert(output != nullptr);
  38. if (length == 0) {
  39. output->clear();
  40. return true;
  41. }
  42. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  43. COMPRESSOR_HANDLE compressor = NULL;
  44. BOOL success = CreateCompressor(
  45. COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  46. allocRoutinesPtr, // Optional allocation routine
  47. &compressor); // Handle
  48. if (!success) {
  49. #ifdef _DEBUG
  50. std::cerr << "XPRESS: Failed to create Compressor LastError: " <<
  51. GetLastError() << std::endl;
  52. #endif
  53. return false;
  54. }
  55. std::unique_ptr<void, decltype(CloseCompressorFun)>
  56. compressorGuard(compressor, CloseCompressorFun);
  57. SIZE_T compressedBufferSize = 0;
  58. // Query compressed buffer size.
  59. success = ::Compress(
  60. compressor, // Compressor Handle
  61. const_cast<char*>(input), // Input buffer
  62. length, // Uncompressed data size
  63. NULL, // Compressed Buffer
  64. 0, // Compressed Buffer size
  65. &compressedBufferSize); // Compressed Data size
  66. if (!success) {
  67. auto lastError = GetLastError();
  68. if (lastError != ERROR_INSUFFICIENT_BUFFER) {
  69. #ifdef _DEBUG
  70. std::cerr <<
  71. "XPRESS: Failed to estimate compressed buffer size LastError " <<
  72. lastError << std::endl;
  73. #endif
  74. return false;
  75. }
  76. }
  77. assert(compressedBufferSize > 0);
  78. std::string result;
  79. result.resize(compressedBufferSize);
  80. SIZE_T compressedDataSize = 0;
  81. // Compress
  82. success = ::Compress(
  83. compressor, // Compressor Handle
  84. const_cast<char*>(input), // Input buffer
  85. length, // Uncompressed data size
  86. &result[0], // Compressed Buffer
  87. compressedBufferSize, // Compressed Buffer size
  88. &compressedDataSize); // Compressed Data size
  89. if (!success) {
  90. #ifdef _DEBUG
  91. std::cerr << "XPRESS: Failed to compress LastError " <<
  92. GetLastError() << std::endl;
  93. #endif
  94. return false;
  95. }
  96. result.resize(compressedDataSize);
  97. output->swap(result);
  98. return true;
  99. }
  100. char* Decompress(const char* input_data, size_t input_length,
  101. int* decompress_size) {
  102. assert(input_data != nullptr);
  103. assert(decompress_size != nullptr);
  104. if (input_length == 0) {
  105. return nullptr;
  106. }
  107. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  108. DECOMPRESSOR_HANDLE decompressor = NULL;
  109. BOOL success = CreateDecompressor(
  110. COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  111. allocRoutinesPtr, // Optional allocation routine
  112. &decompressor); // Handle
  113. if (!success) {
  114. #ifdef _DEBUG
  115. std::cerr << "XPRESS: Failed to create Decompressor LastError "
  116. << GetLastError() << std::endl;
  117. #endif
  118. return nullptr;
  119. }
  120. std::unique_ptr<void, decltype(CloseDecompressorFun)>
  121. compressorGuard(decompressor, CloseDecompressorFun);
  122. SIZE_T decompressedBufferSize = 0;
  123. success = ::Decompress(
  124. decompressor, // Compressor Handle
  125. const_cast<char*>(input_data), // Compressed data
  126. input_length, // Compressed data size
  127. NULL, // Buffer set to NULL
  128. 0, // Buffer size set to 0
  129. &decompressedBufferSize); // Decompressed Data size
  130. if (!success) {
  131. auto lastError = GetLastError();
  132. if (lastError != ERROR_INSUFFICIENT_BUFFER) {
  133. #ifdef _DEBUG
  134. std::cerr
  135. << "XPRESS: Failed to estimate decompressed buffer size LastError "
  136. << lastError << std::endl;
  137. #endif
  138. return nullptr;
  139. }
  140. }
  141. assert(decompressedBufferSize > 0);
  142. // On Windows we are limited to a 32-bit int for the
  143. // output data size argument
  144. // so we hopefully never get here
  145. if (decompressedBufferSize > std::numeric_limits<int>::max()) {
  146. assert(false);
  147. return nullptr;
  148. }
  149. // The callers are deallocating using delete[]
  150. // thus we must allocate with new[]
  151. std::unique_ptr<char[]> outputBuffer(new char[decompressedBufferSize]);
  152. SIZE_T decompressedDataSize = 0;
  153. success = ::Decompress(
  154. decompressor,
  155. const_cast<char*>(input_data),
  156. input_length,
  157. outputBuffer.get(),
  158. decompressedBufferSize,
  159. &decompressedDataSize);
  160. if (!success) {
  161. #ifdef _DEBUG
  162. std::cerr <<
  163. "XPRESS: Failed to decompress LastError " <<
  164. GetLastError() << std::endl;
  165. #endif
  166. return nullptr;
  167. }
  168. *decompress_size = static_cast<int>(decompressedDataSize);
  169. // Return the raw buffer to the caller supporting the tradition
  170. return outputBuffer.release();
  171. }
  172. }
  173. }
  174. } // namespace ROCKSDB_NAMESPACE
  175. #endif