1 package PerlIO
::via
::File
::KDBX
::Compression
;
2 # ABSTRACT: [De]compressor PerlIO layer
9 use File
::KDBX
::Util
qw(load_optional);
13 our $VERSION = '999.999'; # VERSION
14 our $BUFFER_SIZE = 8192;
19 PerlIO
::via
::File
::KDBX
::Compression-
>push($fh);
20 PerlIO
::via
::File
::KDBX
::Compression-
>push($fh, %options);
22 Push a compression
or decompression layer onto a filehandle
. Data
read from the handle
is decompressed
, and
23 data written to a handle
is compressed
.
25 Any arguments are passed along to the Inflate
or Deflate constructors of C
<Compress
::Raw
::Zlib
>.
29 binmode($fh, ':via(File::KDBX::Compression)');
31 except this allows you to specify compression options
.
33 B
<WARNING
:> When writing
, you mustn
't close the filehandle before popping this layer (using
34 C<binmode($fh, ':pop')>) or the stream will be truncated. The layer needs to know when there is no more data
35 before the filehandle closes so it can finish the compression correctly, and the way to indicate that is by
42 @PUSHED_ARGS and throw 'Pushing Compression layer would stomp existing arguments
';
46 binmode($fh, ':via
(' . __PACKAGE__ . ')');
50 my ($class, $mode) = @_;
52 $ENV{DEBUG_STREAM} and print STDERR "PUSHED\t$class\n";
58 $mode =~ /^r/ ? (inflator => _inflator(@PUSHED_ARGS)) : (),
59 $mode =~ /^w/ ? (deflator => _deflator(@PUSHED_ARGS)) : (),
68 $ENV{DEBUG_STREAM} and print STDERR "FILL\t$self\n";
69 return if $self->EOF($fh);
71 $fh->read(my $buf, $BUFFER_SIZE);
72 if (0 < length($buf)) {
73 my $status = $self->inflator->inflate($buf, my $out);
74 $status == Compress::Raw::Zlib::Z_OK() || $status == Compress::Raw::Zlib::Z_STREAM_END() or do {
75 $self->_set_error("Failed to uncompress: $status", status => $status);
81 delete $self->{inflator};
86 my ($self, $buf, $fh) = @_;
88 $ENV{DEBUG_STREAM} and print STDERR "WRITE\t$self\n";
89 return 0 if $self->EOF($fh);
91 my $status = $self->deflator->deflate($buf, my $out);
92 $status == Compress::Raw::Zlib::Z_OK() or do {
93 $self->_set_error("Failed to compress: $status", status => $status);
97 ${$self->buffer} .= $out;
102 my ($self, $fh) = @_;
104 $ENV{DEBUG_STREAM} and print STDERR "POPPED\t$self\n";
105 return if $self->EOF($fh) || $self->mode !~ /^w/;
108 my $status = $self->deflator->flush(my $out, Compress::Raw::Zlib::Z_FINISH());
109 delete $self->{deflator};
110 $status == Compress::Raw::Zlib::Z_OK() or do {
111 $self->_set_error("Failed to compress: $status", status => $status);
115 ${$self->buffer} .= $out;
120 my ($self, $fh) = @_;
122 $ENV{DEBUG_STREAM} and print STDERR "FLUSH\t$self\n";
123 return 0 if !ref $self;
125 my $buf = $self->buffer;
126 print $fh $$buf or return -1 if 0 < length($$buf);
132 $ENV{DEBUG_STREAM} and print STDERR "EOF\t$_[0]\n";
133 (!$_[0]->inflator && !$_[0]->deflator) || $_[0]->ERROR($_[1]);
136 $ENV{DEBUG_STREAM} and print STDERR "ERROR\t$_[0] : ", $_[0]->{error} // 'ok
', "\n";
137 $ERROR = $_[0]->{error} if $_[0]->{error};
138 $_[0]->{error} ? 1 : 0;
141 $ENV{DEBUG_STREAM} and print STDERR "CLEARERR\t$_[0]\n";
142 # delete $_[0]->{error};
145 sub inflator { $_[0]->{inflator} }
146 sub deflator { $_[0]->{deflator} }
147 sub mode { $_[0]->{mode} }
148 sub buffer { $_[0]->{buffer} }
151 load_optional('Compress
::Raw
::Zlib
');
152 my ($inflator, $status)
153 = Compress::Raw::Zlib::Inflate->new(-WindowBits => Compress::Raw::Zlib::WANT_GZIP(), @_);
154 $status == Compress::Raw::Zlib::Z_OK()
155 or throw 'Failed to initialize inflator
', status => $status;
160 load_optional('Compress
::Raw
::Zlib
');
161 my ($deflator, $status)
162 = Compress::Raw::Zlib::Deflate->new(-WindowBits => Compress::Raw::Zlib::WANT_GZIP(), @_);
163 $status == Compress::Raw::Zlib::Z_OK()
164 or throw 'Failed to initialize deflator
', status => $status;
170 $ENV{DEBUG_STREAM} and print STDERR "err\t$self\n";
171 delete $self->{inflator};
172 delete $self->{deflator};
173 if (exists &Errno::EPROTO) {
176 elsif (exists &Errno::EIO) {
179 $self->{error} = $ERROR = File::KDBX::Error->new(@_);