File Coverage

blib/lib/PDF/API2/Basic/PDF/Filter/RunLengthDecode.pm
Criterion Covered Total %
statement 39 50 78.0
branch 14 20 70.0
condition 1 3 33.3
subroutine 5 5 100.0
pod 2 2 100.0
total 61 80 76.2


line stmt bran cond sub pod time code
1             package PDF::API2::Basic::PDF::Filter::RunLengthDecode;
2              
3 43     43   75027 use base 'PDF::API2::Basic::PDF::Filter';
  43         121  
  43         4866  
4              
5 43     43   327 use strict;
  43         123  
  43         1149  
6 43     43   253 use warnings;
  43         112  
  43         21157  
7              
8             our $VERSION = '2.043'; # VERSION
9              
10             # Maintainer's Note: RunLengthDecode is described in the PDF 1.7 spec
11             # in section 7.4.5.
12              
13             sub outfilt {
14 2     2 1 111 my ($self, $input, $include_eod) = @_;
15 2         4 my $output;
16              
17 2         10 while ($input ne '') {
18 6         11 my ($unrepeated, $repeated);
19              
20             # Look for a repeated character (which can be repeated up to
21             # 127 times)
22 6 50       42 if ($input =~ m/^(.*?)((.)\3{1,127})(.*)$/so) {
23 6         14 $unrepeated = $1;
24 6         14 $repeated = $2;
25 6         13 $input = $4;
26             }
27             else {
28 0         0 $unrepeated = $input;
29 0         0 $input = '';
30             }
31              
32             # Print any non-repeating bytes at the beginning of the input
33             # in chunks of up to 128 bytes, prefixed with a run-length (0
34             # to 127, signifying 1 to 128 bytes)
35 6         17 while (length($unrepeated) > 127) {
36 0         0 $output .= pack('C', 127) . substr($unrepeated, 0, 128);
37 0         0 substr($unrepeated, 0, 128) = '';
38             }
39 6 100       21 $output .= pack('C', length($unrepeated) - 1) . $unrepeated if length($unrepeated) > 0;
40              
41             # Then print the number of times the repeated byte was
42             # repeated (using the formula "257 - length" to give a result
43             # in the 129-255 range) followed by the byte to be repeated
44 6 50       14 if (length($repeated)) {
45 6         30 $output .= pack('C', 257 - length($repeated)) . substr($repeated, 0, 1);
46             }
47             }
48              
49             # A byte value of 128 signifies that we're done.
50 2 100       6 $output .= "\x80" if $include_eod;
51              
52 2         14 return $output;
53             }
54              
55             sub infilt {
56 2     2 1 7 my ($self, $input, $is_terminated) = @_;
57 2         5 my ($output, $length);
58              
59             # infilt may be called multiple times, and is expected to continue
60             # where it left off
61 2 50       13 if (exists $self->{'incache'}) {
62 0         0 $input = $self->{'incache'} . $input;
63 0         0 delete $self->{'incache'};
64             }
65              
66 2         8 while (length($input)) {
67             # Read a length byte
68 11         25 $length = unpack("C", $input);
69              
70             # A "length" of 128 represents the end of the document
71 11 100       25 if ($length == 128) {
72 1         5 return $output;
73             }
74              
75             # Any other length needs to be followed by at least one other byte
76 10 50 33     23 if (length($input) == 1 and not $is_terminated) {
77 0         0 die "Premature end to RunLengthEncoded data";
78             }
79              
80             # A length of 129-255 represents a repeated string
81             # (number of repeats = 257 - length)
82 10 100       20 if ($length > 128) {
83 6 50       12 if (length($input) == 1) {
84             # Out of data. Defer until the next call.
85 0         0 $self->{'incache'} = $input;
86 0         0 return $output;
87             }
88 6         17 $output .= substr($input, 1, 1) x (257 - $length);
89 6         15 substr($input, 0, 2) = '';
90             }
91              
92             # Any other length (under 128) represents a non-repeated
93             # stream of bytes (with a length of 0 to 127 representing 1 to
94             # 128 bytes)
95             else {
96 4 50       12 if (length($input) < $length + 2) {
97             # Insufficient data. Defer until the next call.
98 0         0 $self->{'incache'} = $input;
99 0         0 return $output;
100             }
101 4         10 $output .= substr($input, 1, $length + 1);
102 4         11 substr($input, 0, $length + 2) = '';
103             }
104             }
105              
106 1         6 return $output;
107             }
108              
109             1;