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