source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/Fixup.pm@ 24626

Last change on this file since 24626 was 24626, checked in by jmt12, 13 years ago

An (almost) complete copy of the perllib directory from a (circa SEP2011) head checkout from Greenstone 2 trunk - in order to try and make merging in this extension a little easier later on (as there have been some major changes to buildcol.pl commited in the main trunk but not in the x64 branch)

File size: 11.2 KB
Line 
1#------------------------------------------------------------------------------
2# File: Fixup.pm
3#
4# Description: Utility to handle pointer fixups
5#
6# Revisions: 01/19/2005 - P. Harvey Created
7# 04/11/2005 - P. Harvey Allow fixups to be tagged with a marker,
8# and add new marker-related routines
9# 06/21/2006 - P. Harvey Patch to work with negative offsets
10# 07/07/2006 - P. Harvey Added support for 16-bit pointers
11#
12# Data Members:
13#
14# Start - Position in data where a zero pointer points to.
15# Shift - Amount to shift offsets (relative to Start).
16# Fixups - List of Fixup object references to to shift relative to this Fixup.
17# Pointers - Hash of references to fixup pointer arrays, keyed by ByteOrder
18# string (with "2" added if pointer is 16-bit [default is 32-bit],
19# plus "_$marker" suffix if tagged with a marker name).
20#------------------------------------------------------------------------------
21
22package Image::ExifTool::Fixup;
23
24use strict;
25use Image::ExifTool qw(GetByteOrder SetByteOrder Get32u Get32s Set32u
26 Get16u Get16s Set16u);
27use vars qw($VERSION);
28
29$VERSION = '1.04';
30
31sub AddFixup($$;$$);
32sub ApplyFixup($$);
33sub Dump($;$);
34
35#------------------------------------------------------------------------------
36# New - create new Fixup object
37# Inputs: 0) reference to Fixup object or Fixup class name
38sub new
39{
40 local $_;
41 my $that = shift;
42 my $class = ref($that) || $that || 'Image::ExifTool::Fixup';
43 my $self = bless {}, $class;
44
45 # initialize required members
46 $self->{Start} = 0;
47 $self->{Shift} = 0;
48
49 return $self;
50}
51
52#------------------------------------------------------------------------------
53# Clone this object
54# Inputs: 0) reference to Fixup object or Fixup class name
55# Returns: reference to new Fixup object
56sub Clone($)
57{
58 my $self = shift;
59 my $clone = new Image::ExifTool::Fixup;
60 $clone->{Start} = $self->{Start};
61 $clone->{Shift} = $self->{Shift};
62 my $phash = $self->{Pointers};
63 if ($phash) {
64 $clone->{Pointers} = { };
65 my $byteOrder;
66 foreach $byteOrder (keys %$phash) {
67 my @pointers = @{$phash->{$byteOrder}};
68 $clone->{Pointers}->{$byteOrder} = \@pointers;
69 }
70 }
71 if ($self->{Fixups}) {
72 $clone->{Fixups} = [ ];
73 my $subFixup;
74 foreach $subFixup (@{$self->{Fixups}}) {
75 push @{$clone->{Fixups}}, $subFixup->Clone();
76 }
77 }
78 return $clone;
79}
80
81#------------------------------------------------------------------------------
82# Add fixup pointer or another fixup object below this one
83# Inputs: 0) Fixup object reference
84# 1) Scalar for pointer offset, or reference to Fixup object
85# 2) Optional marker name for the pointer
86# 3) Optional pointer format ('int16u' or 'int32u', defaults to 'int32u')
87# Notes: Byte ordering must be set properly for the pointer being added (must keep
88# track of the byte order of each offset since MakerNotes may have different byte order!)
89sub AddFixup($$;$$)
90{
91 my ($self, $pointer, $marker, $format) = @_;
92 if (ref $pointer) {
93 $self->{Fixups} or $self->{Fixups} = [ ];
94 push @{$self->{Fixups}}, $pointer;
95 } else {
96 my $byteOrder = GetByteOrder();
97 if (defined $format) {
98 if ($format eq 'int16u') {
99 $byteOrder .= '2';
100 } elsif ($format ne 'int32u') {
101 warn "Bad Fixup pointer format $format\n";
102 }
103 }
104 $byteOrder .= "_$marker" if defined $marker;
105 my $phash = $self->{Pointers};
106 $phash or $phash = $self->{Pointers} = { };
107 $phash->{$byteOrder} or $phash->{$byteOrder} = [ ];
108 push @{$phash->{$byteOrder}}, $pointer;
109 }
110}
111
112#------------------------------------------------------------------------------
113# fix up pointer offsets
114# Inputs: 0) Fixup object reference, 1) data reference
115# Outputs: Collapses fixup hierarchy into linear lists of fixup pointers
116sub ApplyFixup($$)
117{
118 my ($self, $dataPt) = @_;
119
120 my $start = $self->{Start};
121 my $shift = $self->{Shift} + $start; # make shift relative to start
122 my $phash = $self->{Pointers};
123
124 # fix up pointers in this fixup
125 if ($phash and ($start or $shift)) {
126 my $saveOrder = GetByteOrder(); # save original byte ordering
127 my ($byteOrder, $ptr);
128 foreach $byteOrder (keys %$phash) {
129 SetByteOrder(substr($byteOrder,0,2));
130 # apply the fixup offset shift (must get as signed integer
131 # to avoid overflow in case it was negative before)
132 my ($get, $set) = ($byteOrder =~ /^(II2|MM2)/) ?
133 (\&Get16s, \&Set16u) : (\&Get32s, \&Set32u);
134 foreach $ptr (@{$phash->{$byteOrder}}) {
135 $ptr += $start; # update pointer to new start location
136 next unless $shift;
137 &$set(&$get($dataPt, $ptr) + $shift, $dataPt, $ptr);
138 }
139 }
140 SetByteOrder($saveOrder); # restore original byte ordering
141 }
142 # recurse into contained fixups
143 if ($self->{Fixups}) {
144 # create our pointer hash if it doesn't exist
145 $phash or $phash = $self->{Pointers} = { };
146 # loop through all contained fixups
147 my $subFixup;
148 foreach $subFixup (@{$self->{Fixups}}) {
149 # adjust the subfixup start and shift
150 $subFixup->{Start} += $start;
151 $subFixup->{Shift} += $shift - $start;
152 # recursively apply contained fixups
153 ApplyFixup($subFixup, $dataPt);
154 my $shash = $subFixup->{Pointers} or next;
155 # add all pointers to our collapsed lists
156 my $byteOrder;
157 foreach $byteOrder (keys %$shash) {
158 $phash->{$byteOrder} or $phash->{$byteOrder} = [ ];
159 push @{$phash->{$byteOrder}}, @{$shash->{$byteOrder}};
160 delete $shash->{$byteOrder};
161 }
162 delete $subFixup->{Pointers};
163 }
164 delete $self->{Fixups}; # remove our contained fixups
165 }
166 # reset our Start/Shift for the collapsed fixup
167 $self->{Start} = $self->{Shift} = 0;
168}
169
170#------------------------------------------------------------------------------
171# Does specified marker exist?
172# Inputs: 0) Fixup object reference, 1) marker name
173# Returns: True if fixup contains specified marker name
174sub HasMarker($$)
175{
176 my ($self, $marker) = @_;
177 my $phash = $self->{Pointers};
178 return 0 unless $phash;
179 return 1 if grep /_$marker$/, keys %$phash;
180 return 0 unless $self->{Fixups};
181 my $subFixup;
182 foreach $subFixup (@{$self->{Fixups}}) {
183 return 1 if $subFixup->HasMarker($marker);
184 }
185 return 0;
186}
187
188#------------------------------------------------------------------------------
189# Set all marker pointers to specified value
190# Inputs: 0) Fixup object reference, 1) data reference
191# 2) marker name, 3) pointer value, 4) offset to start of data
192sub SetMarkerPointers($$$$;$)
193{
194 my ($self, $dataPt, $marker, $value, $startOffset) = @_;
195 my $start = $self->{Start} + ($startOffset || 0);
196 my $phash = $self->{Pointers};
197
198 if ($phash) {
199 my $saveOrder = GetByteOrder(); # save original byte ordering
200 my ($byteOrder, $ptr);
201 foreach $byteOrder (keys %$phash) {
202 next unless $byteOrder =~ /^(II|MM)(2?)_$marker$/;
203 SetByteOrder($1);
204 my $set = $2 ? \&Set16u : \&Set32u;
205 foreach $ptr (@{$phash->{$byteOrder}}) {
206 &$set($value, $dataPt, $ptr + $start);
207 }
208 }
209 SetByteOrder($saveOrder); # restore original byte ordering
210 }
211 if ($self->{Fixups}) {
212 my $subFixup;
213 foreach $subFixup (@{$self->{Fixups}}) {
214 $subFixup->SetMarkerPointers($dataPt, $marker, $value, $start);
215 }
216 }
217}
218
219#------------------------------------------------------------------------------
220# Get pointer values for specified marker
221# Inputs: 0) Fixup object reference, 1) data reference,
222# 2) marker name, 3) offset to start of data
223# Returns: List of marker pointers in list context, or first marker pointer otherwise
224sub GetMarkerPointers($$$;$)
225{
226 my ($self, $dataPt, $marker, $startOffset) = @_;
227 my $start = $self->{Start} + ($startOffset || 0);
228 my $phash = $self->{Pointers};
229 my @pointers;
230
231 if ($phash) {
232 my $saveOrder = GetByteOrder();
233 my ($byteOrder, $ptr);
234 foreach $byteOrder (grep /_$marker$/, keys %$phash) {
235 SetByteOrder(substr($byteOrder,0,2));
236 my $get = ($byteOrder =~ /^(II2|MM2)/) ? \&Get16u : \&Get32u;
237 foreach $ptr (@{$phash->{$byteOrder}}) {
238 push @pointers, &$get($dataPt, $ptr + $start);
239 }
240 }
241 SetByteOrder($saveOrder); # restore original byte ordering
242 }
243 if ($self->{Fixups}) {
244 my $subFixup;
245 foreach $subFixup (@{$self->{Fixups}}) {
246 push @pointers, $subFixup->GetMarkerPointers($dataPt, $marker, $start);
247 }
248 }
249 return @pointers if wantarray;
250 return $pointers[0];
251}
252
253#------------------------------------------------------------------------------
254# Dump fixup to console for debugging
255# Inputs: 0) Fixup object reference, 1) optional initial indent string
256sub Dump($;$)
257{
258 my ($self, $indent) = @_;
259 $indent or $indent = '';
260 printf "${indent}Fixup start=0x%x shift=0x%x\n", $self->{Start}, $self->{Shift};
261 my $phash = $self->{Pointers};
262 if ($phash) {
263 my $byteOrder;
264 foreach $byteOrder (sort keys %$phash) {
265 print "$indent $byteOrder: ", join(' ',@{$phash->{$byteOrder}}),"\n";
266 }
267 }
268 if ($self->{Fixups}) {
269 my $subFixup;
270 foreach $subFixup (@{$self->{Fixups}}) {
271 Dump($subFixup, $indent . ' ');
272 }
273 }
274}
275
276
2771; # end
278
279__END__
280
281=head1 NAME
282
283Image::ExifTool::Fixup - Utility to handle pointer fixups
284
285=head1 SYNOPSIS
286
287 use Image::ExifTool::Fixup;
288
289 $fixup = new Image::ExifTool::Fixup;
290
291 # add a new fixup to a pointer at the specified offset in data
292 $fixup->AddFixup($offset);
293
294 # add a new Fixup object to the tree
295 $fixup->AddFixup($subFixup);
296
297 $fixup->{Start} += $shift1; # shift pointer offsets and values
298
299 $fixup->{Shift} += $shift2; # shift pointer values only
300
301 # recursively apply fixups to the specified data
302 $fixup->ApplyFixups(\$data);
303
304 $fixup->Dump(); # dump debugging information
305
306=head1 DESCRIPTION
307
308This module contains the code to keep track of pointers in memory and to
309shift these pointers as required. It is used by ExifTool to maintain the
310pointers in image file directories (IFD's).
311
312=head1 NOTES
313
314Keeps track of pointers with different byte ordering, and relies on
315Image::ExifTool::GetByteOrder() to determine the current byte ordering
316when adding new pointers to a fixup.
317
318Maintains a hierarchical list of fixups so that the whole hierarchy can
319be shifted by a simple shift at the base. Hierarchy is collapsed to a
320linear list when ApplyFixups() is called.
321
322=head1 AUTHOR
323
324Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
325
326This library is free software; you can redistribute it and/or modify it
327under the same terms as Perl itself.
328
329=head1 SEE ALSO
330
331L<Image::ExifTool(3pm)|Image::ExifTool>
332
333=cut
Note: See TracBrowser for help on using the repository browser.