File Coverage

blib/lib/Parse/Sums.pm
Criterion Covered Total %
statement 50 60 83.3
branch 25 36 69.4
condition 5 6 83.3
subroutine 6 6 100.0
pod 1 1 100.0
total 87 109 79.8


line stmt bran cond sub pod time code
1             package Parse::Sums;
2              
3             our $DATE = '2016-11-23'; # DATE
4             our $VERSION = '0.001'; # VERSION
5              
6 1     1   15490 use 5.010001;
  1         3  
7 1     1   4 use strict;
  1         1  
  1         20  
8 1     1   3 use warnings;
  1         1  
  1         27  
9              
10 1     1   3 use Exporter qw(import);
  1         1  
  1         611  
11             our @EXPORT_OK = qw(parse_sums);
12              
13             our %SPEC;
14              
15             sub _guess_algo {
16 10     10   31 my $str = shift;
17 10         10 my $len = length($str);
18 10 50       35 if ($len == 8) {
    100          
    100          
    50          
    50          
    50          
    50          
19 0         0 return ('crc32', 0);
20             } elsif ($len == 32) {
21 7         16 return ('md5', 0);
22             } elsif ($len == 40) {
23 2         5 return ('sha1', 0);
24             } elsif ($len == 56) {
25 0         0 return ('sha224', 1); # or sha512224
26             } elsif ($len == 64) {
27 0         0 return ('sha256', 1); # or sha512256
28             } elsif ($len == 96) {
29 0         0 return ('sha384', 0);
30             } elsif ($len == 128) {
31 0         0 return ('sha512', 0);
32             } else {
33 1         2 return '';
34             }
35             }
36              
37             $SPEC{parse_sums} = {
38             v => 1.1,
39             summary => 'Parse checksums file (e.g. MD5SUMS, SHA1SUMS)',
40             args => {
41             filename => {
42             summary => 'Checksums filename',
43             schema => 'filename*',
44             },
45             content => {
46             summary => 'Content of checksums file',
47             schema => 'str*',
48             description => <<'_',
49              
50             If specified, then `filename` contents will not be read.
51              
52             _
53             },
54             },
55             examples => [
56             ],
57             };
58             sub parse_sums {
59 6     6 1 8604 my %args = @_;
60              
61 6         9 my $filename = $args{filename};
62 6         7 my $content = $args{content};
63 6 50       17 unless (defined $content) {
64 0 0       0 open my($fh), "<", $filename
65             or return [500, "Can't read '$filename': $!"];
66 0         0 local $/;
67 0         0 $content = <$fh>;
68             }
69              
70 6         6 my $algo;
71 6 100       12 if (defined $filename) {
72 4 50       30 if ($filename =~ /(crc32|md5|sha[_-]?(?:512224|512256|224|256|384|512|1))/i) {
73 4         13 $algo = lc($1);
74             }
75             }
76              
77 6         6 my @res;
78 6         6 my $num_invalid_lines = 0;
79 6         6 my $linenum = 0;
80 6         19 for my $line (split /^/, $content) {
81 20         17 $linenum++;
82 20 100       61 next unless $line =~ /\S/;
83 10         9 my ($digest, $line_algo, $multiple, $file);
84 10 100       51 if ($line =~ /\A([0-9A-Fa-f]+)\s+\*?(.+)$/) {
    50          
85 8         12 $digest = $1;
86 8         15 ($line_algo, $multiple) = _guess_algo($1);
87 8         13 $file = $2;
88             } elsif ($line =~ /\A(\w+) \((.+)\) = ([0-9A-Fa-f]+)$/) {
89 2         6 $digest = $3;
90 2         6 (undef, $multiple) = _guess_algo($3);
91 2         6 $file = $2;
92 2         6 $line_algo = lc($1); $line_algo =~ s/-//g;
  2         5  
93             } else {
94 0         0 $num_invalid_lines++;
95 0         0 next;
96             }
97 10 100 66     101 if ($algo && !$multiple && $algo ne $line_algo) {
      100        
98 2         4 $num_invalid_lines++;
99 2         5 next;
100             }
101 8 100       14 $line_algo = $algo if $algo;
102 8 100       15 if (!$line_algo) {
103 1         1 $num_invalid_lines++;
104 1         3 next;
105             }
106 7         35 push @res, {algorithm=>$line_algo, file=>$file, digest=>$digest, linenum=>$linenum};
107             }
108 6 50       48 [200, "OK", \@res, {
109             ('func.warning' => ($num_invalid_lines > 1 ? "$num_invalid_lines lines are" : "1 line is")." improperly formatted") x !!$num_invalid_lines,
110             }];
111             }
112              
113             1;
114             # ABSTRACT: Parse checksums file (e.g. MD5SUMS, SHA1SUMS)
115              
116             __END__