Fix use of a variable before it is initialised, introduced by change
[p5sagit/p5-mst-13.2.git] / ext / IO_Compress_Base / lib / IO / Uncompress / Base.pm
CommitLineData
25f0751f 1
2package IO::Uncompress::Base ;
3
4use strict ;
5use warnings;
6use bytes;
7
8our (@ISA, $VERSION, @EXPORT_OK, %EXPORT_TAGS);
93d092e2 9@ISA = qw(Exporter IO::File);
25f0751f 10
11
a1787f24 12$VERSION = '2.011';
25f0751f 13
14use constant G_EOF => 0 ;
15use constant G_ERR => -1 ;
16
a1787f24 17use IO::Compress::Base::Common 2.011 ;
25f0751f 18#use Parse::Parameters ;
19
20use IO::File ;
21use Symbol;
22use Scalar::Util qw(readonly);
23use List::Util qw(min);
24use Carp ;
25
26%EXPORT_TAGS = ( );
27push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ;
28#Exporter::export_ok_tags('all') ;
29
30
d54256af 31
25f0751f 32sub smartRead
33{
34 my $self = $_[0];
35 my $out = $_[1];
36 my $size = $_[2];
37 $$out = "" ;
38
39 my $offset = 0 ;
40
41
6ecef415 42 if (defined *$self->{InputLength}) {
43 return 0
44 if *$self->{InputLengthRemaining} <= 0 ;
45 $size = min($size, *$self->{InputLengthRemaining});
2b4e0969 46 }
47
25f0751f 48 if ( length *$self->{Prime} ) {
49 #$$out = substr(*$self->{Prime}, 0, $size, '') ;
50 $$out = substr(*$self->{Prime}, 0, $size) ;
51 substr(*$self->{Prime}, 0, $size) = '' ;
6ecef415 52 if (length $$out == $size) {
53 *$self->{InputLengthRemaining} -= length $$out
54 if defined *$self->{InputLength};
55
25f0751f 56 return length $$out ;
57 }
58 $offset = length $$out ;
59 }
60
61 my $get_size = $size - $offset ;
62
d54256af 63 if (defined *$self->{FH}) {
64 if ($offset) {
65 # Not using this
66 #
67 # *$self->{FH}->read($$out, $get_size, $offset);
68 #
69 # because the filehandle may not support the offset parameter
70 # An example is Net::FTP
71 my $tmp = '';
72 *$self->{FH}->read($tmp, $get_size) > 0 &&
73 (substr($$out, $offset) = $tmp);
74 }
75 else
76 { *$self->{FH}->read($$out, $get_size) }
77 }
25f0751f 78 elsif (defined *$self->{InputEvent}) {
79 my $got = 1 ;
80 while (length $$out < $size) {
81 last
82 if ($got = *$self->{InputEvent}->($$out, $get_size)) <= 0;
83 }
84
85 if (length $$out > $size ) {
86 #*$self->{Prime} = substr($$out, $size, length($$out), '');
87 *$self->{Prime} = substr($$out, $size, length($$out));
88 substr($$out, $size, length($$out)) = '';
89 }
90
91 *$self->{EventEof} = 1 if $got <= 0 ;
92 }
93 else {
94 no warnings 'uninitialized';
95 my $buf = *$self->{Buffer} ;
96 $$buf = '' unless defined $$buf ;
97 #$$out = '' unless defined $$out ;
98 substr($$out, $offset) = substr($$buf, *$self->{BufferOffset}, $get_size);
e7d45986 99 if (*$self->{ConsumeInput})
100 { substr($$buf, 0, $get_size) = '' }
101 else
102 { *$self->{BufferOffset} += length($$out) - $offset }
25f0751f 103 }
104
6ecef415 105 *$self->{InputLengthRemaining} -= length($$out) #- $offset
106 if defined *$self->{InputLength};
25f0751f 107
108 $self->saveStatus(length $$out < 0 ? STATUS_ERROR : STATUS_OK) ;
109
110 return length $$out;
111}
112
113sub pushBack
114{
115 my $self = shift ;
116
117 return if ! defined $_[0] || length $_[0] == 0 ;
118
119 if (defined *$self->{FH} || defined *$self->{InputEvent} ) {
120 *$self->{Prime} = $_[0] . *$self->{Prime} ;
2b4e0969 121 *$self->{InputLengthRemaining} += length($_[0]);
25f0751f 122 }
123 else {
124 my $len = length $_[0];
125
126 if($len > *$self->{BufferOffset}) {
127 *$self->{Prime} = substr($_[0], 0, $len - *$self->{BufferOffset}) . *$self->{Prime} ;
128 *$self->{InputLengthRemaining} = *$self->{InputLength};
129 *$self->{BufferOffset} = 0
130 }
131 else {
132 *$self->{InputLengthRemaining} += length($_[0]);
133 *$self->{BufferOffset} -= length($_[0]) ;
134 }
135 }
136}
137
138sub smartSeek
139{
140 my $self = shift ;
141 my $offset = shift ;
142 my $truncate = shift;
143 #print "smartSeek to $offset\n";
144
145 # TODO -- need to take prime into account
146 if (defined *$self->{FH})
147 { *$self->{FH}->seek($offset, SEEK_SET) }
148 else {
149 *$self->{BufferOffset} = $offset ;
150 substr(${ *$self->{Buffer} }, *$self->{BufferOffset}) = ''
151 if $truncate;
152 return 1;
153 }
154}
155
156sub smartWrite
157{
158 my $self = shift ;
159 my $out_data = shift ;
160
161 if (defined *$self->{FH}) {
162 # flush needed for 5.8.0
163 defined *$self->{FH}->write($out_data, length $out_data) &&
164 defined *$self->{FH}->flush() ;
165 }
166 else {
167 my $buf = *$self->{Buffer} ;
168 substr($$buf, *$self->{BufferOffset}, length $out_data) = $out_data ;
169 *$self->{BufferOffset} += length($out_data) ;
170 return 1;
171 }
172}
173
174sub smartReadExact
175{
176 return $_[0]->smartRead($_[1], $_[2]) == $_[2];
177}
178
179sub smartEof
180{
181 my ($self) = $_[0];
182 local $.;
183
e7d45986 184 return 0 if length *$self->{Prime} || *$self->{PushMode};
25f0751f 185
186 if (defined *$self->{FH})
d54256af 187 {
188 # Could use
189 #
190 # *$self->{FH}->eof()
191 #
192 # here, but this can cause trouble if
193 # the filehandle is itself a tied handle, but it uses sysread.
194 # Then we get into mixing buffered & non-buffered IO, which will cause trouble
195
196 my $info = $self->getErrInfo();
197
198 my $buffer = '';
199 my $status = $self->smartRead(\$buffer, 1);
200 $self->pushBack($buffer) if length $buffer;
201 $self->setErrInfo($info);
202
203 return $status == 0 ;
204 }
25f0751f 205 elsif (defined *$self->{InputEvent})
206 { *$self->{EventEof} }
207 else
208 { *$self->{BufferOffset} >= length(${ *$self->{Buffer} }) }
209}
210
211sub clearError
212{
213 my $self = shift ;
214
215 *$self->{ErrorNo} = 0 ;
216 ${ *$self->{Error} } = '' ;
217}
218
d54256af 219sub getErrInfo
220{
221 my $self = shift ;
222
223 return [ *$self->{ErrorNo}, ${ *$self->{Error} } ] ;
224}
225
226sub setErrInfo
227{
228 my $self = shift ;
229 my $ref = shift;
230
231 *$self->{ErrorNo} = $ref->[0] ;
232 ${ *$self->{Error} } = $ref->[1] ;
233}
234
25f0751f 235sub saveStatus
236{
237 my $self = shift ;
238 my $errno = shift() + 0 ;
239 #return $errno unless $errno || ! defined *$self->{ErrorNo};
240 #return $errno unless $errno ;
241
242 *$self->{ErrorNo} = $errno;
243 ${ *$self->{Error} } = '' ;
244
245 return *$self->{ErrorNo} ;
246}
247
248
249sub saveErrorString
250{
251 my $self = shift ;
252 my $retval = shift ;
253
254 #return $retval if ${ *$self->{Error} };
255
256 ${ *$self->{Error} } = shift ;
257 *$self->{ErrorNo} = shift() + 0 if @_ ;
258
259 #warn "saveErrorString: " . ${ *$self->{Error} } . " " . *$self->{Error} . "\n" ;
260 return $retval;
261}
262
263sub croakError
264{
265 my $self = shift ;
266 $self->saveErrorString(0, $_[0]);
267 croak $_[0];
268}
269
270
271sub closeError
272{
273 my $self = shift ;
274 my $retval = shift ;
275
276 my $errno = *$self->{ErrorNo};
277 my $error = ${ *$self->{Error} };
278
279 $self->close();
280
281 *$self->{ErrorNo} = $errno ;
282 ${ *$self->{Error} } = $error ;
283
284 return $retval;
285}
286
287sub error
288{
289 my $self = shift ;
290 return ${ *$self->{Error} } ;
291}
292
293sub errorNo
294{
295 my $self = shift ;
296 return *$self->{ErrorNo};
297}
298
299sub HeaderError
300{
301 my ($self) = shift;
302 return $self->saveErrorString(undef, "Header Error: $_[0]", STATUS_ERROR);
303}
304
305sub TrailerError
306{
307 my ($self) = shift;
308 return $self->saveErrorString(G_ERR, "Trailer Error: $_[0]", STATUS_ERROR);
309}
310
311sub TruncatedHeader
312{
313 my ($self) = shift;
314 return $self->HeaderError("Truncated in $_[0] Section");
315}
316
2b4e0969 317sub TruncatedTrailer
318{
319 my ($self) = shift;
320 return $self->TrailerError("Truncated in $_[0] Section");
321}
322
258133d1 323sub postCheckParams
324{
325 return 1;
326}
327
25f0751f 328sub checkParams
329{
330 my $self = shift ;
331 my $class = shift ;
332
333 my $got = shift || IO::Compress::Base::Parameters::new();
334
335 my $Valid = {
336 'BlockSize' => [1, 1, Parse_unsigned, 16 * 1024],
337 'AutoClose' => [1, 1, Parse_boolean, 0],
338 'Strict' => [1, 1, Parse_boolean, 0],
25f0751f 339 'Append' => [1, 1, Parse_boolean, 0],
340 'Prime' => [1, 1, Parse_any, undef],
341 'MultiStream' => [1, 1, Parse_boolean, 0],
342 'Transparent' => [1, 1, Parse_any, 1],
343 'Scan' => [1, 1, Parse_boolean, 0],
344 'InputLength' => [1, 1, Parse_unsigned, undef],
345 'BinModeOut' => [1, 1, Parse_boolean, 0],
4e7676c7 346 #'Encode' => [1, 1, Parse_any, undef],
347
e7d45986 348 #'ConsumeInput' => [1, 1, Parse_boolean, 0],
25f0751f 349
350 $self->getExtraParams(),
351
25f0751f 352 #'Todo - Revert to ordinary file on end Z_STREAM_END'=> 0,
353 # ContinueAfterEof
354 } ;
355
258133d1 356 $Valid->{TrailingData} = [1, 1, Parse_writable_scalar, undef]
357 if *$self->{OneShot} ;
25f0751f 358
359 $got->parse($Valid, @_ )
360 or $self->croakError("${class}: $got->{Error}") ;
361
258133d1 362 $self->postCheckParams($got)
363 or $self->croakError("${class}: " . $self->error()) ;
25f0751f 364
365 return $got;
366}
367
368sub _create
369{
370 my $obj = shift;
371 my $got = shift;
372 my $append_mode = shift ;
373
374 my $class = ref $obj;
375 $obj->croakError("$class: Missing Input parameter")
376 if ! @_ && ! $got ;
377
378 my $inValue = shift ;
379
258133d1 380 *$obj->{OneShot} = 0 ;
381
25f0751f 382 if (! $got)
383 {
384 $got = $obj->checkParams($class, undef, @_)
385 or return undef ;
386 }
387
388 my $inType = whatIsInput($inValue, 1);
389
390 $obj->ckInputParam($class, $inValue, 1)
391 or return undef ;
392
393 *$obj->{InNew} = 1;
394
395 $obj->ckParams($got)
258133d1 396 or $obj->croakError("${class}: " . *$obj->{Error});
25f0751f 397
398 if ($inType eq 'buffer' || $inType eq 'code') {
399 *$obj->{Buffer} = $inValue ;
400 *$obj->{InputEvent} = $inValue
401 if $inType eq 'code' ;
402 }
403 else {
404 if ($inType eq 'handle') {
405 *$obj->{FH} = $inValue ;
406 *$obj->{Handle} = 1 ;
258133d1 407
25f0751f 408 # Need to rewind for Scan
258133d1 409 *$obj->{FH}->seek(0, SEEK_SET)
410 if $got->value('Scan');
25f0751f 411 }
412 else {
413 my $mode = '<';
414 $mode = '+<' if $got->value('Scan');
415 *$obj->{StdIO} = ($inValue eq '-');
416 *$obj->{FH} = new IO::File "$mode $inValue"
417 or return $obj->saveErrorString(undef, "cannot open file '$inValue': $!", $!) ;
418 }
419
420 *$obj->{LineNo} = $. = 0;
421 setBinModeInput(*$obj->{FH}) ;
422
423 my $buff = "" ;
424 *$obj->{Buffer} = \$buff ;
425 }
426
4e7676c7 427 if ($got->parsed('Encode')) {
428 my $want_encoding = $got->value('Encode');
429 *$obj->{Encoding} = getEncoding($obj, $class, $want_encoding);
430 }
431
25f0751f 432
433 *$obj->{InputLength} = $got->parsed('InputLength')
434 ? $got->value('InputLength')
435 : undef ;
436 *$obj->{InputLengthRemaining} = $got->value('InputLength');
437 *$obj->{BufferOffset} = 0 ;
438 *$obj->{AutoClose} = $got->value('AutoClose');
439 *$obj->{Strict} = $got->value('Strict');
25f0751f 440 *$obj->{BlockSize} = $got->value('BlockSize');
441 *$obj->{Append} = $got->value('Append');
442 *$obj->{AppendOutput} = $append_mode || $got->value('Append');
e7d45986 443 *$obj->{ConsumeInput} = $got->value('ConsumeInput');
25f0751f 444 *$obj->{Transparent} = $got->value('Transparent');
445 *$obj->{MultiStream} = $got->value('MultiStream');
446
447 # TODO - move these two into RawDeflate
448 *$obj->{Scan} = $got->value('Scan');
449 *$obj->{ParseExtra} = $got->value('ParseExtra')
450 || $got->value('Strict') ;
25f0751f 451 *$obj->{Type} = '';
452 *$obj->{Prime} = $got->value('Prime') || '' ;
453 *$obj->{Pending} = '';
454 *$obj->{Plain} = 0;
455 *$obj->{PlainBytesRead} = 0;
456 *$obj->{InflatedBytesRead} = 0;
e7d45986 457 *$obj->{UnCompSize} = new U64;
458 *$obj->{CompSize} = new U64;
25f0751f 459 *$obj->{TotalInflatedBytesRead} = 0;
460 *$obj->{NewStream} = 0 ;
461 *$obj->{EventEof} = 0 ;
462 *$obj->{ClassName} = $class ;
463 *$obj->{Params} = $got ;
464
e7d45986 465 if (*$obj->{ConsumeInput}) {
466 *$obj->{InNew} = 0;
467 *$obj->{Closed} = 0;
468 return $obj
469 }
470
a1787f24 471 my $status = $obj->mkUncomp($got);
25f0751f 472
473 return undef
474 unless defined $status;
475
476 if ( ! $status) {
477 return undef
478 unless *$obj->{Transparent};
479
480 $obj->clearError();
481 *$obj->{Type} = 'plain';
482 *$obj->{Plain} = 1;
483 #$status = $obj->mkIdentityUncomp($class, $got);
484 $obj->pushBack(*$obj->{HeaderPending}) ;
485 }
486
487 push @{ *$obj->{InfoList} }, *$obj->{Info} ;
488
489 $obj->saveStatus(STATUS_OK) ;
490 *$obj->{InNew} = 0;
491 *$obj->{Closed} = 0;
492
493 return $obj;
494}
495
496sub ckInputParam
497{
498 my $self = shift ;
499 my $from = shift ;
500 my $inType = whatIsInput($_[0], $_[1]);
501
502 $self->croakError("$from: input parameter not a filename, filehandle, array ref or scalar ref")
503 if ! $inType ;
504
505 if ($inType eq 'filename' )
506 {
507 $self->croakError("$from: input filename is undef or null string")
508 if ! defined $_[0] || $_[0] eq '' ;
509
510 if ($_[0] ne '-' && ! -e $_[0] )
511 {
512 return $self->saveErrorString(undef,
513 "input file '$_[0]' does not exist", STATUS_ERROR);
514 }
515 }
516
517 return 1;
518}
519
520
521sub _inf
522{
523 my $obj = shift ;
524
525 my $class = (caller)[0] ;
526 my $name = (caller(1))[3] ;
527
528 $obj->croakError("$name: expected at least 1 parameters\n")
529 unless @_ >= 1 ;
530
531 my $input = shift ;
532 my $haveOut = @_ ;
533 my $output = shift ;
534
535
a1787f24 536 my $x = new IO::Compress::Base::Validator($class, *$obj->{Error}, $name, $input, $output)
25f0751f 537 or return undef ;
538
539 push @_, $output if $haveOut && $x->{Hash};
258133d1 540
541 *$obj->{OneShot} = 1 ;
25f0751f 542
543 my $got = $obj->checkParams($name, undef, @_)
544 or return undef ;
545
258133d1 546 if ($got->parsed('TrailingData'))
547 {
548 *$obj->{TrailingData} = $got->value('TrailingData');
549 }
550
e7d45986 551 *$obj->{MultiStream} = $got->value('MultiStream');
552 $got->value('MultiStream', 0);
25f0751f 553
e7d45986 554 $x->{Got} = $got ;
25f0751f 555
e7d45986 556# if ($x->{Hash})
557# {
558# while (my($k, $v) = each %$input)
559# {
560# $v = \$input->{$k}
561# unless defined $v ;
562#
563# $obj->_singleTarget($x, $k, $v, @_)
564# or return undef ;
565# }
566#
567# return keys %$input ;
568# }
25f0751f 569
570 if ($x->{GlobMap})
571 {
572 $x->{oneInput} = 1 ;
573 foreach my $pair (@{ $x->{Pairs} })
574 {
575 my ($from, $to) = @$pair ;
e7d45986 576 $obj->_singleTarget($x, $from, $to, @_)
25f0751f 577 or return undef ;
578 }
579
580 return scalar @{ $x->{Pairs} } ;
581 }
582
25f0751f 583 if (! $x->{oneOutput} )
584 {
585 my $inFile = ($x->{inType} eq 'filenames'
586 || $x->{inType} eq 'filename');
587
588 $x->{inType} = $inFile ? 'filename' : 'buffer';
25f0751f 589
590 foreach my $in ($x->{oneInput} ? $input : @$input)
591 {
592 my $out ;
593 $x->{oneInput} = 1 ;
594
e7d45986 595 $obj->_singleTarget($x, $in, $output, @_)
25f0751f 596 or return undef ;
25f0751f 597 }
598
599 return 1 ;
600 }
601
602 # finally the 1 to 1 and n to 1
e7d45986 603 return $obj->_singleTarget($x, $input, $output, @_);
25f0751f 604
605 croak "should not be here" ;
606}
607
608sub retErr
609{
610 my $x = shift ;
611 my $string = shift ;
612
613 ${ $x->{Error} } = $string ;
614
615 return undef ;
616}
617
618sub _singleTarget
619{
620 my $self = shift ;
621 my $x = shift ;
25f0751f 622 my $input = shift;
623 my $output = shift;
624
e7d45986 625 my $buff = '';
626 $x->{buff} = \$buff ;
25f0751f 627
628 my $fh ;
629 if ($x->{outType} eq 'filename') {
630 my $mode = '>' ;
631 $mode = '>>'
632 if $x->{Got}->value('Append') ;
633 $x->{fh} = new IO::File "$mode $output"
634 or return retErr($x, "cannot open file '$output': $!") ;
635 binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut');
636
637 }
638
639 elsif ($x->{outType} eq 'handle') {
640 $x->{fh} = $output;
641 binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut');
642 if ($x->{Got}->value('Append')) {
643 seek($x->{fh}, 0, SEEK_END)
644 or return retErr($x, "Cannot seek to end of output filehandle: $!") ;
645 }
646 }
647
648
649 elsif ($x->{outType} eq 'buffer' )
650 {
651 $$output = ''
652 unless $x->{Got}->value('Append');
653 $x->{buff} = $output ;
654 }
655
656 if ($x->{oneInput})
657 {
e7d45986 658 defined $self->_rd2($x, $input, $output)
25f0751f 659 or return undef;
660 }
661 else
662 {
25f0751f 663 for my $element ( ($x->{inType} eq 'hash') ? keys %$input : @$input)
664 {
e7d45986 665 defined $self->_rd2($x, $element, $output)
25f0751f 666 or return undef ;
667 }
668 }
669
670
671 if ( ($x->{outType} eq 'filename' && $output ne '-') ||
672 ($x->{outType} eq 'handle' && $x->{Got}->value('AutoClose'))) {
673 $x->{fh}->close()
674 or return retErr($x, $!);
25f0751f 675 delete $x->{fh};
676 }
677
678 return 1 ;
679}
680
681sub _rd2
682{
683 my $self = shift ;
684 my $x = shift ;
685 my $input = shift;
e7d45986 686 my $output = shift;
25f0751f 687
688 my $z = createSelfTiedObject($x->{Class}, *$self->{Error});
689
690 $z->_create($x->{Got}, 1, $input, @_)
691 or return undef ;
692
693 my $status ;
694 my $fh = $x->{fh};
695
e7d45986 696 while (1) {
697
698 while (($status = $z->read($x->{buff})) > 0) {
699 if ($fh) {
700 print $fh ${ $x->{buff} }
701 or return $z->saveErrorString(undef, "Error writing to output file: $!", $!);
702 ${ $x->{buff} } = '' ;
703 }
704 }
705
706 if (! $x->{oneOutput} ) {
707 my $ot = $x->{outType} ;
708
709 if ($ot eq 'array')
710 { push @$output, $x->{buff} }
711 elsif ($ot eq 'hash')
712 { $output->{$input} = $x->{buff} }
713
714 my $buff = '';
715 $x->{buff} = \$buff;
25f0751f 716 }
e7d45986 717
718 last
719 unless *$self->{MultiStream};
720
721 $status = $z->nextStream();
722
723 last
724 unless $status == 1 ;
25f0751f 725 }
726
727 return $z->closeError(undef)
728 if $status < 0 ;
729
258133d1 730 ${ *$self->{TrailingData} } = $z->trailingData()
731 if defined *$self->{TrailingData} ;
732
25f0751f 733 $z->close()
734 or return undef ;
735
736 return 1 ;
737}
738
739sub TIEHANDLE
740{
741 return $_[0] if ref($_[0]);
742 die "OOPS\n" ;
743
744}
745
746sub UNTIE
747{
748 my $self = shift ;
749}
750
751
752sub getHeaderInfo
753{
754 my $self = shift ;
755 wantarray ? @{ *$self->{InfoList} } : *$self->{Info};
756}
757
758sub readBlock
759{
760 my $self = shift ;
761 my $buff = shift ;
762 my $size = shift ;
763
764 if (defined *$self->{CompressedInputLength}) {
765 if (*$self->{CompressedInputLengthRemaining} == 0) {
766 delete *$self->{CompressedInputLength};
767 *$self->{CompressedInputLengthDone} = 1;
768 return STATUS_OK ;
769 }
770 $size = min($size, *$self->{CompressedInputLengthRemaining} );
771 *$self->{CompressedInputLengthRemaining} -= $size ;
772 }
773
774 my $status = $self->smartRead($buff, $size) ;
775 return $self->saveErrorString(STATUS_ERROR, "Error Reading Data")
776 if $status < 0 ;
777
778 if ($status == 0 ) {
779 *$self->{Closed} = 1 ;
780 *$self->{EndStream} = 1 ;
781 return $self->saveErrorString(STATUS_ERROR, "unexpected end of file", STATUS_ERROR);
782 }
783
784 return STATUS_OK;
25f0751f 785}
786
787sub postBlockChk
788{
789 return STATUS_OK;
790}
791
792sub _raw_read
793{
794 # return codes
795 # >0 - ok, number of bytes read
796 # =0 - ok, eof
797 # <0 - not ok
798
799 my $self = shift ;
800
801 return G_EOF if *$self->{Closed} ;
802 #return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ;
803 return G_EOF if *$self->{EndStream} ;
804
805 my $buffer = shift ;
806 my $scan_mode = shift ;
807
808 if (*$self->{Plain}) {
809 my $tmp_buff ;
810 my $len = $self->smartRead(\$tmp_buff, *$self->{BlockSize}) ;
811
812 return $self->saveErrorString(G_ERR, "Error reading data: $!", $!)
813 if $len < 0 ;
814
815 if ($len == 0 ) {
816 *$self->{EndStream} = 1 ;
817 }
818 else {
819 *$self->{PlainBytesRead} += $len ;
820 $$buffer .= $tmp_buff;
821 }
822
823 return $len ;
824 }
825
826 if (*$self->{NewStream}) {
827
e7d45986 828 $self->gotoNextStream() > 0
829 or return G_ERR;
25f0751f 830
831 # For the headers that actually uncompressed data, put the
832 # uncompressed data into the output buffer.
833 $$buffer .= *$self->{Pending} ;
834 my $len = length *$self->{Pending} ;
835 *$self->{Pending} = '';
836 return $len;
837 }
838
e7d45986 839 my $temp_buf = '';
25f0751f 840 my $outSize = 0;
841 my $status = $self->readBlock(\$temp_buf, *$self->{BlockSize}, $outSize) ;
842 return G_ERR
843 if $status == STATUS_ERROR ;
844
845 my $buf_len = 0;
846 if ($status == STATUS_OK) {
e7d45986 847 my $beforeC_len = length $temp_buf;
25f0751f 848 my $before_len = defined $$buffer ? length $$buffer : 0 ;
849 $status = *$self->{Uncomp}->uncompr(\$temp_buf, $buffer,
850 defined *$self->{CompressedInputLengthDone} ||
851 $self->smartEof(), $outSize);
25f0751f 852
853 return $self->saveErrorString(G_ERR, *$self->{Uncomp}{Error}, *$self->{Uncomp}{ErrorNo})
854 if $self->saveStatus($status) == STATUS_ERROR;
855
258133d1 856 $self->postBlockChk($buffer, $before_len) == STATUS_OK
25f0751f 857 or return G_ERR;
858
25f0751f 859 $buf_len = length($$buffer) - $before_len;
25f0751f 860
e7d45986 861 *$self->{CompSize}->add($beforeC_len - length $temp_buf) ;
862
25f0751f 863 *$self->{InflatedBytesRead} += $buf_len ;
864 *$self->{TotalInflatedBytesRead} += $buf_len ;
e7d45986 865 *$self->{UnCompSize}->add($buf_len) ;
4e7676c7 866
867 $self->filterUncompressed($buffer);
868
869 if (*$self->{Encoding}) {
870 $$buffer = *$self->{Encoding}->decode($$buffer);
871 }
25f0751f 872 }
873
874 if ($status == STATUS_ENDSTREAM) {
875
876 *$self->{EndStream} = 1 ;
877 $self->pushBack($temp_buf) ;
878 $temp_buf = '';
879
880 my $trailer;
881 my $trailer_size = *$self->{Info}{TrailerLength} ;
882 my $got = 0;
883 if (*$self->{Info}{TrailerLength})
884 {
885 $got = $self->smartRead(\$trailer, $trailer_size) ;
886 }
887
888 if ($got == $trailer_size) {
889 $self->chkTrailer($trailer) == STATUS_OK
890 or return G_ERR;
891 }
892 else {
893 return $self->TrailerError("trailer truncated. Expected " .
894 "$trailer_size bytes, got $got")
895 if *$self->{Strict};
896 $self->pushBack($trailer) ;
897 }
898
258133d1 899 # TODO - if want to file file pointer, do it here
900
e7d45986 901 if (! $self->smartEof()) {
25f0751f 902 *$self->{NewStream} = 1 ;
e7d45986 903
904 if (*$self->{MultiStream}) {
905 *$self->{EndStream} = 0 ;
906 return $buf_len ;
907 }
25f0751f 908 }
909
910 }
911
912
913 # return the number of uncompressed bytes read
914 return $buf_len ;
915}
916
2b4e0969 917sub reset
918{
919 my $self = shift ;
920
921 return *$self->{Uncomp}->reset();
922}
923
924sub filterUncompressed
925{
926}
927
25f0751f 928#sub isEndStream
929#{
930# my $self = shift ;
931# return *$self->{NewStream} ||
932# *$self->{EndStream} ;
933#}
934
e7d45986 935sub nextStream
936{
937 my $self = shift ;
938
939 my $status = $self->gotoNextStream();
940 $status == 1
941 or return $status ;
942
943 *$self->{TotalInflatedBytesRead} = 0 ;
944 *$self->{LineNo} = $. = 0;
945
946 return 1;
947}
948
949sub gotoNextStream
950{
951 my $self = shift ;
952
953 if (! *$self->{NewStream}) {
954 my $status = 1;
955 my $buffer ;
956
957 # TODO - make this more efficient if know the offset for the end of
958 # the stream and seekable
959 $status = $self->read($buffer)
960 while $status > 0 ;
961
962 return $status
963 if $status < 0;
964 }
965
966 *$self->{NewStream} = 0 ;
967 *$self->{EndStream} = 0 ;
968 $self->reset();
969 *$self->{UnCompSize}->reset();
970 *$self->{CompSize}->reset();
971
6ecef415 972 my $magic = $self->ckMagic();
f6fd7794 973 #*$self->{EndStream} = 0 ;
e7d45986 974
d54256af 975 if ( ! defined $magic) {
f6fd7794 976 if (! *$self->{Transparent} )
977 {
978 *$self->{EndStream} = 1 ;
979 return 0;
980 }
e7d45986 981
f6fd7794 982 $self->clearError();
983 *$self->{Type} = 'plain';
984 *$self->{Plain} = 1;
985 $self->pushBack(*$self->{HeaderPending}) ;
986 }
987 else
988 {
989 *$self->{Info} = $self->readHeader($magic);
6ecef415 990
f6fd7794 991 if ( ! defined *$self->{Info} ) {
992 *$self->{EndStream} = 1 ;
993 return -1;
994 }
6ecef415 995 }
e7d45986 996
997 push @{ *$self->{InfoList} }, *$self->{Info} ;
998
999 return 1;
1000}
1001
25f0751f 1002sub streamCount
1003{
1004 my $self = shift ;
1005 return 1 if ! defined *$self->{InfoList};
1006 return scalar @{ *$self->{InfoList} } ;
1007}
1008
1009sub read
1010{
1011 # return codes
1012 # >0 - ok, number of bytes read
1013 # =0 - ok, eof
1014 # <0 - not ok
1015
1016 my $self = shift ;
1017
1018 return G_EOF if *$self->{Closed} ;
25f0751f 1019
1020 my $buffer ;
1021
25f0751f 1022 if (ref $_[0] ) {
1023 $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
1024 if readonly(${ $_[0] });
1025
1026 $self->croakError(*$self->{ClassName} . "::read: not a scalar reference $_[0]" )
1027 unless ref $_[0] eq 'SCALAR' ;
1028 $buffer = $_[0] ;
1029 }
1030 else {
1031 $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
1032 if readonly($_[0]);
1033
1034 $buffer = \$_[0] ;
1035 }
1036
1037 my $length = $_[1] ;
1038 my $offset = $_[2] || 0;
1039
93d092e2 1040 if (! *$self->{AppendOutput}) {
1041 if (! $offset) {
1042 $$buffer = '' ;
1043 }
1044 else {
1045 if ($offset > length($$buffer)) {
1046 $$buffer .= "\x00" x ($offset - length($$buffer));
1047 }
1048 else {
1049 substr($$buffer, $offset) = '';
1050 }
1051 }
1052 }
1053
1054 return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ;
1055
25f0751f 1056 # the core read will return 0 if asked for 0 bytes
1057 return 0 if defined $length && $length == 0 ;
1058
1059 $length = $length || 0;
1060
1061 $self->croakError(*$self->{ClassName} . "::read: length parameter is negative")
1062 if $length < 0 ;
1063
25f0751f 1064 # Short-circuit if this is a simple read, with no length
1065 # or offset specified.
1066 unless ( $length || $offset) {
1067 if (length *$self->{Pending}) {
1068 $$buffer .= *$self->{Pending} ;
1069 my $len = length *$self->{Pending};
1070 *$self->{Pending} = '' ;
1071 return $len ;
1072 }
1073 else {
1074 my $len = 0;
1075 $len = $self->_raw_read($buffer)
1076 while ! *$self->{EndStream} && $len == 0 ;
1077 return $len ;
1078 }
1079 }
1080
1081 # Need to jump through more hoops - either length or offset
1082 # or both are specified.
f6fd7794 1083 my $out_buffer = *$self->{Pending} ;
25f0751f 1084
93d092e2 1085
f6fd7794 1086 while (! *$self->{EndStream} && length($out_buffer) < $length)
25f0751f 1087 {
f6fd7794 1088 my $buf_len = $self->_raw_read(\$out_buffer);
25f0751f 1089 return $buf_len
1090 if $buf_len < 0 ;
1091 }
1092
f6fd7794 1093 $length = length $out_buffer
1094 if length($out_buffer) < $length ;
25f0751f 1095
258133d1 1096 return 0
1097 if $length == 0 ;
1098
93d092e2 1099 $$buffer = ''
1100 if ! defined $$buffer;
1101
1102 $offset = length $$buffer
1103 if *$self->{AppendOutput} ;
1104
f6fd7794 1105 *$self->{Pending} = $out_buffer;
1106 $out_buffer = \*$self->{Pending} ;
1107
93d092e2 1108 #substr($$buffer, $offset) = substr($$out_buffer, 0, $length, '') ;
1109 substr($$buffer, $offset) = substr($$out_buffer, 0, $length) ;
1110 substr($$out_buffer, 0, $length) = '' ;
25f0751f 1111
1112 return $length ;
1113}
1114
1115sub _getline
1116{
1117 my $self = shift ;
1118
1119 # Slurp Mode
1120 if ( ! defined $/ ) {
1121 my $data ;
1122 1 while $self->read($data) > 0 ;
258133d1 1123 return \$data ;
1124 }
1125
1126 # Record Mode
1127 if ( ref $/ eq 'SCALAR' && ${$/} =~ /^\d+$/ && ${$/} > 0) {
1128 my $reclen = ${$/} ;
1129 my $data ;
1130 $self->read($data, $reclen) ;
25f0751f 1131 return \$data ;
1132 }
1133
1134 # Paragraph Mode
1135 if ( ! length $/ ) {
1136 my $paragraph ;
1137 while ($self->read($paragraph) > 0 ) {
1138 if ($paragraph =~ s/^(.*?\n\n+)//s) {
1139 *$self->{Pending} = $paragraph ;
1140 my $par = $1 ;
25f0751f 1141 return \$par ;
1142 }
1143 }
25f0751f 1144 return \$paragraph;
1145 }
1146
258133d1 1147 # $/ isn't empty, or a reference, so it's Line Mode.
25f0751f 1148 {
1149 my $line ;
258133d1 1150 my $offset;
1151 my $p = \*$self->{Pending} ;
1152
1153 if (length(*$self->{Pending}) &&
1154 ($offset = index(*$self->{Pending}, $/)) >=0) {
1155 my $l = substr(*$self->{Pending}, 0, $offset + length $/ );
1156 substr(*$self->{Pending}, 0, $offset + length $/) = '';
1157 return \$l;
1158 }
1159
25f0751f 1160 while ($self->read($line) > 0 ) {
258133d1 1161 my $offset = index($line, $/);
1162 if ($offset >= 0) {
1163 my $l = substr($line, 0, $offset + length $/ );
1164 substr($line, 0, $offset + length $/) = '';
1165 $$p = $line;
1166 return \$l;
25f0751f 1167 }
1168 }
258133d1 1169
25f0751f 1170 return \$line;
1171 }
1172}
1173
1174sub getline
1175{
1176 my $self = shift;
1177 my $current_append = *$self->{AppendOutput} ;
1178 *$self->{AppendOutput} = 1;
1179 my $lineref = $self->_getline();
258133d1 1180 $. = ++ *$self->{LineNo} if defined $$lineref ;
25f0751f 1181 *$self->{AppendOutput} = $current_append;
1182 return $$lineref ;
1183}
1184
1185sub getlines
1186{
1187 my $self = shift;
1188 $self->croakError(*$self->{ClassName} .
1189 "::getlines: called in scalar context\n") unless wantarray;
1190 my($line, @lines);
258133d1 1191 push(@lines, $line)
1192 while defined($line = $self->getline);
25f0751f 1193 return @lines;
1194}
1195
1196sub READLINE
1197{
1198 goto &getlines if wantarray;
1199 goto &getline;
1200}
1201
1202sub getc
1203{
1204 my $self = shift;
1205 my $buf;
1206 return $buf if $self->read($buf, 1);
1207 return undef;
1208}
1209
1210sub ungetc
1211{
1212 my $self = shift;
1213 *$self->{Pending} = "" unless defined *$self->{Pending} ;
1214 *$self->{Pending} = $_[0] . *$self->{Pending} ;
1215}
1216
1217
1218sub trailingData
1219{
1220 my $self = shift ;
25f0751f 1221
1222 if (defined *$self->{FH} || defined *$self->{InputEvent} ) {
1223 return *$self->{Prime} ;
1224 }
1225 else {
1226 my $buf = *$self->{Buffer} ;
1227 my $offset = *$self->{BufferOffset} ;
258133d1 1228 return substr($$buf, $offset) ;
25f0751f 1229 }
1230}
1231
1232
1233sub eof
1234{
1235 my $self = shift ;
1236
1237 return (*$self->{Closed} ||
1238 (!length *$self->{Pending}
1239 && ( $self->smartEof() || *$self->{EndStream}))) ;
1240}
1241
1242sub tell
1243{
1244 my $self = shift ;
1245
1246 my $in ;
1247 if (*$self->{Plain}) {
1248 $in = *$self->{PlainBytesRead} ;
1249 }
1250 else {
1251 $in = *$self->{TotalInflatedBytesRead} ;
1252 }
1253
1254 my $pending = length *$self->{Pending} ;
1255
1256 return 0 if $pending > $in ;
1257 return $in - $pending ;
1258}
1259
1260sub close
1261{
1262 # todo - what to do if close is called before the end of the gzip file
1263 # do we remember any trailing data?
1264 my $self = shift ;
1265
1266 return 1 if *$self->{Closed} ;
1267
1268 untie *$self
1269 if $] >= 5.008 ;
1270
1271 my $status = 1 ;
1272
1273 if (defined *$self->{FH}) {
1274 if ((! *$self->{Handle} || *$self->{AutoClose}) && ! *$self->{StdIO}) {
1275 #if ( *$self->{AutoClose}) {
1276 local $.;
1277 $! = 0 ;
1278 $status = *$self->{FH}->close();
1279 return $self->saveErrorString(0, $!, $!)
1280 if !*$self->{InNew} && $self->saveStatus($!) != 0 ;
1281 }
1282 delete *$self->{FH} ;
1283 $! = 0 ;
1284 }
1285 *$self->{Closed} = 1 ;
1286
1287 return 1;
1288}
1289
1290sub DESTROY
1291{
1292 my $self = shift ;
1293 $self->close() ;
1294}
1295
1296sub seek
1297{
1298 my $self = shift ;
1299 my $position = shift;
1300 my $whence = shift ;
1301
1302 my $here = $self->tell() ;
1303 my $target = 0 ;
1304
1305
1306 if ($whence == SEEK_SET) {
1307 $target = $position ;
1308 }
1309 elsif ($whence == SEEK_CUR) {
1310 $target = $here + $position ;
1311 }
1312 elsif ($whence == SEEK_END) {
1313 $target = $position ;
1314 $self->croakError(*$self->{ClassName} . "::seek: SEEK_END not allowed") ;
1315 }
1316 else {
1317 $self->croakError(*$self->{ClassName} ."::seek: unknown value, $whence, for whence parameter");
1318 }
1319
1320 # short circuit if seeking to current offset
1321 return 1 if $target == $here ;
1322
1323 # Outlaw any attempt to seek backwards
1324 $self->croakError( *$self->{ClassName} ."::seek: cannot seek backwards")
1325 if $target < $here ;
1326
1327 # Walk the file to the new offset
1328 my $offset = $target - $here ;
1329
4e7676c7 1330 my $got;
1331 while (($got = $self->read(my $buffer, min($offset, *$self->{BlockSize})) ) > 0)
1332 {
1333 $offset -= $got;
1334 last if $offset == 0 ;
1335 }
25f0751f 1336
4e7676c7 1337 return $offset == 0 ? 1 : 0 ;
25f0751f 1338}
1339
1340sub fileno
1341{
1342 my $self = shift ;
1343 return defined *$self->{FH}
1344 ? fileno *$self->{FH}
1345 : undef ;
1346}
1347
1348sub binmode
1349{
1350 1;
1351# my $self = shift ;
1352# return defined *$self->{FH}
1353# ? binmode *$self->{FH}
1354# : 1 ;
1355}
1356
1357sub opened
1358{
1359 my $self = shift ;
1360 return ! *$self->{Closed} ;
1361}
1362
1363sub autoflush
1364{
1365 my $self = shift ;
1366 return defined *$self->{FH}
1367 ? *$self->{FH}->autoflush(@_)
1368 : undef ;
1369}
1370
1371sub input_line_number
1372{
1373 my $self = shift ;
1374 my $last = *$self->{LineNo};
1375 $. = *$self->{LineNo} = $_[1] if @_ ;
1376 return $last;
1377}
1378
1379
1380*BINMODE = \&binmode;
1381*SEEK = \&seek;
1382*READ = \&read;
1383*sysread = \&read;
1384*TELL = \&tell;
1385*EOF = \&eof;
1386
1387*FILENO = \&fileno;
1388*CLOSE = \&close;
1389
1390sub _notAvailable
1391{
1392 my $name = shift ;
1393 #return sub { croak "$name Not Available" ; } ;
1394 return sub { croak "$name Not Available: File opened only for intput" ; } ;
1395}
1396
1397
1398*print = _notAvailable('print');
1399*PRINT = _notAvailable('print');
1400*printf = _notAvailable('printf');
1401*PRINTF = _notAvailable('printf');
1402*write = _notAvailable('write');
1403*WRITE = _notAvailable('write');
1404
1405#*sysread = \&read;
1406#*syswrite = \&_notAvailable;
1407
25f0751f 1408
1409
1410package IO::Uncompress::Base ;
1411
1412
14131 ;
1414__END__
1415
1416=head1 NAME
1417
25f0751f 1418IO::Uncompress::Base - Base Class for IO::Uncompress modules
1419
25f0751f 1420=head1 SYNOPSIS
1421
1422 use IO::Uncompress::Base ;
1423
1424=head1 DESCRIPTION
1425
25f0751f 1426This module is not intended for direct use in application code. Its sole
1427purpose if to to be sub-classed by IO::Unompress modules.
1428
25f0751f 1429=head1 SEE ALSO
1430
258133d1 1431L<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::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress>
25f0751f 1432
1433L<Compress::Zlib::FAQ|Compress::Zlib::FAQ>
1434
1435L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>,
1436L<Archive::Tar|Archive::Tar>,
1437L<IO::Zlib|IO::Zlib>
1438
25f0751f 1439=head1 AUTHOR
1440
cb7abd7f 1441This module was written by Paul Marquess, F<pmqs@cpan.org>.
25f0751f 1442
25f0751f 1443=head1 MODIFICATION HISTORY
1444
1445See the Changes file.
1446
1447=head1 COPYRIGHT AND LICENSE
25f0751f 1448
d54256af 1449Copyright (c) 2005-2008 Paul Marquess. All rights reserved.
25f0751f 1450
1451This program is free software; you can redistribute it and/or
1452modify it under the same terms as Perl itself.
1453
a1787f24 1454