123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- #include "bzip2.h"
- #include <util/memory/addstorage.h>
- #include <util/generic/scope.h>
- #include <contrib/libs/libbz2/bzlib.h>
- class TBZipDecompress::TImpl: public TAdditionalStorage<TImpl> {
- public:
- inline TImpl(IInputStream* input)
- : Stream_(input)
- {
- Zero(BzStream_);
- Init();
- }
- inline ~TImpl() {
- Clear();
- }
- inline void Init() {
- if (BZ2_bzDecompressInit(&BzStream_, 0, 0) != BZ_OK) {
- ythrow TBZipDecompressError() << "can not init bzip engine";
- }
- }
- inline void Clear() noexcept {
- BZ2_bzDecompressEnd(&BzStream_);
- }
- inline size_t Read(void* buf, size_t size) {
- BzStream_.next_out = (char*)buf;
- BzStream_.avail_out = size;
- while (true) {
- if (BzStream_.avail_in == 0) {
- if (FillInputBuffer() == 0) {
- return 0;
- }
- }
- switch (BZ2_bzDecompress(&BzStream_)) {
- case BZ_STREAM_END: {
- Clear();
- Init();
- [[fallthrough]];
- }
- case BZ_OK: {
- const size_t processed = size - BzStream_.avail_out;
- if (processed) {
- return processed;
- }
- break;
- }
- default:
- ythrow TBZipDecompressError() << "bzip error";
- }
- }
- }
- inline size_t FillInputBuffer() {
- BzStream_.next_in = (char*)AdditionalData();
- BzStream_.avail_in = Stream_->Read(BzStream_.next_in, AdditionalDataLength());
- return BzStream_.avail_in;
- }
- private:
- IInputStream* Stream_;
- bz_stream BzStream_;
- };
- TBZipDecompress::TBZipDecompress(IInputStream* input, size_t bufLen)
- : Impl_(new (bufLen) TImpl(input))
- {
- }
- TBZipDecompress::~TBZipDecompress() {
- }
- size_t TBZipDecompress::DoRead(void* buf, size_t size) {
- return Impl_->Read(buf, size);
- }
- class TBZipCompress::TImpl: public TAdditionalStorage<TImpl> {
- public:
- inline TImpl(IOutputStream* stream, size_t level)
- : Stream_(stream)
- {
- Zero(BzStream_);
- if (BZ2_bzCompressInit(&BzStream_, level, 0, 0) != BZ_OK) {
- ythrow TBZipCompressError() << "can not init bzip engine";
- }
- BzStream_.next_out = TmpBuf();
- BzStream_.avail_out = TmpBufLen();
- }
- inline ~TImpl() {
- BZ2_bzCompressEnd(&BzStream_);
- }
- inline void Write(const void* buf, size_t size) {
- BzStream_.next_in = (char*)buf;
- BzStream_.avail_in = size;
- Y_DEFER {
- BzStream_.next_in = 0;
- BzStream_.avail_in = 0;
- };
- while (BzStream_.avail_in) {
- const int ret = BZ2_bzCompress(&BzStream_, BZ_RUN);
- switch (ret) {
- case BZ_RUN_OK:
- continue;
- case BZ_PARAM_ERROR:
- case BZ_OUTBUFF_FULL:
- Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
- BzStream_.next_out = TmpBuf();
- BzStream_.avail_out = TmpBufLen();
- break;
- default:
- ythrow TBZipCompressError() << "bzip error(" << ret << ", " << BzStream_.avail_out << ")";
- }
- }
- }
- inline void Flush() {
- /*
- * TODO ?
- */
- }
- inline void Finish() {
- int ret = BZ2_bzCompress(&BzStream_, BZ_FINISH);
- while (ret != BZ_STREAM_END) {
- Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
- BzStream_.next_out = TmpBuf();
- BzStream_.avail_out = TmpBufLen();
- ret = BZ2_bzCompress(&BzStream_, BZ_FINISH);
- }
- Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
- }
- private:
- inline char* TmpBuf() noexcept {
- return (char*)AdditionalData();
- }
- inline size_t TmpBufLen() const noexcept {
- return AdditionalDataLength();
- }
- private:
- IOutputStream* Stream_;
- bz_stream BzStream_;
- };
- TBZipCompress::TBZipCompress(IOutputStream* out, size_t compressionLevel, size_t bufLen)
- : Impl_(new (bufLen) TImpl(out, compressionLevel))
- {
- }
- TBZipCompress::~TBZipCompress() {
- try {
- Finish();
- } catch (...) {
- }
- }
- void TBZipCompress::DoWrite(const void* buf, size_t size) {
- if (!Impl_) {
- ythrow TBZipCompressError() << "can not write to finished bzip stream";
- }
- Impl_->Write(buf, size);
- }
- void TBZipCompress::DoFlush() {
- if (Impl_) {
- Impl_->Flush();
- }
- }
- void TBZipCompress::DoFinish() {
- THolder<TImpl> impl(Impl_.Release());
- if (impl) {
- impl->Finish();
- }
- }
|