File Coverage

blib/lib/PDF/Builder/Basic/PDF/Objind.pm
Criterion Covered Total %
statement 64 78 82.0
branch 24 34 70.5
condition 11 17 64.7
subroutine 15 18 83.3
pod 12 12 100.0
total 126 159 79.2


line stmt bran cond sub pod time code
1             #=======================================================================
2             #
3             # THIS IS A REUSED PERL MODULE, FOR PROPER LICENCING TERMS SEE BELOW:
4             #
5             # Copyright Martin Hosken <Martin_Hosken@sil.org>
6             #
7             # No warranty or expression of effectiveness, least of all regarding
8             # anyone's safety, is implied in this software or documentation.
9             #
10             # This specific module is licensed under the Perl Artistic License.
11             # Effective 28 January 2021, the original author and copyright holder,
12             # Martin Hosken, has given permission to use and redistribute this module
13             # under the MIT license.
14             #
15             #=======================================================================
16             package PDF::Builder::Basic::PDF::Objind;
17              
18 42     42   399 use strict;
  42         109  
  42         1723  
19 42     42   221 use warnings;
  42         80  
  42         2534  
20 42     42   299 use Scalar::Util 'isweak';
  42         107  
  42         5289  
21              
22             our $VERSION = '3.028'; # VERSION
23             our $LAST_UPDATE = '3.027'; # manually update whenever code is changed
24              
25             =head1 NAME
26              
27             PDF::Builder::Basic::PDF::Objind - PDF indirect object reference
28              
29             Also acts as an abstract superclass for all elements in a PDF file
30              
31             =head1 INSTANCE VARIABLES
32              
33             Instance variables differ from content variables in that they all start with
34             a space.
35              
36             =over
37              
38             =item ' parent'
39              
40             For an object which is a reference to an object in some source, this holds the
41             reference to the source object, so that should the reference have to be
42             de-referenced, then we know where to go and get the info.
43              
44             =item ' objnum' (R)
45              
46             The object number in the source (only for object references)
47              
48             =item ' objgen' (R)
49              
50             The object generation in the source
51              
52             There are other instance variables which are used by the parent for file control.
53              
54             =item ' isfree'
55              
56             This marks whether the object is in the free list and available for re-use as
57             another object elsewhere in the file.
58              
59             =item ' nextfree'
60              
61             Holds a direct reference to the next free object in the free list.
62              
63             =back
64              
65             =head1 METHODS
66              
67             =cut
68              
69 42     42   298 use Scalar::Util qw(blessed reftype weaken);
  42         304  
  42         3240  
70              
71 42     42   393 use vars qw($uidc @inst %inst);
  42         75  
  42         14846  
72             $uidc = "pdfuid000";
73              
74             # protected keys during emptying and copying, etc.
75             @inst = qw(parent objnum objgen isfree nextfree uid realised);
76             $inst{" $_"} = 1 for @inst;
77              
78             =head2 new
79              
80             PDF::Builder::Basic::PDF::Objind->new()
81              
82             =over
83              
84             Creates a new indirect object
85              
86             =back
87              
88             =cut
89              
90             sub new {
91 2197     2197 1 4760 my ($class) = @_;
92              
93 2197   33     11930 return bless {}, ref $class || $class;
94             }
95              
96             =head2 uid
97              
98             $UID = $r->uid()
99              
100             =over
101              
102             Returns a Unique id for this object, creating one if it didn't have one before
103              
104             =back
105              
106             =cut
107              
108             sub uid {
109 32453 100   32453 1 97587 $_[0]->{' uid'} || ($_[0]->{' uid'} = $uidc++);
110 32453         105516 return $_[0]->{' uid'};
111             }
112              
113             =head2 release
114              
115             $r->release()
116              
117             =over
118              
119             Releases ALL of the memory used by this indirect object, and all of
120             its component/child objects. This method is called automatically by
121             'C<PDF::Builder::Basic::PDF::File-E<gt>release>' (so you don't have to
122             call it yourself).
123              
124             B<Note:> it is important that this method get called at some point
125             prior to the actual destruction of the object. Internally, PDF files
126             have an enormous amount of cross-references and this causes circular
127             references within our own internal data structures. Calling
128             'C<release()>' forces these circular references to be cleaned up and
129             the entire internal data structure purged.
130              
131             =back
132              
133             =cut
134              
135             # Maintainer's Question: Couldn't this be handled by a DESTROY method
136             # instead of requiring an explicit call to release()?
137             sub release {
138 16451     16451 1 27476 my ($self) = @_;
139              
140 16451         34354 my @tofree = grep { !isweak $_ } values %$self;
  51381         98685  
141 16451         32609 %$self = ();
142              
143             # PDFs with highly-interconnected page trees or outlines can hit Perl's
144             # recursion limit pretty easily, so disable the warning for this specific
145             # loop.
146 42     42   313 no warnings 'recursion'; ## no critic
  42         97  
  42         52504  
147              
148 16451         35161 while (my $item = shift @tofree) {
149             # common case: value is not reference
150 54340   100     138512 my $ref = ref($item) || next;
151              
152 14973 100 100     79545 if (blessed($item) and $item->can('release')) {
    100 33        
    50          
153 13924         25444 $item->release();
154             } elsif ($ref eq 'ARRAY') {
155 1017         4877 push @tofree, @$item;
156             } elsif (defined(reftype($ref)) and reftype($ref) eq 'HASH') {
157 0         0 release($item);
158             }
159             }
160 16451         53397 return;
161             }
162              
163             =head2 val
164              
165             $value = $r->val()
166              
167             =over
168              
169             Returns the value of this object or reads the object and then returns
170             its value.
171              
172             Note that all direct subclasses *must* make their own versions of this
173             subroutine otherwise we could be in for a very deep loop!
174              
175             =back
176              
177             =cut
178              
179             sub val {
180 0     0 1 0 my ($self) = @_;
181              
182             # this original code is very confusing. is this a
183             # recursive call to this val(), or another? what is
184             # supposed to be returned when self->realised is True?
185             # perlcritic doesn't like this...
186             #$self->{' parent'}->read_obj(@_)->val()
187             # unless $self->{' realised'}; ## no critic
188              
189 0 0       0 if ($self->{' realised'}) {
190 0         0 return $self->{' realised'}; # return undef in any cases?
191             } else {
192 0         0 return $self->{' parent'}->read_obj(@_)->val();
193             }
194             }
195              
196             =head2 realise
197              
198             $r->realise()
199              
200             =over
201              
202             Makes sure that the object is fully read in, etc.
203              
204             =back
205              
206             =cut
207              
208             sub realise {
209 2745     2745 1 4408 my $self = shift();
210              
211 2745 100       11094 return $self if $self->{' realised'};
212 118 100       705 return $self->{' parent'}->read_obj($self, @_) if $self->{' objnum'};
213 32         113 return $self;
214             }
215              
216             =head2 outobjdeep
217              
218             $v = $r->outobjdeep($fh, $pdf)
219              
220             =over
221              
222             If you really want to output this object, then you need to read it first.
223             This also means that all direct subclasses must subclass this method, or they
224             will loop forever!
225              
226             =back
227              
228             =cut
229              
230             sub outobjdeep {
231 0     0 1 0 my ($self, $fh, $pdf) = @_;
232              
233             # this original code is very confusing. is this a
234             # recursive call to this outobjdeep(), or another? what is
235             # supposed to be returned when self->realised is True?
236             # perlcritic doesn't like the lack of explicit return...
237             #$self->{' parent'}->read_obj($self)->outobjdeep($fh, $pdf)
238             # unless $self->{' realised'}; ## no critic
239              
240 0 0       0 if ($self->{' realised'}) {
241 0         0 return $self->{' realised'}; # return undef in any cases?
242             } else {
243 0         0 return $self->{' parent'}->read_obj($self)->outobjdeep($fh, $pdf);
244             }
245             }
246              
247             =head2 outobj
248              
249             $r->outobj($fh, $pdf)
250              
251             =over
252              
253             If this is a full object then outputs a reference to the object, otherwise calls
254             outobjdeep to output the contents of the object at this point.
255              
256             =back
257              
258             =cut
259              
260             sub outobj {
261 15384     15384 1 27974 my ($self, $fh, $pdf) = @_;
262              
263 15384 100       33578 if (defined $pdf->{' objects'}{$self->uid()}) {
264 1254         2338 $fh->printf("%d %d R", @{$pdf->{' objects'}{$self->uid()}}[0..1]);
  1254         2555  
265             } else {
266 14130         33829 $self->outobjdeep($fh, $pdf);
267             }
268 15384         38858 return;
269             }
270              
271             =head2 elements
272              
273             $s = $r->elements()
274              
275             =over
276              
277             Abstract superclass function filler. Returns self here but should return
278             something more useful if an array.
279              
280             =back
281              
282             =cut
283              
284             sub elements {
285 3     3 1 18 my ($self) = @_;
286              
287 3 50       12 if ($self->{' realised'}) {
288 3         12 return $self;
289             } else {
290 0         0 return $self->{' parent'}->read_obj($self)->elements();
291             }
292             }
293              
294             =head2 empty
295              
296             $s = $r->empty()
297              
298             =over
299              
300             Empties all content from this object to free up memory or to be read to pass
301             the object into the free list. Simplistically undefs all instance variables
302             other than object number and generation.
303              
304             =back
305              
306             =cut
307              
308             sub empty {
309 0     0 1 0 my ($self) = @_;
310              
311 0         0 for my $k (keys %$self) {
312 0 0       0 undef $self->{$k} unless $inst{$k};
313             }
314              
315 0         0 return $self;
316             }
317              
318             =head2 merge
319              
320             $o = $r->merge($objind)
321              
322             =over
323              
324             This merges content information into an object reference placeholder.
325             This occurs when an object reference is read before the object definition
326             and the information in the read data needs to be merged into the object
327             placeholder.
328              
329             =back
330              
331             =cut
332              
333             sub merge {
334 90     90 1 199 my ($self, $other) = @_;
335              
336 90         521 for my $k (keys %$other) {
337 434 100       983 next if $inst{$k};
338 344         894 $self->{$k} = $other->{$k};
339              
340             # This doesn't seem like the right place to do this, but I haven't
341             # yet found all of the places where Parent is being set
342 344 100       878 weaken $self->{$k} if $k eq 'Parent';
343             }
344 90         241 $self->{' realised'} = 1;
345 90         301 return bless $self, ref($other);
346             }
347              
348             =head2 is_obj
349              
350             $r->is_obj($pdf)
351              
352             =over
353              
354             Returns whether this object is a full object with its own object number or
355             whether it is purely a sub-object. C<$pdf> indicates which output file we are
356             concerned that the object is an object in.
357              
358             =back
359              
360             =cut
361              
362             sub is_obj {
363 4681     4681 1 12636 return defined $_[1]->{' objects'}{$_[0]->uid()};
364             }
365              
366             =head2 copy
367              
368             $r->copy($pdf, $res)
369              
370             =over
371              
372             Returns a new copy of this object. The object is assumed to be some kind
373             of associative array and the copy is a deep copy for elements which are
374             not PDF objects, according to C<$pdf>, and shallow copy for those that are.
375             Notice that calling C<copy> on an object forces at least a one level
376             copy even if it is a PDF object. The returned object loses its PDF
377             object status though.
378              
379             If C<$res> is defined then the copy goes into that object rather than creating a
380             new one. It is up to the caller to bless C<$res>, etc. Notice that elements from
381             C<$self> are not copied into C<$res> if there is already an entry for them
382             existing in C<$res>.
383              
384             =back
385              
386             =cut
387              
388             sub copy {
389 3115     3115 1 6553 my ($self, $pdf, $res) = @_;
390              
391 3115 50       7025 unless (defined $res) {
392 3115         7395 $res = {};
393 3115         6080 bless $res, ref($self);
394             }
395 3115         8925 foreach my $k (keys %$self) {
396 9370 100       23224 next if $inst{$k};
397 3126 50       7188 next if defined $res->{$k};
398 3126 100 66     10199 if (blessed($self->{$k}) and $self->{$k}->can('is_obj') and not $self->{$k}->is_obj($pdf)) {
      66        
399 206         935 $res->{$k} = $self->{$k}->copy($pdf);
400             } else {
401 2920         12943 $res->{$k} = $self->{$k};
402             }
403             }
404 3115         10049 return $res;
405             }
406              
407             1;