Archive-Lha
view release on metacpan or search on metacpan
sub _print_to_stdout {
my ($fname, $opts, @targets) = @_;
my %target = map { $_ => 1 } @targets;
my $stream = open_archive($fname);
while ( defined( my $level = $stream->search_header ) ) {
my $header = Archive::Lha::Header->new( level => $level, stream => $stream );
if (%target && !$target{$header->pathname}) {
$stream->seek( $header->{next_header} );
next;
}
next if _is_directory($header);
$stream->seek( $header->data_top );
my ($decoded) = _decode_entry($header, $stream);
$stream->seek( $header->{next_header} );
print $decoded;
}
}
sub _extract_lhasa {
my ($fname, $opts, @targets) = @_;
my %target = map { $_ => 1 } @targets;
my $stream = open_archive($fname);
while ( defined( my $level = $stream->search_header ) ) {
my $header = Archive::Lha::Header->new( level => $level, stream => $stream );
my $pathname = $header->pathname;
$pathname =~ s{.*/}{} if $opts->{ignore_path};
if (%target && !$target{$pathname}) {
$stream->seek( $header->{next_header} );
next;
}
$pathname = File::Spec->catfile($opts->{extract_dir}, $pathname)
if $opts->{extract_dir};
if (_is_directory($header)) {
mkpath $pathname unless -d $pathname || $opts->{dry_run};
$stream->seek( $header->{next_header} );
next;
}
$stream->seek( $header->data_top );
my ($decoded, $crc) = _decode_entry($header, $stream);
$stream->seek( $header->{next_header} );
die "crc mismatch for " . $header->pathname if $crc != $header->crc16;
unless ($opts->{dry_run}) {
if (-e $pathname && !$opts->{force}) {
print STDERR "$pathname already exists, skipping (use -f to force)\n";
next;
}
write_all($pathname, $decoded);
}
printf " %s\n", $pathname if $opts->{verbose};
}
}
sub usage_lhasa {
die "plhasa -- Perl LHA tool (lhasa-compatible)\n" .
"usage: plhasa [-]{lvtxep[q{num}][finv]}[w=<dir>] archive_file [file...]\n" .
"commands: options:\n" .
" l List (terse) f Force overwrite (no prompt)\n" .
" v Verbose list i Ignore directory path\n" .
" t Test file CRC in archive n Perform dry run\n" .
" x,e Extract from archive q{num} Quiet mode\n" .
" p Print to stdout from archive v Verbose\n" .
" w=<dir> Specify extract directory\n";
}
sub usage {
my ($msg) = @_;
my $text = "Usage: $0 [options] (l|v|vv|x|t|d) archive (files)\n" .
" l - list contents (LhA terse format, filename only)\n" .
" v - list archive verbose (LhA v format)\n" .
" vv - list archive full (LhA vv format)\n" .
" x - extract archive\n" .
" t - test file\n" .
" d - dump each header\n" .
" -fc, --from-charset <charset> source encoding for filenames (default: auto-detect)\n" .
" -tc, --to-charset <charset> output encoding for filenames (default: UTF-8)\n" .
" --use-locale use system locale for month names (default: English)\n";
if ($msg) {
die "$msg\n$text";
}
die $text;
}
sub _header_date {
my ($h) = @_;
return $h->{timestamp_is_unix}
? strftime("%d-%b-%y", localtime($h->{timestamp}))
: strftime("%d-%b-%y", Archive::Lha::Header::Utils::dostime_fields($h->{timestamp}));
}
sub _header_time {
my ($h) = @_;
return $h->{timestamp_is_unix}
? strftime("%T", localtime($h->{timestamp}))
: strftime("%T", Archive::Lha::Header::Utils::dostime_fields($h->{timestamp}));
}
# ls-style date from Unix epoch (stat mtime etc)
# Note: avoid %e (space-padded day) â not supported on Windows MSVC runtime.
# Use %d and strip the leading zero manually instead.
sub _ls_stamp {
my ($epoch) = @_;
my $six_months = 6 * 30 * 86400;
my @t = localtime($epoch);
my $day = sprintf "%2d", $t[3]; # space-pad day
if (abs(time - $epoch) < $six_months) {
return strftime("%b", @t) . " $day " . strftime("%H:%M", @t);
}
return strftime("%b", @t) . " $day " . strftime("%Y", @t);
}
# ls-style date from a header (handles both DOS and Unix timestamps)
sub _ls_stamp_header {
my ($header) = @_;
my $epoch = $header->{timestamp_is_unix}
? $header->{timestamp}
: Archive::Lha::Header::Utils::_dostime2utime($header->{timestamp});
return _ls_stamp($epoch);
( run in 0.576 second using v1.01-cache-2.11-cpan-0b5f733616e )