File Coverage

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