xref: /openbsd-src/gnu/usr.bin/perl/cpan/IO-Compress/lib/IO/Uncompress/Base.pm (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
1b39c5158Smillert
2b39c5158Smillertpackage IO::Uncompress::Base ;
3b39c5158Smillert
4b39c5158Smillertuse strict ;
5b39c5158Smillertuse warnings;
69f11ffb7Safresh1use bytes;
7b39c5158Smillert
8b39c5158Smillertour (@ISA, $VERSION, @EXPORT_OK, %EXPORT_TAGS);
99f11ffb7Safresh1@ISA    = qw(IO::File Exporter);
10b39c5158Smillert
11b39c5158Smillert
12*3d61058aSafresh1$VERSION = '2.212';
13b39c5158Smillert
14b39c5158Smillertuse constant G_EOF => 0 ;
15b39c5158Smillertuse constant G_ERR => -1 ;
16b39c5158Smillert
17*3d61058aSafresh1use IO::Compress::Base::Common 2.212 ;
18b39c5158Smillert
19b39c5158Smillertuse IO::File ;
20b39c5158Smillertuse Symbol;
2191f110e0Safresh1use Scalar::Util ();
2291f110e0Safresh1use List::Util ();
23b39c5158Smillertuse Carp ;
24b39c5158Smillert
25b39c5158Smillert%EXPORT_TAGS = ( );
26b39c5158Smillertpush @{ $EXPORT_TAGS{all} }, @EXPORT_OK ;
27b39c5158Smillert
28b39c5158Smillertsub smartRead
29b39c5158Smillert{
30b39c5158Smillert    my $self = $_[0];
31b39c5158Smillert    my $out = $_[1];
32b39c5158Smillert    my $size = $_[2];
33b39c5158Smillert    $$out = "" ;
34b39c5158Smillert
35b39c5158Smillert    my $offset = 0 ;
36898184e3Ssthen    my $status = 1;
37b39c5158Smillert
38b39c5158Smillert
39b39c5158Smillert    if (defined *$self->{InputLength}) {
40b39c5158Smillert        return 0
41b39c5158Smillert            if *$self->{InputLengthRemaining} <= 0 ;
4291f110e0Safresh1        $size = List::Util::min($size, *$self->{InputLengthRemaining});
43b39c5158Smillert    }
44b39c5158Smillert
45b39c5158Smillert    if ( length *$self->{Prime} ) {
46b39c5158Smillert        $$out = substr(*$self->{Prime}, 0, $size) ;
47b39c5158Smillert        substr(*$self->{Prime}, 0, $size) =  '' ;
48b39c5158Smillert        if (length $$out == $size) {
49b39c5158Smillert            *$self->{InputLengthRemaining} -= length $$out
50b39c5158Smillert                if defined *$self->{InputLength};
51b39c5158Smillert
52b39c5158Smillert            return length $$out ;
53b39c5158Smillert        }
54b39c5158Smillert        $offset = length $$out ;
55b39c5158Smillert    }
56b39c5158Smillert
57b39c5158Smillert    my $get_size = $size - $offset ;
58b39c5158Smillert
59b39c5158Smillert    if (defined *$self->{FH}) {
60b39c5158Smillert        if ($offset) {
61b39c5158Smillert            # Not using this
62b39c5158Smillert            #
63b39c5158Smillert            #  *$self->{FH}->read($$out, $get_size, $offset);
64b39c5158Smillert            #
65b39c5158Smillert            # because the filehandle may not support the offset parameter
66b39c5158Smillert            # An example is Net::FTP
67b39c5158Smillert            my $tmp = '';
68898184e3Ssthen            $status = *$self->{FH}->read($tmp, $get_size) ;
69898184e3Ssthen            substr($$out, $offset) = $tmp
70898184e3Ssthen                if defined $status && $status > 0 ;
71b39c5158Smillert        }
72b39c5158Smillert        else
73898184e3Ssthen          { $status = *$self->{FH}->read($$out, $get_size) }
74b39c5158Smillert    }
75b39c5158Smillert    elsif (defined *$self->{InputEvent}) {
76b39c5158Smillert        my $got = 1 ;
77b39c5158Smillert        while (length $$out < $size) {
78b39c5158Smillert            last
79b39c5158Smillert                if ($got = *$self->{InputEvent}->($$out, $get_size)) <= 0;
80b39c5158Smillert        }
81b39c5158Smillert
82b39c5158Smillert        if (length $$out > $size ) {
83b39c5158Smillert            *$self->{Prime} = substr($$out, $size, length($$out));
84b39c5158Smillert            substr($$out, $size, length($$out)) =  '';
85b39c5158Smillert        }
86b39c5158Smillert
87b39c5158Smillert       *$self->{EventEof} = 1 if $got <= 0 ;
88b39c5158Smillert    }
89b39c5158Smillert    else {
90b39c5158Smillert       no warnings 'uninitialized';
91b39c5158Smillert       my $buf = *$self->{Buffer} ;
92b39c5158Smillert       $$buf = '' unless defined $$buf ;
93b39c5158Smillert       substr($$out, $offset) = substr($$buf, *$self->{BufferOffset}, $get_size);
94b39c5158Smillert       if (*$self->{ConsumeInput})
95b39c5158Smillert         { substr($$buf, 0, $get_size) = '' }
96b39c5158Smillert       else
97b39c5158Smillert         { *$self->{BufferOffset} += length($$out) - $offset }
98b39c5158Smillert    }
99b39c5158Smillert
100b39c5158Smillert    *$self->{InputLengthRemaining} -= length($$out) #- $offset
101b39c5158Smillert        if defined *$self->{InputLength};
102b39c5158Smillert
103898184e3Ssthen    if (! defined $status) {
104898184e3Ssthen        $self->saveStatus($!) ;
105898184e3Ssthen        return STATUS_ERROR;
106898184e3Ssthen    }
107898184e3Ssthen
108b39c5158Smillert    $self->saveStatus(length $$out < 0 ? STATUS_ERROR : STATUS_OK) ;
109b39c5158Smillert
110b39c5158Smillert    return length $$out;
111b39c5158Smillert}
112b39c5158Smillert
113b39c5158Smillertsub pushBack
114b39c5158Smillert{
115b39c5158Smillert    my $self = shift ;
116b39c5158Smillert
117b39c5158Smillert    return if ! defined $_[0] || length $_[0] == 0 ;
118b39c5158Smillert
119b39c5158Smillert    if (defined *$self->{FH} || defined *$self->{InputEvent} ) {
120b39c5158Smillert        *$self->{Prime} = $_[0] . *$self->{Prime} ;
121b39c5158Smillert        *$self->{InputLengthRemaining} += length($_[0]);
122b39c5158Smillert    }
123b39c5158Smillert    else {
124b39c5158Smillert        my $len = length $_[0];
125b39c5158Smillert
126b39c5158Smillert        if($len > *$self->{BufferOffset}) {
127b39c5158Smillert            *$self->{Prime} = substr($_[0], 0, $len - *$self->{BufferOffset}) . *$self->{Prime} ;
128b39c5158Smillert            *$self->{InputLengthRemaining} = *$self->{InputLength};
129b39c5158Smillert            *$self->{BufferOffset} = 0
130b39c5158Smillert        }
131b39c5158Smillert        else {
132b39c5158Smillert            *$self->{InputLengthRemaining} += length($_[0]);
133b39c5158Smillert            *$self->{BufferOffset} -= length($_[0]) ;
134b39c5158Smillert        }
135b39c5158Smillert    }
136b39c5158Smillert}
137b39c5158Smillert
138b39c5158Smillertsub smartSeek
139b39c5158Smillert{
140b39c5158Smillert    my $self   = shift ;
141b39c5158Smillert    my $offset = shift ;
142b39c5158Smillert    my $truncate = shift;
143898184e3Ssthen    my $position = shift || SEEK_SET;
144b39c5158Smillert
145b39c5158Smillert    # TODO -- need to take prime into account
146b46d8ef2Safresh1    *$self->{Prime} = '';
147b39c5158Smillert    if (defined *$self->{FH})
148898184e3Ssthen      { *$self->{FH}->seek($offset, $position) }
149898184e3Ssthen    else {
150898184e3Ssthen        if ($position == SEEK_END) {
151b46d8ef2Safresh1            *$self->{BufferOffset} = length(${ *$self->{Buffer} }) + $offset ;
152898184e3Ssthen        }
153898184e3Ssthen        elsif ($position == SEEK_CUR) {
154898184e3Ssthen            *$self->{BufferOffset} += $offset ;
155898184e3Ssthen        }
156b39c5158Smillert        else {
157b39c5158Smillert            *$self->{BufferOffset} = $offset ;
158898184e3Ssthen        }
159898184e3Ssthen
160b39c5158Smillert        substr(${ *$self->{Buffer} }, *$self->{BufferOffset}) = ''
161b39c5158Smillert            if $truncate;
162b39c5158Smillert        return 1;
163b39c5158Smillert    }
164b39c5158Smillert}
165b39c5158Smillert
166898184e3Ssthensub smartTell
167898184e3Ssthen{
168898184e3Ssthen    my $self   = shift ;
169898184e3Ssthen
170898184e3Ssthen    if (defined *$self->{FH})
171898184e3Ssthen      { return *$self->{FH}->tell() }
172898184e3Ssthen    else
173898184e3Ssthen      { return *$self->{BufferOffset} }
174898184e3Ssthen}
175898184e3Ssthen
176b39c5158Smillertsub smartWrite
177b39c5158Smillert{
178b39c5158Smillert    my $self   = shift ;
179b39c5158Smillert    my $out_data = shift ;
180b39c5158Smillert
181b39c5158Smillert    if (defined *$self->{FH}) {
182b39c5158Smillert        # flush needed for 5.8.0
183b39c5158Smillert        defined *$self->{FH}->write($out_data, length $out_data) &&
184b39c5158Smillert        defined *$self->{FH}->flush() ;
185b39c5158Smillert    }
186b39c5158Smillert    else {
187b39c5158Smillert       my $buf = *$self->{Buffer} ;
188b39c5158Smillert       substr($$buf, *$self->{BufferOffset}, length $out_data) = $out_data ;
189b39c5158Smillert       *$self->{BufferOffset} += length($out_data) ;
190b39c5158Smillert       return 1;
191b39c5158Smillert    }
192b39c5158Smillert}
193b39c5158Smillert
194b39c5158Smillertsub smartReadExact
195b39c5158Smillert{
196b39c5158Smillert    return $_[0]->smartRead($_[1], $_[2]) == $_[2];
197b39c5158Smillert}
198b39c5158Smillert
199b39c5158Smillertsub smartEof
200b39c5158Smillert{
201b39c5158Smillert    my ($self) = $_[0];
202b39c5158Smillert    local $.;
203b39c5158Smillert
204b39c5158Smillert    return 0 if length *$self->{Prime} || *$self->{PushMode};
205b39c5158Smillert
206b39c5158Smillert    if (defined *$self->{FH})
207b39c5158Smillert    {
208b39c5158Smillert        # Could use
209b39c5158Smillert        #
210b39c5158Smillert        #  *$self->{FH}->eof()
211b39c5158Smillert        #
212b39c5158Smillert        # here, but this can cause trouble if
213b39c5158Smillert        # the filehandle is itself a tied handle, but it uses sysread.
214898184e3Ssthen        # Then we get into mixing buffered & non-buffered IO,
215898184e3Ssthen        # which will cause trouble
216b39c5158Smillert
217b39c5158Smillert        my $info = $self->getErrInfo();
218b39c5158Smillert
219b39c5158Smillert        my $buffer = '';
220b39c5158Smillert        my $status = $self->smartRead(\$buffer, 1);
221b39c5158Smillert        $self->pushBack($buffer) if length $buffer;
222b39c5158Smillert        $self->setErrInfo($info);
223b39c5158Smillert
224b39c5158Smillert        return $status == 0 ;
225b39c5158Smillert    }
226b39c5158Smillert    elsif (defined *$self->{InputEvent})
227b39c5158Smillert     { *$self->{EventEof} }
228b39c5158Smillert    else
229b39c5158Smillert     { *$self->{BufferOffset} >= length(${ *$self->{Buffer} }) }
230b39c5158Smillert}
231b39c5158Smillert
232b39c5158Smillertsub clearError
233b39c5158Smillert{
234b39c5158Smillert    my $self   = shift ;
235b39c5158Smillert
236b39c5158Smillert    *$self->{ErrorNo}  =  0 ;
237b39c5158Smillert    ${ *$self->{Error} } = '' ;
238b39c5158Smillert}
239b39c5158Smillert
240b39c5158Smillertsub getErrInfo
241b39c5158Smillert{
242b39c5158Smillert    my $self   = shift ;
243b39c5158Smillert
244b39c5158Smillert    return [ *$self->{ErrorNo}, ${ *$self->{Error} } ] ;
245b39c5158Smillert}
246b39c5158Smillert
247b39c5158Smillertsub setErrInfo
248b39c5158Smillert{
249b39c5158Smillert    my $self   = shift ;
250b39c5158Smillert    my $ref    = shift;
251b39c5158Smillert
252b39c5158Smillert    *$self->{ErrorNo}  =  $ref->[0] ;
253b39c5158Smillert    ${ *$self->{Error} } = $ref->[1] ;
254b39c5158Smillert}
255b39c5158Smillert
256b39c5158Smillertsub saveStatus
257b39c5158Smillert{
258b39c5158Smillert    my $self   = shift ;
259b39c5158Smillert    my $errno = shift() + 0 ;
260b39c5158Smillert
261b39c5158Smillert    *$self->{ErrorNo}  = $errno;
262b39c5158Smillert    ${ *$self->{Error} } = '' ;
263b39c5158Smillert
264b39c5158Smillert    return *$self->{ErrorNo} ;
265b39c5158Smillert}
266b39c5158Smillert
267b39c5158Smillert
268b39c5158Smillertsub saveErrorString
269b39c5158Smillert{
270b39c5158Smillert    my $self   = shift ;
271b39c5158Smillert    my $retval = shift ;
272b39c5158Smillert
273b39c5158Smillert    ${ *$self->{Error} } = shift ;
274898184e3Ssthen    *$self->{ErrorNo} = @_ ? shift() + 0 : STATUS_ERROR ;
275b39c5158Smillert
276b39c5158Smillert    return $retval;
277b39c5158Smillert}
278b39c5158Smillert
279b39c5158Smillertsub croakError
280b39c5158Smillert{
281b39c5158Smillert    my $self   = shift ;
282b39c5158Smillert    $self->saveErrorString(0, $_[0]);
283b39c5158Smillert    croak $_[0];
284b39c5158Smillert}
285b39c5158Smillert
286b39c5158Smillert
287b39c5158Smillertsub closeError
288b39c5158Smillert{
289b39c5158Smillert    my $self = shift ;
290b39c5158Smillert    my $retval = shift ;
291b39c5158Smillert
292b39c5158Smillert    my $errno = *$self->{ErrorNo};
293b39c5158Smillert    my $error = ${ *$self->{Error} };
294b39c5158Smillert
295b39c5158Smillert    $self->close();
296b39c5158Smillert
297b39c5158Smillert    *$self->{ErrorNo} = $errno ;
298b39c5158Smillert    ${ *$self->{Error} } = $error ;
299b39c5158Smillert
300b39c5158Smillert    return $retval;
301b39c5158Smillert}
302b39c5158Smillert
303b39c5158Smillertsub error
304b39c5158Smillert{
305b39c5158Smillert    my $self   = shift ;
306b39c5158Smillert    return ${ *$self->{Error} } ;
307b39c5158Smillert}
308b39c5158Smillert
309b39c5158Smillertsub errorNo
310b39c5158Smillert{
311b39c5158Smillert    my $self   = shift ;
312b39c5158Smillert    return *$self->{ErrorNo};
313b39c5158Smillert}
314b39c5158Smillert
315b39c5158Smillertsub HeaderError
316b39c5158Smillert{
317b39c5158Smillert    my ($self) = shift;
318b39c5158Smillert    return $self->saveErrorString(undef, "Header Error: $_[0]", STATUS_ERROR);
319b39c5158Smillert}
320b39c5158Smillert
321b39c5158Smillertsub TrailerError
322b39c5158Smillert{
323b39c5158Smillert    my ($self) = shift;
324b39c5158Smillert    return $self->saveErrorString(G_ERR, "Trailer Error: $_[0]", STATUS_ERROR);
325b39c5158Smillert}
326b39c5158Smillert
327b39c5158Smillertsub TruncatedHeader
328b39c5158Smillert{
329b39c5158Smillert    my ($self) = shift;
330b39c5158Smillert    return $self->HeaderError("Truncated in $_[0] Section");
331b39c5158Smillert}
332b39c5158Smillert
333b39c5158Smillertsub TruncatedTrailer
334b39c5158Smillert{
335b39c5158Smillert    my ($self) = shift;
336b39c5158Smillert    return $self->TrailerError("Truncated in $_[0] Section");
337b39c5158Smillert}
338b39c5158Smillert
339b39c5158Smillertsub postCheckParams
340b39c5158Smillert{
341b39c5158Smillert    return 1;
342b39c5158Smillert}
343b39c5158Smillert
344b39c5158Smillertsub checkParams
345b39c5158Smillert{
346b39c5158Smillert    my $self = shift ;
347b39c5158Smillert    my $class = shift ;
348b39c5158Smillert
349b39c5158Smillert    my $got = shift || IO::Compress::Base::Parameters::new();
350b39c5158Smillert
351b39c5158Smillert    my $Valid = {
35291f110e0Safresh1                    'blocksize'     => [IO::Compress::Base::Common::Parse_unsigned, 16 * 1024],
35391f110e0Safresh1                    'autoclose'     => [IO::Compress::Base::Common::Parse_boolean,  0],
35491f110e0Safresh1                    'strict'        => [IO::Compress::Base::Common::Parse_boolean,  0],
35591f110e0Safresh1                    'append'        => [IO::Compress::Base::Common::Parse_boolean,  0],
35691f110e0Safresh1                    'prime'         => [IO::Compress::Base::Common::Parse_any,      undef],
35791f110e0Safresh1                    'multistream'   => [IO::Compress::Base::Common::Parse_boolean,  0],
35891f110e0Safresh1                    'transparent'   => [IO::Compress::Base::Common::Parse_any,      1],
35991f110e0Safresh1                    'scan'          => [IO::Compress::Base::Common::Parse_boolean,  0],
36091f110e0Safresh1                    'inputlength'   => [IO::Compress::Base::Common::Parse_unsigned, undef],
36191f110e0Safresh1                    'binmodeout'    => [IO::Compress::Base::Common::Parse_boolean,  0],
36291f110e0Safresh1                   #'decode'        => [IO::Compress::Base::Common::Parse_any,      undef],
363b39c5158Smillert
36491f110e0Safresh1                   #'consumeinput'  => [IO::Compress::Base::Common::Parse_boolean,  0],
365b39c5158Smillert
366b39c5158Smillert                    $self->getExtraParams(),
367b39c5158Smillert
368b39c5158Smillert                    #'Todo - Revert to ordinary file on end Z_STREAM_END'=> 0,
369b39c5158Smillert                    # ContinueAfterEof
370b39c5158Smillert                } ;
371b39c5158Smillert
37291f110e0Safresh1    $Valid->{trailingdata} = [IO::Compress::Base::Common::Parse_writable_scalar, undef]
373b39c5158Smillert        if  *$self->{OneShot} ;
374b39c5158Smillert
375b39c5158Smillert    $got->parse($Valid, @_ )
37691f110e0Safresh1        or $self->croakError("${class}: " . $got->getError()) ;
377b39c5158Smillert
378b39c5158Smillert    $self->postCheckParams($got)
379b39c5158Smillert        or $self->croakError("${class}: " . $self->error()) ;
380b39c5158Smillert
381b39c5158Smillert    return $got;
382b39c5158Smillert}
383b39c5158Smillert
384b39c5158Smillertsub _create
385b39c5158Smillert{
386b39c5158Smillert    my $obj = shift;
387b39c5158Smillert    my $got = shift;
388b39c5158Smillert    my $append_mode = shift ;
389b39c5158Smillert
390b39c5158Smillert    my $class = ref $obj;
391b39c5158Smillert    $obj->croakError("$class: Missing Input parameter")
392b39c5158Smillert        if ! @_ && ! $got ;
393b39c5158Smillert
394b39c5158Smillert    my $inValue = shift ;
395b39c5158Smillert
396b39c5158Smillert    *$obj->{OneShot} = 0 ;
397b39c5158Smillert
398b39c5158Smillert    if (! $got)
399b39c5158Smillert    {
400b39c5158Smillert        $got = $obj->checkParams($class, undef, @_)
401b39c5158Smillert            or return undef ;
402b39c5158Smillert    }
403b39c5158Smillert
404b39c5158Smillert    my $inType  = whatIsInput($inValue, 1);
405b39c5158Smillert
406b39c5158Smillert    $obj->ckInputParam($class, $inValue, 1)
407b39c5158Smillert        or return undef ;
408b39c5158Smillert
409b39c5158Smillert    *$obj->{InNew} = 1;
410b39c5158Smillert
411b39c5158Smillert    $obj->ckParams($got)
412b39c5158Smillert        or $obj->croakError("${class}: " . *$obj->{Error});
413b39c5158Smillert
414b39c5158Smillert    if ($inType eq 'buffer' || $inType eq 'code') {
415b39c5158Smillert        *$obj->{Buffer} = $inValue ;
416b39c5158Smillert        *$obj->{InputEvent} = $inValue
417b39c5158Smillert           if $inType eq 'code' ;
418b39c5158Smillert    }
419b39c5158Smillert    else {
420b39c5158Smillert        if ($inType eq 'handle') {
421b39c5158Smillert            *$obj->{FH} = $inValue ;
422b39c5158Smillert            *$obj->{Handle} = 1 ;
423b39c5158Smillert
424b39c5158Smillert            # Need to rewind for Scan
425b39c5158Smillert            *$obj->{FH}->seek(0, SEEK_SET)
42691f110e0Safresh1                if $got->getValue('scan');
427b39c5158Smillert        }
428b39c5158Smillert        else {
429b39c5158Smillert            no warnings ;
430b39c5158Smillert            my $mode = '<';
43191f110e0Safresh1            $mode = '+<' if $got->getValue('scan');
432b39c5158Smillert            *$obj->{StdIO} = ($inValue eq '-');
433eac174f2Safresh1            *$obj->{FH} = IO::File->new( "$mode $inValue" )
434b39c5158Smillert                or return $obj->saveErrorString(undef, "cannot open file '$inValue': $!", $!) ;
435b39c5158Smillert        }
436b39c5158Smillert
437b39c5158Smillert        *$obj->{LineNo} = $. = 0;
438b39c5158Smillert        setBinModeInput(*$obj->{FH}) ;
439b39c5158Smillert
440b39c5158Smillert        my $buff = "" ;
441b39c5158Smillert        *$obj->{Buffer} = \$buff ;
442b39c5158Smillert    }
443b39c5158Smillert
44491f110e0Safresh1#    if ($got->getValue('decode')) {
44591f110e0Safresh1#        my $want_encoding = $got->getValue('decode');
44691f110e0Safresh1#        *$obj->{Encoding} = IO::Compress::Base::Common::getEncoding($obj, $class, $want_encoding);
44791f110e0Safresh1#    }
44891f110e0Safresh1#    else {
44991f110e0Safresh1#        *$obj->{Encoding} = undef;
45091f110e0Safresh1#    }
451b39c5158Smillert
45291f110e0Safresh1    *$obj->{InputLength}       = $got->parsed('inputlength')
45391f110e0Safresh1                                    ? $got->getValue('inputlength')
454b39c5158Smillert                                    : undef ;
45591f110e0Safresh1    *$obj->{InputLengthRemaining} = $got->getValue('inputlength');
456b39c5158Smillert    *$obj->{BufferOffset}      = 0 ;
45791f110e0Safresh1    *$obj->{AutoClose}         = $got->getValue('autoclose');
45891f110e0Safresh1    *$obj->{Strict}            = $got->getValue('strict');
45991f110e0Safresh1    *$obj->{BlockSize}         = $got->getValue('blocksize');
46091f110e0Safresh1    *$obj->{Append}            = $got->getValue('append');
46191f110e0Safresh1    *$obj->{AppendOutput}      = $append_mode || $got->getValue('append');
46291f110e0Safresh1    *$obj->{ConsumeInput}      = $got->getValue('consumeinput');
46391f110e0Safresh1    *$obj->{Transparent}       = $got->getValue('transparent');
46491f110e0Safresh1    *$obj->{MultiStream}       = $got->getValue('multistream');
465b39c5158Smillert
466b39c5158Smillert    # TODO - move these two into RawDeflate
46791f110e0Safresh1    *$obj->{Scan}              = $got->getValue('scan');
46891f110e0Safresh1    *$obj->{ParseExtra}        = $got->getValue('parseextra')
46991f110e0Safresh1                                  || $got->getValue('strict')  ;
470b39c5158Smillert    *$obj->{Type}              = '';
47191f110e0Safresh1    *$obj->{Prime}             = $got->getValue('prime') || '' ;
472b39c5158Smillert    *$obj->{Pending}           = '';
473b39c5158Smillert    *$obj->{Plain}             = 0;
474b39c5158Smillert    *$obj->{PlainBytesRead}    = 0;
475b39c5158Smillert    *$obj->{InflatedBytesRead} = 0;
476eac174f2Safresh1    *$obj->{UnCompSize}        = U64->new;
477eac174f2Safresh1    *$obj->{CompSize}          = U64->new;
478b39c5158Smillert    *$obj->{TotalInflatedBytesRead} = 0;
479b39c5158Smillert    *$obj->{NewStream}         = 0 ;
480b39c5158Smillert    *$obj->{EventEof}          = 0 ;
481b39c5158Smillert    *$obj->{ClassName}         = $class ;
482b39c5158Smillert    *$obj->{Params}            = $got ;
483b39c5158Smillert
484b39c5158Smillert    if (*$obj->{ConsumeInput}) {
485b39c5158Smillert        *$obj->{InNew} = 0;
486b39c5158Smillert        *$obj->{Closed} = 0;
487b39c5158Smillert        return $obj
488b39c5158Smillert    }
489b39c5158Smillert
490b39c5158Smillert    my $status = $obj->mkUncomp($got);
491b39c5158Smillert
492b39c5158Smillert    return undef
493b39c5158Smillert        unless defined $status;
494b39c5158Smillert
495898184e3Ssthen    *$obj->{InNew} = 0;
496898184e3Ssthen    *$obj->{Closed} = 0;
497898184e3Ssthen
498b46d8ef2Safresh1    return $obj
499b46d8ef2Safresh1        if *$obj->{Pause} ;
500b46d8ef2Safresh1
501898184e3Ssthen    if ($status) {
502898184e3Ssthen        # Need to try uncompressing to catch the case
503898184e3Ssthen        # where the compressed file uncompresses to an
504898184e3Ssthen        # empty string - so eof is set immediately.
505898184e3Ssthen
506898184e3Ssthen        my $out_buffer = '';
507898184e3Ssthen
508898184e3Ssthen        $status = $obj->read(\$out_buffer);
509898184e3Ssthen
510898184e3Ssthen        if ($status < 0) {
511898184e3Ssthen            *$obj->{ReadStatus} = [ $status, $obj->error(), $obj->errorNo() ];
512898184e3Ssthen        }
513898184e3Ssthen
514898184e3Ssthen        $obj->ungetc($out_buffer)
515898184e3Ssthen            if length $out_buffer;
516898184e3Ssthen    }
517898184e3Ssthen    else {
518b39c5158Smillert        return undef
519b39c5158Smillert            unless *$obj->{Transparent};
520b39c5158Smillert
521b39c5158Smillert        $obj->clearError();
522b39c5158Smillert        *$obj->{Type} = 'plain';
523b39c5158Smillert        *$obj->{Plain} = 1;
524b39c5158Smillert        $obj->pushBack(*$obj->{HeaderPending})  ;
525b39c5158Smillert    }
526b39c5158Smillert
527b39c5158Smillert    push @{ *$obj->{InfoList} }, *$obj->{Info} ;
528b39c5158Smillert
529b39c5158Smillert    $obj->saveStatus(STATUS_OK) ;
530b39c5158Smillert    *$obj->{InNew} = 0;
531b39c5158Smillert    *$obj->{Closed} = 0;
532b39c5158Smillert
533b39c5158Smillert    return $obj;
534b39c5158Smillert}
535b39c5158Smillert
536b39c5158Smillertsub ckInputParam
537b39c5158Smillert{
538b39c5158Smillert    my $self = shift ;
539b39c5158Smillert    my $from = shift ;
540b39c5158Smillert    my $inType = whatIsInput($_[0], $_[1]);
541b39c5158Smillert
542b39c5158Smillert    $self->croakError("$from: input parameter not a filename, filehandle, array ref or scalar ref")
543b39c5158Smillert        if ! $inType ;
544b39c5158Smillert
545b39c5158Smillert#    if ($inType  eq 'filename' )
546b39c5158Smillert#    {
547b39c5158Smillert#        return $self->saveErrorString(1, "$from: input filename is undef or null string", STATUS_ERROR)
548b39c5158Smillert#            if ! defined $_[0] || $_[0] eq ''  ;
549b39c5158Smillert#
550b39c5158Smillert#        if ($_[0] ne '-' && ! -e $_[0] )
551b39c5158Smillert#        {
552b39c5158Smillert#            return $self->saveErrorString(1,
553b39c5158Smillert#                            "input file '$_[0]' does not exist", STATUS_ERROR);
554b39c5158Smillert#        }
555b39c5158Smillert#    }
556b39c5158Smillert
557b39c5158Smillert    return 1;
558b39c5158Smillert}
559b39c5158Smillert
560b39c5158Smillert
561b39c5158Smillertsub _inf
562b39c5158Smillert{
563b39c5158Smillert    my $obj = shift ;
564b39c5158Smillert
565b39c5158Smillert    my $class = (caller)[0] ;
566b39c5158Smillert    my $name = (caller(1))[3] ;
567b39c5158Smillert
568b39c5158Smillert    $obj->croakError("$name: expected at least 1 parameters\n")
569b39c5158Smillert        unless @_ >= 1 ;
570b39c5158Smillert
571b39c5158Smillert    my $input = shift ;
572b39c5158Smillert    my $haveOut = @_ ;
573b39c5158Smillert    my $output = shift ;
574b39c5158Smillert
575b39c5158Smillert
576eac174f2Safresh1    my $x = IO::Compress::Base::Validator->new($class, *$obj->{Error}, $name, $input, $output)
577b39c5158Smillert        or return undef ;
578b39c5158Smillert
579b39c5158Smillert    push @_, $output if $haveOut && $x->{Hash};
580b39c5158Smillert
581b39c5158Smillert    *$obj->{OneShot} = 1 ;
582b39c5158Smillert
583b39c5158Smillert    my $got = $obj->checkParams($name, undef, @_)
584b39c5158Smillert        or return undef ;
585b39c5158Smillert
58691f110e0Safresh1    if ($got->parsed('trailingdata'))
587b39c5158Smillert    {
58891f110e0Safresh1#        my $value = $got->valueRef('TrailingData');
58991f110e0Safresh1#        warn "TD $value ";
59091f110e0Safresh1#        #$value = $$value;
59191f110e0Safresh1##                warn "TD $value $$value ";
59291f110e0Safresh1#
59391f110e0Safresh1#        return retErr($obj, "Parameter 'TrailingData' not writable")
59491f110e0Safresh1#            if readonly $$value ;
59591f110e0Safresh1#
59691f110e0Safresh1#        if (ref $$value)
59791f110e0Safresh1#        {
59891f110e0Safresh1#            return retErr($obj,"Parameter 'TrailingData' not a scalar reference")
59991f110e0Safresh1#                if ref $$value ne 'SCALAR' ;
60091f110e0Safresh1#
60191f110e0Safresh1#            *$obj->{TrailingData} = $$value ;
60291f110e0Safresh1#        }
60391f110e0Safresh1#        else
60491f110e0Safresh1#        {
60591f110e0Safresh1#            return retErr($obj,"Parameter 'TrailingData' not a scalar")
60691f110e0Safresh1#                if ref $value ne 'SCALAR' ;
60791f110e0Safresh1#
60891f110e0Safresh1#            *$obj->{TrailingData} = $value ;
60991f110e0Safresh1#        }
61091f110e0Safresh1
61191f110e0Safresh1        *$obj->{TrailingData} = $got->getValue('trailingdata');
612b39c5158Smillert    }
613b39c5158Smillert
61491f110e0Safresh1    *$obj->{MultiStream} = $got->getValue('multistream');
61591f110e0Safresh1    $got->setValue('multistream', 0);
616b39c5158Smillert
617b39c5158Smillert    $x->{Got} = $got ;
618b39c5158Smillert
619b39c5158Smillert#    if ($x->{Hash})
620b39c5158Smillert#    {
621b39c5158Smillert#        while (my($k, $v) = each %$input)
622b39c5158Smillert#        {
623b39c5158Smillert#            $v = \$input->{$k}
624b39c5158Smillert#                unless defined $v ;
625b39c5158Smillert#
626b39c5158Smillert#            $obj->_singleTarget($x, $k, $v, @_)
627b39c5158Smillert#                or return undef ;
628b39c5158Smillert#        }
629b39c5158Smillert#
630b39c5158Smillert#        return keys %$input ;
631b39c5158Smillert#    }
632b39c5158Smillert
633b39c5158Smillert    if ($x->{GlobMap})
634b39c5158Smillert    {
635b39c5158Smillert        $x->{oneInput} = 1 ;
636b39c5158Smillert        foreach my $pair (@{ $x->{Pairs} })
637b39c5158Smillert        {
638b39c5158Smillert            my ($from, $to) = @$pair ;
639b39c5158Smillert            $obj->_singleTarget($x, $from, $to, @_)
640b39c5158Smillert                or return undef ;
641b39c5158Smillert        }
642b39c5158Smillert
643b39c5158Smillert        return scalar @{ $x->{Pairs} } ;
644b39c5158Smillert    }
645b39c5158Smillert
646b39c5158Smillert    if (! $x->{oneOutput} )
647b39c5158Smillert    {
648b39c5158Smillert        my $inFile = ($x->{inType} eq 'filenames'
649b39c5158Smillert                        || $x->{inType} eq 'filename');
650b39c5158Smillert
651b39c5158Smillert        $x->{inType} = $inFile ? 'filename' : 'buffer';
652b39c5158Smillert
653b39c5158Smillert        foreach my $in ($x->{oneInput} ? $input : @$input)
654b39c5158Smillert        {
655b39c5158Smillert            my $out ;
656b39c5158Smillert            $x->{oneInput} = 1 ;
657b39c5158Smillert
658b39c5158Smillert            $obj->_singleTarget($x, $in, $output, @_)
659b39c5158Smillert                or return undef ;
660b39c5158Smillert        }
661b39c5158Smillert
662b39c5158Smillert        return 1 ;
663b39c5158Smillert    }
664b39c5158Smillert
665b39c5158Smillert    # finally the 1 to 1 and n to 1
666b39c5158Smillert    return $obj->_singleTarget($x, $input, $output, @_);
667b39c5158Smillert
668b39c5158Smillert    croak "should not be here" ;
669b39c5158Smillert}
670b39c5158Smillert
671b39c5158Smillertsub retErr
672b39c5158Smillert{
673b39c5158Smillert    my $x = shift ;
674b39c5158Smillert    my $string = shift ;
675b39c5158Smillert
676b39c5158Smillert    ${ $x->{Error} } = $string ;
677b39c5158Smillert
678b39c5158Smillert    return undef ;
679b39c5158Smillert}
680b39c5158Smillert
681b39c5158Smillertsub _singleTarget
682b39c5158Smillert{
683b39c5158Smillert    my $self      = shift ;
684b39c5158Smillert    my $x         = shift ;
685b39c5158Smillert    my $input     = shift;
686b39c5158Smillert    my $output    = shift;
687b39c5158Smillert
688b39c5158Smillert    my $buff = '';
689b39c5158Smillert    $x->{buff} = \$buff ;
690b39c5158Smillert
691b39c5158Smillert    my $fh ;
692b39c5158Smillert    if ($x->{outType} eq 'filename') {
693b39c5158Smillert        my $mode = '>' ;
694b39c5158Smillert        $mode = '>>'
69591f110e0Safresh1            if $x->{Got}->getValue('append') ;
696eac174f2Safresh1        $x->{fh} = IO::File->new( "$mode $output" )
697b39c5158Smillert            or return retErr($x, "cannot open file '$output': $!") ;
698b46d8ef2Safresh1        binmode $x->{fh} ;
699b39c5158Smillert
700b39c5158Smillert    }
701b39c5158Smillert
702b39c5158Smillert    elsif ($x->{outType} eq 'handle') {
703b39c5158Smillert        $x->{fh} = $output;
704b46d8ef2Safresh1        binmode $x->{fh} ;
70591f110e0Safresh1        if ($x->{Got}->getValue('append')) {
706b39c5158Smillert                seek($x->{fh}, 0, SEEK_END)
707b39c5158Smillert                    or return retErr($x, "Cannot seek to end of output filehandle: $!") ;
708b39c5158Smillert            }
709b39c5158Smillert    }
710b39c5158Smillert
711b39c5158Smillert
712b39c5158Smillert    elsif ($x->{outType} eq 'buffer' )
713b39c5158Smillert    {
714b39c5158Smillert        $$output = ''
71591f110e0Safresh1            unless $x->{Got}->getValue('append');
716b39c5158Smillert        $x->{buff} = $output ;
717b39c5158Smillert    }
718b39c5158Smillert
719b39c5158Smillert    if ($x->{oneInput})
720b39c5158Smillert    {
721b39c5158Smillert        defined $self->_rd2($x, $input, $output)
722b39c5158Smillert            or return undef;
723b39c5158Smillert    }
724b39c5158Smillert    else
725b39c5158Smillert    {
726b39c5158Smillert        for my $element ( ($x->{inType} eq 'hash') ? keys %$input : @$input)
727b39c5158Smillert        {
728b39c5158Smillert            defined $self->_rd2($x, $element, $output)
729b39c5158Smillert                or return undef ;
730b39c5158Smillert        }
731b39c5158Smillert    }
732b39c5158Smillert
733b39c5158Smillert
734b39c5158Smillert    if ( ($x->{outType} eq 'filename' && $output ne '-') ||
73591f110e0Safresh1         ($x->{outType} eq 'handle' && $x->{Got}->getValue('autoclose'))) {
736b39c5158Smillert        $x->{fh}->close()
737b39c5158Smillert            or return retErr($x, $!);
738b39c5158Smillert        delete $x->{fh};
739b39c5158Smillert    }
740b39c5158Smillert
741b39c5158Smillert    return 1 ;
742b39c5158Smillert}
743b39c5158Smillert
744b39c5158Smillertsub _rd2
745b39c5158Smillert{
746b39c5158Smillert    my $self      = shift ;
747b39c5158Smillert    my $x         = shift ;
748b39c5158Smillert    my $input     = shift;
749b39c5158Smillert    my $output    = shift;
750b39c5158Smillert
75191f110e0Safresh1    my $z = IO::Compress::Base::Common::createSelfTiedObject($x->{Class}, *$self->{Error});
752b39c5158Smillert
753b39c5158Smillert    $z->_create($x->{Got}, 1, $input, @_)
754b39c5158Smillert        or return undef ;
755b39c5158Smillert
756b39c5158Smillert    my $status ;
757b39c5158Smillert    my $fh = $x->{fh};
758b39c5158Smillert
759b39c5158Smillert    while (1) {
760b39c5158Smillert
761b39c5158Smillert        while (($status = $z->read($x->{buff})) > 0) {
762b39c5158Smillert            if ($fh) {
763b8851fccSafresh1                local $\;
764b8851fccSafresh1                print $fh ${ $x->{buff} }
765b39c5158Smillert                    or return $z->saveErrorString(undef, "Error writing to output file: $!", $!);
766b39c5158Smillert                ${ $x->{buff} } = '' ;
767b39c5158Smillert            }
768b39c5158Smillert        }
769b39c5158Smillert
770b39c5158Smillert        if (! $x->{oneOutput} ) {
771b39c5158Smillert            my $ot = $x->{outType} ;
772b39c5158Smillert
773b39c5158Smillert            if ($ot eq 'array')
774b39c5158Smillert              { push @$output, $x->{buff} }
775b39c5158Smillert            elsif ($ot eq 'hash')
776b39c5158Smillert              { $output->{$input} = $x->{buff} }
777b39c5158Smillert
778b39c5158Smillert            my $buff = '';
779b39c5158Smillert            $x->{buff} = \$buff;
780b39c5158Smillert        }
781b39c5158Smillert
782b39c5158Smillert        last if $status < 0 || $z->smartEof();
783b39c5158Smillert
784b39c5158Smillert        last
785b39c5158Smillert            unless *$self->{MultiStream};
786b39c5158Smillert
787b39c5158Smillert        $status = $z->nextStream();
788b39c5158Smillert
789b39c5158Smillert        last
790b39c5158Smillert            unless $status == 1 ;
791b39c5158Smillert    }
792b39c5158Smillert
793b39c5158Smillert    return $z->closeError(undef)
794b39c5158Smillert        if $status < 0 ;
795b39c5158Smillert
796b39c5158Smillert    ${ *$self->{TrailingData} } = $z->trailingData()
797b39c5158Smillert        if defined *$self->{TrailingData} ;
798b39c5158Smillert
799b39c5158Smillert    $z->close()
800b39c5158Smillert        or return undef ;
801b39c5158Smillert
802b39c5158Smillert    return 1 ;
803b39c5158Smillert}
804b39c5158Smillert
805b39c5158Smillertsub TIEHANDLE
806b39c5158Smillert{
807b39c5158Smillert    return $_[0] if ref($_[0]);
808b39c5158Smillert    die "OOPS\n" ;
809b39c5158Smillert
810b39c5158Smillert}
811b39c5158Smillert
812b39c5158Smillertsub UNTIE
813b39c5158Smillert{
814b39c5158Smillert    my $self = shift ;
815b39c5158Smillert}
816b39c5158Smillert
817b39c5158Smillert
818b39c5158Smillertsub getHeaderInfo
819b39c5158Smillert{
820b39c5158Smillert    my $self = shift ;
821b39c5158Smillert    wantarray ? @{ *$self->{InfoList} } : *$self->{Info};
822b39c5158Smillert}
823b39c5158Smillert
824b39c5158Smillertsub readBlock
825b39c5158Smillert{
826b39c5158Smillert    my $self = shift ;
827b39c5158Smillert    my $buff = shift ;
828b39c5158Smillert    my $size = shift ;
829b39c5158Smillert
830b39c5158Smillert    if (defined *$self->{CompressedInputLength}) {
831b39c5158Smillert        if (*$self->{CompressedInputLengthRemaining} == 0) {
832b39c5158Smillert            delete *$self->{CompressedInputLength};
833b39c5158Smillert            *$self->{CompressedInputLengthDone} = 1;
834b39c5158Smillert            return STATUS_OK ;
835b39c5158Smillert        }
83691f110e0Safresh1        $size = List::Util::min($size, *$self->{CompressedInputLengthRemaining} );
837b39c5158Smillert        *$self->{CompressedInputLengthRemaining} -= $size ;
838b39c5158Smillert    }
839b39c5158Smillert
840b39c5158Smillert    my $status = $self->smartRead($buff, $size) ;
841898184e3Ssthen    return $self->saveErrorString(STATUS_ERROR, "Error Reading Data: $!", $!)
842898184e3Ssthen        if $status == STATUS_ERROR  ;
843b39c5158Smillert
844b39c5158Smillert    if ($status == 0 ) {
845b39c5158Smillert        *$self->{Closed} = 1 ;
846b39c5158Smillert        *$self->{EndStream} = 1 ;
847b39c5158Smillert        return $self->saveErrorString(STATUS_ERROR, "unexpected end of file", STATUS_ERROR);
848b39c5158Smillert    }
849b39c5158Smillert
850b39c5158Smillert    return STATUS_OK;
851b39c5158Smillert}
852b39c5158Smillert
853b39c5158Smillertsub postBlockChk
854b39c5158Smillert{
855b39c5158Smillert    return STATUS_OK;
856b39c5158Smillert}
857b39c5158Smillert
858b39c5158Smillertsub _raw_read
859b39c5158Smillert{
860b39c5158Smillert    # return codes
861b39c5158Smillert    # >0 - ok, number of bytes read
862b39c5158Smillert    # =0 - ok, eof
863b39c5158Smillert    # <0 - not ok
864b39c5158Smillert
865b39c5158Smillert    my $self = shift ;
866b39c5158Smillert
867b39c5158Smillert    return G_EOF if *$self->{Closed} ;
868b39c5158Smillert    return G_EOF if *$self->{EndStream} ;
869b39c5158Smillert
870b39c5158Smillert    my $buffer = shift ;
871b39c5158Smillert    my $scan_mode = shift ;
872b39c5158Smillert
873b39c5158Smillert    if (*$self->{Plain}) {
874b39c5158Smillert        my $tmp_buff ;
875b39c5158Smillert        my $len = $self->smartRead(\$tmp_buff, *$self->{BlockSize}) ;
876b39c5158Smillert
877b39c5158Smillert        return $self->saveErrorString(G_ERR, "Error reading data: $!", $!)
878898184e3Ssthen                if $len == STATUS_ERROR ;
879b39c5158Smillert
880b39c5158Smillert        if ($len == 0 ) {
881b39c5158Smillert            *$self->{EndStream} = 1 ;
882b39c5158Smillert        }
883b39c5158Smillert        else {
884b39c5158Smillert            *$self->{PlainBytesRead} += $len ;
885b39c5158Smillert            $$buffer .= $tmp_buff;
886b39c5158Smillert        }
887b39c5158Smillert
888b39c5158Smillert        return $len ;
889b39c5158Smillert    }
890b39c5158Smillert
891b39c5158Smillert    if (*$self->{NewStream}) {
892b39c5158Smillert
893b39c5158Smillert        $self->gotoNextStream() > 0
894b39c5158Smillert            or return G_ERR;
895b39c5158Smillert
896b39c5158Smillert        # For the headers that actually uncompressed data, put the
897b39c5158Smillert        # uncompressed data into the output buffer.
898b39c5158Smillert        $$buffer .=  *$self->{Pending} ;
899b39c5158Smillert        my $len = length  *$self->{Pending} ;
900b39c5158Smillert        *$self->{Pending} = '';
901b39c5158Smillert        return $len;
902b39c5158Smillert    }
903b39c5158Smillert
904b39c5158Smillert    my $temp_buf = '';
905b39c5158Smillert    my $outSize = 0;
906b39c5158Smillert    my $status = $self->readBlock(\$temp_buf, *$self->{BlockSize}, $outSize) ;
907898184e3Ssthen
908b39c5158Smillert    return G_ERR
909b39c5158Smillert        if $status == STATUS_ERROR  ;
910b39c5158Smillert
911b39c5158Smillert    my $buf_len = 0;
912b39c5158Smillert    if ($status == STATUS_OK) {
913b39c5158Smillert        my $beforeC_len = length $temp_buf;
914b39c5158Smillert        my $before_len = defined $$buffer ? length $$buffer : 0 ;
915b39c5158Smillert        $status = *$self->{Uncomp}->uncompr(\$temp_buf, $buffer,
916b39c5158Smillert                                    defined *$self->{CompressedInputLengthDone} ||
917b39c5158Smillert                                                $self->smartEof(), $outSize);
918b39c5158Smillert
919b39c5158Smillert        # Remember the input buffer if it wasn't consumed completely
920b39c5158Smillert        $self->pushBack($temp_buf) if *$self->{Uncomp}{ConsumesInput};
921b39c5158Smillert
922b39c5158Smillert        return $self->saveErrorString(G_ERR, *$self->{Uncomp}{Error}, *$self->{Uncomp}{ErrorNo})
923b39c5158Smillert            if $self->saveStatus($status) == STATUS_ERROR;
924b39c5158Smillert
925b39c5158Smillert        $self->postBlockChk($buffer, $before_len) == STATUS_OK
926b39c5158Smillert            or return G_ERR;
927b39c5158Smillert
928b39c5158Smillert        $buf_len = defined $$buffer ? length($$buffer) - $before_len : 0;
929b39c5158Smillert
930b39c5158Smillert        *$self->{CompSize}->add($beforeC_len - length $temp_buf) ;
931b39c5158Smillert
932b39c5158Smillert        *$self->{InflatedBytesRead} += $buf_len ;
933b39c5158Smillert        *$self->{TotalInflatedBytesRead} += $buf_len ;
934b39c5158Smillert        *$self->{UnCompSize}->add($buf_len) ;
935b39c5158Smillert
936898184e3Ssthen        $self->filterUncompressed($buffer, $before_len);
937b39c5158Smillert
93891f110e0Safresh1#        if (*$self->{Encoding}) {
93991f110e0Safresh1#            use Encode ;
94091f110e0Safresh1#            *$self->{PendingDecode} .= substr($$buffer, $before_len) ;
94191f110e0Safresh1#            my $got = *$self->{Encoding}->decode(*$self->{PendingDecode}, Encode::FB_QUIET) ;
94291f110e0Safresh1#            substr($$buffer, $before_len) = $got;
94391f110e0Safresh1#        }
944b39c5158Smillert    }
945b39c5158Smillert
946b39c5158Smillert    if ($status == STATUS_ENDSTREAM) {
947b39c5158Smillert
948b39c5158Smillert        *$self->{EndStream} = 1 ;
949b39c5158Smillert
950b39c5158Smillert        my $trailer;
951b39c5158Smillert        my $trailer_size = *$self->{Info}{TrailerLength} ;
952b39c5158Smillert        my $got = 0;
953b39c5158Smillert        if (*$self->{Info}{TrailerLength})
954b39c5158Smillert        {
955b39c5158Smillert            $got = $self->smartRead(\$trailer, $trailer_size) ;
956b39c5158Smillert        }
957b39c5158Smillert
958b39c5158Smillert        if ($got == $trailer_size) {
959b39c5158Smillert            $self->chkTrailer($trailer) == STATUS_OK
960b39c5158Smillert                or return G_ERR;
961b39c5158Smillert        }
962b39c5158Smillert        else {
963b39c5158Smillert            return $self->TrailerError("trailer truncated. Expected " .
964b39c5158Smillert                                      "$trailer_size bytes, got $got")
965b39c5158Smillert                if *$self->{Strict};
966b39c5158Smillert            $self->pushBack($trailer)  ;
967b39c5158Smillert        }
968b39c5158Smillert
9696fb12b70Safresh1        # TODO - if want file pointer, do it here
970b39c5158Smillert
971b39c5158Smillert        if (! $self->smartEof()) {
972b39c5158Smillert            *$self->{NewStream} = 1 ;
973b39c5158Smillert
974b39c5158Smillert            if (*$self->{MultiStream}) {
975b39c5158Smillert                *$self->{EndStream} = 0 ;
976b39c5158Smillert                return $buf_len ;
977b39c5158Smillert            }
978b39c5158Smillert        }
979b39c5158Smillert
980b39c5158Smillert    }
981b39c5158Smillert
982b39c5158Smillert
983b39c5158Smillert    # return the number of uncompressed bytes read
984b39c5158Smillert    return $buf_len ;
985b39c5158Smillert}
986b39c5158Smillert
987b39c5158Smillertsub reset
988b39c5158Smillert{
989b39c5158Smillert    my $self = shift ;
990b39c5158Smillert
991b39c5158Smillert    return *$self->{Uncomp}->reset();
992b39c5158Smillert}
993b39c5158Smillert
994b39c5158Smillertsub filterUncompressed
995b39c5158Smillert{
996b39c5158Smillert}
997b39c5158Smillert
998b39c5158Smillert#sub isEndStream
999b39c5158Smillert#{
1000b39c5158Smillert#    my $self = shift ;
1001b39c5158Smillert#    return *$self->{NewStream} ||
1002b39c5158Smillert#           *$self->{EndStream} ;
1003b39c5158Smillert#}
1004b39c5158Smillert
1005b39c5158Smillertsub nextStream
1006b39c5158Smillert{
1007b39c5158Smillert    my $self = shift ;
1008b39c5158Smillert
1009eac174f2Safresh1    # An uncompressed file cannot have a next stream, so
1010eac174f2Safresh1    # return immediately.
1011eac174f2Safresh1    return 0
1012eac174f2Safresh1        if *$self->{Plain} ;
1013eac174f2Safresh1
1014b39c5158Smillert    my $status = $self->gotoNextStream();
1015b39c5158Smillert    $status == 1
1016b39c5158Smillert        or return $status ;
1017b39c5158Smillert
101856d68f1eSafresh1    *$self->{Pending} = ''
101956d68f1eSafresh1        if $self !~ /IO::Uncompress::RawInflate/ && ! *$self->{MultiStream};
102056d68f1eSafresh1
1021b39c5158Smillert    *$self->{TotalInflatedBytesRead} = 0 ;
1022b39c5158Smillert    *$self->{LineNo} = $. = 0;
1023b39c5158Smillert
1024b39c5158Smillert    return 1;
1025b39c5158Smillert}
1026b39c5158Smillert
1027b39c5158Smillertsub gotoNextStream
1028b39c5158Smillert{
1029b39c5158Smillert    my $self = shift ;
1030b39c5158Smillert
1031b39c5158Smillert    if (! *$self->{NewStream}) {
1032b39c5158Smillert        my $status = 1;
1033b39c5158Smillert        my $buffer ;
1034b39c5158Smillert
1035b39c5158Smillert        # TODO - make this more efficient if know the offset for the end of
1036b39c5158Smillert        # the stream and seekable
1037b39c5158Smillert        $status = $self->read($buffer)
1038b39c5158Smillert            while $status > 0 ;
1039b39c5158Smillert
1040b39c5158Smillert        return $status
1041b39c5158Smillert            if $status < 0;
1042b39c5158Smillert    }
1043b39c5158Smillert
1044b39c5158Smillert    *$self->{NewStream} = 0 ;
1045b39c5158Smillert    *$self->{EndStream} = 0 ;
1046898184e3Ssthen    *$self->{CompressedInputLengthDone} = undef ;
1047898184e3Ssthen    *$self->{CompressedInputLength} = undef ;
1048b39c5158Smillert    $self->reset();
1049b39c5158Smillert    *$self->{UnCompSize}->reset();
1050b39c5158Smillert    *$self->{CompSize}->reset();
1051b39c5158Smillert
1052b39c5158Smillert    my $magic = $self->ckMagic();
1053b39c5158Smillert
1054b39c5158Smillert    if ( ! defined $magic) {
1055898184e3Ssthen        if (! *$self->{Transparent} || $self->eof())
1056b39c5158Smillert        {
1057b39c5158Smillert            *$self->{EndStream} = 1 ;
1058b39c5158Smillert            return 0;
1059b39c5158Smillert        }
1060b39c5158Smillert
106156d68f1eSafresh1        # Not EOF, so Transparent mode kicks in now for trailing data
106256d68f1eSafresh1        # Reset member name in case anyone calls getHeaderInfo()->{Name}
106356d68f1eSafresh1        *$self->{Info} = { Name => undef, Type  => 'plain' };
106456d68f1eSafresh1
1065b39c5158Smillert        $self->clearError();
1066b39c5158Smillert        *$self->{Type} = 'plain';
1067b39c5158Smillert        *$self->{Plain} = 1;
1068b39c5158Smillert        $self->pushBack(*$self->{HeaderPending})  ;
1069b39c5158Smillert    }
1070b39c5158Smillert    else
1071b39c5158Smillert    {
1072b39c5158Smillert        *$self->{Info} = $self->readHeader($magic);
1073b39c5158Smillert
1074b39c5158Smillert        if ( ! defined *$self->{Info} ) {
1075b39c5158Smillert            *$self->{EndStream} = 1 ;
1076b39c5158Smillert            return -1;
1077b39c5158Smillert        }
1078b39c5158Smillert    }
1079b39c5158Smillert
1080b39c5158Smillert    push @{ *$self->{InfoList} }, *$self->{Info} ;
1081b39c5158Smillert
1082b39c5158Smillert    return 1;
1083b39c5158Smillert}
1084b39c5158Smillert
1085b39c5158Smillertsub streamCount
1086b39c5158Smillert{
1087b39c5158Smillert    my $self = shift ;
1088b39c5158Smillert    return 1 if ! defined *$self->{InfoList};
1089b39c5158Smillert    return scalar @{ *$self->{InfoList} }  ;
1090b39c5158Smillert}
1091b39c5158Smillert
1092b39c5158Smillertsub read
1093b39c5158Smillert{
1094b39c5158Smillert    # return codes
1095b39c5158Smillert    # >0 - ok, number of bytes read
1096b39c5158Smillert    # =0 - ok, eof
1097b39c5158Smillert    # <0 - not ok
1098b39c5158Smillert
1099b39c5158Smillert    my $self = shift ;
1100b39c5158Smillert
1101898184e3Ssthen    if (defined *$self->{ReadStatus} ) {
1102898184e3Ssthen        my $status = *$self->{ReadStatus}[0];
1103898184e3Ssthen        $self->saveErrorString( @{ *$self->{ReadStatus} } );
1104898184e3Ssthen        delete  *$self->{ReadStatus} ;
1105898184e3Ssthen        return $status ;
1106898184e3Ssthen    }
1107898184e3Ssthen
1108b39c5158Smillert    return G_EOF if *$self->{Closed} ;
1109b39c5158Smillert
1110b39c5158Smillert    my $buffer ;
1111b39c5158Smillert
1112b39c5158Smillert    if (ref $_[0] ) {
1113b39c5158Smillert        $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
111491f110e0Safresh1            if Scalar::Util::readonly(${ $_[0] });
1115b39c5158Smillert
1116b39c5158Smillert        $self->croakError(*$self->{ClassName} . "::read: not a scalar reference $_[0]" )
1117b39c5158Smillert            unless ref $_[0] eq 'SCALAR' ;
1118b39c5158Smillert        $buffer = $_[0] ;
1119b39c5158Smillert    }
1120b39c5158Smillert    else {
1121b39c5158Smillert        $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
112291f110e0Safresh1            if Scalar::Util::readonly($_[0]);
1123b39c5158Smillert
1124b39c5158Smillert        $buffer = \$_[0] ;
1125b39c5158Smillert    }
1126b39c5158Smillert
1127b39c5158Smillert    my $length = $_[1] ;
1128b39c5158Smillert    my $offset = $_[2] || 0;
1129b39c5158Smillert
1130b39c5158Smillert    if (! *$self->{AppendOutput}) {
1131b39c5158Smillert        if (! $offset) {
1132b46d8ef2Safresh1
1133b39c5158Smillert            $$buffer = '' ;
1134b39c5158Smillert        }
1135b39c5158Smillert        else {
1136b39c5158Smillert            if ($offset > length($$buffer)) {
1137b39c5158Smillert                $$buffer .= "\x00" x ($offset - length($$buffer));
1138b39c5158Smillert            }
1139b39c5158Smillert            else {
1140b39c5158Smillert                substr($$buffer, $offset) = '';
1141b39c5158Smillert            }
1142b39c5158Smillert        }
1143b39c5158Smillert    }
1144898184e3Ssthen    elsif (! defined $$buffer) {
1145898184e3Ssthen        $$buffer = '' ;
1146898184e3Ssthen    }
1147b39c5158Smillert
1148b39c5158Smillert    return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ;
1149b39c5158Smillert
1150b39c5158Smillert    # the core read will return 0 if asked for 0 bytes
1151b39c5158Smillert    return 0 if defined $length && $length == 0 ;
1152b39c5158Smillert
1153b39c5158Smillert    $length = $length || 0;
1154b39c5158Smillert
1155b39c5158Smillert    $self->croakError(*$self->{ClassName} . "::read: length parameter is negative")
1156b39c5158Smillert        if $length < 0 ;
1157b39c5158Smillert
1158b39c5158Smillert    # Short-circuit if this is a simple read, with no length
1159b39c5158Smillert    # or offset specified.
1160b39c5158Smillert    unless ( $length || $offset) {
1161b39c5158Smillert        if (length *$self->{Pending}) {
1162b39c5158Smillert            $$buffer .= *$self->{Pending} ;
1163b39c5158Smillert            my $len = length *$self->{Pending};
1164b39c5158Smillert            *$self->{Pending} = '' ;
1165b39c5158Smillert            return $len ;
1166b39c5158Smillert        }
1167b39c5158Smillert        else {
1168b39c5158Smillert            my $len = 0;
1169b39c5158Smillert            $len = $self->_raw_read($buffer)
1170b39c5158Smillert                while ! *$self->{EndStream} && $len == 0 ;
1171b39c5158Smillert            return $len ;
1172b39c5158Smillert        }
1173b39c5158Smillert    }
1174b39c5158Smillert
1175b39c5158Smillert    # Need to jump through more hoops - either length or offset
1176b39c5158Smillert    # or both are specified.
1177b39c5158Smillert    my $out_buffer = *$self->{Pending} ;
1178b39c5158Smillert    *$self->{Pending} = '';
1179b39c5158Smillert
1180b39c5158Smillert
1181b39c5158Smillert    while (! *$self->{EndStream} && length($out_buffer) < $length)
1182b39c5158Smillert    {
1183b39c5158Smillert        my $buf_len = $self->_raw_read(\$out_buffer);
1184b39c5158Smillert        return $buf_len
1185b39c5158Smillert            if $buf_len < 0 ;
1186b39c5158Smillert    }
1187b39c5158Smillert
1188b39c5158Smillert    $length = length $out_buffer
1189b39c5158Smillert        if length($out_buffer) < $length ;
1190b39c5158Smillert
1191b39c5158Smillert    return 0
1192b39c5158Smillert        if $length == 0 ;
1193b39c5158Smillert
1194b39c5158Smillert    $$buffer = ''
1195b39c5158Smillert        if ! defined $$buffer;
1196b39c5158Smillert
1197b39c5158Smillert    $offset = length $$buffer
1198b39c5158Smillert        if *$self->{AppendOutput} ;
1199b39c5158Smillert
1200b39c5158Smillert    *$self->{Pending} = $out_buffer;
1201b39c5158Smillert    $out_buffer = \*$self->{Pending} ;
1202b39c5158Smillert
1203b39c5158Smillert    substr($$buffer, $offset) = substr($$out_buffer, 0, $length) ;
1204b39c5158Smillert    substr($$out_buffer, 0, $length) =  '' ;
1205b39c5158Smillert
1206b39c5158Smillert    return $length ;
1207b39c5158Smillert}
1208b39c5158Smillert
1209b39c5158Smillertsub _getline
1210b39c5158Smillert{
1211b39c5158Smillert    my $self = shift ;
1212898184e3Ssthen    my $status = 0 ;
1213b39c5158Smillert
1214b39c5158Smillert    # Slurp Mode
1215b39c5158Smillert    if ( ! defined $/ ) {
1216b39c5158Smillert        my $data ;
1217898184e3Ssthen        1 while ($status = $self->read($data)) > 0 ;
1218898184e3Ssthen        return ($status, \$data);
1219b39c5158Smillert    }
1220b39c5158Smillert
1221b39c5158Smillert    # Record Mode
1222b39c5158Smillert    if ( ref $/ eq 'SCALAR' && ${$/} =~ /^\d+$/ && ${$/} > 0) {
1223b39c5158Smillert        my $reclen = ${$/} ;
1224b39c5158Smillert        my $data ;
1225898184e3Ssthen        $status = $self->read($data, $reclen) ;
1226898184e3Ssthen        return ($status, \$data);
1227b39c5158Smillert    }
1228b39c5158Smillert
1229b39c5158Smillert    # Paragraph Mode
1230b39c5158Smillert    if ( ! length $/ ) {
1231b39c5158Smillert        my $paragraph ;
1232898184e3Ssthen        while (($status = $self->read($paragraph)) > 0 ) {
1233b39c5158Smillert            if ($paragraph =~ s/^(.*?\n\n+)//s) {
1234b39c5158Smillert                *$self->{Pending}  = $paragraph ;
1235b39c5158Smillert                my $par = $1 ;
1236898184e3Ssthen                return (1, \$par);
1237b39c5158Smillert            }
1238b39c5158Smillert        }
1239898184e3Ssthen        return ($status, \$paragraph);
1240b39c5158Smillert    }
1241b39c5158Smillert
1242b39c5158Smillert    # $/ isn't empty, or a reference, so it's Line Mode.
1243b39c5158Smillert    {
1244b39c5158Smillert        my $line ;
1245b39c5158Smillert        my $p = \*$self->{Pending}  ;
1246898184e3Ssthen        while (($status = $self->read($line)) > 0 ) {
1247b39c5158Smillert            my $offset = index($line, $/);
1248b39c5158Smillert            if ($offset >= 0) {
1249b39c5158Smillert                my $l = substr($line, 0, $offset + length $/ );
1250b39c5158Smillert                substr($line, 0, $offset + length $/) = '';
1251b39c5158Smillert                $$p = $line;
1252898184e3Ssthen                return (1, \$l);
1253b39c5158Smillert            }
1254b39c5158Smillert        }
1255b39c5158Smillert
1256898184e3Ssthen        return ($status, \$line);
1257b39c5158Smillert    }
1258b39c5158Smillert}
1259b39c5158Smillert
1260b39c5158Smillertsub getline
1261b39c5158Smillert{
1262b39c5158Smillert    my $self = shift;
1263898184e3Ssthen
1264898184e3Ssthen    if (defined *$self->{ReadStatus} ) {
1265898184e3Ssthen        $self->saveErrorString( @{ *$self->{ReadStatus} } );
1266898184e3Ssthen        delete  *$self->{ReadStatus} ;
1267898184e3Ssthen        return undef;
1268898184e3Ssthen    }
1269898184e3Ssthen
1270898184e3Ssthen    return undef
1271898184e3Ssthen        if *$self->{Closed} || (!length *$self->{Pending} && *$self->{EndStream}) ;
1272898184e3Ssthen
1273b39c5158Smillert    my $current_append = *$self->{AppendOutput} ;
1274b39c5158Smillert    *$self->{AppendOutput} = 1;
1275898184e3Ssthen
1276898184e3Ssthen    my ($status, $lineref) = $self->_getline();
1277b39c5158Smillert    *$self->{AppendOutput} = $current_append;
1278898184e3Ssthen
1279898184e3Ssthen    return undef
1280898184e3Ssthen        if $status < 0 || length $$lineref == 0 ;
1281898184e3Ssthen
1282898184e3Ssthen    $. = ++ *$self->{LineNo} ;
1283898184e3Ssthen
1284b39c5158Smillert    return $$lineref ;
1285b39c5158Smillert}
1286b39c5158Smillert
1287b39c5158Smillertsub getlines
1288b39c5158Smillert{
1289b39c5158Smillert    my $self = shift;
1290b39c5158Smillert    $self->croakError(*$self->{ClassName} .
1291b39c5158Smillert            "::getlines: called in scalar context\n") unless wantarray;
1292b39c5158Smillert    my($line, @lines);
1293b39c5158Smillert    push(@lines, $line)
1294b39c5158Smillert        while defined($line = $self->getline);
1295b39c5158Smillert    return @lines;
1296b39c5158Smillert}
1297b39c5158Smillert
1298b39c5158Smillertsub READLINE
1299b39c5158Smillert{
1300b39c5158Smillert    goto &getlines if wantarray;
1301b39c5158Smillert    goto &getline;
1302b39c5158Smillert}
1303b39c5158Smillert
1304b39c5158Smillertsub getc
1305b39c5158Smillert{
1306b39c5158Smillert    my $self = shift;
1307b39c5158Smillert    my $buf;
1308b39c5158Smillert    return $buf if $self->read($buf, 1);
1309b39c5158Smillert    return undef;
1310b39c5158Smillert}
1311b39c5158Smillert
1312b39c5158Smillertsub ungetc
1313b39c5158Smillert{
1314b39c5158Smillert    my $self = shift;
1315b39c5158Smillert    *$self->{Pending} = ""  unless defined *$self->{Pending} ;
1316b39c5158Smillert    *$self->{Pending} = $_[0] . *$self->{Pending} ;
1317b39c5158Smillert}
1318b39c5158Smillert
1319b39c5158Smillert
1320b39c5158Smillertsub trailingData
1321b39c5158Smillert{
1322b39c5158Smillert    my $self = shift ;
1323b39c5158Smillert
1324b39c5158Smillert    if (defined *$self->{FH} || defined *$self->{InputEvent} ) {
1325b39c5158Smillert        return *$self->{Prime} ;
1326b39c5158Smillert    }
1327b39c5158Smillert    else {
1328b39c5158Smillert        my $buf = *$self->{Buffer} ;
1329b39c5158Smillert        my $offset = *$self->{BufferOffset} ;
1330b39c5158Smillert        return substr($$buf, $offset) ;
1331b39c5158Smillert    }
1332b39c5158Smillert}
1333b39c5158Smillert
1334b39c5158Smillert
1335b39c5158Smillertsub eof
1336b39c5158Smillert{
1337b39c5158Smillert    my $self = shift ;
1338b39c5158Smillert
1339b39c5158Smillert    return (*$self->{Closed} ||
1340b39c5158Smillert              (!length *$self->{Pending}
1341b39c5158Smillert                && ( $self->smartEof() || *$self->{EndStream}))) ;
1342b39c5158Smillert}
1343b39c5158Smillert
1344b39c5158Smillertsub tell
1345b39c5158Smillert{
1346b39c5158Smillert    my $self = shift ;
1347b39c5158Smillert
1348b39c5158Smillert    my $in ;
1349b39c5158Smillert    if (*$self->{Plain}) {
1350b39c5158Smillert        $in = *$self->{PlainBytesRead} ;
1351b39c5158Smillert    }
1352b39c5158Smillert    else {
1353b39c5158Smillert        $in = *$self->{TotalInflatedBytesRead} ;
1354b39c5158Smillert    }
1355b39c5158Smillert
1356b39c5158Smillert    my $pending = length *$self->{Pending} ;
1357b39c5158Smillert
1358b39c5158Smillert    return 0 if $pending > $in ;
1359b39c5158Smillert    return $in - $pending ;
1360b39c5158Smillert}
1361b39c5158Smillert
1362b39c5158Smillertsub close
1363b39c5158Smillert{
1364b39c5158Smillert    # todo - what to do if close is called before the end of the gzip file
1365b39c5158Smillert    #        do we remember any trailing data?
1366b39c5158Smillert    my $self = shift ;
1367b39c5158Smillert
1368b39c5158Smillert    return 1 if *$self->{Closed} ;
1369b39c5158Smillert
1370b39c5158Smillert    untie *$self
1371b39c5158Smillert        if $] >= 5.008 ;
1372b39c5158Smillert
1373b39c5158Smillert    my $status = 1 ;
1374b39c5158Smillert
1375b39c5158Smillert    if (defined *$self->{FH}) {
1376b39c5158Smillert        if ((! *$self->{Handle} || *$self->{AutoClose}) && ! *$self->{StdIO}) {
1377b39c5158Smillert            local $.;
1378b39c5158Smillert            $! = 0 ;
1379b39c5158Smillert            $status = *$self->{FH}->close();
1380b39c5158Smillert            return $self->saveErrorString(0, $!, $!)
1381b39c5158Smillert                if !*$self->{InNew} && $self->saveStatus($!) != 0 ;
1382b39c5158Smillert        }
1383b39c5158Smillert        delete *$self->{FH} ;
1384b39c5158Smillert        $! = 0 ;
1385b39c5158Smillert    }
1386b39c5158Smillert    *$self->{Closed} = 1 ;
1387b39c5158Smillert
1388b39c5158Smillert    return 1;
1389b39c5158Smillert}
1390b39c5158Smillert
1391b39c5158Smillertsub DESTROY
1392b39c5158Smillert{
1393b39c5158Smillert    my $self = shift ;
1394b39c5158Smillert    local ($., $@, $!, $^E, $?);
1395b39c5158Smillert
1396b39c5158Smillert    $self->close() ;
1397b39c5158Smillert}
1398b39c5158Smillert
1399b39c5158Smillertsub seek
1400b39c5158Smillert{
1401b39c5158Smillert    my $self     = shift ;
1402b39c5158Smillert    my $position = shift;
1403b39c5158Smillert    my $whence   = shift ;
1404b39c5158Smillert
1405b39c5158Smillert    my $here = $self->tell() ;
1406b39c5158Smillert    my $target = 0 ;
1407b39c5158Smillert
1408b39c5158Smillert
1409b39c5158Smillert    if ($whence == SEEK_SET) {
1410b39c5158Smillert        $target = $position ;
1411b39c5158Smillert    }
1412b39c5158Smillert    elsif ($whence == SEEK_CUR) {
1413b39c5158Smillert        $target = $here + $position ;
1414b39c5158Smillert    }
1415b39c5158Smillert    elsif ($whence == SEEK_END) {
1416b39c5158Smillert        $target = $position ;
1417b39c5158Smillert        $self->croakError(*$self->{ClassName} . "::seek: SEEK_END not allowed") ;
1418b39c5158Smillert    }
1419b39c5158Smillert    else {
1420b39c5158Smillert        $self->croakError(*$self->{ClassName} ."::seek: unknown value, $whence, for whence parameter");
1421b39c5158Smillert    }
1422b39c5158Smillert
1423b39c5158Smillert    # short circuit if seeking to current offset
1424b39c5158Smillert    if ($target == $here) {
1425b39c5158Smillert        # On ordinary filehandles, seeking to the current
1426b39c5158Smillert        # position also clears the EOF condition, so we
1427b39c5158Smillert        # emulate this behavior locally while simultaneously
1428b39c5158Smillert        # cascading it to the underlying filehandle
1429b39c5158Smillert        if (*$self->{Plain}) {
1430b39c5158Smillert            *$self->{EndStream} = 0;
1431b39c5158Smillert            seek(*$self->{FH},0,1) if *$self->{FH};
1432b39c5158Smillert        }
1433b39c5158Smillert        return 1;
1434b39c5158Smillert    }
1435b39c5158Smillert
1436b39c5158Smillert    # Outlaw any attempt to seek backwards
1437b39c5158Smillert    $self->croakError( *$self->{ClassName} ."::seek: cannot seek backwards")
1438b39c5158Smillert        if $target < $here ;
1439b39c5158Smillert
1440b39c5158Smillert    # Walk the file to the new offset
1441b39c5158Smillert    my $offset = $target - $here ;
1442b39c5158Smillert
1443b39c5158Smillert    my $got;
144491f110e0Safresh1    while (($got = $self->read(my $buffer, List::Util::min($offset, *$self->{BlockSize})) ) > 0)
1445b39c5158Smillert    {
1446b39c5158Smillert        $offset -= $got;
1447b39c5158Smillert        last if $offset == 0 ;
1448b39c5158Smillert    }
1449b39c5158Smillert
1450b39c5158Smillert    $here = $self->tell() ;
1451b39c5158Smillert    return $offset == 0 ? 1 : 0 ;
1452b39c5158Smillert}
1453b39c5158Smillert
1454b39c5158Smillertsub fileno
1455b39c5158Smillert{
1456b39c5158Smillert    my $self = shift ;
1457b39c5158Smillert    return defined *$self->{FH}
1458b39c5158Smillert           ? fileno *$self->{FH}
1459b39c5158Smillert           : undef ;
1460b39c5158Smillert}
1461b39c5158Smillert
1462b39c5158Smillertsub binmode
1463b39c5158Smillert{
1464b39c5158Smillert    1;
1465b39c5158Smillert#    my $self     = shift ;
1466b39c5158Smillert#    return defined *$self->{FH}
1467b39c5158Smillert#            ? binmode *$self->{FH}
1468b39c5158Smillert#            : 1 ;
1469b39c5158Smillert}
1470b39c5158Smillert
1471b39c5158Smillertsub opened
1472b39c5158Smillert{
1473b39c5158Smillert    my $self     = shift ;
1474b39c5158Smillert    return ! *$self->{Closed} ;
1475b39c5158Smillert}
1476b39c5158Smillert
1477b39c5158Smillertsub autoflush
1478b39c5158Smillert{
1479b39c5158Smillert    my $self     = shift ;
1480b39c5158Smillert    return defined *$self->{FH}
1481b39c5158Smillert            ? *$self->{FH}->autoflush(@_)
1482b39c5158Smillert            : undef ;
1483b39c5158Smillert}
1484b39c5158Smillert
1485b39c5158Smillertsub input_line_number
1486b39c5158Smillert{
1487b39c5158Smillert    my $self = shift ;
1488b39c5158Smillert    my $last = *$self->{LineNo};
1489b39c5158Smillert    $. = *$self->{LineNo} = $_[1] if @_ ;
1490b39c5158Smillert    return $last;
1491b39c5158Smillert}
1492b39c5158Smillert
1493eac174f2Safresh1sub _notAvailable
1494eac174f2Safresh1{
1495eac174f2Safresh1    my $name = shift ;
1496eac174f2Safresh1    return sub { croak "$name Not Available: File opened only for intput" ; } ;
1497eac174f2Safresh1}
1498eac174f2Safresh1
1499eac174f2Safresh1{
1500eac174f2Safresh1    no warnings 'once';
1501b39c5158Smillert
1502b39c5158Smillert    *BINMODE  = \&binmode;
1503b39c5158Smillert    *SEEK     = \&seek;
1504b39c5158Smillert    *READ     = \&read;
1505b39c5158Smillert    *sysread  = \&read;
1506b39c5158Smillert    *TELL     = \&tell;
1507b39c5158Smillert    *EOF      = \&eof;
1508b39c5158Smillert
1509b39c5158Smillert    *FILENO   = \&fileno;
1510b39c5158Smillert    *CLOSE    = \&close;
1511b39c5158Smillert
1512b39c5158Smillert    *print    = _notAvailable('print');
1513b39c5158Smillert    *PRINT    = _notAvailable('print');
1514b39c5158Smillert    *printf   = _notAvailable('printf');
1515b39c5158Smillert    *PRINTF   = _notAvailable('printf');
1516b39c5158Smillert    *write    = _notAvailable('write');
1517b39c5158Smillert    *WRITE    = _notAvailable('write');
1518b39c5158Smillert
1519b39c5158Smillert    #*sysread  = \&read;
1520b39c5158Smillert    #*syswrite = \&_notAvailable;
1521eac174f2Safresh1}
1522b39c5158Smillert
1523b39c5158Smillert
1524b39c5158Smillert
1525b39c5158Smillertpackage IO::Uncompress::Base ;
1526b39c5158Smillert
1527b39c5158Smillert
1528b39c5158Smillert1 ;
1529b39c5158Smillert__END__
1530b39c5158Smillert
1531b39c5158Smillert=head1 NAME
1532b39c5158Smillert
1533b39c5158SmillertIO::Uncompress::Base - Base Class for IO::Uncompress modules
1534b39c5158Smillert
1535b39c5158Smillert=head1 SYNOPSIS
1536b39c5158Smillert
1537b39c5158Smillert    use IO::Uncompress::Base ;
1538b39c5158Smillert
1539b39c5158Smillert=head1 DESCRIPTION
1540b39c5158Smillert
1541b39c5158SmillertThis module is not intended for direct use in application code. Its sole
15426fb12b70Safresh1purpose is to be sub-classed by IO::Uncompress modules.
1543b39c5158Smillert
154456d68f1eSafresh1=head1 SUPPORT
154556d68f1eSafresh1
154656d68f1eSafresh1General feedback/questions/bug reports should be sent to
154756d68f1eSafresh1L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
154856d68f1eSafresh1L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
154956d68f1eSafresh1
1550b39c5158Smillert=head1 SEE ALSO
1551b39c5158Smillert
1552b46d8ef2Safresh1L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzip>, L<IO::Uncompress::UnLzip>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Compress::Zstd>, L<IO::Uncompress::UnZstd>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress>
1553b39c5158Smillert
1554898184e3SsthenL<IO::Compress::FAQ|IO::Compress::FAQ>
1555b39c5158Smillert
1556b39c5158SmillertL<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>,
1557b39c5158SmillertL<Archive::Tar|Archive::Tar>,
1558b39c5158SmillertL<IO::Zlib|IO::Zlib>
1559b39c5158Smillert
1560b39c5158Smillert=head1 AUTHOR
1561b39c5158Smillert
15629f11ffb7Safresh1This module was written by Paul Marquess, C<pmqs@cpan.org>.
1563b39c5158Smillert
1564b39c5158Smillert=head1 MODIFICATION HISTORY
1565b39c5158Smillert
1566b39c5158SmillertSee the Changes file.
1567b39c5158Smillert
1568b39c5158Smillert=head1 COPYRIGHT AND LICENSE
1569b39c5158Smillert
1570*3d61058aSafresh1Copyright (c) 2005-2024 Paul Marquess. All rights reserved.
1571b39c5158Smillert
1572b39c5158SmillertThis program is free software; you can redistribute it and/or
1573b39c5158Smillertmodify it under the same terms as Perl itself.
1574