]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
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). | |
7c673cae FG |
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 | ||
20effc67 TL |
10 | #if defined(OS_WIN) |
11 | ||
7c673cae | 12 | #include "port/win/xpress_win.h" |
11fdf7f2 | 13 | #include <windows.h> |
7c673cae FG |
14 | |
15 | #include <cassert> | |
16 | #include <memory> | |
17 | #include <limits> | |
18 | #include <iostream> | |
19 | ||
20 | #ifdef XPRESS | |
21 | ||
7c673cae FG |
22 | // Put this under ifdef so windows systems w/o this |
23 | // can still build | |
24 | #include <compressapi.h> | |
25 | ||
f67539c2 | 26 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
27 | namespace port { |
28 | namespace xpress { | |
29 | ||
30 | // Helpers | |
31 | namespace { | |
32 | ||
33 | auto CloseCompressorFun = [](void* h) { | |
34 | if (NULL != h) { | |
35 | ::CloseCompressor(reinterpret_cast<COMPRESSOR_HANDLE>(h)); | |
36 | } | |
37 | }; | |
38 | ||
39 | auto CloseDecompressorFun = [](void* h) { | |
40 | if (NULL != h) { | |
41 | ::CloseDecompressor(reinterpret_cast<DECOMPRESSOR_HANDLE>(h)); | |
42 | } | |
43 | }; | |
7c673cae FG |
44 | } |
45 | ||
46 | bool Compress(const char* input, size_t length, std::string* output) { | |
47 | ||
48 | assert(input != nullptr); | |
49 | assert(output != nullptr); | |
50 | ||
51 | if (length == 0) { | |
52 | output->clear(); | |
53 | return true; | |
54 | } | |
55 | ||
56 | COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr; | |
57 | ||
7c673cae FG |
58 | COMPRESSOR_HANDLE compressor = NULL; |
59 | ||
60 | BOOL success = CreateCompressor( | |
61 | COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm | |
62 | allocRoutinesPtr, // Optional allocation routine | |
63 | &compressor); // Handle | |
64 | ||
65 | if (!success) { | |
66 | #ifdef _DEBUG | |
67 | std::cerr << "XPRESS: Failed to create Compressor LastError: " << | |
11fdf7f2 | 68 | GetLastError() << std::endl; |
7c673cae FG |
69 | #endif |
70 | return false; | |
71 | } | |
72 | ||
73 | std::unique_ptr<void, decltype(CloseCompressorFun)> | |
11fdf7f2 | 74 | compressorGuard(compressor, CloseCompressorFun); |
7c673cae FG |
75 | |
76 | SIZE_T compressedBufferSize = 0; | |
77 | ||
11fdf7f2 | 78 | // Query compressed buffer size. |
7c673cae FG |
79 | success = ::Compress( |
80 | compressor, // Compressor Handle | |
81 | const_cast<char*>(input), // Input buffer | |
82 | length, // Uncompressed data size | |
83 | NULL, // Compressed Buffer | |
84 | 0, // Compressed Buffer size | |
85 | &compressedBufferSize); // Compressed Data size | |
86 | ||
87 | if (!success) { | |
88 | ||
89 | auto lastError = GetLastError(); | |
90 | ||
91 | if (lastError != ERROR_INSUFFICIENT_BUFFER) { | |
92 | #ifdef _DEBUG | |
93 | std::cerr << | |
94 | "XPRESS: Failed to estimate compressed buffer size LastError " << | |
95 | lastError << std::endl; | |
96 | #endif | |
11fdf7f2 TL |
97 | return false; |
98 | } | |
7c673cae FG |
99 | } |
100 | ||
101 | assert(compressedBufferSize > 0); | |
102 | ||
103 | std::string result; | |
104 | result.resize(compressedBufferSize); | |
105 | ||
106 | SIZE_T compressedDataSize = 0; | |
107 | ||
108 | // Compress | |
109 | success = ::Compress( | |
110 | compressor, // Compressor Handle | |
111 | const_cast<char*>(input), // Input buffer | |
112 | length, // Uncompressed data size | |
113 | &result[0], // Compressed Buffer | |
114 | compressedBufferSize, // Compressed Buffer size | |
115 | &compressedDataSize); // Compressed Data size | |
116 | ||
117 | if (!success) { | |
118 | #ifdef _DEBUG | |
119 | std::cerr << "XPRESS: Failed to compress LastError " << | |
11fdf7f2 | 120 | GetLastError() << std::endl; |
7c673cae FG |
121 | #endif |
122 | return false; | |
123 | } | |
124 | ||
125 | result.resize(compressedDataSize); | |
126 | output->swap(result); | |
127 | ||
128 | return true; | |
129 | } | |
130 | ||
131 | char* Decompress(const char* input_data, size_t input_length, | |
20effc67 | 132 | size_t* uncompressed_size) { |
7c673cae | 133 | assert(input_data != nullptr); |
20effc67 | 134 | assert(uncompressed_size != nullptr); |
7c673cae FG |
135 | |
136 | if (input_length == 0) { | |
137 | return nullptr; | |
138 | } | |
139 | ||
140 | COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr; | |
141 | ||
7c673cae FG |
142 | DECOMPRESSOR_HANDLE decompressor = NULL; |
143 | ||
144 | BOOL success = CreateDecompressor( | |
145 | COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm | |
146 | allocRoutinesPtr, // Optional allocation routine | |
147 | &decompressor); // Handle | |
148 | ||
149 | ||
150 | if (!success) { | |
151 | #ifdef _DEBUG | |
152 | std::cerr << "XPRESS: Failed to create Decompressor LastError " | |
11fdf7f2 | 153 | << GetLastError() << std::endl; |
7c673cae FG |
154 | #endif |
155 | return nullptr; | |
156 | } | |
157 | ||
158 | std::unique_ptr<void, decltype(CloseDecompressorFun)> | |
159 | compressorGuard(decompressor, CloseDecompressorFun); | |
160 | ||
161 | SIZE_T decompressedBufferSize = 0; | |
162 | ||
163 | success = ::Decompress( | |
164 | decompressor, // Compressor Handle | |
165 | const_cast<char*>(input_data), // Compressed data | |
166 | input_length, // Compressed data size | |
167 | NULL, // Buffer set to NULL | |
168 | 0, // Buffer size set to 0 | |
169 | &decompressedBufferSize); // Decompressed Data size | |
170 | ||
171 | if (!success) { | |
172 | ||
173 | auto lastError = GetLastError(); | |
174 | ||
175 | if (lastError != ERROR_INSUFFICIENT_BUFFER) { | |
176 | #ifdef _DEBUG | |
177 | std::cerr | |
11fdf7f2 TL |
178 | << "XPRESS: Failed to estimate decompressed buffer size LastError " |
179 | << lastError << std::endl; | |
7c673cae FG |
180 | #endif |
181 | return nullptr; | |
182 | } | |
183 | } | |
184 | ||
185 | assert(decompressedBufferSize > 0); | |
186 | ||
7c673cae FG |
187 | // The callers are deallocating using delete[] |
188 | // thus we must allocate with new[] | |
189 | std::unique_ptr<char[]> outputBuffer(new char[decompressedBufferSize]); | |
190 | ||
191 | SIZE_T decompressedDataSize = 0; | |
192 | ||
193 | success = ::Decompress( | |
194 | decompressor, | |
195 | const_cast<char*>(input_data), | |
196 | input_length, | |
197 | outputBuffer.get(), | |
198 | decompressedBufferSize, | |
199 | &decompressedDataSize); | |
200 | ||
201 | if (!success) { | |
202 | #ifdef _DEBUG | |
203 | std::cerr << | |
204 | "XPRESS: Failed to decompress LastError " << | |
205 | GetLastError() << std::endl; | |
206 | #endif | |
207 | return nullptr; | |
208 | } | |
209 | ||
20effc67 | 210 | *uncompressed_size = decompressedDataSize; |
7c673cae FG |
211 | |
212 | // Return the raw buffer to the caller supporting the tradition | |
213 | return outputBuffer.release(); | |
214 | } | |
215 | } | |
216 | } | |
f67539c2 | 217 | } // namespace ROCKSDB_NAMESPACE |
7c673cae FG |
218 | |
219 | #endif | |
20effc67 TL |
220 | |
221 | #endif |