File Coverage

blib/lib/Filename/Type/Archive.pm
Criterion Covered Total %
statement 34 35 97.1
branch 8 10 80.0
condition 1 2 50.0
subroutine 5 5 100.0
pod 1 1 100.0
total 49 53 92.4


line stmt bran cond sub pod time code
1             package Filename::Type::Archive;
2              
3 2     2   582931 use 5.010001;
  2         7  
4 2     2   13 use strict;
  2         3  
  2         65  
5 2     2   11 use warnings;
  2         181  
  2         159  
6              
7 2     2   10 use Exporter 'import';
  2         5  
  2         1501  
8              
9             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
10             our $DATE = '2024-12-20'; # DATE
11             our $DIST = 'Filename-Type-Archive'; # DIST
12             our $VERSION = '0.033'; # VERSION
13              
14             our @EXPORT_OK = qw(check_archive_filename);
15             #list_archive_suffixes
16              
17             # XXX multi-part archive?
18              
19             our %SUFFIXES = (
20             '.7z' => {name=>'7-zip'},
21             '.cb7' => {name=>'7-zip'},
22              
23             '.zip' => {name=>'Zip'},
24             '.cbz' => {name=>'Zip'},
25              
26             '.rar' => {name=>'RAR'},
27             '.cbr' => {name=>'RAR'},
28              
29             '.tar' => {name=>'tar'},
30             '.cbt' => {name=>'tar'},
31              
32             '.tgz' => {name=>'tar+gzip'},
33             '.tbz' => {name=>'tar+bzip2'},
34              
35             '.ace' => {name=>'ACE'},
36             '.cba' => {name=>'ACE'},
37              
38             '.arj' => {name=>'arj'},
39             # XXX other older/less popular: lha, zoo
40             # XXX windows: cab
41             # XXX zip-based archives: war, etc
42             # XXX tar-based archives: linux packages
43             );
44              
45             our %ARCHIVES = (
46             'arj' => {
47             },
48             '7-zip' => {
49             },
50             Zip => {
51             # all programs mentioned here must accept filename(s) as arguments.
52             # preferably CLI. XXX specify capabilities (password-protection, unix
53             # permission, etc). XXX specify how to create (with password, etc). XXX
54             # specify how to extract.
55             archiver_programs => [
56             {name => 'zip', opts => ''},
57             ],
58             extractor_programs => [
59             {name => 'zip', opts => ''},
60             {name => 'unzip', opts => ''},
61             ],
62             },
63             RAR => {
64             },
65             tar => {
66             },
67             'tar+gzip' => {
68             },
69             'tar+bzip2' => {
70             },
71             ace => {
72             extractor_programs => [
73             {name => 'unace', opts => ''},
74             ],
75             },
76             );
77              
78             our %SPEC;
79              
80             $SPEC{check_archive_filename} = {
81             v => 1.1,
82             summary => 'Check whether filename indicates being an archive file',
83             description => <<'_',
84              
85              
86             _
87             args => {
88             filename => {
89             schema => 'str*',
90             req => 1,
91             pos => 0,
92             },
93             # XXX recurse?
94             ignore_case => {
95             summary => 'Whether to match case-insensitively',
96             schema => 'bool',
97             default => 1,
98             },
99             },
100             result_naked => 1,
101             result => {
102             schema => ['any*', of=>['bool*', 'hash*']],
103             description => <<'MARKDOWN',
104              
105             Return false if no archive suffixes detected. Otherwise return a hash of
106             information, which contains these keys: `archive_name`, `archive_suffix`,
107             `compressor_info`, `filename_without_suffix`.
108              
109             MARKDOWN
110             },
111             examples => [
112             {
113             args => {filename=>'foo.tar.bz2'},
114             },
115             {
116             args => {filename=>'bar.Zip', ignore_case=>1},
117             },
118             ],
119             };
120             sub check_archive_filename {
121 4     4 1 459567 require Filename::Type::Compressed;
122              
123 4         1444 my %args = @_;
124              
125 4         11 my $filename = $args{filename};
126 4   50     25 my $ci = $args{ignore_case} // 1;
127              
128 4         8 my @compressor_info;
129 4         7 while (1) {
130 7         22 my $res = Filename::Type::Compressed::check_compressed_filename(
131             filename => $filename, ci => $ci);
132 7 100       315 if ($res) {
133 3         8 push @compressor_info, $res;
134 3         7 $filename = $res->{uncompressed_filename};
135 3         6 next;
136             } else {
137 4         10 last;
138             }
139             }
140              
141 4 50       26 $filename =~ /(.+)(\.\w+)\z/ or return 0;
142 4         17 my ($filename_without_suffix, $suffix) = ($1, $2);
143              
144 4         6 my $spec;
145 4 50       9 if ($ci) {
146 4         8 my $suffix_lc = lc($suffix);
147 4         21 for (keys %SUFFIXES) {
148 40 100       88 if (lc($_) eq $suffix_lc) {
149 3         7 $spec = $SUFFIXES{$_};
150 3         7 last;
151             }
152             }
153             } else {
154 0         0 $spec = $SUFFIXES{$suffix};
155             }
156 4 100       23 return 0 unless $spec;
157              
158             return {
159             archive_name => $spec->{name},
160 3         59 archive_suffix => $suffix,
161             filename_without_suffix => $filename_without_suffix,
162             (compressor_info => \@compressor_info) x !!@compressor_info,
163             };
164             }
165              
166             1;
167             # ABSTRACT: Check whether filename indicates being an archive file
168              
169             __END__