| Current File : //usr/tmp/par-streamof/cache-019bf52da828c7d4df54624dfe058723871c67b9/105b7f84.pm |
#line 1 "/usr/local/lib/perl5/site_perl/5.8.8/Archive/Zip.pm"
package Archive::Zip;
use strict;
BEGIN {
require 5.003_96;
}
use UNIVERSAL ();
use Carp ();
use IO::File ();
use IO::Seekable ();
use Compress::Zlib ();
use File::Spec ();
use File::Temp ();
use vars qw( $VERSION @ISA );
BEGIN {
$VERSION = '1.23';
require Exporter;
@ISA = qw( Exporter );
}
use vars qw( $ChunkSize $ErrorHandler );
BEGIN {
# This is the size we'll try to read, write, and (de)compress.
# You could set it to something different if you had lots of memory
# and needed more speed.
$ChunkSize ||= 32768;
$ErrorHandler = \&Carp::carp;
}
# BEGIN block is necessary here so that other modules can use the constants.
use vars qw( @EXPORT_OK %EXPORT_TAGS );
BEGIN {
@EXPORT_OK = ('computeCRC32');
%EXPORT_TAGS = (
CONSTANTS => [ qw(
FA_MSDOS
FA_UNIX
GPBF_ENCRYPTED_MASK
GPBF_DEFLATING_COMPRESSION_MASK
GPBF_HAS_DATA_DESCRIPTOR_MASK
COMPRESSION_STORED
COMPRESSION_DEFLATED
COMPRESSION_LEVEL_NONE
COMPRESSION_LEVEL_DEFAULT
COMPRESSION_LEVEL_FASTEST
COMPRESSION_LEVEL_BEST_COMPRESSION
IFA_TEXT_FILE_MASK
IFA_TEXT_FILE
IFA_BINARY_FILE
) ],
MISC_CONSTANTS => [ qw(
FA_AMIGA
FA_VAX_VMS
FA_VM_CMS
FA_ATARI_ST
FA_OS2_HPFS
FA_MACINTOSH
FA_Z_SYSTEM
FA_CPM
FA_TOPS20
FA_WINDOWS_NTFS
FA_QDOS
FA_ACORN
FA_VFAT
FA_MVS
FA_BEOS
FA_TANDEM
FA_THEOS
GPBF_IMPLODING_8K_SLIDING_DICTIONARY_MASK
GPBF_IMPLODING_3_SHANNON_FANO_TREES_MASK
GPBF_IS_COMPRESSED_PATCHED_DATA_MASK
COMPRESSION_SHRUNK
DEFLATING_COMPRESSION_NORMAL
DEFLATING_COMPRESSION_MAXIMUM
DEFLATING_COMPRESSION_FAST
DEFLATING_COMPRESSION_SUPER_FAST
COMPRESSION_REDUCED_1
COMPRESSION_REDUCED_2
COMPRESSION_REDUCED_3
COMPRESSION_REDUCED_4
COMPRESSION_IMPLODED
COMPRESSION_TOKENIZED
COMPRESSION_DEFLATED_ENHANCED
COMPRESSION_PKWARE_DATA_COMPRESSION_LIBRARY_IMPLODED
) ],
ERROR_CODES => [ qw(
AZ_OK
AZ_STREAM_END
AZ_ERROR
AZ_FORMAT_ERROR
AZ_IO_ERROR
) ],
# For Internal Use Only
PKZIP_CONSTANTS => [ qw(
SIGNATURE_FORMAT
SIGNATURE_LENGTH
LOCAL_FILE_HEADER_SIGNATURE
LOCAL_FILE_HEADER_FORMAT
LOCAL_FILE_HEADER_LENGTH
CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE
DATA_DESCRIPTOR_FORMAT
DATA_DESCRIPTOR_LENGTH
DATA_DESCRIPTOR_SIGNATURE
DATA_DESCRIPTOR_FORMAT_NO_SIG
DATA_DESCRIPTOR_LENGTH_NO_SIG
CENTRAL_DIRECTORY_FILE_HEADER_FORMAT
CENTRAL_DIRECTORY_FILE_HEADER_LENGTH
END_OF_CENTRAL_DIRECTORY_SIGNATURE
END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING
END_OF_CENTRAL_DIRECTORY_FORMAT
END_OF_CENTRAL_DIRECTORY_LENGTH
) ],
# For Internal Use Only
UTILITY_METHODS => [ qw(
_error
_printError
_ioError
_formatError
_subclassResponsibility
_binmode
_isSeekable
_newFileHandle
_readSignature
_asZipDirName
) ],
);
# Add all the constant names and error code names to @EXPORT_OK
Exporter::export_ok_tags( qw(
CONSTANTS
ERROR_CODES
PKZIP_CONSTANTS
UTILITY_METHODS
MISC_CONSTANTS
) );
}
# Error codes
use constant AZ_OK => 0;
use constant AZ_STREAM_END => 1;
use constant AZ_ERROR => 2;
use constant AZ_FORMAT_ERROR => 3;
use constant AZ_IO_ERROR => 4;
# File types
# Values of Archive::Zip::Member->fileAttributeFormat()
use constant FA_MSDOS => 0;
use constant FA_AMIGA => 1;
use constant FA_VAX_VMS => 2;
use constant FA_UNIX => 3;
use constant FA_VM_CMS => 4;
use constant FA_ATARI_ST => 5;
use constant FA_OS2_HPFS => 6;
use constant FA_MACINTOSH => 7;
use constant FA_Z_SYSTEM => 8;
use constant FA_CPM => 9;
use constant FA_TOPS20 => 10;
use constant FA_WINDOWS_NTFS => 11;
use constant FA_QDOS => 12;
use constant FA_ACORN => 13;
use constant FA_VFAT => 14;
use constant FA_MVS => 15;
use constant FA_BEOS => 16;
use constant FA_TANDEM => 17;
use constant FA_THEOS => 18;
# general-purpose bit flag masks
# Found in Archive::Zip::Member->bitFlag()
use constant GPBF_ENCRYPTED_MASK => 1 << 0;
use constant GPBF_DEFLATING_COMPRESSION_MASK => 3 << 1;
use constant GPBF_HAS_DATA_DESCRIPTOR_MASK => 1 << 3;
# deflating compression types, if compressionMethod == COMPRESSION_DEFLATED
# ( Archive::Zip::Member->bitFlag() & GPBF_DEFLATING_COMPRESSION_MASK )
use constant DEFLATING_COMPRESSION_NORMAL => 0 << 1;
use constant DEFLATING_COMPRESSION_MAXIMUM => 1 << 1;
use constant DEFLATING_COMPRESSION_FAST => 2 << 1;
use constant DEFLATING_COMPRESSION_SUPER_FAST => 3 << 1;
# compression method
# these two are the only ones supported in this module
use constant COMPRESSION_STORED => 0; # file is stored (no compression)
use constant COMPRESSION_DEFLATED => 8; # file is Deflated
use constant COMPRESSION_LEVEL_NONE => 0;
use constant COMPRESSION_LEVEL_DEFAULT => -1;
use constant COMPRESSION_LEVEL_FASTEST => 1;
use constant COMPRESSION_LEVEL_BEST_COMPRESSION => 9;
# internal file attribute bits
# Found in Archive::Zip::Member::internalFileAttributes()
use constant IFA_TEXT_FILE_MASK => 1;
use constant IFA_TEXT_FILE => 1;
use constant IFA_BINARY_FILE => 0;
# PKZIP file format miscellaneous constants (for internal use only)
use constant SIGNATURE_FORMAT => "V";
use constant SIGNATURE_LENGTH => 4;
# these lengths are without the signature.
use constant LOCAL_FILE_HEADER_SIGNATURE => 0x04034b50;
use constant LOCAL_FILE_HEADER_FORMAT => "v3 V4 v2";
use constant LOCAL_FILE_HEADER_LENGTH => 26;
# PKZIP docs don't mention the signature, but Info-Zip writes it.
use constant DATA_DESCRIPTOR_SIGNATURE => 0x08074b50;
use constant DATA_DESCRIPTOR_FORMAT => "V3";
use constant DATA_DESCRIPTOR_LENGTH => 12;
# but the signature is apparently optional.
use constant DATA_DESCRIPTOR_FORMAT_NO_SIG => "V2";
use constant DATA_DESCRIPTOR_LENGTH_NO_SIG => 8;
use constant CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE => 0x02014b50;
use constant CENTRAL_DIRECTORY_FILE_HEADER_FORMAT => "C2 v3 V4 v5 V2";
use constant CENTRAL_DIRECTORY_FILE_HEADER_LENGTH => 42;
use constant END_OF_CENTRAL_DIRECTORY_SIGNATURE => 0x06054b50;
use constant END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING =>
pack( "V", END_OF_CENTRAL_DIRECTORY_SIGNATURE );
use constant END_OF_CENTRAL_DIRECTORY_FORMAT => "v4 V2 v";
use constant END_OF_CENTRAL_DIRECTORY_LENGTH => 18;
use constant GPBF_IMPLODING_8K_SLIDING_DICTIONARY_MASK => 1 << 1;
use constant GPBF_IMPLODING_3_SHANNON_FANO_TREES_MASK => 1 << 2;
use constant GPBF_IS_COMPRESSED_PATCHED_DATA_MASK => 1 << 5;
# the rest of these are not supported in this module
use constant COMPRESSION_SHRUNK => 1; # file is Shrunk
use constant COMPRESSION_REDUCED_1 => 2; # file is Reduced CF=1
use constant COMPRESSION_REDUCED_2 => 3; # file is Reduced CF=2
use constant COMPRESSION_REDUCED_3 => 4; # file is Reduced CF=3
use constant COMPRESSION_REDUCED_4 => 5; # file is Reduced CF=4
use constant COMPRESSION_IMPLODED => 6; # file is Imploded
use constant COMPRESSION_TOKENIZED => 7; # reserved for Tokenizing compr.
use constant COMPRESSION_DEFLATED_ENHANCED => 9; # reserved for enh. Deflating
use constant COMPRESSION_PKWARE_DATA_COMPRESSION_LIBRARY_IMPLODED => 10;
# Load the various required classes
require Archive::Zip::Archive;
require Archive::Zip::Member;
require Archive::Zip::FileMember;
require Archive::Zip::DirectoryMember;
require Archive::Zip::ZipFileMember;
require Archive::Zip::NewFileMember;
require Archive::Zip::StringMember;
use constant ZIPARCHIVECLASS => 'Archive::Zip::Archive';
use constant ZIPMEMBERCLASS => 'Archive::Zip::Member';
# Convenience functions
sub _ISA ($$) {
# Can't rely on Scalar::Util, so use the next best way
!! eval { ref $_[0] and $_[0]->isa($_[1]) };
}
sub _CAN ($$) {
!! eval { ref $_[0] and $_[0]->can($_[1]) };
}
#####################################################################
# Methods
sub new {
my $class = shift;
return $class->ZIPARCHIVECLASS->new(@_);
}
sub computeCRC32 {
my $data = shift;
$data = shift if ref($data); # allow calling as an obj method
my $crc = shift;
return Compress::Zlib::crc32( $data, $crc );
}
# Report or change chunk size used for reading and writing.
# Also sets Zlib's default buffer size (eventually).
sub setChunkSize {
my $chunkSize = shift;
$chunkSize = shift if ref($chunkSize); # object method on zip?
my $oldChunkSize = $Archive::Zip::ChunkSize;
$Archive::Zip::ChunkSize = $chunkSize if ($chunkSize);
return $oldChunkSize;
}
sub chunkSize {
return $Archive::Zip::ChunkSize;
}
sub setErrorHandler (&) {
my $errorHandler = shift;
$errorHandler = \&Carp::carp unless defined($errorHandler);
my $oldErrorHandler = $Archive::Zip::ErrorHandler;
$Archive::Zip::ErrorHandler = $errorHandler;
return $oldErrorHandler;
}
######################################################################
# Private utility functions (not methods).
sub _printError {
my $string = join ( ' ', @_, "\n" );
my $oldCarpLevel = $Carp::CarpLevel;
$Carp::CarpLevel += 2;
&{$ErrorHandler} ($string);
$Carp::CarpLevel = $oldCarpLevel;
}
# This is called on format errors.
sub _formatError {
shift if ref( $_[0] );
_printError( 'format error:', @_ );
return AZ_FORMAT_ERROR;
}
# This is called on IO errors.
sub _ioError {
shift if ref( $_[0] );
_printError( 'IO error:', @_, ':', $! );
return AZ_IO_ERROR;
}
# This is called on generic errors.
sub _error {
shift if ref( $_[0] );
_printError( 'error:', @_ );
return AZ_ERROR;
}
# Called when a subclass should have implemented
# something but didn't
sub _subclassResponsibility {
Carp::croak("subclass Responsibility\n");
}
# Try to set the given file handle or object into binary mode.
sub _binmode {
my $fh = shift;
return _CAN( $fh, 'binmode' ) ? $fh->binmode() : binmode($fh);
}
# Attempt to guess whether file handle is seekable.
# Because of problems with Windows, this only returns true when
# the file handle is a real file.
sub _isSeekable {
my $fh = shift;
return 0 unless ref $fh;
if ( _ISA($fh, 'IO::Scalar') ) {
# IO::Scalar objects are brokenly-seekable
return 0;
}
if ( _ISA($fh, 'IO::String') ) {
return 1;
}
if ( _ISA($fh, 'IO::Seekable') ) {
# Unfortunately, some things like FileHandle objects
# return true for Seekable, but AREN'T!!!!!
if ( _ISA($fh, 'FileHandle') ) {
return 0;
} else {
return 1;
}
}
if ( _CAN($fh, 'stat') ) {
return -f $fh;
}
return (
_CAN($fh, 'seek') and _CAN($fh, 'tell')
) ? 1 : 0;
}
# Return an opened IO::Handle
# my ( $status, fh ) = _newFileHandle( 'fileName', 'w' );
# Can take a filename, file handle, or ref to GLOB
# Or, if given something that is a ref but not an IO::Handle,
# passes back the same thing.
sub _newFileHandle {
my $fd = shift;
my $status = 1;
my $handle;
if ( ref($fd) ) {
if ( _ISA($fd, 'IO::Scalar') or _ISA($fd, 'IO::String') ) {
$handle = $fd;
} elsif ( _ISA($fd, 'IO::Handle') or ref($fd) eq 'GLOB' ) {
$handle = IO::File->new();
$status = $handle->fdopen( $fd, @_ );
} else {
$handle = $fd;
}
} else {
$handle = IO::File->new();
$status = $handle->open( $fd, @_ );
}
return ( $status, $handle );
}
# Returns next signature from given file handle, leaves
# file handle positioned afterwards.
# In list context, returns ($status, $signature)
# ( $status, $signature) = _readSignature( $fh, $fileName );
sub _readSignature {
my $fh = shift;
my $fileName = shift;
my $expectedSignature = shift; # optional
my $signatureData;
my $bytesRead = $fh->read( $signatureData, SIGNATURE_LENGTH );
if ( $bytesRead != SIGNATURE_LENGTH ) {
return _ioError("reading header signature");
}
my $signature = unpack( SIGNATURE_FORMAT, $signatureData );
my $status = AZ_OK;
# compare with expected signature, if any, or any known signature.
if ( ( defined($expectedSignature) && $signature != $expectedSignature )
|| ( !defined($expectedSignature)
&& $signature != CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE
&& $signature != LOCAL_FILE_HEADER_SIGNATURE
&& $signature != END_OF_CENTRAL_DIRECTORY_SIGNATURE
&& $signature != DATA_DESCRIPTOR_SIGNATURE ) )
{
my $errmsg = sprintf( "bad signature: 0x%08x", $signature );
if ( _isSeekable($fh) )
{
$errmsg .=
sprintf( " at offset %d", $fh->tell() - SIGNATURE_LENGTH );
}
$status = _formatError("$errmsg in file $fileName");
}
return ( $status, $signature );
}
# Utility method to make and open a temp file.
# Will create $temp_dir if it doesn't exist.
# Returns file handle and name:
#
# my ($fh, $name) = Archive::Zip::tempFile();
# my ($fh, $name) = Archive::Zip::tempFile('mytempdir');
#
sub tempFile {
my $dir = shift;
my ( $fh, $filename ) = File::Temp::tempfile(
SUFFIX => '.zip',
UNLINK => 0, # we will delete it!
$dir ? ( DIR => $dir ) : ()
);
return ( undef, undef ) unless $fh;
my ( $status, $newfh ) = _newFileHandle( $fh, 'w+' );
return ( $newfh, $filename );
}
# Return the normalized directory name as used in a zip file (path
# separators become slashes, etc.).
# Will translate internal slashes in path components (i.e. on Macs) to
# underscores. Discards volume names.
# When $forceDir is set, returns paths with trailing slashes (or arrays
# with trailing blank members).
#
# If third argument is a reference, returns volume information there.
#
# input output
# . ('.') '.'
# ./a ('a') a
# ./a/b ('a','b') a/b
# ./a/b/ ('a','b') a/b
# a/b/ ('a','b') a/b
# /a/b/ ('','a','b') /a/b
# c:\a\b\c.doc ('','a','b','c.doc') /a/b/c.doc # on Windoze
# "i/o maps:whatever" ('i_o maps', 'whatever') "i_o maps/whatever" # on Macs
sub _asZipDirName
{
my $name = shift;
my $forceDir = shift;
my $volReturn = shift;
my ( $volume, $directories, $file ) =
File::Spec->splitpath( File::Spec->canonpath($name), $forceDir );
$$volReturn = $volume if ( ref($volReturn) );
my @dirs = map { $_ =~ s{/}{_}g; $_ } File::Spec->splitdir($directories);
if ( @dirs > 0 ) { pop (@dirs) unless $dirs[-1] } # remove empty component
push ( @dirs, defined($file) ? $file : '' );
#return wantarray ? @dirs : join ( '/', @dirs );
return join ( '/', @dirs );
}
# Return an absolute local name for a zip name.
# Assume a directory if zip name has trailing slash.
# Takes an optional volume name in FS format (like 'a:').
#
sub _asLocalName
{
my $name = shift; # zip format
my $volume = shift;
$volume = '' unless defined($volume); # local FS format
my @paths = split ( /\//, $name );
my $filename = pop (@paths);
$filename = '' unless defined($filename);
my $localDirs = @paths?File::Spec->catdir(@paths):'';
my $localName = File::Spec->catpath( $volume, $localDirs, $filename );
$localName = File::Spec->rel2abs($localName) unless $volume;
return $localName;
}
1;
__END__
#line 2030