Imported Upstream version 0.06

This commit is contained in:
Mario Fetka
2017-09-14 11:26:13 +02:00
commit fd6c0eeda3
47 changed files with 2570 additions and 0 deletions

726
lib/Archive/SevenZip.pm Normal file
View File

@@ -0,0 +1,726 @@
package Archive::SevenZip;
use strict;
use Carp qw(croak);
use Encode qw( decode encode );
use File::Basename qw(dirname basename);
use Archive::SevenZip::Entry;
use File::Temp qw(tempfile tempdir);
use File::Copy;
use IPC::Open3 'open3';
use Path::Class;
use Exporter 'import'; # for the error codes, in Archive::Zip API compatibility
=head1 NAME
Archive::SevenZip - Read/write 7z , zip , ISO9960 and other archives
=head1 SYNOPSIS
my $ar = Archive::SevenZip->new(
find => 1,
archivename => $archivename,
verbose => $verbose,
);
for my $entry ( $ar->list ) {
my $target = join "/", "$target_dir", $entry->basename;
$ar->extractMember( $entry->fileName, $target );
};
=head1 METHODS
=cut
use vars qw(%sevenzip_charsetname %class_defaults $VERSION @EXPORT_OK %EXPORT_TAGS);
$VERSION= '0.06';
# Archive::Zip API
# Error codes
use constant AZ_OK => 0;
use constant COMPRESSION_STORED => 'Store'; # file is stored (no compression)
use constant COMPRESSION_DEFLATED => 'Deflate'; # file is Deflated
@EXPORT_OK = (qw(AZ_OK COMPRESSION_STORED COMPRESSION_DEFLATED));
%EXPORT_TAGS = (
ERROR_CODES => [
qw(
AZ_OK
)
#AZ_STREAM_END
#AZ_ERROR
#AZ_FORMAT_ERROR
#AZ_IO_ERROR
],
CONSTANTS => [
qw(COMPRESSION_STORED COMPRESSION_DEFLATED)
],
);
%sevenzip_charsetname = (
'UTF-8' => 'UTF-8',
'Latin-1' => 'WIN',
'ISO-8859-1' => 'WIN',
'' => 'DOS', # dunno what the appropriate name would be
);
if( $^O !~ /MSWin/ ) {
# Wipe all filesystem encodings because my Debian 7z 9.20 doesn't understand them
$sevenzip_charsetname{ $_ } = ''
for keys %sevenzip_charsetname;
};
%class_defaults = (
'7zip' => '7z',
fs_encoding => 'UTF-8',
default_options => [ "-y", "-bd" ],
type => 'zip',
);
=head2 C<< Archive::SevenZip->find_7z_executable >>
Finds the 7z executable in the path or in C<< $ENV{ProgramFiles} >>
or C<< $ENV{ProgramFiles(x86)} >>. This is called
when a C<< Archive::SevenZip >> instance is created with the C<find>
parameter set to 1.
=cut
sub find_7z_executable {
my($class) = @_;
my $old_default = $class_defaults{ '7zip' };
my $envsep = $^O =~ /MSWin/ ? ';' : ':';
my @search = split /$envsep/, $ENV{PATH};
if( $^O =~ /MSWin/i ) {
push @search, map { "$_\\7-Zip" } grep {defined} ($ENV{'ProgramFiles'}, $ENV{'ProgramFiles(x86)'});
};
my $found = $class->version;
while( ! defined $found and @search) {
my $dir = shift @search;
if ($^O eq 'MSWin32') {
next unless -e file("$dir", "7z.exe" );
}
$class_defaults{'7zip'} = "" . file("$dir", "7z" );
$found = $class->version;
};
if( ! $found) {
$class_defaults{ '7zip' } = $old_default;
};
return defined $found ? $found : ()
}
=head2 C<< Archive::SevenZip->new >>
my $ar = Archive::SevenZip->new( $archivename );
my $ar = Archive::SevenZip->new(
archivename => $archivename,
find => 1,
);
Creates a new class instance.
C<find> - will try to find the executable using C<< ->find_7z_executable >>
=cut
sub new {
my( $class, %options);
if( @_ == 2 ) {
($class, $options{ archivename }) = @_;
} else {
($class, %options) = @_;
};
if( $options{ find }) {
$class->find_7z_executable();
};
for( keys %class_defaults ) {
$options{ $_ } = $class_defaults{ $_ }
unless defined $options{ $_ };
};
bless \%options => $class
}
sub version {
my( $self_or_class, %options) = @_;
for( keys %class_defaults ) {
$options{ $_ } = $class_defaults{ $_ }
unless defined $options{ $_ };
};
my $self = ref $self_or_class ? $self_or_class : $self_or_class->new( %options );
my $cmd = $self->get_command(
command => '',
archivename => undef,
options => [], # on Debian, 7z doesn't like any options...
fs_encoding => undef, # on Debian, 7z doesn't like any options...
default_options => [], # on Debian, 7z doesn't like any options...
);
my $fh = eval { $self->run($cmd, binmode => ':raw') };
if( ! $@ ) {
local $/ = "\n";
my @output = <$fh>;
if( @output >= 3) {
$output[1] =~ /^7-Zip\s+.*?(\d+\.\d+)\s+(?:\s*:\s*)?Copyright/
or return undef;
return $1;
} else {
return undef
}
}
}
=head2 C<< $ar->open >>
my @entries = $ar->open;
for my $entry (@entries) {
print $entry->name, "\n";
};
Lists the entries in the archive. A fresh archive which does not
exist on disk yet has no entries. The returned entries
are L<Archive::SevenZip::Entry> instances.
This method will one day move to the Path::Class-compatibility
API.
=cut
# Iterate over the entries in the archive
# Path::Class API
sub open {
my( $self )= @_;
my @contents = $self->list();
}
=head2 C<< $ar->memberNamed >>
my $entry = $ar->memberNamed('hello_world.txt');
print $entry->fileName, "\n";
The path separator must be a forward slash ("/")
This method will one day move to the Archive::Zip-compatibility
API.
=cut
# Archive::Zip API
sub memberNamed {
my( $self, $name, %options )= @_;
my( $entry ) = grep { $_->fileName eq $name } $self->members( %options );
$entry
}
# Archive::Zip API
sub list {
my( $self, %options )= @_;
if( ! grep { defined $_ } $options{archivename}, $self->{archivename}) {
# We are an archive that does not exist on disk yet
return
};
my $cmd = $self->get_command( command => "l", options => ["-slt"], %options );
my $fh = $self->run($cmd, encoding => $options{ fs_encoding } );
my @output = <$fh>;
my %results = (
header => [],
archive => [],
);
# Get/skip header
while( @output and $output[0] !~ /^--\s*$/ ) {
my $line = shift @output;
$line =~ s!\s+$!!;
push @{ $results{ header }}, $line;
};
# Get/skip archive information
while( @output and $output[0] !~ /^----------\s*$/ ) {
my $line = shift @output;
$line =~ s!\s+$!!;
push @{ $results{ archive }}, $line;
};
if( $output[0] =~ /^----------\s*$/ ) {
shift @output;
} else {
warn "Unexpected line in 7zip output, hope that's OK: [$output[0]]";
};
my @members;
# Split entries
my %entry_info;
while( @output ) {
my $line = shift @output;
if( $line =~ /^([\w ]+) =(?: (.*?)|)\s*$/ ) {
$entry_info{ $1 } = $2;
} elsif($line =~ /^\s*$/) {
push @members, Archive::SevenZip::Entry->new(
%entry_info,
_Container => $self,
);
%entry_info = ();
} else {
croak "Unknown file entry [$line]";
};
};
return @members
}
{ no warnings 'once';
*members = \&list;
}
=head2 C<< $ar->openMemberFH >>
my $fh = $ar->openMemberFH('test.txt');
while( <$fh> ) {
print "test.txt: $_";
};
Reads the uncompressed content of the member from the archive.
This method will one day move to the Archive::Zip-compatibility
API.
=cut
sub openMemberFH {
my( $self, %options );
if( @_ == 2 ) {
($self,$options{ membername })= @_;
} else {
($self,%options) = @_;
};
defined $options{ membername } or croak "Need member name to extract";
my $cmd = $self->get_command( command => "e", options => ["-so"], members => [$options{membername}] );
my $fh = $self->run($cmd, encoding => $options{ encoding }, binmode => $options{ binmode });
return $fh
}
sub content {
my( $self, %options ) = @_;
my $fh = $self->openMemberFH( %options );
local $/;
<$fh>
}
=head2 C<< $ar->extractMember >>
$ar->extractMember('test.txt' => 'extracted_test.txt');
Extracts the uncompressed content of the member from the archive.
This method will one day move to the Archive::Zip-compatibility
API.
=cut
# Archive::Zip API
sub extractMember {
my( $self, $memberOrName, $extractedName, %_options ) = @_;
$extractedName = $memberOrName
unless defined $extractedName;
my %options = (%$self, %_options);
my $target_dir = dirname $extractedName;
my $target_name = basename $extractedName;
my $cmd = $self->get_command(
command => "e",
archivename => $options{ archivename },
members => [ $memberOrName ],
options => [ "-o$target_dir" ],
);
my $fh = $self->run($cmd, encoding => $options{ encoding });
while( <$fh>) {
warn $_ if $options{ verbose };
};
if( basename $memberOrName ne $target_name ) {
rename "$target_dir/" . basename($memberOrName) => $extractedName
or croak "Couldn't move '$memberOrName' to '$extractedName': $!";
};
return AZ_OK;
};
=head2 C<< $ar->removeMember >>
$ar->removeMember('test.txt');
Removes the member from the archive.
=cut
# strikingly similar to Archive::Zip API
sub removeMember {
my( $self, $name, %_options ) = @_;
my %options = (%$self, %_options);
if( $^O =~ /MSWin/ ) {
$name =~ s!/!\\!g;
}
my $cmd = $self->get_command(
command => "d",
archivename => $options{ archivename },
members => [ $name ],
);
my $fh = $self->run($cmd, encoding => $options{ encoding } );
$self->wait($fh, %options);
return AZ_OK;
};
sub add_quotes {
map {
defined $_ && /\s/ ? qq{"$_"} : $_
} @_
};
sub get_command {
my( $self, %options )= @_;
$options{ members } ||= [];
$options{ archivename } = $self->{ archivename }
unless defined $options{ archivename };
if( ! exists $options{ fs_encoding }) {
$options{ fs_encoding } = defined $self->{ fs_encoding } ? $self->{ fs_encoding } : $class_defaults{ fs_encoding };
};
if( ! defined $options{ default_options }) {
$options{ default_options } = defined $self->{ default_options } ? $self->{ default_options } : $class_defaults{ default_options };
};
my @charset;
if( defined $options{ fs_encoding }) {
exists $sevenzip_charsetname{ $options{ fs_encoding }}
or croak "Unknown filesystem encoding '$options{ fs_encoding }'";
if( my $charset = $sevenzip_charsetname{ $options{ fs_encoding }}) {
push @charset, "-scs" . $sevenzip_charsetname{ $options{ fs_encoding }};
};
};
for(@{ $options{ members }}) {
$_ = encode $options{ fs_encoding }, $_;
};
# Now quote what needs to be quoted
for( @{ $options{ options }}, @{ $options{ members }}, $options{ archivename }, "$self->{ '7zip' }") {
};
return [grep {defined $_}
add_quotes($self->{ '7zip' }),
@{ $options{ default_options }},
$options{ command },
@charset,
add_quotes( @{ $options{ options }} ),
add_quotes( $options{ archivename } ),
add_quotes( @{ $options{ members }} ),
];
}
sub run {
my( $self, $cmd, %options )= @_;
my $mode = '-|';
if( defined $options{ stdin }) {
$mode = '|-';
};
my $fh;
warn "Opening [@$cmd]"
if $options{ verbose };
if( $self->{verbose} ) {
CORE::open( $fh, $mode, @$cmd)
or croak "Couldn't launch [$mode @$cmd]: $!/$?";
} else {
CORE::open( my $fh_err, '>', File::Spec->devnull )
or warn "Couldn't redirect child STDERR";
my $errh = fileno $fh_err;
# We accumulate zombie PIDs here, ah well.
my $pid = open3( my $fh_in, my $fh_out, '>&' . $errh, @$cmd)
or croak "Couldn't launch [$mode @$cmd]: $!/$?";
if( $mode eq '|-' ) {
$fh = $fh_in;
} else {
$fh = $fh_out
};
}
if( $options{ encoding }) {
binmode $fh, ":encoding($options{ encoding })";
} elsif( $options{ binmode } ) {
binmode $fh, $options{ binmode };
};
if( $options{ stdin }) {
print {$fh} $options{ stdin };
close $fh;
} elsif( $options{ skip }) {
for( 1..$options{ skip }) {
# Read that many lines
local $/ = "\n";
scalar <$fh>;
};
};
$fh;
}
sub archive_or_temp {
my( $self ) = @_;
if( ! defined $self->{archivename} ) {
$self->{is_tempfile} = 1;
(my( $fh ),$self->{archivename}) = tempfile( SUFFIX => ".$self->{type}" );
close $fh;
unlink $self->{archivename};
};
$self->{archivename}
};
sub wait {
my( $self, $fh, %options ) = @_;
while( <$fh>) {
warn $_ if ($options{ verbose } || $self->{verbose})
};
}
=head2 C<< $ar->add_scalar >>
$ar->add_scalar( "Some name.txt", "This is the content" );
Adds a scalar as an archive member.
Unfortunately, 7zip doesn't reliably read archive members from STDIN,
so the scalar will be written to a tempfile, added to the archive and then
renamed in the archive.
This requires 7zip version 9.30+
=cut
sub add_scalar {
my( $self, $name, $scalar )= @_;
# 7zip doesn't really support reading archive members from STDIN :-(
my($fh, $tempname) = tempfile;
binmode $fh, ':raw';
print {$fh} $scalar;
close $fh;
# Only supports 7z archive type?!
# 7zip will magically append .7z to the filename :-(
my $cmd = $self->get_command(
command => 'a',
archivename => $self->archive_or_temp,
members => [$tempname],
#options => ],
);
$fh = $self->run( $cmd );
$self->wait($fh);
unlink $tempname
or warn "Couldn't unlink '$tempname': $!";
# Hopefully your version of 7zip can rename members (9.30+):
$cmd = $self->get_command(
command => 'rn',
archivename => $self->archive_or_temp,
members => [basename($tempname), $name],
#options => ],
);
$fh = $self->run( $cmd );
$self->wait($fh);
# Once 7zip supports reading from stdin, this will work again:
#my $fh = $self->run( $cmd,
# binmode => ':raw',
# stdin => $scalar,
# verbose => 1,
#);
};
=head2 C<< $ar->add_directory >>
$ar->add_directory( "real_etc", "etc" );
Adds an empty directory
This currently ignores the directory date and time if the directory
exists
=cut
sub add_directory {
my( $self, $localname, $target )= @_;
$target ||= $localname;
# Create an empty directory, add it to the archive,
# then rename that temp name to the wanted name:
my $tempname = tempdir;
my $cmd = $self->get_command(
command => 'a',
archivename => $self->archive_or_temp,
members => [$tempname],
options => ['-r0'],
);
my $fh = $self->run( $cmd );
$self->wait($fh);
# Hopefully your version of 7zip can rename members (9.30+):
$cmd = $self->get_command(
command => 'rn',
archivename => $self->archive_or_temp,
members => [basename($tempname), $target],
);
$fh = $self->run( $cmd );
$self->wait($fh);
# Once 7zip supports reading from stdin, this will work again:
#my $fh = $self->run( $cmd,
# binmode => ':raw',
# stdin => $scalar,
# verbose => 1,
#);
};
sub add {
my( $self, %options )= @_;
my @items = @{ delete $options{ items } || [] };
# Split up the list into one batch for the listfiles
# and the list of files we need to rename
my @filelist;
for my $item (@items) {
if( ! ref $item ) {
$item = [ $item, $item ];
};
my( $name, $storedName ) = @$item;
if( $name ne $storedName ) {
# We need to pipe to 7zip from stdin (no, we don't, we can rename afterwards)
# This still means we might overwrite an already existing file in the archive...
# But 7-zip seems to not like duplicate filenames anyway in "@"-listfiles...
my $cmd = $self->get_command(
command => 'a',
archivename => $self->archive_or_temp,
members => [$name],
#options => ],
);
my $fh = $self->run( $cmd );
$self->wait($fh, %options );
$cmd = $self->get_command(
command => 'rn',
archivename => $self->archive_or_temp,
members => [$name, $storedName],
#options => ],
);
$fh = $self->run( $cmd );
$self->wait($fh, %options );
} else {
# 7zip can read the file from disk
# Write the name to a tempfile to be read by 7zip for batching
push @filelist, $name;
};
};
if( @filelist ) {
my( $fh, $name) = tempfile;
binmode $fh, ':raw';
print {$fh} join "\r\n", @filelist;
close $fh;
my @options;
if( $options{ recursive }) {
push @options, '-r';
};
my $cmd = $self->get_command(
command => 'a',
archivename => $self->archive_or_temp,
members => ['@'.$name],
options => \@options
);
$fh = $self->run( $cmd );
$self->wait($fh, %options);
};
};
sub archiveZipApi {
my( $class, %options ) = @_;
require Archive::SevenZip::API::ArchiveZip;
Archive::SevenZip::API::ArchiveZip->new( %options )
}
package Path::Class::Archive::Handle;
use strict;
=head1 NAME
Path::Class::Archive - treat archives as directories
=cut
package Path::Class::Archive;
1;
__END__
=head1 CAUTION
This module tries to mimic the API of L<Archive::Zip> in some cases
and in other cases, the API of L<Path::Class>. It is also a very rough
draft that just happens to be doing what I need, mostly extracting
files.
=head1 SEE ALSO
L<File::Unpack> - also supports unpacking from 7z archives
L<Compress::unLZMA> - uncompressor for the LZMA compression method used by 7z
=head1 REPOSITORY
The public repository of this module is
L<http://github.com/Corion/archive-sevenzip>.
=head1 SUPPORT
The public support forum of this module is
L<https://perlmonks.org/>.
=head1 BUG TRACKER
Please report bugs in this module via the RT CPAN bug queue at
L<https://rt.cpan.org/Public/Dist/Display.html?Name=Archive-SevenZip>
or via mail to L<archive-sevenzip-Bugs@rt.cpan.org>.
=head1 AUTHOR
Max Maischein C<corion@cpan.org>
=head1 COPYRIGHT (c)
Copyright 2015-2016 by Max Maischein C<corion@cpan.org>.
=head1 LICENSE
This module is released under the same terms as Perl itself.
=cut

View File

@@ -0,0 +1,244 @@
package Archive::SevenZip::API::ArchiveZip;
use strict;
use Carp qw(croak);
use Encode qw( decode encode );
use File::Basename qw(dirname basename);
use File::Copy;
use Archive::SevenZip 'AZ_OK';
use vars qw($VERSION);
$VERSION= '0.06';
sub new {
my( $class, %options )= @_;
$options{ sevenZip } = Archive::SevenZip->new();
bless \%options => $class;
};
sub sevenZip { $_[0]->{sevenZip} }
=head1 NAME
Archive::SevenZip::API::ArchiveZip - Archive::Zip compatibility API
=head1 SYNOPSIS
my $ar = Archive::SevenZip->archiveZipApi(
find => 1,
archivename => $archivename,
verbose => $verbose,
);
This module implements just enough of the L<Archive::Zip>
API to pass some of the Archive::Zip test files. Ideally you can
use this API to enable a script that uses Archive::Zip
to also read other archive files supported by 7z.
=cut
sub writeToFileNamed {
my( $self, $targetName )= @_;
copy( $self->sevenZip->{archivename}, $targetName );
return AZ_OK;
}
sub addFileOrDirectory {
my($self, $name, $newName, $compressionLevel) = @_;
$newName = $name
unless defined $newName;
$self->sevenZip->add(
items => [ [$name, $newName] ],
compression => $compressionLevel
);
}
sub addString {
my( $self, $content, $name, %options ) = @_;
$self->sevenZip->add_scalar($name => $content);
$self->memberNamed($name, %options);
}
sub addDirectory {
# Create just a directory name
my( $self, $name, $target, %options ) = @_;
$target ||= $name;
if( ref $name ) {
croak "Hashref API not supported, sorry";
};
$self->sevenZip->add_directory($name, $target, %options);
$self->memberNamed($target, %options);
}
sub members {
my( $self ) = @_;
$self->sevenZip->members;
}
sub memberNames {
my( $self ) = @_;
map { $_->fileName } $self->sevenZip->members;
}
sub membersMatching {
my( $self, $re, %options ) = @_;
grep { $_->fileName =~ /$re/ } $self->sevenZip->members;
}
=head2 C<< $ar->numberOfMembers >>
my $count = $az->numberOfMembers();
=cut
sub numberOfMembers {
my( $self, %options ) = @_;
my @m = $self->members( %options );
0+@m
}
=head2 C<< $az->memberNamed >>
my $entry = $az->memberNamed('hello_world.txt');
print $entry->fileName, "\n";
=cut
# Archive::Zip API
sub memberNamed {
my( $self, $name, %options )= @_;
$self->sevenZip->memberNamed($name, %options );
}
sub extractMember {
my( $self, $name, $target, %options ) = @_;
if( ref $name and $name->can('fileName')) {
$name = $name->fileName;
};
$self->sevenZip->extractMember( $name, $target, %options );
}
sub removeMember {
my( $self, $name, $target, %options ) = @_;
# Just for the result:
my $res = ref $name ? $name : $self->memberNamed( $name );
if( ref $name and $name->can('fileName')) {
$name = $name->fileName;
};
$self->sevenZip->removeMember( $name, %options );
$res
}
=head2 C<< $ar->replaceMember >>
$ar->replaceMember('backup.txt', 'new-backup.txt');
Replaces the member in the archive. This is just delete then add.
I clearly don't understand the utility of this method. It clearly
does not update the content of one file with the content of another
file, as the name of the new file can be different.
=cut
# strikingly similar to Archive::Zip API
sub replaceMember {
my( $self, $name, $replacement, %_options ) = @_;
my %options = (%$self, %_options);
if( $^O =~ /MSWin/ ) {
$name =~ s!/!\\!g;
}
my $res = $self->removeMember( $name );
$self->add( $replacement );
$res
};
sub addFile {
my( $self, $name, $target, %options ) = @_;
if( ref $name and $name->can('fileName')) {
$name = $name->fileName;
};
$target ||= $name;
$self->sevenZip->add( items => [[ $name, $target ]], %options );
return $self->memberNamed($target, %options);
}
sub addMember {
my( $self, $name, $target, %options ) = @_;
if( ref $name and $name->can('fileName')) {
$name = $name->fileName;
};
$target ||= $name;
$self->sevenZip->add( items => [[ $name, $target ]], %options );
return $self->memberNamed($target, %options);
}
{ no warnings 'once';
*add = \&addMember;
}
sub addTree {
my( $self, $sourceDir, $target, $predicate, %options ) = @_;
croak "Predicates are not supported, sorry"
if $predicate;
$target ||= $sourceDir;
croak "Different target for ->addTree not supported, sorry"
if $target ne $sourceDir;
$self->sevenZip->add( items => [[ $sourceDir, $target ]], recursive => 1, %options );
return $self->memberNamed($target, %options);
}
*add = \&addMember;
__END__
=head1 CAUTION
This module tries to mimic the API of L<Archive::Zip>.
=head2 Differences between Archive::Zip and Archive::SevenZip
=head3 7-Zip does not guarantee the order of entries within an archive
The Archive::Zip test suite assumes that items added later to an
archive will appear later in the directory listing. 7-zip makes no
such guarantee.
=head1 REPOSITORY
The public repository of this module is
L<http://github.com/Corion/archive-sevenzip>.
=head1 SUPPORT
The public support forum of this module is
L<https://perlmonks.org/>.
=head1 BUG TRACKER
Please report bugs in this module via the RT CPAN bug queue at
L<https://rt.cpan.org/Public/Dist/Display.html?Name=Archive-SevenZip>
or via mail to L<archive-sevenzip-Bugs@rt.cpan.org>.
=head1 AUTHOR
Max Maischein C<corion@cpan.org>
=head1 COPYRIGHT (c)
Copyright 2015-2016 by Max Maischein C<corion@cpan.org>.
=head1 LICENSE
This module is released under the same terms as Perl itself.
=cut

View File

@@ -0,0 +1,138 @@
package Archive::SevenZip::Entry;
use strict;
use Time::Piece; # for strptime
use File::Basename ();
use Path::Class ();
use vars qw($VERSION);
$VERSION= '0.06';
sub new {
my( $class, %options) = @_;
bless \%options => $class
}
sub archive {
$_[0]->{_Container}
}
sub fileName {
my( $self ) = @_;
my $res = $self->{Path};
# Normalize to unixy path names
$res =~ s!\\!/!g;
# If we're a directory, append the slash:
if( $self->{Folder} eq '+') {
$res .= '/';
};
$res
}
# Class::Path API
sub basename {
Path::Class::file( $_[0]->{Path} )->basename
}
sub components {
my $cp = file( $_[0]->{Path} );
$cp->components()
}
sub lastModFileDateTime {
0
}
sub crc32 {
hex( $_[0]->{CRC} );
}
sub crc32String {
lc $_[0]->{CRC};
}
sub desiredCompressionMethod {
$_[0]->{Method}
}
sub uncompressedSize {
$_[0]->{Size}
}
sub dir {
# We need to return the appropriate class here
# so that further calls to (like) dir->list
# still work properly
die "->dir Not implemented";
}
sub open {
my( $self, $mode, $permissions )= @_;
$self->archive->openMemberFH( membername => $self->fileName, binmode => $mode );
}
{ no warnings 'once';
*fh = \&open; # Archive::Zip API
}
# Path::Class API
sub slurp {
my( $self, %options )= @_;
my $fh = $self->archive->openMemberFH( membername => $self->fileName, binmode => $options{ iomode } );
local $/;
<$fh>
}
# Archive::Zip API
#externalFileName()
# Archive::Zip API
#fileName()
# Archive::Zip API
#lastModFileDateTime()
# Archive::Zip API
#lastModTime()
# Archive::Zip API
sub extractToFileNamed {
my($self, $target) = @_;
$self->archive->extractMember( $self->fileName, $target );
};
1;
=head1 REPOSITORY
The public repository of this module is
L<http://github.com/Corion/archive-sevenzip>.
=head1 SUPPORT
The public support forum of this module is
L<https://perlmonks.org/>.
=head1 BUG TRACKER
Please report bugs in this module via the RT CPAN bug queue at
L<https://rt.cpan.org/Public/Dist/Display.html?Name=Archive-SevenZip>
or via mail to L<archive-sevenzip-Bugs@rt.cpan.org>.
=head1 AUTHOR
Max Maischein C<corion@cpan.org>
=head1 COPYRIGHT (c)
Copyright 2015-2016 by Max Maischein C<corion@cpan.org>.
=head1 LICENSE
This module is released under the same terms as Perl itself.
=cut