overload.pl shouldnt update its output unconditionally
[p5sagit/p5-mst-13.2.git] / ext / IO-Compress / 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
80b215cb 12$VERSION = '2.019';
25f0751f 13
14use constant G_EOF => 0 ;
15use constant G_ERR => -1 ;
16
80b215cb 17use IO::Compress::Base::Common 2.019 ;
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 {
319fab50 413 no warnings ;
25f0751f 414 my $mode = '<';
415 $mode = '+<' if $got->value('Scan');
416 *$obj->{StdIO} = ($inValue eq '-');
417 *$obj->{FH} = new IO::File "$mode $inValue"
418 or return $obj->saveErrorString(undef, "cannot open file '$inValue': $!", $!) ;
419 }
420
421 *$obj->{LineNo} = $. = 0;
422 setBinModeInput(*$obj->{FH}) ;
423
424 my $buff = "" ;
425 *$obj->{Buffer} = \$buff ;
426 }
427
4e7676c7 428 if ($got->parsed('Encode')) {
429 my $want_encoding = $got->value('Encode');
430 *$obj->{Encoding} = getEncoding($obj, $class, $want_encoding);
431 }
432
25f0751f 433
434 *$obj->{InputLength} = $got->parsed('InputLength')
435 ? $got->value('InputLength')
436 : undef ;
437 *$obj->{InputLengthRemaining} = $got->value('InputLength');
438 *$obj->{BufferOffset} = 0 ;
439 *$obj->{AutoClose} = $got->value('AutoClose');
440 *$obj->{Strict} = $got->value('Strict');
25f0751f 441 *$obj->{BlockSize} = $got->value('BlockSize');
442 *$obj->{Append} = $got->value('Append');
443 *$obj->{AppendOutput} = $append_mode || $got->value('Append');
e7d45986 444 *$obj->{ConsumeInput} = $got->value('ConsumeInput');
25f0751f 445 *$obj->{Transparent} = $got->value('Transparent');
446 *$obj->{MultiStream} = $got->value('MultiStream');
447
448 # TODO - move these two into RawDeflate
449 *$obj->{Scan} = $got->value('Scan');
450 *$obj->{ParseExtra} = $got->value('ParseExtra')
451 || $got->value('Strict') ;
25f0751f 452 *$obj->{Type} = '';
453 *$obj->{Prime} = $got->value('Prime') || '' ;
454 *$obj->{Pending} = '';
455 *$obj->{Plain} = 0;
456 *$obj->{PlainBytesRead} = 0;
457 *$obj->{InflatedBytesRead} = 0;
e7d45986 458 *$obj->{UnCompSize} = new U64;
459 *$obj->{CompSize} = new U64;
25f0751f 460 *$obj->{TotalInflatedBytesRead} = 0;
461 *$obj->{NewStream} = 0 ;
462 *$obj->{EventEof} = 0 ;
463 *$obj->{ClassName} = $class ;
464 *$obj->{Params} = $got ;
465
e7d45986 466 if (*$obj->{ConsumeInput}) {
467 *$obj->{InNew} = 0;
468 *$obj->{Closed} = 0;
469 return $obj
470 }
471
a1787f24 472 my $status = $obj->mkUncomp($got);
25f0751f 473
474 return undef
475 unless defined $status;
476
477 if ( ! $status) {
478 return undef
479 unless *$obj->{Transparent};
480
481 $obj->clearError();
482 *$obj->{Type} = 'plain';
483 *$obj->{Plain} = 1;
484 #$status = $obj->mkIdentityUncomp($class, $got);
485 $obj->pushBack(*$obj->{HeaderPending}) ;
486 }
487
488 push @{ *$obj->{InfoList} }, *$obj->{Info} ;
489
490 $obj->saveStatus(STATUS_OK) ;
491 *$obj->{InNew} = 0;
492 *$obj->{Closed} = 0;
493
494 return $obj;
495}
496
497sub ckInputParam
498{
499 my $self = shift ;
500 my $from = shift ;
501 my $inType = whatIsInput($_[0], $_[1]);
502
503 $self->croakError("$from: input parameter not a filename, filehandle, array ref or scalar ref")
504 if ! $inType ;
505
319fab50 506# if ($inType eq 'filename' )
507# {
508# return $self->saveErrorString(1, "$from: input filename is undef or null string", STATUS_ERROR)
509# if ! defined $_[0] || $_[0] eq '' ;
510#
511# if ($_[0] ne '-' && ! -e $_[0] )
512# {
513# return $self->saveErrorString(1,
514# "input file '$_[0]' does not exist", STATUS_ERROR);
515# }
516# }
25f0751f 517
518 return 1;
519}
520
521
522sub _inf
523{
524 my $obj = shift ;
525
526 my $class = (caller)[0] ;
527 my $name = (caller(1))[3] ;
528
529 $obj->croakError("$name: expected at least 1 parameters\n")
530 unless @_ >= 1 ;
531
532 my $input = shift ;
533 my $haveOut = @_ ;
534 my $output = shift ;
535
536
a1787f24 537 my $x = new IO::Compress::Base::Validator($class, *$obj->{Error}, $name, $input, $output)
25f0751f 538 or return undef ;
539
540 push @_, $output if $haveOut && $x->{Hash};
258133d1 541
542 *$obj->{OneShot} = 1 ;
25f0751f 543
544 my $got = $obj->checkParams($name, undef, @_)
545 or return undef ;
546
258133d1 547 if ($got->parsed('TrailingData'))
548 {
549 *$obj->{TrailingData} = $got->value('TrailingData');
550 }
551
e7d45986 552 *$obj->{MultiStream} = $got->value('MultiStream');
553 $got->value('MultiStream', 0);
25f0751f 554
e7d45986 555 $x->{Got} = $got ;
25f0751f 556
e7d45986 557# if ($x->{Hash})
558# {
559# while (my($k, $v) = each %$input)
560# {
561# $v = \$input->{$k}
562# unless defined $v ;
563#
564# $obj->_singleTarget($x, $k, $v, @_)
565# or return undef ;
566# }
567#
568# return keys %$input ;
569# }
25f0751f 570
571 if ($x->{GlobMap})
572 {
573 $x->{oneInput} = 1 ;
574 foreach my $pair (@{ $x->{Pairs} })
575 {
576 my ($from, $to) = @$pair ;
e7d45986 577 $obj->_singleTarget($x, $from, $to, @_)
25f0751f 578 or return undef ;
579 }
580
581 return scalar @{ $x->{Pairs} } ;
582 }
583
25f0751f 584 if (! $x->{oneOutput} )
585 {
586 my $inFile = ($x->{inType} eq 'filenames'
587 || $x->{inType} eq 'filename');
588
589 $x->{inType} = $inFile ? 'filename' : 'buffer';
25f0751f 590
591 foreach my $in ($x->{oneInput} ? $input : @$input)
592 {
593 my $out ;
594 $x->{oneInput} = 1 ;
595
e7d45986 596 $obj->_singleTarget($x, $in, $output, @_)
25f0751f 597 or return undef ;
25f0751f 598 }
599
600 return 1 ;
601 }
602
603 # finally the 1 to 1 and n to 1
e7d45986 604 return $obj->_singleTarget($x, $input, $output, @_);
25f0751f 605
606 croak "should not be here" ;
607}
608
609sub retErr
610{
611 my $x = shift ;
612 my $string = shift ;
613
614 ${ $x->{Error} } = $string ;
615
616 return undef ;
617}
618
619sub _singleTarget
620{
621 my $self = shift ;
622 my $x = shift ;
25f0751f 623 my $input = shift;
624 my $output = shift;
625
e7d45986 626 my $buff = '';
627 $x->{buff} = \$buff ;
25f0751f 628
629 my $fh ;
630 if ($x->{outType} eq 'filename') {
631 my $mode = '>' ;
632 $mode = '>>'
633 if $x->{Got}->value('Append') ;
634 $x->{fh} = new IO::File "$mode $output"
635 or return retErr($x, "cannot open file '$output': $!") ;
636 binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut');
637
638 }
639
640 elsif ($x->{outType} eq 'handle') {
641 $x->{fh} = $output;
642 binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut');
643 if ($x->{Got}->value('Append')) {
644 seek($x->{fh}, 0, SEEK_END)
645 or return retErr($x, "Cannot seek to end of output filehandle: $!") ;
646 }
647 }
648
649
650 elsif ($x->{outType} eq 'buffer' )
651 {
652 $$output = ''
653 unless $x->{Got}->value('Append');
654 $x->{buff} = $output ;
655 }
656
657 if ($x->{oneInput})
658 {
e7d45986 659 defined $self->_rd2($x, $input, $output)
25f0751f 660 or return undef;
661 }
662 else
663 {
25f0751f 664 for my $element ( ($x->{inType} eq 'hash') ? keys %$input : @$input)
665 {
e7d45986 666 defined $self->_rd2($x, $element, $output)
25f0751f 667 or return undef ;
668 }
669 }
670
671
672 if ( ($x->{outType} eq 'filename' && $output ne '-') ||
673 ($x->{outType} eq 'handle' && $x->{Got}->value('AutoClose'))) {
674 $x->{fh}->close()
675 or return retErr($x, $!);
25f0751f 676 delete $x->{fh};
677 }
678
679 return 1 ;
680}
681
682sub _rd2
683{
684 my $self = shift ;
685 my $x = shift ;
686 my $input = shift;
e7d45986 687 my $output = shift;
25f0751f 688
689 my $z = createSelfTiedObject($x->{Class}, *$self->{Error});
690
691 $z->_create($x->{Got}, 1, $input, @_)
692 or return undef ;
693
694 my $status ;
695 my $fh = $x->{fh};
696
e7d45986 697 while (1) {
698
699 while (($status = $z->read($x->{buff})) > 0) {
700 if ($fh) {
701 print $fh ${ $x->{buff} }
702 or return $z->saveErrorString(undef, "Error writing to output file: $!", $!);
703 ${ $x->{buff} } = '' ;
704 }
705 }
706
707 if (! $x->{oneOutput} ) {
708 my $ot = $x->{outType} ;
709
710 if ($ot eq 'array')
711 { push @$output, $x->{buff} }
712 elsif ($ot eq 'hash')
713 { $output->{$input} = $x->{buff} }
714
715 my $buff = '';
716 $x->{buff} = \$buff;
25f0751f 717 }
e7d45986 718
319fab50 719 last if $status < 0 || $z->smartEof();
720 #last if $status < 0 ;
721
e7d45986 722 last
723 unless *$self->{MultiStream};
724
725 $status = $z->nextStream();
726
727 last
728 unless $status == 1 ;
25f0751f 729 }
730
731 return $z->closeError(undef)
732 if $status < 0 ;
733
258133d1 734 ${ *$self->{TrailingData} } = $z->trailingData()
735 if defined *$self->{TrailingData} ;
736
25f0751f 737 $z->close()
738 or return undef ;
739
740 return 1 ;
741}
742
743sub TIEHANDLE
744{
745 return $_[0] if ref($_[0]);
746 die "OOPS\n" ;
747
748}
749
750sub UNTIE
751{
752 my $self = shift ;
753}
754
755
756sub getHeaderInfo
757{
758 my $self = shift ;
759 wantarray ? @{ *$self->{InfoList} } : *$self->{Info};
760}
761
762sub readBlock
763{
764 my $self = shift ;
765 my $buff = shift ;
766 my $size = shift ;
767
768 if (defined *$self->{CompressedInputLength}) {
769 if (*$self->{CompressedInputLengthRemaining} == 0) {
770 delete *$self->{CompressedInputLength};
771 *$self->{CompressedInputLengthDone} = 1;
772 return STATUS_OK ;
773 }
774 $size = min($size, *$self->{CompressedInputLengthRemaining} );
775 *$self->{CompressedInputLengthRemaining} -= $size ;
776 }
777
778 my $status = $self->smartRead($buff, $size) ;
779 return $self->saveErrorString(STATUS_ERROR, "Error Reading Data")
780 if $status < 0 ;
781
782 if ($status == 0 ) {
783 *$self->{Closed} = 1 ;
784 *$self->{EndStream} = 1 ;
785 return $self->saveErrorString(STATUS_ERROR, "unexpected end of file", STATUS_ERROR);
786 }
787
788 return STATUS_OK;
25f0751f 789}
790
791sub postBlockChk
792{
793 return STATUS_OK;
794}
795
796sub _raw_read
797{
798 # return codes
799 # >0 - ok, number of bytes read
800 # =0 - ok, eof
801 # <0 - not ok
802
803 my $self = shift ;
804
805 return G_EOF if *$self->{Closed} ;
806 #return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ;
807 return G_EOF if *$self->{EndStream} ;
808
809 my $buffer = shift ;
810 my $scan_mode = shift ;
811
812 if (*$self->{Plain}) {
813 my $tmp_buff ;
814 my $len = $self->smartRead(\$tmp_buff, *$self->{BlockSize}) ;
815
816 return $self->saveErrorString(G_ERR, "Error reading data: $!", $!)
817 if $len < 0 ;
818
819 if ($len == 0 ) {
820 *$self->{EndStream} = 1 ;
821 }
822 else {
823 *$self->{PlainBytesRead} += $len ;
824 $$buffer .= $tmp_buff;
825 }
826
827 return $len ;
828 }
829
830 if (*$self->{NewStream}) {
831
e7d45986 832 $self->gotoNextStream() > 0
833 or return G_ERR;
25f0751f 834
835 # For the headers that actually uncompressed data, put the
836 # uncompressed data into the output buffer.
837 $$buffer .= *$self->{Pending} ;
838 my $len = length *$self->{Pending} ;
839 *$self->{Pending} = '';
840 return $len;
841 }
842
e7d45986 843 my $temp_buf = '';
25f0751f 844 my $outSize = 0;
845 my $status = $self->readBlock(\$temp_buf, *$self->{BlockSize}, $outSize) ;
846 return G_ERR
847 if $status == STATUS_ERROR ;
848
849 my $buf_len = 0;
850 if ($status == STATUS_OK) {
e7d45986 851 my $beforeC_len = length $temp_buf;
25f0751f 852 my $before_len = defined $$buffer ? length $$buffer : 0 ;
853 $status = *$self->{Uncomp}->uncompr(\$temp_buf, $buffer,
854 defined *$self->{CompressedInputLengthDone} ||
855 $self->smartEof(), $outSize);
319fab50 856
857 $self->pushBack($temp_buf) if $beforeC_len != length $temp_buf;
25f0751f 858
319fab50 859#return $self->saveErrorString(G_ERR, "unexpected end of file", STATUS_ERROR)
860# if $self->smartEof() && $status != STATUS_ENDSTREAM;
861
25f0751f 862 return $self->saveErrorString(G_ERR, *$self->{Uncomp}{Error}, *$self->{Uncomp}{ErrorNo})
319fab50 863 if $self->saveStatus($status) == STATUS_ERROR;
25f0751f 864
258133d1 865 $self->postBlockChk($buffer, $before_len) == STATUS_OK
25f0751f 866 or return G_ERR;
867
e11a3f9e 868 $buf_len = defined $$buffer ? length($$buffer) - $before_len : 0;
25f0751f 869
e7d45986 870 *$self->{CompSize}->add($beforeC_len - length $temp_buf) ;
871
25f0751f 872 *$self->{InflatedBytesRead} += $buf_len ;
873 *$self->{TotalInflatedBytesRead} += $buf_len ;
e7d45986 874 *$self->{UnCompSize}->add($buf_len) ;
4e7676c7 875
876 $self->filterUncompressed($buffer);
877
878 if (*$self->{Encoding}) {
879 $$buffer = *$self->{Encoding}->decode($$buffer);
880 }
25f0751f 881 }
882
883 if ($status == STATUS_ENDSTREAM) {
884
885 *$self->{EndStream} = 1 ;
319fab50 886#$self->pushBack($temp_buf) ;
887#$temp_buf = '';
25f0751f 888
889 my $trailer;
890 my $trailer_size = *$self->{Info}{TrailerLength} ;
891 my $got = 0;
892 if (*$self->{Info}{TrailerLength})
893 {
894 $got = $self->smartRead(\$trailer, $trailer_size) ;
895 }
896
897 if ($got == $trailer_size) {
898 $self->chkTrailer($trailer) == STATUS_OK
899 or return G_ERR;
900 }
901 else {
902 return $self->TrailerError("trailer truncated. Expected " .
903 "$trailer_size bytes, got $got")
904 if *$self->{Strict};
905 $self->pushBack($trailer) ;
906 }
907
258133d1 908 # TODO - if want to file file pointer, do it here
909
e7d45986 910 if (! $self->smartEof()) {
25f0751f 911 *$self->{NewStream} = 1 ;
e7d45986 912
913 if (*$self->{MultiStream}) {
914 *$self->{EndStream} = 0 ;
915 return $buf_len ;
916 }
25f0751f 917 }
918
919 }
920
921
922 # return the number of uncompressed bytes read
923 return $buf_len ;
924}
925
2b4e0969 926sub reset
927{
928 my $self = shift ;
929
930 return *$self->{Uncomp}->reset();
931}
932
933sub filterUncompressed
934{
935}
936
25f0751f 937#sub isEndStream
938#{
939# my $self = shift ;
940# return *$self->{NewStream} ||
941# *$self->{EndStream} ;
942#}
943
e7d45986 944sub nextStream
945{
946 my $self = shift ;
947
948 my $status = $self->gotoNextStream();
949 $status == 1
950 or return $status ;
951
952 *$self->{TotalInflatedBytesRead} = 0 ;
953 *$self->{LineNo} = $. = 0;
954
955 return 1;
956}
957
958sub gotoNextStream
959{
960 my $self = shift ;
961
962 if (! *$self->{NewStream}) {
963 my $status = 1;
964 my $buffer ;
965
966 # TODO - make this more efficient if know the offset for the end of
967 # the stream and seekable
968 $status = $self->read($buffer)
969 while $status > 0 ;
970
971 return $status
972 if $status < 0;
973 }
974
975 *$self->{NewStream} = 0 ;
976 *$self->{EndStream} = 0 ;
977 $self->reset();
978 *$self->{UnCompSize}->reset();
979 *$self->{CompSize}->reset();
980
6ecef415 981 my $magic = $self->ckMagic();
f6fd7794 982 #*$self->{EndStream} = 0 ;
e7d45986 983
d54256af 984 if ( ! defined $magic) {
f6fd7794 985 if (! *$self->{Transparent} )
986 {
987 *$self->{EndStream} = 1 ;
988 return 0;
989 }
e7d45986 990
f6fd7794 991 $self->clearError();
992 *$self->{Type} = 'plain';
993 *$self->{Plain} = 1;
994 $self->pushBack(*$self->{HeaderPending}) ;
995 }
996 else
997 {
998 *$self->{Info} = $self->readHeader($magic);
6ecef415 999
f6fd7794 1000 if ( ! defined *$self->{Info} ) {
1001 *$self->{EndStream} = 1 ;
1002 return -1;
1003 }
6ecef415 1004 }
e7d45986 1005
1006 push @{ *$self->{InfoList} }, *$self->{Info} ;
1007
1008 return 1;
1009}
1010
25f0751f 1011sub streamCount
1012{
1013 my $self = shift ;
1014 return 1 if ! defined *$self->{InfoList};
1015 return scalar @{ *$self->{InfoList} } ;
1016}
1017
1018sub read
1019{
1020 # return codes
1021 # >0 - ok, number of bytes read
1022 # =0 - ok, eof
1023 # <0 - not ok
1024
1025 my $self = shift ;
1026
1027 return G_EOF if *$self->{Closed} ;
25f0751f 1028
1029 my $buffer ;
1030
25f0751f 1031 if (ref $_[0] ) {
1032 $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
1033 if readonly(${ $_[0] });
1034
1035 $self->croakError(*$self->{ClassName} . "::read: not a scalar reference $_[0]" )
1036 unless ref $_[0] eq 'SCALAR' ;
1037 $buffer = $_[0] ;
1038 }
1039 else {
1040 $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only")
1041 if readonly($_[0]);
1042
1043 $buffer = \$_[0] ;
1044 }
1045
1046 my $length = $_[1] ;
1047 my $offset = $_[2] || 0;
1048
93d092e2 1049 if (! *$self->{AppendOutput}) {
1050 if (! $offset) {
1051 $$buffer = '' ;
1052 }
1053 else {
1054 if ($offset > length($$buffer)) {
1055 $$buffer .= "\x00" x ($offset - length($$buffer));
1056 }
1057 else {
1058 substr($$buffer, $offset) = '';
1059 }
1060 }
1061 }
1062
1063 return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ;
1064
25f0751f 1065 # the core read will return 0 if asked for 0 bytes
1066 return 0 if defined $length && $length == 0 ;
1067
1068 $length = $length || 0;
1069
1070 $self->croakError(*$self->{ClassName} . "::read: length parameter is negative")
1071 if $length < 0 ;
1072
25f0751f 1073 # Short-circuit if this is a simple read, with no length
1074 # or offset specified.
1075 unless ( $length || $offset) {
1076 if (length *$self->{Pending}) {
1077 $$buffer .= *$self->{Pending} ;
1078 my $len = length *$self->{Pending};
1079 *$self->{Pending} = '' ;
1080 return $len ;
1081 }
1082 else {
1083 my $len = 0;
1084 $len = $self->_raw_read($buffer)
1085 while ! *$self->{EndStream} && $len == 0 ;
1086 return $len ;
1087 }
1088 }
1089
1090 # Need to jump through more hoops - either length or offset
1091 # or both are specified.
f6fd7794 1092 my $out_buffer = *$self->{Pending} ;
319fab50 1093 *$self->{Pending} = '';
25f0751f 1094
93d092e2 1095
f6fd7794 1096 while (! *$self->{EndStream} && length($out_buffer) < $length)
25f0751f 1097 {
f6fd7794 1098 my $buf_len = $self->_raw_read(\$out_buffer);
25f0751f 1099 return $buf_len
1100 if $buf_len < 0 ;
1101 }
1102
f6fd7794 1103 $length = length $out_buffer
1104 if length($out_buffer) < $length ;
25f0751f 1105
258133d1 1106 return 0
1107 if $length == 0 ;
1108
93d092e2 1109 $$buffer = ''
1110 if ! defined $$buffer;
1111
1112 $offset = length $$buffer
1113 if *$self->{AppendOutput} ;
1114
f6fd7794 1115 *$self->{Pending} = $out_buffer;
1116 $out_buffer = \*$self->{Pending} ;
1117
93d092e2 1118 #substr($$buffer, $offset) = substr($$out_buffer, 0, $length, '') ;
1119 substr($$buffer, $offset) = substr($$out_buffer, 0, $length) ;
1120 substr($$out_buffer, 0, $length) = '' ;
25f0751f 1121
1122 return $length ;
1123}
1124
1125sub _getline
1126{
1127 my $self = shift ;
1128
1129 # Slurp Mode
1130 if ( ! defined $/ ) {
1131 my $data ;
1132 1 while $self->read($data) > 0 ;
258133d1 1133 return \$data ;
1134 }
1135
1136 # Record Mode
1137 if ( ref $/ eq 'SCALAR' && ${$/} =~ /^\d+$/ && ${$/} > 0) {
1138 my $reclen = ${$/} ;
1139 my $data ;
1140 $self->read($data, $reclen) ;
25f0751f 1141 return \$data ;
1142 }
1143
1144 # Paragraph Mode
1145 if ( ! length $/ ) {
1146 my $paragraph ;
1147 while ($self->read($paragraph) > 0 ) {
1148 if ($paragraph =~ s/^(.*?\n\n+)//s) {
1149 *$self->{Pending} = $paragraph ;
1150 my $par = $1 ;
25f0751f 1151 return \$par ;
1152 }
1153 }
25f0751f 1154 return \$paragraph;
1155 }
1156
258133d1 1157 # $/ isn't empty, or a reference, so it's Line Mode.
25f0751f 1158 {
1159 my $line ;
258133d1 1160 my $offset;
1161 my $p = \*$self->{Pending} ;
1162
1163 if (length(*$self->{Pending}) &&
1164 ($offset = index(*$self->{Pending}, $/)) >=0) {
1165 my $l = substr(*$self->{Pending}, 0, $offset + length $/ );
1166 substr(*$self->{Pending}, 0, $offset + length $/) = '';
1167 return \$l;
1168 }
1169
25f0751f 1170 while ($self->read($line) > 0 ) {
258133d1 1171 my $offset = index($line, $/);
1172 if ($offset >= 0) {
1173 my $l = substr($line, 0, $offset + length $/ );
1174 substr($line, 0, $offset + length $/) = '';
1175 $$p = $line;
1176 return \$l;
25f0751f 1177 }
1178 }
258133d1 1179
25f0751f 1180 return \$line;
1181 }
1182}
1183
1184sub getline
1185{
1186 my $self = shift;
1187 my $current_append = *$self->{AppendOutput} ;
1188 *$self->{AppendOutput} = 1;
1189 my $lineref = $self->_getline();
258133d1 1190 $. = ++ *$self->{LineNo} if defined $$lineref ;
25f0751f 1191 *$self->{AppendOutput} = $current_append;
1192 return $$lineref ;
1193}
1194
1195sub getlines
1196{
1197 my $self = shift;
1198 $self->croakError(*$self->{ClassName} .
1199 "::getlines: called in scalar context\n") unless wantarray;
1200 my($line, @lines);
258133d1 1201 push(@lines, $line)
1202 while defined($line = $self->getline);
25f0751f 1203 return @lines;
1204}
1205
1206sub READLINE
1207{
1208 goto &getlines if wantarray;
1209 goto &getline;
1210}
1211
1212sub getc
1213{
1214 my $self = shift;
1215 my $buf;
1216 return $buf if $self->read($buf, 1);
1217 return undef;
1218}
1219
1220sub ungetc
1221{
1222 my $self = shift;
1223 *$self->{Pending} = "" unless defined *$self->{Pending} ;
1224 *$self->{Pending} = $_[0] . *$self->{Pending} ;
1225}
1226
1227
1228sub trailingData
1229{
1230 my $self = shift ;
25f0751f 1231
1232 if (defined *$self->{FH} || defined *$self->{InputEvent} ) {
1233 return *$self->{Prime} ;
1234 }
1235 else {
1236 my $buf = *$self->{Buffer} ;
1237 my $offset = *$self->{BufferOffset} ;
258133d1 1238 return substr($$buf, $offset) ;
25f0751f 1239 }
1240}
1241
1242
1243sub eof
1244{
1245 my $self = shift ;
1246
1247 return (*$self->{Closed} ||
1248 (!length *$self->{Pending}
1249 && ( $self->smartEof() || *$self->{EndStream}))) ;
1250}
1251
1252sub tell
1253{
1254 my $self = shift ;
1255
1256 my $in ;
1257 if (*$self->{Plain}) {
1258 $in = *$self->{PlainBytesRead} ;
1259 }
1260 else {
1261 $in = *$self->{TotalInflatedBytesRead} ;
1262 }
1263
1264 my $pending = length *$self->{Pending} ;
1265
1266 return 0 if $pending > $in ;
1267 return $in - $pending ;
1268}
1269
1270sub close
1271{
1272 # todo - what to do if close is called before the end of the gzip file
1273 # do we remember any trailing data?
1274 my $self = shift ;
1275
1276 return 1 if *$self->{Closed} ;
1277
1278 untie *$self
1279 if $] >= 5.008 ;
1280
1281 my $status = 1 ;
1282
1283 if (defined *$self->{FH}) {
1284 if ((! *$self->{Handle} || *$self->{AutoClose}) && ! *$self->{StdIO}) {
1285 #if ( *$self->{AutoClose}) {
1286 local $.;
1287 $! = 0 ;
1288 $status = *$self->{FH}->close();
1289 return $self->saveErrorString(0, $!, $!)
1290 if !*$self->{InNew} && $self->saveStatus($!) != 0 ;
1291 }
1292 delete *$self->{FH} ;
1293 $! = 0 ;
1294 }
1295 *$self->{Closed} = 1 ;
1296
1297 return 1;
1298}
1299
1300sub DESTROY
1301{
1302 my $self = shift ;
e11a3f9e 1303 local ($., $@, $!, $^E, $?);
1304
25f0751f 1305 $self->close() ;
1306}
1307
1308sub seek
1309{
1310 my $self = shift ;
1311 my $position = shift;
1312 my $whence = shift ;
1313
1314 my $here = $self->tell() ;
1315 my $target = 0 ;
1316
1317
1318 if ($whence == SEEK_SET) {
1319 $target = $position ;
1320 }
1321 elsif ($whence == SEEK_CUR) {
1322 $target = $here + $position ;
1323 }
1324 elsif ($whence == SEEK_END) {
1325 $target = $position ;
1326 $self->croakError(*$self->{ClassName} . "::seek: SEEK_END not allowed") ;
1327 }
1328 else {
1329 $self->croakError(*$self->{ClassName} ."::seek: unknown value, $whence, for whence parameter");
1330 }
1331
1332 # short circuit if seeking to current offset
1333 return 1 if $target == $here ;
1334
1335 # Outlaw any attempt to seek backwards
1336 $self->croakError( *$self->{ClassName} ."::seek: cannot seek backwards")
1337 if $target < $here ;
1338
1339 # Walk the file to the new offset
1340 my $offset = $target - $here ;
1341
4e7676c7 1342 my $got;
1343 while (($got = $self->read(my $buffer, min($offset, *$self->{BlockSize})) ) > 0)
1344 {
1345 $offset -= $got;
1346 last if $offset == 0 ;
1347 }
25f0751f 1348
319fab50 1349 $here = $self->tell() ;
4e7676c7 1350 return $offset == 0 ? 1 : 0 ;
25f0751f 1351}
1352
1353sub fileno
1354{
1355 my $self = shift ;
1356 return defined *$self->{FH}
1357 ? fileno *$self->{FH}
1358 : undef ;
1359}
1360
1361sub binmode
1362{
1363 1;
1364# my $self = shift ;
1365# return defined *$self->{FH}
1366# ? binmode *$self->{FH}
1367# : 1 ;
1368}
1369
1370sub opened
1371{
1372 my $self = shift ;
1373 return ! *$self->{Closed} ;
1374}
1375
1376sub autoflush
1377{
1378 my $self = shift ;
1379 return defined *$self->{FH}
1380 ? *$self->{FH}->autoflush(@_)
1381 : undef ;
1382}
1383
1384sub input_line_number
1385{
1386 my $self = shift ;
1387 my $last = *$self->{LineNo};
1388 $. = *$self->{LineNo} = $_[1] if @_ ;
1389 return $last;
1390}
1391
1392
1393*BINMODE = \&binmode;
1394*SEEK = \&seek;
1395*READ = \&read;
1396*sysread = \&read;
1397*TELL = \&tell;
1398*EOF = \&eof;
1399
1400*FILENO = \&fileno;
1401*CLOSE = \&close;
1402
1403sub _notAvailable
1404{
1405 my $name = shift ;
1406 #return sub { croak "$name Not Available" ; } ;
1407 return sub { croak "$name Not Available: File opened only for intput" ; } ;
1408}
1409
1410
1411*print = _notAvailable('print');
1412*PRINT = _notAvailable('print');
1413*printf = _notAvailable('printf');
1414*PRINTF = _notAvailable('printf');
1415*write = _notAvailable('write');
1416*WRITE = _notAvailable('write');
1417
1418#*sysread = \&read;
1419#*syswrite = \&_notAvailable;
1420
25f0751f 1421
1422
1423package IO::Uncompress::Base ;
1424
1425
14261 ;
1427__END__
1428
1429=head1 NAME
1430
25f0751f 1431IO::Uncompress::Base - Base Class for IO::Uncompress modules
1432
25f0751f 1433=head1 SYNOPSIS
1434
1435 use IO::Uncompress::Base ;
1436
1437=head1 DESCRIPTION
1438
25f0751f 1439This module is not intended for direct use in application code. Its sole
1440purpose if to to be sub-classed by IO::Unompress modules.
1441
25f0751f 1442=head1 SEE ALSO
1443
258133d1 1444L<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 1445
1446L<Compress::Zlib::FAQ|Compress::Zlib::FAQ>
1447
1448L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>,
1449L<Archive::Tar|Archive::Tar>,
1450L<IO::Zlib|IO::Zlib>
1451
25f0751f 1452=head1 AUTHOR
1453
cb7abd7f 1454This module was written by Paul Marquess, F<pmqs@cpan.org>.
25f0751f 1455
25f0751f 1456=head1 MODIFICATION HISTORY
1457
1458See the Changes file.
1459
1460=head1 COPYRIGHT AND LICENSE
25f0751f 1461
319fab50 1462Copyright (c) 2005-2009 Paul Marquess. All rights reserved.
25f0751f 1463
1464This program is free software; you can redistribute it and/or
1465modify it under the same terms as Perl itself.
1466