File Coverage

blib/lib/PDF/API2/Basic/PDF/String.pm
Criterion Covered Total %
statement 66 67 98.5
branch 19 20 95.0
condition 5 9 55.5
subroutine 8 8 100.0
pod 6 6 100.0
total 104 110 94.5


line stmt bran cond sub pod time code
1             # Code in the PDF::API2::Basic::PDF namespace was originally copied from the
2             # Text::PDF distribution.
3             #
4             # Copyright Martin Hosken
5             #
6             # Martin Hosken's code may be used under the terms of the MIT license.
7             # Subsequent versions of the code have the same license as PDF::API2.
8              
9             package PDF::API2::Basic::PDF::String;
10              
11 40     40   70854 use base 'PDF::API2::Basic::PDF::Objind';
  40         97  
  40         6516  
12              
13 40     40   303 use strict;
  40         100  
  40         48510  
14              
15             our $VERSION = '2.043'; # VERSION
16              
17             =head1 NAME
18              
19             PDF::API2::Basic::PDF::String - Low-level PDF string object
20              
21             =head1 METHODS
22              
23             =cut
24              
25             our %trans = (
26             'n' => "\n",
27             'r' => "\r",
28             't' => "\t",
29             'b' => "\b",
30             'f' => "\f",
31             "\\" => "\\",
32             '(' => '(',
33             ')' => ')',
34             );
35              
36             our %out_trans = (
37             "\n" => 'n',
38             "\r" => 'r',
39             "\t" => 't',
40             "\b" => 'b',
41             "\f" => 'f',
42             "\\" => "\\",
43             '(' => '(',
44             ')' => ')',
45             );
46              
47             =head2 PDF::API2::Basic::PDF::String->from_pdf($string)
48              
49             Creates a new string object (not a full object yet) from a given
50             string. The string is parsed according to input criteria with
51             escaping working.
52              
53             =cut
54              
55             sub from_pdf {
56 388     388 1 863 my ($class, $str) = @_;
57 388         701 my $self = {};
58              
59 388         714 bless $self, $class;
60 388         1069 $self->{'val'} = $self->convert($str);
61 388         674 $self->{' realised'} = 1;
62 388         935 return $self;
63             }
64              
65             =head2 PDF::API2::Basic::PDF::String->new($string)
66              
67             Creates a new string object (not a full object yet) from a given
68             string. The string is parsed according to input criteria with
69             escaping working.
70              
71             =cut
72              
73             sub new {
74 30503     30503 1 47265 my ($class, $str) = @_;
75 30503         44203 my $self = {};
76              
77 30503         44016 bless $self, $class;
78 30503         55754 $self->{'val'} = $str;
79 30503         43426 $self->{' realised'} = 1;
80 30503         71310 return $self;
81             }
82              
83             =head2 $s->convert($str)
84              
85             Returns $str converted as per criteria for input from PDF file
86              
87             =cut
88              
89             sub convert {
90 30     30 1 56 my ($self, $input) = @_;
91 30         51 my $output = '';
92              
93             # Hexadecimal Strings (PDF 1.7 section 7.3.4.3)
94 30 100       104 if ($input =~ m|^\s*\<|o) {
95 3         8 $self->{' ishex'} = 1;
96 3         6 $output = $input;
97              
98             # Remove any extraneous characters to simplify processing
99 3         17 $output =~ s/[^0-9a-f]+//gio;
100 3         7 $output = "<$output>";
101              
102             # Convert each sequence of two hexadecimal characters into a byte
103 3         15 1 while $output =~ s/\<([0-9a-f]{2})/chr(hex($1)) . '<'/oige;
  7         48  
104              
105             # If a single hexadecimal character remains, append 0 and
106             # convert it into a byte.
107 3         8 $output =~ s/\<([0-9a-f])\>/chr(hex($1 . '0'))/oige;
  1         6  
108              
109             # Remove surrounding angle brackets
110 3         9 $output =~ s/\<\>//og;
111             }
112              
113             # Literal Strings (PDF 1.7 section 7.3.4.2)
114             else {
115             # Remove surrounding parentheses
116 27         195 $input =~ s/^\s*\((.*)\)\s*$/$1/os;
117              
118 27         51 my $cr = '(?:\015\012|\015|\012)';
119 27         81 my $prev_input;
120 27         67 while ($input) {
121 52 50 66     154 if (defined $prev_input and $input eq $prev_input) {
122 0         0 die "Infinite loop while parsing literal string";
123             }
124 52         78 $prev_input = $input;
125              
126             # Convert bachslash followed by up to three octal digits
127             # into that binary byte
128 52 100       461 if ($input =~ /^\\([0-7]{1,3})(.*)/os) {
    100          
    100          
    100          
    100          
129 13         35 $output .= chr(oct($1));
130 13         33 $input = $2;
131             }
132             # Convert backslash followed by an escaped character into that
133             # character
134             elsif ($input =~ /^\\([nrtbf\\\(\)])(.*)/osi) {
135 9         26 $output .= $trans{$1};
136 9         27 $input = $2;
137             }
138             # Ignore backslash followed by an end-of-line marker
139             elsif ($input =~ /^\\$cr(.*)/os) {
140 5         12 $input = $1;
141             }
142             # Convert an unescaped end-of-line marker to a line-feed
143             elsif ($input =~ /^\015\012?(.*)/os) {
144 2         4 $output .= "\012";
145 2         6 $input = $1;
146             }
147             # Check to see if there are any other special sequences
148             elsif ($input =~ /^(.*?)((?:\\(?:[nrtbf\\\(\)0-7]|$cr)|\015\012?).*)/os) {
149 10         24 $output .= $1;
150 10         26 $input = $2;
151             }
152             else {
153 13         29 $output .= $input;
154 13         43 $input = undef;
155             }
156             }
157             }
158              
159 30         92 return $output;
160             }
161              
162              
163             =head2 $s->val
164              
165             Returns the value of this string (the string itself).
166              
167             =cut
168              
169             sub val {
170 1050     1050 1 3988 return $_[0]->{'val'};
171             }
172              
173              
174             =head2 $->as_pdf
175              
176             Returns the string formatted for output as PDF for PDF File object $pdf.
177              
178             =cut
179              
180             sub as_pdf {
181 164     164 1 351 my ($self) = @_;
182 164         432 my $str = $self->{'val'};
183              
184 164 100 66     1082 if ($self->{' ishex'}) { # imported as hex ?
    100 33        
185 1         7 $str = unpack('H*', $str);
186 1         6 return "<$str>";
187             }
188             elsif ($self->{' isutf'} or (utf8::is_utf8($str) and $str =~ /[^[:ascii:]]/)) {
189 1         9 $str = join('', map { sprintf('%04X' , $_) } unpack('U*', $str) );
  3         13  
190 1         8 return "";
191             }
192             else {
193 162 100       606 if ($str =~ m/[^\n\r\t\b\f\040-\176\200-\377]/) {
194 3         12 $str =~ s/(.)/sprintf('%02X', ord($1))/sge;
  18         57  
195 3         17 return "<$str>";
196             }
197             else {
198 159         1487 $str =~ s/([\n\r\t\b\f\\()])/\\$out_trans{$1}/g;
199 159         823 return "($str)";
200             }
201             }
202             }
203              
204             =head2 $s->outobjdeep
205              
206             Outputs the string in PDF format, complete with necessary conversions
207              
208             =cut
209              
210             sub outobjdeep {
211 3078     3078 1 4805 my ($self, $fh, $pdf) = @_;
212              
213 3078         6386 $fh->print($self->as_pdf($pdf));
214             }
215              
216             1;