| 187 | } // namespace |
| 188 | |
| 189 | class TZLibCompress::TImpl: public TAdditionalStorage<TImpl>, private TZLibCommon { |
| 190 | static inline ZLib::StreamType Type(ZLib::StreamType type) { |
| 191 | if (type == ZLib::Auto) { |
| 192 | return ZLib::ZLib; |
| 193 | } |
| 194 | |
| 195 | if (type >= ZLib::Invalid) { |
| 196 | ythrow TZLibError() << "invalid compression type: " << static_cast<unsigned long>(type); |
| 197 | } |
| 198 | |
| 199 | return type; |
| 200 | } |
| 201 | |
| 202 | public: |
| 203 | inline TImpl(const TParams& p) |
| 204 | : Stream_(p.Out) |
| 205 | { |
| 206 | if (deflateInit2(Z(), Min<size_t>(9, p.CompressionLevel), Z_DEFLATED, opts[Type(p.Type)], 8, Z_DEFAULT_STRATEGY)) { |
| 207 | ythrow TZLibCompressorError() << "can not init inflate engine"; |
| 208 | } |
| 209 | |
| 210 | // Create exactly the same files on all platforms by fixing OS field in the header. |
| 211 | if (p.Type == ZLib::GZip) { |
| 212 | GZHeader_ = MakeHolder<gz_header>(); |
| 213 | GZHeader_->os = 3; // UNIX |
| 214 | deflateSetHeader(Z(), GZHeader_.Get()); |
| 215 | } |
| 216 | |
| 217 | if (p.Dict.size()) { |
| 218 | if (deflateSetDictionary(Z(), (const Bytef*)p.Dict.data(), p.Dict.size())) { |
| 219 | ythrow TZLibCompressorError() << "can not set deflate dictionary"; |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | Z()->next_out = TmpBuf(); |
| 224 | Z()->avail_out = TmpBufLen(); |
| 225 | } |
| 226 | |
| 227 | inline ~TImpl() { |
| 228 | deflateEnd(Z()); |
| 229 | } |
| 230 | |
| 231 | inline void Write(const void* buf, size_t size) { |
| 232 | const Bytef* b = (const Bytef*)buf; |
| 233 | const Bytef* e = b + size; |
| 234 | |
| 235 | Y_DEFER { |
| 236 | Z()->next_in = nullptr; |
| 237 | Z()->avail_in = 0; |
| 238 | }; |
| 239 | do { |
| 240 | b = WritePart(b, e); |
| 241 | } while (b < e); |
| 242 | } |
| 243 | |
| 244 | inline const Bytef* WritePart(const Bytef* b, const Bytef* e) { |
nothing calls this directly
no test coverage detected