xpress_win.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. #if defined(OS_WIN)
  10. #include "port/win/xpress_win.h"
  11. #include <windows.h>
  12. #include <cassert>
  13. #include <iostream>
  14. #include <limits>
  15. #include <memory>
  16. #ifdef XPRESS
  17. // Put this under ifdef so windows systems w/o this
  18. // can still build
  19. #include <compressapi.h>
  20. namespace ROCKSDB_NAMESPACE {
  21. namespace port {
  22. namespace xpress {
  23. // Helpers
  24. namespace {
  25. auto CloseCompressorFun = [](void* h) {
  26. if (NULL != h) {
  27. ::CloseCompressor(reinterpret_cast<COMPRESSOR_HANDLE>(h));
  28. }
  29. };
  30. auto CloseDecompressorFun = [](void* h) {
  31. if (NULL != h) {
  32. ::CloseDecompressor(reinterpret_cast<DECOMPRESSOR_HANDLE>(h));
  33. }
  34. };
  35. } // namespace
  36. bool Compress(const char* input, size_t length, std::string* output) {
  37. assert(input != nullptr);
  38. assert(output != nullptr);
  39. if (length == 0) {
  40. output->clear();
  41. return true;
  42. }
  43. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  44. COMPRESSOR_HANDLE compressor = NULL;
  45. BOOL success =
  46. CreateCompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  47. allocRoutinesPtr, // Optional allocation routine
  48. &compressor); // Handle
  49. if (!success) {
  50. #ifdef _DEBUG
  51. std::cerr << "XPRESS: Failed to create Compressor LastError: "
  52. << GetLastError() << std::endl;
  53. #endif
  54. return false;
  55. }
  56. std::unique_ptr<void, decltype(CloseCompressorFun)> compressorGuard(
  57. compressor, CloseCompressorFun);
  58. SIZE_T compressedBufferSize = 0;
  59. // Query compressed buffer size.
  60. success = ::Compress(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(compressor, // Compressor Handle
  83. const_cast<char*>(input), // Input buffer
  84. length, // Uncompressed data size
  85. &result[0], // Compressed Buffer
  86. compressedBufferSize, // Compressed Buffer size
  87. &compressedDataSize); // Compressed Data size
  88. if (!success) {
  89. #ifdef _DEBUG
  90. std::cerr << "XPRESS: Failed to compress LastError " << GetLastError()
  91. << std::endl;
  92. #endif
  93. return false;
  94. }
  95. result.resize(compressedDataSize);
  96. output->swap(result);
  97. return true;
  98. }
  99. size_t CompressWithMaxSize(const char* input, size_t length, char* output,
  100. size_t max_output_size) {
  101. assert(input != nullptr);
  102. if (max_output_size == 0) {
  103. return 0;
  104. }
  105. assert(output != nullptr);
  106. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  107. COMPRESSOR_HANDLE compressor = NULL;
  108. BOOL success =
  109. CreateCompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  110. allocRoutinesPtr, // Optional allocation routine
  111. &compressor); // Handle
  112. if (!success) {
  113. #ifdef _DEBUG
  114. std::cerr << "XPRESS: Failed to create Compressor LastError: "
  115. << GetLastError() << std::endl;
  116. #endif
  117. return 0;
  118. }
  119. std::unique_ptr<void, decltype(CloseCompressorFun)> compressorGuard(
  120. compressor, CloseCompressorFun);
  121. SIZE_T compressed_size = 0;
  122. // Compress
  123. success = ::Compress(compressor, // Compressor Handle
  124. const_cast<char*>(input), // Input buffer
  125. length, // Uncompressed data size
  126. output, // Compressed Buffer
  127. max_output_size, // Compressed Buffer size
  128. &compressed_size); // Compressed Data size
  129. if (!success) {
  130. #ifdef _DEBUG
  131. auto error = GetLastError();
  132. if (error != ERROR_INSUFFICIENT_BUFFER) {
  133. std::cerr << "XPRESS: Failed to compress LastError " << error
  134. << std::endl;
  135. }
  136. #endif
  137. return 0;
  138. } else {
  139. return compressed_size;
  140. }
  141. }
  142. char* Decompress(const char* input_data, size_t input_length,
  143. size_t* uncompressed_size) {
  144. assert(input_data != nullptr);
  145. assert(uncompressed_size != nullptr);
  146. if (input_length == 0) {
  147. return nullptr;
  148. }
  149. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  150. DECOMPRESSOR_HANDLE decompressor = NULL;
  151. BOOL success =
  152. CreateDecompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  153. allocRoutinesPtr, // Optional allocation routine
  154. &decompressor); // Handle
  155. if (!success) {
  156. #ifdef _DEBUG
  157. std::cerr << "XPRESS: Failed to create Decompressor LastError "
  158. << GetLastError() << std::endl;
  159. #endif
  160. return nullptr;
  161. }
  162. std::unique_ptr<void, decltype(CloseDecompressorFun)> decompressorGuard(
  163. decompressor, CloseDecompressorFun);
  164. SIZE_T decompressedBufferSize = 0;
  165. success = ::Decompress(decompressor, // Compressor Handle
  166. const_cast<char*>(input_data), // Compressed data
  167. input_length, // Compressed data size
  168. NULL, // Buffer set to NULL
  169. 0, // Buffer size set to 0
  170. &decompressedBufferSize); // Decompressed Data size
  171. if (!success) {
  172. auto lastError = GetLastError();
  173. if (lastError != ERROR_INSUFFICIENT_BUFFER) {
  174. #ifdef _DEBUG
  175. std::cerr
  176. << "XPRESS: Failed to estimate decompressed buffer size LastError "
  177. << lastError << std::endl;
  178. #endif
  179. return nullptr;
  180. }
  181. }
  182. assert(decompressedBufferSize > 0);
  183. // The callers are deallocating using delete[]
  184. // thus we must allocate with new[]
  185. std::unique_ptr<char[]> outputBuffer(new char[decompressedBufferSize]);
  186. SIZE_T decompressedDataSize = 0;
  187. success = ::Decompress(decompressor, const_cast<char*>(input_data),
  188. input_length, outputBuffer.get(),
  189. decompressedBufferSize, &decompressedDataSize);
  190. if (!success) {
  191. #ifdef _DEBUG
  192. std::cerr << "XPRESS: Failed to decompress LastError " << GetLastError()
  193. << std::endl;
  194. #endif
  195. return nullptr;
  196. }
  197. *uncompressed_size = decompressedDataSize;
  198. // Return the raw buffer to the caller supporting the tradition
  199. return outputBuffer.release();
  200. }
  201. int64_t GetDecompressedSize(const char* input_data, size_t input_length) {
  202. assert(input_data != nullptr);
  203. if (input_length == 0) {
  204. return 0;
  205. }
  206. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  207. DECOMPRESSOR_HANDLE decompressor = NULL;
  208. BOOL success =
  209. CreateDecompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  210. allocRoutinesPtr, // Optional allocation routine
  211. &decompressor); // Handle
  212. if (!success) {
  213. #ifdef _DEBUG
  214. std::cerr << "XPRESS: Failed to create Decompressor LastError "
  215. << GetLastError() << std::endl;
  216. #endif
  217. return -1;
  218. }
  219. std::unique_ptr<void, decltype(CloseDecompressorFun)> decompressorGuard(
  220. decompressor, CloseDecompressorFun);
  221. SIZE_T decompressedBufferSize = 0;
  222. success = ::Decompress(decompressor, // Compressor Handle
  223. const_cast<char*>(input_data), // Compressed data
  224. input_length, // Compressed data size
  225. NULL, // Buffer set to NULL
  226. 0, // Buffer size set to 0
  227. &decompressedBufferSize); // Decompressed Data size
  228. assert(!success);
  229. auto lastError = GetLastError();
  230. if (lastError != ERROR_INSUFFICIENT_BUFFER) {
  231. #ifdef _DEBUG
  232. std::cerr
  233. << "XPRESS: Failed to estimate decompressed buffer size LastError "
  234. << lastError << std::endl;
  235. #endif
  236. return -1;
  237. }
  238. assert(decompressedBufferSize > 0);
  239. return static_cast<int64_t>(decompressedBufferSize);
  240. }
  241. int64_t DecompressToBuffer(const char* input, size_t input_length, char* output,
  242. size_t output_length) {
  243. assert(input != nullptr);
  244. assert(output != nullptr);
  245. if (input_length == 0) {
  246. return 0;
  247. }
  248. COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
  249. DECOMPRESSOR_HANDLE decompressor = NULL;
  250. BOOL success =
  251. CreateDecompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
  252. allocRoutinesPtr, // Optional allocation routine
  253. &decompressor); // Handle
  254. if (!success) {
  255. #ifdef _DEBUG
  256. std::cerr << "XPRESS: Failed to create Decompressor LastError "
  257. << GetLastError() << std::endl;
  258. #endif
  259. return -1;
  260. }
  261. std::unique_ptr<void, decltype(CloseDecompressorFun)> decompressorGuard(
  262. decompressor, CloseDecompressorFun);
  263. SIZE_T decompressedDataSize = 0;
  264. success = ::Decompress(decompressor, const_cast<char*>(input), input_length,
  265. output, output_length, &decompressedDataSize);
  266. if (!success) {
  267. #ifdef _DEBUG
  268. std::cerr << "XPRESS: Failed to decompress LastError " << GetLastError()
  269. << std::endl;
  270. #endif
  271. return -1;
  272. }
  273. return static_cast<int64_t>(decompressedDataSize);
  274. }
  275. } // namespace xpress
  276. } // namespace port
  277. } // namespace ROCKSDB_NAMESPACE
  278. #endif
  279. #endif