7 #ifndef LIBIME_ZSTDFILTER_H 8 #define LIBIME_ZSTDFILTER_H 16 #include <boost/iostreams/categories.hpp> 17 #include <boost/iostreams/constants.hpp> 18 #include <boost/iostreams/filter/symmetric.hpp> 19 #include <boost/iostreams/filtering_streambuf.hpp> 20 #include <boost/iostreams/pipeline.hpp> 21 #include <boost/throw_exception.hpp> 22 #include <fcitx-utils/log.h> 23 #include <fcitx-utils/misc.h> 31 : std::ios::failure(ZSTD_getErrorName(error)), error_(error) {}
33 size_t error()
const {
return error_; }
34 static void check(
size_t error) {
35 if (ZSTD_isError(error)) {
46 enum class ZSTDResult {
53 using char_type = char;
59 void before(
const char *&src_begin,
const char *src_end,
char *&dest_begin,
60 const char *dest_end) {
62 in_.size =
static_cast<size_t>(src_end - src_begin);
64 out_.dst = dest_begin;
65 out_.size =
static_cast<size_t>(dest_end - dest_begin);
68 void after(
const char *&src_begin,
char *&dest_begin,
70 src_begin =
reinterpret_cast<const char *
>(in_.src) + in_.pos;
71 dest_begin = reinterpret_cast<char *>(out_.dst) + out_.pos;
74 memset(&in_, 0,
sizeof(in_));
75 memset(&out_, 0,
sizeof(out_));
87 bool filter(
const char *&src_begin,
const char *src_end,
char *&dest_begin,
88 char *dest_end,
bool flush) {
89 before(src_begin, src_end, dest_begin, dest_end);
90 auto result = deflate(flush);
91 after(src_begin, dest_begin,
true);
92 return result != ZSTDResult::StreamEnd;
94 void close() { reset(); }
98 ZSTDFilterBase::reset();
99 ZSTDError::check(ZSTD_initCStream(cstream_.get(), 0));
102 ZSTD_CCtx_setParameter(cstream_.get(), ZSTD_c_checksumFlag, 1));
105 ZSTDResult deflate(
bool finish) {
108 if (eof_ && in_.size == 0) {
109 return ZSTDResult::StreamEnd;
111 size_t result = ZSTD_compressStream(cstream_.get(), &out_, &in_);
112 ZSTDError::check(result);
114 result = ZSTD_endStream(cstream_.get(), &out_);
115 ZSTDError::check(result);
117 return eof_ ? ZSTDResult::StreamEnd : ZSTDResult::Okay;
119 return ZSTDResult::Okay;
122 fcitx::UniqueCPtr<ZSTD_CStream, &ZSTD_freeCStream> cstream_;
128 bool filter(
const char *&src_begin,
const char *src_end,
char *&dest_begin,
129 char *dest_end,
bool flush) {
130 before(src_begin, src_end, dest_begin, dest_end);
131 auto result = inflate(flush);
132 after(src_begin, dest_begin,
false);
133 return result != ZSTDResult::StreamEnd;
135 void close() { reset(); }
139 ZSTDFilterBase::reset();
140 ZSTDError::check(ZSTD_initDStream(dstream_.get()));
143 ZSTDResult inflate(
bool finish) {
146 size_t result = ZSTD_decompressStream(dstream_.get(), &out_, &in_);
147 ZSTDError::check(result);
148 }
while (in_.pos < in_.size && out_.pos < out_.size);
149 return finish && in_.size == 0 && out_.pos == 0 ? ZSTDResult::StreamEnd
153 fcitx::UniqueCPtr<ZSTD_DStream, &ZSTD_freeDStream> dstream_;
159 : boost::iostreams::symmetric_filter<details::ZSTDCompressorImpl> {
162 using base_type = symmetric_filter<impl_type>;
165 using char_type =
typename base_type::char_type;
166 using category =
typename base_type::category;
168 boost::iostreams::default_device_buffer_size)
169 : base_type(buffer_size) {}
174 : boost::iostreams::symmetric_filter<details::ZSTDDecompressorImpl> {
177 using base_type = symmetric_filter<impl_type>;
180 using char_type =
typename base_type::char_type;
181 using category =
typename base_type::category;
183 boost::iostreams::default_device_buffer_size)
184 : base_type(buffer_size) {}
188 template <
typename Callback>
189 inline void readZSTDCompressed(std::istream &in,
const Callback &callback) {
190 boost::iostreams::filtering_istreambuf compressBuf;
192 compressBuf.push(in);
193 std::istream compressIn(&compressBuf);
194 callback(compressIn);
198 if (compressIn.bad()) {
199 throw std::invalid_argument(
"Failed to load dict data");
203 template <
typename Callback>
204 inline void writeZSTDCompressed(std::ostream &out,
const Callback &callback) {
205 boost::iostreams::filtering_streambuf<boost::iostreams::output> compressBuf;
207 compressBuf.push(out);
208 std::ostream compressOut(&compressBuf);
209 callback(compressOut);