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   68377 use base 'PDF::API2::Basic::PDF::Filter';
  43         136  
  43         4756  
4              
5 43     43   370 use strict;
  43         121  
  43         1111  
6 43     43   233 use warnings;
  43         96  
  43         20616  
7              
8             our $VERSION = '2.044'; # 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 97 my ($self, $input, $include_eod) = @_;
15 2         3 my $output;
16              
17 2         7 while ($input ne '') {
18 6         13 my ($unrepeated, $repeated);
19              
20             # Look for a repeated character (which can be repeated up to
21             # 127 times)
22 6 50       64 if ($input =~ m/^(.*?)((.)\3{1,127})(.*)$/so) {
23 6         15 $unrepeated = $1;
24 6         12 $repeated = $2;
25 6         12 $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         16 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       18 $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         25 $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       7 $output .= "\x80" if $include_eod;
51              
52 2         11 return $output;
53             }
54              
55             sub infilt {
56 2     2 1 8 my ($self, $input, $is_terminated) = @_;
57 2         3 my ($output, $length);
58              
59             # infilt may be called multiple times, and is expected to continue
60             # where it left off
61 2 50       30 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         23 $length = unpack("C", $input);
69              
70             # A "length" of 128 represents the end of the document
71 11 100       24 if ($length == 128) {
72 1         4 return $output;
73             }
74              
75             # Any other length needs to be followed by at least one other byte
76 10 50 33     20 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       21 if ($length > 128) {
83 6 50       13 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         15 $output .= substr($input, 1, 1) x (257 - $length);
89 6         14 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       13 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         9 substr($input, 0, $length + 2) = '';
103             }
104             }
105              
106 1         5 return $output;
107             }
108              
109             1;