File Coverage

lib/Archive/Lha/Header/Base.pm
Criterion Covered Total %
statement 55 63 87.3
branch 15 22 68.1
condition 12 16 75.0
subroutine 12 13 92.3
pod 3 3 100.0
total 97 117 82.9


line stmt bran cond sub pod time code
1             package Archive::Lha::Header::Base;
2            
3 17     17   113 use strict;
  17         34  
  17         617  
4 17     17   81 use warnings;
  17         31  
  17         888  
5 17     17   88 use Carp;
  17         31  
  17         1134  
6 17     17   112 use File::Spec;
  17         46  
  17         529  
7 17     17   99 use File::Spec::Unix;
  17         56  
  17         1619  
8            
9             sub import {
10 124     124   3231 my $class = shift;
11 124         344 my $caller = caller;
12            
13 124         435 my @accessors = qw(
14             method header_top data_top next_header
15             encoded_size original_size crc16 timestamp os
16             );
17            
18             {
19 17     17   92 no strict 'refs'; no warnings 'redefine';
  17     17   34  
  17         789  
  17         97  
  17         30  
  17         14787  
  124         255  
20 124         331 foreach my $name ( @accessors ) {
21 1116     135   21823 *{"$class\::$name"} = sub { shift->{$name} };
  1116         5943  
  135         1191  
22             }
23 124         199 push @{"$caller\::ISA"}, $class;
  124         8716  
24             }
25             }
26            
27             # Map OS identifier to the most likely filename encoding used by that platform.
28             my %_os_charset = (
29             'a' => 'iso-8859-15', # Amiga
30             'M' => 'cp1252', # MS-DOS / Windows
31             'w' => 'cp1252', # WinNT / Win95
32             'U' => 'guess', # Unix (encoding varies: UTF-8 on modern, latin-1 on older)
33             'H' => 'cp932', # Human68K (Sharp X68000)
34             'J' => 'cp932', # Java VM (often used with Japanese archives)
35             'm' => 'UTF-8', # Macintosh (modern)
36             );
37            
38             sub charset_for_os {
39 191     191 1 250518 my ($self) = @_;
40 191 100       493 my $os_id = $self->{os} ? $self->{os}[0] : undef;
41 191 100 100     3014 return $os_id && $os_id ne '?' ? ( $_os_charset{$os_id} // 'guess' ) : 'guess';
      50        
42             }
43            
44             sub pathname {
45 280     280 1 18103 my ($self, $from, $to) = @_;
46 280         376 my $path;
47 280 50 66     1123 if ( $self->{pathname} ) {
    100          
    50          
    0          
48 0         0 $path = _conv_sep( $self->{pathname} );
49             }
50             elsif ( $self->{directory} && $self->{filename} ) {
51             $path = File::Spec::Unix->catfile(
52             _conv_sep( $self->{directory} ),
53             _conv_sep( $self->{filename} )
54 266         544 );
55             }
56             elsif ( $self->{filename} ) {
57 14         40 $path = _conv_sep( $self->{filename} );
58             }
59             elsif ( $self->{directory} ) {
60 0         0 $path = _conv_sep( $self->{directory} . '/' );
61             }
62            
63             # avoid traversal
64 280 50       1505 if ( File::Spec::Unix->file_name_is_absolute( $path ) ) {
65 0         0 my ($vol, $dir, $file) = File::Spec::Unix->splitpath( $path );
66 0         0 $path = File::Spec::Unix->catfile( '.', $dir, $file );
67             }
68            
69             # default from-encoding: auto-detect from OS field
70 280   66     916 $from //= $self->charset_for_os;
71 280   100     623 $to //= 'UTF-8';
72            
73 280         1606 require Encode;
74 280 100       891 if ( lc $from eq 'guess' ) {
    50          
75 2         636 require Encode::Guess;
76 2         3969 my $enc = Encode::Guess::guess_encoding(
77             $path => qw( latin1 latin2 cp932 euc-jp )
78             );
79 2 50       17942 Encode::from_to( $path, ref($enc) ? $enc->name : 'latin1', $to );
80             }
81             elsif ( lc $from ne lc $to ) {
82 278         1452 Encode::from_to( $path, $from, $to );
83             }
84            
85 280         36792 my $trailing_slash = $path =~ m{/$};
86 280         862 $path = File::Spec::Unix->canonpath( $path );
87 280 100 66     718 $path .= '/' if $trailing_slash && $path !~ m{/$};
88 280         2272 return $path;
89             }
90            
91             sub dirname {
92 0     0 1 0 my $self = shift;
93 0         0 my $path = $self->pathname(@_);
94 0         0 require File::Basename;
95 0         0 return File::Basename::dirname( $path );
96             }
97            
98             sub _conv_sep {
99 546     546   769 my $path = shift;
100            
101 546         2110 $path =~ s{\xff|\\}{/}g;
102 546         2953 return $path;
103             }
104            
105             1;
106            
107             __END__