File Coverage

lib/Archive/Lha/Header/Utils.pm
Criterion Covered Total %
statement 59 73 80.8
branch 38 58 65.5
condition 16 29 55.1
subroutine 10 15 66.6
pod 0 1 0.0
total 123 176 69.8


line stmt bran cond sub pod time code
1             package Archive::Lha::Header::Utils;
2              
3 18     18   80693 use strict;
  18         61  
  18         683  
4 18     18   87 use warnings;
  18         31  
  18         827  
5 18     18   93 use Carp;
  18         45  
  18         1221  
6 18     18   10182 use Time::Local ();
  18         42624  
  18         610  
7 18     18   9983 use POSIX ();
  18         176516  
  18         967  
8             eval { require Archive::Lha::Decode::Base }; # bootstrap XS functions
9 18     18   9655 use Exporter::Lite;
  18         22004  
  18         127  
10              
11             our @EXPORT = qw(
12             _int _short _dostime2utime dostime_fields _os_id _extended_header _extended_header_buf
13             );
14              
15 0     0   0 sub _int { unpack 'V', ( pack 'aaaa', @_ ) }
16 0     0   0 sub _short { unpack 'v', ( pack 'aa', @_ ) }
17              
18             # Fast variants that operate directly on a raw buffer + offset
19 0     0   0 sub _int_at { unpack 'V', substr($_[0], $_[1], 4) }
20 0     0   0 sub _short_at { unpack 'v', substr($_[0], $_[1], 2) }
21              
22             # Decode DOS timestamp into (sec, min, hour, mday, mon_0based, year_since_1900)
23             sub dostime_fields {
24 388 100 66 388 0 1092 return (0) x 6 unless @_ && $_[0];
25 384         438 my $v = $_[0];
26             return (
27 384         5996 ($v & 0x1F) * 2,
28             ($v >> 5) & 0x3F,
29             ($v >> 11) & 0x1F,
30             ($v >> 16) & 0x1F,
31             (($v >> 21) & 0x0F) - 1,
32             (($v >> 25) & 0x7F) + 80,
33             );
34             }
35              
36             sub _dostime2utime {
37 5 100 66 5   14821793 return 0 unless @_ && $_[0];
38 2 50       77 return Archive::Lha::Header::Utils::dostime2utime($_[0])
39             if defined &Archive::Lha::Header::Utils::dostime2utime;
40 0         0 my $v = $_[0];
41 0         0 my @t = (
42             ($v & 0x1F) * 2,
43             ($v >> 5) & 0x3F,
44             ($v >> 11) & 0x1F,
45             ($v >> 16) & 0x1F,
46             (($v >> 21) & 0x0F) - 1,
47             (($v >> 25) & 0x7F) + 80,
48             );
49 0   0     0 eval { Time::Local::timegm(@t) } // 0;
  0         0  
50             }
51              
52             sub _os_id {
53 296 50   296   1098 my $hex = ref $_[0] ? ord($_[0]) : ord(substr($_[0], 0, 1));
54              
55 296 100       738 return [ M => 'MS-DOS' ] if $hex == 0x4D;
56 245 50       441 return [ w => 'WinNT' ] if $hex == 0x57;
57 245 50       389 return [ w => 'Win95' ] if $hex == 0x77;
58 245 50       397 return [ g => 'generic' ] if $hex == 0x00;
59 245 100       387 return [ U => 'UNIX' ] if $hex == 0x55;
60 235 50       381 return [ m => 'Macintosh' ] if $hex == 0x6D;
61 235 50       345 return [ J => 'Java VM' ] if $hex == 0x4A;
62 235 50       341 return [ 2 => 'OS/2' ] if $hex == 0x32;
63 235 50       349 return [ 9 => 'OS/9' ] if $hex == 0x39;
64 235 50       430 return [ K => 'OS/68K' ] if $hex == 0x4B;
65 235 50       368 return [ 3 => 'OS/386' ] if $hex == 0x33;
66 235 50       340 return [ H => 'Human68K' ] if $hex == 0x48;
67 235 50       349 return [ C => 'CP/M' ] if $hex == 0x43;
68 235 50       463 return [ F => 'FLEX' ] if $hex == 0x46;
69 235 50       392 return [ R => 'Runser' ] if $hex == 0x52;
70 235 50       343 return [ T => 'TownsOS' ] if $hex == 0x54;
71 235 50       376 return [ X => 'XOSK' ] if $hex == 0x58;
72 235         676 return [ a => 'Amiga' ];
73             }
74              
75             # Legacy: called with a list of single chars
76             sub _extended_header {
77 0     0   0 my $buf = join '', @_;
78 0         0 return _extended_header_buf($buf, 0, length($buf));
79             }
80              
81             # Fast: called with a raw buffer, offset, and length
82             sub _extended_header_buf {
83 750     750   1268 my ($buf, $from, $len) = @_;
84 750         1063 my $to = $from + $len;
85 750         1404 my $next = unpack 'v', substr($buf, $to - 2, 2);
86              
87 750         999 my %hash;
88 750         1106 my $type = ord(substr($buf, $from, 1));
89              
90 750 100 33     2685 if ( $type == 0x00 ) {
    100 66        
    100 100        
    100 66        
    100 66        
    50 33        
    50 33        
    50          
91 288         667 $hash{additional_crc} = unpack 'v', substr($buf, $from + 1, 2);
92             }
93             elsif ( $type == 0x01 ) {
94 57         157 my $name = substr($buf, $from + 1, $len - 3);
95 57         178 $name =~ s/\0.*//s;
96 57         190 $hash{filename} = $name;
97             }
98             elsif ( $type == 0x02 ) {
99 287         572 my $dir = substr($buf, $from + 1, $len - 3);
100 287         513 $dir =~ s/\0.*//s;
101 287         630 $hash{directory} = $dir;
102             }
103             elsif ( $type == 0x50 ) {
104 10         35 $hash{unix_perm} = unpack 'v', substr($buf, $from + 1, 2);
105             }
106             elsif ( $type == 0x51 ) {
107 10         36 $hash{unix_gid} = unpack 'v', substr($buf, $from + 1, 2);
108 10         33 $hash{unix_uid} = unpack 'v', substr($buf, $from + 3, 2);
109             }
110             elsif ( $type == 0x52 ) {
111 0         0 $hash{unix_group} = substr($buf, $from + 1, $len - 3);
112             }
113             elsif ( $type == 0x54 ) {
114 0         0 $hash{timestamp} = unpack 'V', substr($buf, $from + 1, 4);
115 0         0 $hash{timestamp_is_unix} = 1;
116             }
117             elsif ( $type == 0x39 || $type == 0x3F || $type == 0x40 || $type == 0x41
118             || $type == 0x42 || $type == 0x46 || $type == 0x7D || $type == 0x7E ) {
119             # known but ignored header types
120             }
121             else {
122 0         0 warn sprintf "Unknown extended header type: %02x\n", $type;
123             }
124              
125 750         1718 return ($next, \%hash);
126             }
127              
128             1;
129              
130             __END__