File Coverage

blib/lib/Image/ExifTool/WriteExif.pl
Criterion Covered Total %
statement 1008 1449 69.5
branch 579 998 58.0
condition 398 778 51.1
subroutine 11 18 61.1
pod 0 15 0.0
total 1996 3258 61.2


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: WriteExif.pl
3             #
4             # Description: Write EXIF meta information
5             #
6             # Revisions: 12/13/2004 - P. Harvey Created
7             #------------------------------------------------------------------------------
8              
9             package Image::ExifTool::Exif;
10              
11 41     41   356 use strict;
  41         125  
  41         1896  
12 41         3569 use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber
13 41     41   308 %compression %photometricInterpretation %orientation);
  41         110  
14              
15 41     41   310 use Image::ExifTool::Fixup;
  41         133  
  41         847118  
16              
17             # some information may be stored in different IFD's with the same meaning.
18             # Use this lookup to decide when we should delete information that is stored
19             # in another IFD when we write it to the preferred IFD.
20             my %crossDelete = (
21             ExifIFD => 'IFD0',
22             IFD0 => 'ExifIFD',
23             );
24              
25             # mandatory tag default values
26             my %mandatory = (
27             IFD0 => {
28             0x011a => 72, # XResolution
29             0x011b => 72, # YResolution
30             0x0128 => 2, # ResolutionUnit (inches)
31             0x0213 => 1, # YCbCrPositioning (centered)
32             # 0x8769 => ????, # ExifOffset
33             },
34             IFD1 => {
35             0x0103 => 6, # Compression (JPEG)
36             0x011a => 72, # XResolution
37             0x011b => 72, # YResolution
38             0x0128 => 2, # ResolutionUnit (inches)
39             },
40             ExifIFD => {
41             0x9000 => '0232', # ExifVersion
42             0x9101 => "1 2 3 0",# ComponentsConfiguration
43             0xa000 => '0100', # FlashpixVersion
44             0xa001 => 0xffff, # ColorSpace (uncalibrated)
45             # 0xa002 => ????, # ExifImageWidth
46             # 0xa003 => ????, # ExifImageHeight
47             },
48             GPS => {
49             0x0000 => '2 3 0 0',# GPSVersionID
50             },
51             InteropIFD => {
52             0x0002 => '0100', # InteropVersion
53             },
54             );
55              
56             #------------------------------------------------------------------------------
57             # Inverse print conversion for OffsetTime tags
58             # Inputs: 0) input time zone or date/time value, 1) ExifTool ref
59             # Returns: Time zone string for writing to EXIF
60             sub InverseOffsetTime($$)
61             {
62 0     0 0 0 my ($val, $et) = @_;
63 0 0       0 $val = $et->TimeNow() if lc($val) eq 'now';
64 0 0       0 return '+00:00' if $val =~ /Z$/;
65 0 0       0 return sprintf('%s%.2d:%.2d',$1,$2,$3) if $val =~ /([-+])(\d{1,2}):?(\d{2})/;
66 0         0 return undef;
67             }
68              
69             #------------------------------------------------------------------------------
70             # Inverse print conversion for LensInfo
71             # Inputs: 0) lens info string
72             # Returns: PrintConvInv of string
73             sub ConvertLensInfo($)
74             {
75 7     7 0 25 my $val = shift;
76 7         48 my @a = GetLensInfo($val, 1); # (allow unknown "?" values)
77 7 100       66 return @a ? join(' ', @a) : $val;
78             }
79              
80             #------------------------------------------------------------------------------
81             # Get binary CFA Pattern from a text string
82             # Inputs: Print-converted CFA pattern (eg. '[Blue,Green][Green,Red]')
83             # Returns: CFA pattern as a string of numbers
84             sub GetCFAPattern($)
85             {
86 1     1 0 3 my $val = shift;
87 1         10 my @rows = split /\]\s*\[/, $val;
88 1 50       6 @rows or warn("Rows not properly bracketed by '[]'\n"), return undef;
89 1         6 my @cols = split /,/, $rows[0];
90 1 50       6 @cols or warn("Colors not separated by ','\n"), return undef;
91 1         3 my $ny = @cols;
92 1         4 my @a = (scalar(@rows), scalar(@cols));
93 1         9 my %cfaLookup = (red=>0, green=>1, blue=>2, cyan=>3, magenta=>4, yellow=>5, white=>6);
94 1         2 my $row;
95 1         3 foreach $row (@rows) {
96 2         6 @cols = split /,/, $row;
97 2 50       6 @cols == $ny or warn("Inconsistent number of colors in each row\n"), return undef;
98 2         5 foreach (@cols) {
99 4         9 tr/ \]\[//d; # remove remaining brackets and any spaces
100 4         10 my $c = $cfaLookup{lc($_)};
101 4 50       10 defined $c or warn("Unknown color '${_}'\n"), return undef;
102 4         8 push @a, $c;
103             }
104             }
105 1         30 return "@a";
106             }
107              
108             #------------------------------------------------------------------------------
109             # validate raw values for writing
110             # Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) raw value ref
111             # Returns: error string or undef (and possibly changes value) on success
112             sub CheckExif($$$)
113             {
114 6353     6353 0 14541 my ($et, $tagInfo, $valPtr) = @_;
115 6353   66     29476 my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $$tagInfo{Table}{WRITABLE};
116 6353 100 66     22583 if (not $format or $format eq '1') {
117 124 50       622 if ($$tagInfo{Groups}{0} eq 'MakerNotes') {
118 124         430 return undef; # OK to have no format for makernotes
119             } else {
120 0         0 return 'No writable format';
121             }
122             }
123 6229         26751 return Image::ExifTool::CheckValue($valPtr, $format, $$tagInfo{Count});
124             }
125              
126             #------------------------------------------------------------------------------
127             # encode exif ASCII/Unicode text from UTF8 or Latin
128             # Inputs: 0) ExifTool ref, 1) text string
129             # Returns: encoded string
130             # Note: MUST be called Raw conversion time so the EXIF byte order is known!
131             sub EncodeExifText($$)
132             {
133 13     13 0 78 my ($et, $val) = @_;
134             # does the string contain special characters?
135 13 50       135 if ($val =~ /[\x80-\xff]/) {
136 0         0 my $order = $et->GetNewValue('ExifUnicodeByteOrder');
137 0         0 return "UNICODE\0" . $et->Encode($val,'UTF16',$order);
138             } else {
139 13         157 return "ASCII\0\0\0$val";
140             }
141             }
142              
143             #------------------------------------------------------------------------------
144             # rebuild maker notes to properly contain all value data
145             # (some manufacturers put value data outside maker notes!!)
146             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
147             # Returns: new maker note data (and creates MAKER_NOTE_FIXUP), or undef on error
148             sub RebuildMakerNotes($$$)
149             {
150 23     23 0 136 my ($et, $dirInfo, $tagTablePtr) = @_;
151 23         99 my $dirStart = $$dirInfo{DirStart};
152 23         74 my $dirLen = $$dirInfo{DirLen};
153 23         84 my $dataPt = $$dirInfo{DataPt};
154 23   100     159 my $dataPos = $$dirInfo{DataPos} || 0;
155 23         64 my $rtnValue;
156 23         204 my %subdirInfo = %$dirInfo;
157              
158 23         101 delete $$et{MAKER_NOTE_FIXUP};
159              
160             # don't need to rebuild text, BinaryData or PreviewImage maker notes
161 23         77 my $tagInfo = $$dirInfo{TagInfo};
162 23         80 my $subdir = $$tagInfo{SubDirectory};
163 23   100     215 my $proc = $$subdir{ProcessProc} || $$tagTablePtr{PROCESS_PROC} || \&ProcessExif;
164 23 0 66     479 if (($proc ne \&ProcessExif and $$tagInfo{Name} =~ /Text/) or
      33        
      33        
      33        
      33        
165             $proc eq \&Image::ExifTool::ProcessBinaryData or
166             ($$tagInfo{PossiblePreview} and $dirLen > 6 and
167             substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff"))
168             {
169 0         0 return substr($$dataPt, $dirStart, $dirLen);
170             }
171 23         115 my $saveOrder = GetByteOrder();
172 23         169 my $loc = Image::ExifTool::MakerNotes::LocateIFD($et,\%subdirInfo);
173 23 50       127 if (defined $loc) {
174 23         315 my $makerFixup = $subdirInfo{Fixup} = new Image::ExifTool::Fixup;
175             # create new exiftool object to rewrite the directory without changing it
176 23         174 my $newTool = new Image::ExifTool;
177             $newTool->Options(
178             IgnoreMinorErrors => $$et{OPTIONS}{IgnoreMinorErrors},
179             FixBase => $$et{OPTIONS}{FixBase},
180 23         200 );
181 23         235 $newTool->Init(); # must do this before calling WriteDirectory()!
182             # don't copy over preview image
183 23         199 $newTool->SetNewValue(PreviewImage => '');
184             # copy all transient members over in case they are used for writing
185             # (Make, Model, etc)
186 23         902 foreach (grep /[a-z]/, keys %$et) {
187 232         587 $$newTool{$_} = $$et{$_};
188             }
189             # fix base offsets if specified
190 23         218 $newTool->Options(FixBase => $et->Options('FixBase'));
191             # set GENERATE_PREVIEW_INFO flag so PREVIEW_INFO will be generated
192 23         127 $$newTool{GENERATE_PREVIEW_INFO} = 1;
193             # drop any large tags
194 23         88 $$newTool{DropTags} = 1;
195             # initialize other necessary data members
196 23         106 $$newTool{FILE_TYPE} = $$et{FILE_TYPE};
197 23         93 $$newTool{TIFF_TYPE} = $$et{TIFF_TYPE};
198             # rewrite maker notes
199 23         191 $rtnValue = $newTool->WriteDirectory(\%subdirInfo, $tagTablePtr);
200 23 50 33     248 if (defined $rtnValue and length $rtnValue) {
201             # add the dummy/empty preview image if necessary
202 23 100       129 if ($$newTool{PREVIEW_INFO}) {
203 2         21 $makerFixup->SetMarkerPointers(\$rtnValue, 'PreviewImage', length($rtnValue));
204 2         18 $rtnValue .= $$newTool{PREVIEW_INFO}{Data};
205 2         11 delete $$newTool{PREVIEW_INFO};
206             }
207             # add makernote header
208 23 100       117 if ($loc) {
209 9         43 my $hdr = substr($$dataPt, $dirStart, $loc);
210             # special case: convert Pentax/Samsung DNG maker notes to JPEG style
211             # (in JPEG, Pentax makernotes are absolute and start with "AOC\0" for some
212             # models, but in DNG images they are stored in tag 0xc634 of IFD0 and
213             # start with either "PENTAX \0" or "SAMSUNG\0")
214 9 50 33     69 if ($$dirInfo{Parent} eq 'IFD0' and $hdr =~ /^(PENTAX |SAMSUNG)\0/) {
215             # convert to JPEG-style AOC maker notes if used by this model
216             # (Note: this expression also appears in Exif.pm)
217 0 0       0 if ($$et{Model} =~ /\b(K(-[57mrx]|(10|20|100|110|200)D|2000)|GX(10|20))\b/) {
218 0         0 $hdr =~ s/^(PENTAX |SAMSUNG)\0/AOC\0/;
219             # save fixup because AOC maker notes have absolute offsets
220 0         0 $$et{MAKER_NOTE_FIXUP} = $makerFixup;
221             }
222             }
223 9         52 $rtnValue = $hdr . $rtnValue;
224             # adjust fixup for shift in start position
225 9         48 $$makerFixup{Start} += length $hdr;
226             }
227             # shift offsets according to original position of maker notes,
228             # and relative to the makernotes Base
229             $$makerFixup{Shift} += $dataPos + $dirStart +
230 23         129 $$dirInfo{Base} - $subdirInfo{Base};
231             # repair incorrect offsets if offsets were fixed
232 23   50     156 $$makerFixup{Shift} += $subdirInfo{FixedBy} || 0;
233             # fix up pointers to the specified offset
234 23         162 $makerFixup->ApplyFixup(\$rtnValue);
235             # save fixup information unless offsets were relative
236 23 100       311 unless ($subdirInfo{Relative}) {
237             # set shift so offsets are all relative to start of maker notes
238 19         75 $$makerFixup{Shift} -= $dataPos + $dirStart;
239 19         417 $$et{MAKER_NOTE_FIXUP} = $makerFixup; # save fixup for later
240             }
241             }
242             }
243 23         170 SetByteOrder($saveOrder);
244              
245 23         401 return $rtnValue;
246             }
247              
248             #------------------------------------------------------------------------------
249             # Sort IFD directory entries
250             # Inputs: 0) data reference, 1) directory start, 2) number of entries,
251             # 3) flag to treat 0 as a valid tag ID (as opposed to an empty IFD entry)
252             sub SortIFD($$$;$)
253             {
254 0     0 0 0 my ($dataPt, $dirStart, $numEntries, $allowZero) = @_;
255 0         0 my ($index, %entries);
256             # split the directory into separate entries
257 0         0 for ($index=0; $index<$numEntries; ++$index) {
258 0         0 my $entry = $dirStart + 2 + 12 * $index;
259 0         0 my $tagID = Get16u($dataPt, $entry);
260 0         0 my $entryData = substr($$dataPt, $entry, 12);
261             # silly software can pad directories with zero entries -- put these at the end
262 0 0 0     0 $tagID = 0x10000 unless $tagID or $index == 0 or $allowZero;
      0        
263             # add new entry (allow for duplicate tag ID's, which shouldn't normally happen)
264 0 0       0 if ($entries{$tagID}) {
265 0         0 $entries{$tagID} .= $entryData;
266             } else {
267 0         0 $entries{$tagID} = $entryData;
268             }
269             }
270             # sort the directory entries
271 0         0 my @sortedTags = sort { $a <=> $b } keys %entries;
  0         0  
272             # generate the sorted IFD
273 0         0 my $newDir = '';
274 0         0 foreach (@sortedTags) {
275 0         0 $newDir .= $entries{$_};
276             }
277             # replace original directory with new, sorted one
278 0         0 substr($$dataPt, $dirStart + 2, 12 * $numEntries) = $newDir;
279             }
280              
281             #------------------------------------------------------------------------------
282             # Validate IFD entries (strict validation to test possible chained IFD's)
283             # Inputs: 0) dirInfo ref (must have RAF set), 1) optional DirStart
284             # Returns: true if IFD looks OK
285             sub ValidateIFD($;$)
286             {
287 0     0 0 0 my ($dirInfo, $dirStart) = @_;
288 0 0       0 my $raf = $$dirInfo{RAF} or return 0;
289 0         0 my $base = $$dirInfo{Base};
290 0 0 0     0 $dirStart = $$dirInfo{DirStart} || 0 unless defined $dirStart;
291 0   0     0 my $offset = $dirStart + ($$dirInfo{DataPos} || 0);
292 0         0 my ($buff, $index);
293 0 0 0     0 $raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2 or return 0;
294 0         0 my $numEntries = Get16u(\$buff,0);
295 0 0 0     0 $numEntries > 1 and $numEntries < 64 or return 0;
296 0         0 my $len = 12 * $numEntries;
297 0 0       0 $raf->Read($buff, $len) == $len or return 0;
298 0         0 my $lastID = -1;
299 0         0 for ($index=0; $index<$numEntries; ++$index) {
300 0         0 my $entry = 12 * $index;
301 0         0 my $tagID = Get16u(\$buff, $entry);
302 0 0 0     0 $tagID > $lastID or $$dirInfo{AllowOutOfOrderTags} or return 0;
303 0         0 my $format = Get16u(\$buff, $entry+2);
304 0 0 0     0 $format > 0 and $format <= 13 or return 0;
305 0         0 my $count = Get32u(\$buff, $entry+4);
306 0 0       0 $count > 0 or return 0;
307 0         0 $lastID = $tagID;
308             }
309 0         0 return 1;
310             }
311              
312             #------------------------------------------------------------------------------
313             # Get sorted list of offsets used in IFD
314             # Inputs: 0) data ref, 1) directory start, 2) dataPos, 3) IFD entries, 4) tag table ref
315             # Returns: 0) sorted list of offsets (only offsets after the end of the IFD)
316             # 1) hash of list indices keyed by offset value
317             # Notes: This is used in a patch to fix the count for tags in Kodak SubIFD3
318             sub GetOffList($$$$$)
319             {
320 0     0 0 0 my ($dataPt, $dirStart, $dataPos, $numEntries, $tagTablePtr) = @_;
321 0         0 my $ifdEnd = $dirStart + 2 + 12 * $numEntries + $dataPos;
322 0         0 my ($index, $offset, %offHash);
323 0         0 for ($index=0; $index<$numEntries; ++$index) {
324 0         0 my $entry = $dirStart + 2 + 12 * $index;
325 0         0 my $format = Get16u($dataPt, $entry + 2);
326 0 0 0     0 next if $format < 1 or $format > 13;
327 0         0 my $count = Get16u($dataPt, $entry + 4);
328 0         0 my $size = $formatSize[$format] * $count;
329 0 0       0 if ($size <= 4) {
330 0         0 my $tagID = Get16u($dataPt, $entry);
331 0 0 0     0 next unless ref $$tagTablePtr{$tagID} eq 'HASH' and $$tagTablePtr{$tagID}{FixCount};
332             }
333 0         0 my $offset = Get16u($dataPt, $entry + 8);
334 0 0       0 $offHash{$offset} = 1 if $offset >= $ifdEnd;
335             }
336             # set offset hash values to indices in list
337 0         0 my @offList = sort keys %offHash;
338 0         0 $index = 0;
339 0         0 foreach $offset (@offList) {
340 0         0 $offHash{$offset} = $index++;
341             }
342 0         0 return(\@offList, \%offHash);
343             }
344              
345             #------------------------------------------------------------------------------
346             # Update TIFF_END member if defined
347             # Inputs: 0) ExifTool ref, 1) end of valid TIFF data
348             sub UpdateTiffEnd($$)
349             {
350 332     332 0 746 my ($et, $end) = @_;
351 332 100 100     1627 if (defined $$et{TIFF_END} and
352             $$et{TIFF_END} < $end)
353             {
354 278         668 $$et{TIFF_END} = $end;
355             }
356             }
357              
358             #------------------------------------------------------------------------------
359             # Validate image data size
360             # Inputs: 0) ExifTool ref, 1) validate info hash ref,
361             # 2) flag to issue error (ie. we're writing)
362             # - issues warning or error if problems found
363             sub ValidateImageData($$$;$)
364             {
365 85     85 0 199 local $_;
366 85         310 my ($et, $vInfo, $dirName, $errFlag) = @_;
367              
368             # determine the expected size of the image data for an uncompressed image
369             # (0x102 BitsPerSample, 0x103 Compression and 0x115 SamplesPerPixel
370             # all default to a value of 1 if they don't exist)
371 85 100 100     796 if ((not defined $$vInfo{0x103} or $$vInfo{0x103} eq '1') and
      100        
      66        
      66        
      66        
372             $$vInfo{0x100} and $$vInfo{0x101} and ($$vInfo{0x117} or $$vInfo{0x145}))
373             {
374 5   100     24 my $samplesPerPix = $$vInfo{0x115} || 1;
375 5 50       34 my @bitsPerSample = $$vInfo{0x102} ? split(' ',$$vInfo{0x102}) : (1) x $samplesPerPix;
376 5   33     24 my $byteCountInfo = $$vInfo{0x117} || $$vInfo{0x145};
377 5         15 my $byteCounts = $$byteCountInfo[1];
378 5         11 my $totalBytes = 0;
379 5         31 $totalBytes += $_ foreach split ' ', $byteCounts;
380 5         12 my $minor;
381 5 50 33     93 $minor = 1 if $$et{DOC_NUM} or $$et{FILE_TYPE} ne 'TIFF';
382 5 50       24 unless (@bitsPerSample == $samplesPerPix) {
383 0 0 0     0 unless ($$et{FILE_TYPE} eq 'EPS' and @bitsPerSample == 1) {
384             # (just a warning for this problem)
385 0 0       0 my $s = $samplesPerPix eq '1' ? '' : 's';
386 0         0 $et->Warn("$dirName BitsPerSample should have $samplesPerPix value$s", $minor);
387             }
388 0         0 push @bitsPerSample, $bitsPerSample[0] while @bitsPerSample < $samplesPerPix;
389 0         0 foreach (@bitsPerSample) {
390 0 0       0 $et->WarnOnce("$dirName BitsPerSample values are different", $minor) if $_ ne $bitsPerSample[0];
391 0 0 0     0 $et->WarnOnce("Invalid $dirName BitsPerSample value", $minor) if $_ < 1 or $_ > 32;
392             }
393             }
394 5         30 my $bitsPerPixel = 0;
395 5         27 $bitsPerPixel += $_ foreach @bitsPerSample;
396 5         41 my $expectedBytes = int(($$vInfo{0x100} * $$vInfo{0x101} * $bitsPerPixel + 7) / 8);
397 5 100 66     36 if ($expectedBytes != $totalBytes and
398             # (this problem seems normal for certain types of RAW files...)
399             $$et{TIFF_TYPE} !~ /^(K25|KDC|MEF|ORF|SRF)$/)
400             {
401 1         4 my ($adj, $minor);
402 1 50       6 if ($expectedBytes > $totalBytes) {
403 1         4 $adj = 'Under'; # undersized is a bigger problem because we may lose data
404 1 50       4 $minor = 0 unless $errFlag;
405             } else {
406 0         0 $adj = 'Over';
407 0         0 $minor = 1;
408             }
409 1         10 my $msg = "${adj}sized $dirName $$byteCountInfo[0]{Name} ($totalBytes bytes, but expected $expectedBytes)";
410 1 50       5 if (not defined $minor) {
411             # this is a serious error if we are writing the file and there
412             # is a chance that we may not copy all of the image data
413             # (but make it minor to allow the file to be written anyway)
414 1         8 $et->Error($msg, 1);
415             } else {
416 0         0 $et->Warn($msg, $minor);
417             }
418             }
419             }
420             }
421              
422             #------------------------------------------------------------------------------
423             # Add specified image data to ImageDataMD5 hash
424             # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) lookup for [tagInfo,value] based on tagID
425             sub AddImageDataMD5($$$)
426             {
427 0     0 0 0 my ($et, $dirInfo, $offsetInfo) = @_;
428 0         0 my ($tagID, $offset, $buff);
429              
430 0         0 my $verbose = $et->Options('Verbose');
431 0         0 my $md5 = $$et{ImageDataMD5};
432 0         0 my $raf = $$dirInfo{RAF};
433              
434 0         0 foreach $tagID (sort keys %$offsetInfo) {
435 0 0       0 next unless ref $$offsetInfo{$tagID} eq 'ARRAY'; # ignore scalar tag values used for Validate
436 0         0 my $tagInfo = $$offsetInfo{$tagID}[0];
437 0 0       0 next unless $$tagInfo{IsImageData}; # only consider image data
438 0         0 my $sizeID = $$tagInfo{OffsetPair};
439 0         0 my @sizes;
440 0 0 0     0 if ($$tagInfo{NotRealPair}) {
    0          
441 0         0 @sizes = 999999999; # (Panasonic hack: raw data runs to end of file)
442             } elsif ($sizeID and $$offsetInfo{$sizeID}) {
443 0         0 @sizes = split ' ', $$offsetInfo{$sizeID}[1];
444             } else {
445 0         0 next;
446             }
447 0         0 my @offsets = split ' ', $$offsetInfo{$tagID}[1];
448 0 0       0 $sizes[0] = 999999999 if $$tagInfo{NotRealPair};
449 0         0 my $total = 0;
450 0         0 foreach $offset (@offsets) {
451 0         0 my $size = shift @sizes;
452 0 0 0     0 next unless $offset =~ /^\d+$/ and $size and $size =~ /^\d+$/ and $size;
      0        
      0        
453 0 0       0 next unless $raf->Seek($offset, 0); # (offset is absolute)
454 0         0 $total += $et->ImageDataMD5($raf, $size);
455             }
456 0 0       0 if ($verbose) {
457 0         0 my $name = "$$dirInfo{DirName}:$$tagInfo{Name}";
458 0         0 $name =~ s/Offsets?|Start$//;
459 0         0 $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $total bytes of $name data)\n");
460             }
461             }
462             }
463              
464             #------------------------------------------------------------------------------
465             # Handle error while writing EXIF
466             # Inputs: 0) ExifTool ref, 1) error string, 2) tag table ref
467             # Returns: undef on fatal error, or '' if minor error is ignored
468             sub ExifErr($$$)
469             {
470 0     0 0 0 my ($et, $errStr, $tagTablePtr) = @_;
471             # MakerNote errors are minor by default
472 0   0     0 my $minor = ($$tagTablePtr{GROUPS}{0} eq 'MakerNotes' or $$et{FILE_TYPE} eq 'MOV');
473 0 0 0     0 if ($$tagTablePtr{VARS} and $$tagTablePtr{VARS}{MINOR_ERRORS}) {
474 0 0 0     0 $et->Warn("$errStr. IFD dropped.") and return '' if $minor;
475 0         0 $minor = 1;
476             }
477 0 0       0 return undef if $et->Error($errStr, $minor);
478 0         0 return '';
479             }
480              
481             #------------------------------------------------------------------------------
482             # Read/Write IFD with TIFF-like header (used by DNG 1.2)
483             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
484             # Returns: Reading: 1 on success, otherwise returns 0 and sets a Warning
485             # Writing: new data block or undef on error
486             sub ProcessTiffIFD($$$)
487             {
488 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
489 0 0       0 $et or return 1; # allow dummy access
490 0         0 my $raf = $$dirInfo{RAF};
491 0   0     0 my $base = $$dirInfo{Base} || 0;
492 0         0 my $dirName = $$dirInfo{DirName};
493 0   0     0 my $magic = $$dirInfo{Subdir}{Magic} || 0x002a;
494 0         0 my $buff;
495              
496             # structured with a TIFF-like header and relative offsets
497 0 0 0     0 $raf->Seek($base, 0) and $raf->Read($buff, 8) == 8 or return 0;
498 0 0 0     0 unless (SetByteOrder(substr($buff,0,2)) and Get16u(\$buff, 2) == $magic) {
499 0         0 my $msg = "Invalid $dirName header";
500 0 0       0 if ($$dirInfo{IsWriting}) {
501 0         0 $et->Error($msg);
502 0         0 return undef;
503             } else {
504 0         0 $et->Warn($msg);
505 0         0 return 0;
506             }
507             }
508 0         0 my $offset = Get32u(\$buff, 4);
509             my %dirInfo = (
510             DirName => $$dirInfo{DirName},
511             Parent => $$dirInfo{Parent},
512 0         0 Base => $base,
513             DataPt => \$buff,
514             DataLen => length $buff,
515             DataPos => 0,
516             DirStart => $offset,
517             DirLen => length($buff) - $offset,
518             RAF => $raf,
519             NewDataPos => 8,
520             );
521 0 0       0 if ($$dirInfo{IsWriting}) {
522             # rewrite the Camera Profile IFD
523 0         0 my $newDir = WriteExif($et, \%dirInfo, $tagTablePtr);
524             # don't add header if error writing directory ($newDir is undef)
525             # or if directory is being deleted ($newDir is empty)
526 0 0       0 return $newDir unless $newDir;
527             # return directory with TIFF-like header
528 0         0 return GetByteOrder() . Set16u($magic) . Set32u(8) . $newDir;
529             }
530 0 0       0 if ($$et{HTML_DUMP}) {
531 0 0       0 my $tip = sprintf("Byte order: %s endian\nIdentifier: 0x%.4x\n%s offset: 0x%.4x",
532             (GetByteOrder() eq 'II') ? 'Little' : 'Big', $magic, $dirName, $offset);
533 0         0 $et->HDump($base, 8, "$dirName header", $tip, 0);
534             }
535 0         0 return ProcessExif($et, \%dirInfo, $tagTablePtr);
536             }
537              
538             #------------------------------------------------------------------------------
539             # Write EXIF directory
540             # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
541             # Returns: Exif data block (may be empty if no Exif data) or undef on error
542             # Notes: Increments ExifTool CHANGED flag for each tag changed. Also updates
543             # TIFF_END if defined with location of end of original TIFF image.
544             # Returns IFD data in the following order:
545             # 1. IFD0 directory followed by its data
546             # 2. SubIFD directory followed by its data, thumbnail and image
547             # 3. GlobalParameters, EXIF, GPS, Interop IFD's each with their data
548             # 4. IFD1,IFD2,... directories each followed by their data
549             # 5. Thumbnail and/or image data for each IFD, with IFD0 image last
550             sub WriteExif($$$)
551             {
552 8553     8553 0 17668 my ($et, $dirInfo, $tagTablePtr) = @_;
553 8553 100       33856 $et or return 1; # allow dummy access to autoload this package
554 331         1395 my $origDirInfo = $dirInfo; # save original dirInfo
555 331         848 my $dataPt = $$dirInfo{DataPt};
556 331 100       1088 unless ($dataPt) {
557 34         157 my $emptyData = '';
558 34         144 $dataPt = \$emptyData;
559             }
560 331   100     1545 my $dataPos = $$dirInfo{DataPos} || 0;
561 331   100     1189 my $dirStart = $$dirInfo{DirStart} || 0;
562 331   66     1216 my $dataLen = $$dirInfo{DataLen} || length($$dataPt);
563 331   100     1974 my $dirLen = $$dirInfo{DirLen} || ($dataLen - $dirStart);
564 331   100     1163 my $base = $$dirInfo{Base} || 0;
565 331         636 my $firstBase = $base;
566 331         668 my $raf = $$dirInfo{RAF};
567 331   50     1147 my $dirName = $$dirInfo{DirName} || 'unknown';
568 331   66     3330 my $fixup = $$dirInfo{Fixup} || new Image::ExifTool::Fixup;
569 331   100     1558 my $imageDataFlag = $$dirInfo{ImageData} || '';
570 331         1370 my $verbose = $et->Options('Verbose');
571 331         1248 my $out = $et->Options('TextOut');
572 331         1437 my ($nextIfdPos, %offsetData, $inMakerNotes);
573 331         0 my (@offsetInfo, %validateInfo, %xDelete, $strEnc);
574 331         655 my $deleteAll = 0;
575 331         671 my $newData = ''; # initialize buffer to receive new directory data
576 331         634 my @imageData; # image data blocks to copy later if requested
577 331         744 my $name = $$dirInfo{Name};
578 331 100 100     5336 $name = $dirName unless $name and $dirName eq 'MakerNotes' and $name !~ /^MakerNote/;
      100        
579              
580             # save byte order of existing EXIF
581 331 100 100     2064 $$et{SaveExifByteOrder} = GetByteOrder() if $dirName eq 'IFD0' or $dirName eq 'ExifIFD';
582              
583             # set encoding for strings
584 331 100       1780 $strEnc = $et->Options('CharsetEXIF') if $$tagTablePtr{GROUPS}{0} eq 'EXIF';
585              
586             # allow multiple IFD's in IFD0-IFD1-IFD2... chain
587 331 100 66     2908 $$dirInfo{Multi} = 1 if $dirName =~ /^(IFD0|SubIFD)$/ and not defined $$dirInfo{Multi};
588 331 100       1220 $inMakerNotes = 1 if $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
589 331         628 my $ifd;
590              
591             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
592             # loop through each IFD
593             #
594 331         816 for ($ifd=0; ; ++$ifd) { # loop through multiple IFD's
595              
596             # make sure that Compression and SubfileType are defined for this IFD (for Condition's)
597 379         1193 $$et{Compression} = $$et{SubfileType} = '';
598              
599             # save pointer to start of this IFD within the newData
600 379         867 my $newStart = length($newData);
601 379         790 my @subdirs; # list of subdirectory data and tag table pointers
602             # determine if directory is contained within our data
603             my $mustRead;
604 379 100 66     2371 if ($dirStart < 0 or $dirStart > $dataLen-2) {
    50          
605 118         279 $mustRead = 1;
606             } elsif ($dirLen >= 2) {
607 261         973 my $len = 2 + 12 * Get16u($dataPt, $dirStart);
608 261 50       1080 $mustRead = 1 if $dirStart + $len > $dataLen;
609             }
610             # read IFD from file if necessary
611 379 100       1051 if ($mustRead) {
612 118 100 33     637 if ($raf) {
    50          
613             # read the count of entries in this IFD
614 38         102 my $offset = $dirStart + $dataPos;
615 38         84 my ($buff, $buf2);
616 38 50 33     180 unless ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) {
617 0         0 return ExifErr($et, "Bad IFD or truncated file in $name", $tagTablePtr);
618             }
619 38         276 my $len = 12 * Get16u(\$buff,0);
620             # (also read next IFD pointer if available)
621 38 50       183 unless ($raf->Read($buf2, $len+4) >= $len) {
622 0         0 return ExifErr($et, "Error reading $name", $tagTablePtr);
623             }
624 38         126 $buff .= $buf2;
625             # make copy of dirInfo since we're going to modify it
626 38         499 my %newDirInfo = %$dirInfo;
627 38         152 $dirInfo = \%newDirInfo;
628             # update directory parameters for the newly loaded IFD
629 38         127 $dataPt = $$dirInfo{DataPt} = \$buff;
630 38         96 $dirStart = $$dirInfo{DirStart} = 0;
631 38         98 $dataPos = $$dirInfo{DataPos} = $offset;
632 38         90 $dataLen = $$dirInfo{DataLen} = length $buff;
633 38         91 $dirLen = $$dirInfo{DirLen} = $dataLen;
634             # only account for nextIFD pointer if we are going to use it
635 38 50 66     365 $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/);
      66        
636 38         182 UpdateTiffEnd($et, $offset+$base+2+$len);
637             } elsif ($dirLen and $dirStart + 4 >= $dataLen) {
638             # error if we can't load IFD (unless we are creating
639             # from scratch, in which case dirLen will be zero)
640 0 0       0 my $str = $et->Options('IgnoreMinorErrors') ? 'Deleted bad' : 'Bad';
641 0         0 $et->Error("$str $name directory", 1);
642             }
643             }
644 379         966 my ($index, $dirEnd, $numEntries, %hasOldID, $unsorted);
645 379 100       1223 if ($dirStart + 4 < $dataLen) {
646 292         838 $numEntries = Get16u($dataPt, $dirStart);
647 292         795 $dirEnd = $dirStart + 2 + 12 * $numEntries;
648 292 50       910 if ($dirEnd > $dataLen) {
649 0         0 my $n = int(($dataLen - $dirStart - 2) / 12);
650 0         0 my $rtn = ExifErr($et, "Truncated $name directory", $tagTablePtr);
651 0 0 0     0 return undef unless $n and defined $rtn;
652 0         0 $numEntries = $n; # continue processing the entries we have
653             }
654             # create lookup for existing tag ID's and determine if directory is sorted
655 292         590 my $lastID = -1;
656 292         969 for ($index=0; $index<$numEntries; ++$index) {
657 4746         9675 my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index);
658 4746         13541 $hasOldID{$tagID} = 1;
659             # check for proper sequence (but ignore null entries at end)
660 4746 100 100     9035 $unsorted = 1 if $tagID < $lastID and ($tagID or $$tagTablePtr{0});
      100        
661 4746         9175 $lastID = $tagID;
662             }
663             # sort entries if out-of-order (but not in maker notes IFDs or RAW files)
664 292 50 33     1386 if ($unsorted and not ($inMakerNotes or $et->IsRawType())) {
      66        
665 0         0 SortIFD($dataPt, $dirStart, $numEntries, $$tagTablePtr{0});
666 0         0 $et->Warn("Entries in $name were out of sequence. Fixed.",1);
667 0         0 $unsorted = 0;
668             }
669             } else {
670 87         177 $numEntries = 0;
671 87         219 $dirEnd = $dirStart;
672             }
673              
674             # loop through new values and accumulate all information for this IFD
675 379         933 my (%set, %mayDelete, $tagInfo, %hasNewID);
676 379         1171 my $wrongDir = $crossDelete{$dirName};
677 379         1722 my @newTagInfo = $et->GetNewTagInfoList($tagTablePtr);
678 379         1204 foreach $tagInfo (@newTagInfo) {
679 2042         4281 my $tagID = $$tagInfo{TagID};
680 2042         3958 $hasNewID{$tagID} = 1;
681             # must evaluate Condition later when we have all DataMember's available
682 2042 100 100     7889 $set{$tagID} = (ref $$tagTablePtr{$tagID} eq 'ARRAY' or $$tagInfo{Condition}) ? '' : $tagInfo;
683             }
684              
685             # fix base offsets (some cameras incorrectly write maker notes in IFD0)
686 379 100 100     3209 if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} =~ /^(ExifIFD|IFD0)$/ and
      66        
      66        
      66        
687             $$et{TIFF_TYPE} !~ /^(ARW|SR2)$/ and not $$et{LeicaTrailerPos} and
688             Image::ExifTool::MakerNotes::FixBase($et, $dirInfo))
689             {
690             # update local variables from fixed values
691 2         6 $base = $$dirInfo{Base};
692 2         18 $dataPos = $$dirInfo{DataPos};
693             # changed if ForceWrite tag was was set to "FixBase"
694 2 50       9 ++$$et{CHANGED} if $$et{FORCE_WRITE}{FixBase};
695 2 0 33     14 if ($$et{TIFF_TYPE} eq 'SRW' and $$et{Make} eq 'SAMSUNG' and $$et{Model} eq 'EK-GN120') {
      33        
696 0         0 $et->Error("EK-GN120 SRW files are too buggy to write");
697             }
698             }
699              
700             # initialize variables to handle mandatory tags
701 379         1203 my $mandatory = $mandatory{$dirName};
702 379         871 my ($allMandatory, $addMandatory);
703 379 100       1095 if ($mandatory) {
704             # use X/Y resolution values from JFIF if available
705 293 100 100     1397 if ($dirName eq 'IFD0' and defined $$et{JFIFYResolution}) {
706 6         57 my %ifd0Vals = %$mandatory;
707 6         23 $ifd0Vals{0x011a} = $$et{JFIFXResolution};
708 6         27 $ifd0Vals{0x011b} = $$et{JFIFYResolution};
709 6         18 $ifd0Vals{0x0128} = $$et{JFIFResolutionUnit} + 1;
710 6         18 $mandatory = \%ifd0Vals;
711             }
712 293         943 $allMandatory = $addMandatory = 0; # initialize to zero
713             # add mandatory tags if creating a new directory
714 293 100       843 unless ($numEntries) {
715 87         515 foreach (keys %$mandatory) {
716 321 100       1141 defined $set{$_} or $set{$_} = $$tagTablePtr{$_};
717             }
718             }
719             } else {
720 86         204 undef $deleteAll; # don't remove directory (no mandatory entries)
721             }
722 379         902 my ($addDirs, @newTags);
723 379 100       1004 if ($inMakerNotes) {
724 74         242 $addDirs = { }; # can't currently add new directories in MakerNotes
725             # allow non-permanent makernotes tags to be added
726             # (note: we may get into trouble if there are too many of these
727             # because we allow out-of-order tags in MakerNote IFD's but our
728             # logic to add new tags relies on ordered entries)
729 74         377 foreach (keys %set) {
730 41 100       136 next unless $set{$_};
731 36         111 my $perm = $set{$_}{Permanent};
732 36 50 66     179 push @newTags, $_ if defined $perm and not $perm;
733             }
734 74 50       328 @newTags = sort { $a <=> $b } @newTags if @newTags > 1;
  0         0  
735             } else {
736             # get a hash of directories we will be writing in this one
737 305         1478 $addDirs = $et->GetAddDirHash($tagTablePtr, $dirName);
738             # make a union of tags & dirs (can set whole dirs, like MakerNotes)
739 305         3041 my %allTags = ( %set, %$addDirs );
740             # make sorted list of new tags to be added
741 305         2241 @newTags = sort { $a <=> $b } keys(%allTags);
  7429         11290  
742             }
743 379         1227 my $dirBuff = ''; # buffer for directory data
744 379         822 my $valBuff = ''; # buffer for value data
745 379         718 my @valFixups; # list of fixups for offsets in valBuff
746             # fixup for offsets in dirBuff
747 379         2027 my $dirFixup = new Image::ExifTool::Fixup;
748 379         904 my $entryBasedFixup;
749 379         932 my $lastTagID = -1;
750 379         2371 my ($oldInfo, $oldFormat, $oldFormName, $oldCount, $oldSize, $oldValue, $oldImageData);
751 379         0 my ($readFormat, $readFormName, $readCount); # format for reading old value(s)
752 379         0 my ($entry, $valueDataPt, $valueDataPos, $valueDataLen, $valuePtr, $valEnd);
753 379         0 my ($offList, $offHash, $ignoreCount, $fixCount);
754 379         663 my $oldID = -1;
755 379         687 my $newID = -1;
756              
757             # patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts)
758 379 50 66     1588 if ($inMakerNotes and $$et{Model} eq 'Canon EOS 40D') {
759 0         0 my $fmt = Get16u($dataPt, $dirStart + 2 + 12 * ($numEntries - 1) + 2);
760 0 0 0     0 if ($fmt < 1 or $fmt > 13) {
761             # adjust the number of directory entries
762 0         0 --$numEntries;
763 0         0 $dirEnd -= 12;
764 0         0 $ignoreCount = 1;
765             }
766             }
767             #..............................................................................
768             # loop through entries in new directory
769             #
770 379         869 $index = 0;
771 379         767 Entry: for (;;) {
772              
773 7127 100 100     23111 if (defined $oldID and $oldID == $newID) {
774             #
775             # read next entry from existing directory
776             #
777 5125 100       10591 if ($index < $numEntries) {
778 4746         8407 $entry = $dirStart + 2 + 12 * $index;
779 4746         11049 $oldID = Get16u($dataPt, $entry);
780 4746         11375 $readFormat = $oldFormat = Get16u($dataPt, $entry+2);
781 4746         12038 $readCount = $oldCount = Get32u($dataPt, $entry+4);
782 4746         8511 undef $oldImageData;
783 4746 50 0     16070 if ($oldFormat < 1 or $oldFormat > 13 and not ($oldFormat == 16 and $$et{Make} eq 'Apple' and $inMakerNotes)) {
      33        
      33        
784 0         0 my $msg = "Bad format ($oldFormat) for $name entry $index";
785             # patch to preserve invalid directory entries in SubIFD3 of
786             # various Kodak Z-series cameras (Z812, Z1085IS, Z1275)
787             # and some Sony cameras such as the DSC-P10
788 0 0 0     0 if ($dirName eq 'MakerNotes' and (($$et{Make}=~/KODAK/i and
      0        
789             $$dirInfo{Name} and $$dirInfo{Name} eq 'SubIFD3') or
790             ($numEntries == 12 and $$et{Make} eq 'SONY' and $index >= 8)))
791             {
792 0         0 $dirBuff .= substr($$dataPt, $entry, 12);
793 0         0 ++$index;
794 0         0 $newID = $oldID; # we wrote this
795 0         0 $et->Warn($msg, 1);
796 0         0 next;
797             }
798             # don't write out null directory entry
799 0 0 0     0 if ($oldFormat==0 and $index and $oldCount==0) {
      0        
800 0   0     0 $ignoreCount = ($ignoreCount || 0) + 1;
801             # must keep same directory size to avoid messing up our fixed offsets
802 0 0       0 $dirBuff .= ("\0" x 12) if $$dirInfo{FixBase};
803 0         0 ++$index;
804 0         0 $newID = $oldID; # pretend we wrote this
805 0         0 next;
806             }
807 0         0 return ExifErr($et, $msg, $tagTablePtr);
808             }
809 4746         10369 $readFormName = $oldFormName = $formatName[$oldFormat];
810 4746         6825 $valueDataPt = $dataPt;
811 4746         6814 $valueDataPos = $dataPos;
812 4746         6814 $valueDataLen = $dataLen;
813 4746         6867 $valuePtr = $entry + 8;
814             # try direct method first for speed
815 4746         11403 $oldInfo = $$tagTablePtr{$oldID};
816 4746 100 100     20228 if (ref $oldInfo ne 'HASH' or $$oldInfo{Condition}) {
817             # must get unknown tags too
818             # (necessary so we don't miss a tag we want to Drop)
819 585         2283 my $unk = $et->Options(Unknown => 1);
820 585         2073 $oldInfo = $et->GetTagInfo($tagTablePtr, $oldID);
821 585         2061 $et->Options(Unknown => $unk);
822             }
823             # patch incorrect count in Kodak SubIFD3 tags
824 4746 50 100     19404 if ($oldCount < 2 and $oldInfo and $$oldInfo{FixCount}) {
      66        
825 0 0       0 $offList or ($offList, $offHash) = GetOffList($dataPt, $dirStart, $dataPos,
826             $numEntries, $tagTablePtr);
827 0         0 my $i = $$offHash{Get32u($dataPt, $valuePtr)};
828 0 0 0     0 if (defined $i and $i < $#$offList) {
829 0         0 $oldCount = int(($$offList[$i+1] - $$offList[$i]) / $formatSize[$oldFormat]);
830 0 0 0     0 $fixCount = ($fixCount || 0) + 1 if $oldCount != $readCount;
831             }
832             }
833 4746         8408 $oldSize = $oldCount * $formatSize[$oldFormat];
834 4746         6922 my $readFromFile;
835 4746 100       9329 if ($oldSize > 4) {
836 2165         5032 $valuePtr = Get32u($dataPt, $valuePtr);
837             # fix valuePtr if necessary
838 2165 50       5766 if ($$dirInfo{FixOffsets}) {
839 0 0       0 $valEnd or $valEnd = $dataPos + $dirStart + 2 + 12 * $numEntries + 4;
840 0         0 my ($tagID, $size, $wFlag) = ($oldID, $oldSize, 1);
841             #### eval FixOffsets ($valuePtr, $valEnd, $size, $tagID, $wFlag)
842 0         0 eval $$dirInfo{FixOffsets};
843 0 0       0 unless (defined $valuePtr) {
844 0 0       0 unless ($$et{DropTags}) {
845 0 0       0 my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf("tag 0x%.4x",$oldID);
846 0 0       0 return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
847             }
848 0         0 ++$index; $oldID = $newID; next; # drop this tag
  0         0  
  0         0  
849             }
850             }
851             # offset shouldn't point into TIFF or IFD header
852 2165         3857 my $suspect = ($valuePtr < 8);
853             # convert offset to pointer in $$dataPt
854 2165 100 66     11649 if ($$dirInfo{EntryBased} or (ref $$tagTablePtr{$oldID} eq 'HASH' and
      66        
855             $$tagTablePtr{$oldID}{EntryBased}))
856             {
857 5         13 $valuePtr += $entry;
858             } else {
859 2160         3653 $valuePtr -= $dataPos;
860             }
861             # value shouldn't overlap our directory
862 2165 50 66     5386 $suspect = 1 if $valuePtr < $dirEnd and $valuePtr+$oldSize > $dirStart;
863             # get value by seeking in file if we are allowed
864 2165 100 100     7961 if ($valuePtr < 0 or $valuePtr+$oldSize > $dataLen) {
865 226         438 my ($pos, $tagStr, $invalidPreview, $tmpInfo, $leicaTrailer);
866 226 100       543 if ($oldInfo) {
    50          
867 218         632 $tagStr = $$oldInfo{Name};
868 218         373 $leicaTrailer = $$oldInfo{LeicaTrailer};
869             } elsif (defined $oldInfo) {
870 8         52 $tmpInfo = $et->GetTagInfo($tagTablePtr, $oldID, \ '', $oldFormName, $oldCount);
871 8 50       69 if ($tmpInfo) {
872 8         33 $tagStr = $$tmpInfo{Name};
873 8         43 $leicaTrailer = $$tmpInfo{LeicaTrailer};
874             }
875             }
876 226 50       492 $tagStr or $tagStr = sprintf("tag 0x%.4x",$oldID);
877             # allow PreviewImage to run outside EXIF segment in JPEG images
878 226 50       547 if (not $raf) {
879 0 0       0 if ($tagStr eq 'PreviewImage') {
    0          
880 0         0 $raf = $$et{RAF};
881 0 0       0 if ($raf) {
882 0         0 $pos = $raf->Tell();
883 0 0 0     0 if ($oldInfo and $$oldInfo{ChangeBase}) {
884             # adjust base offset for this tag only
885             #### eval ChangeBase ($dirStart,$dataPos)
886 0         0 my $newBase = eval $$oldInfo{ChangeBase};
887 0         0 $valuePtr += $newBase;
888             }
889             } else {
890 0         0 $invalidPreview = 1;
891             }
892             } elsif ($leicaTrailer) {
893             # save information about Leica makernote trailer
894             $$et{LeicaTrailer} = {
895 0   0     0 TagInfo => $oldInfo || $tmpInfo,
896             Offset => $base + $valuePtr + $dataPos,
897             Size => $oldSize,
898             Fixup => new Image::ExifTool::Fixup,
899             },
900             $invalidPreview = 2;
901             # remove SubDirectory to prevent processing (for now)
902 0 0       0 my %copy = %{$oldInfo || $tmpInfo};
  0         0  
903 0         0 delete $copy{SubDirectory};
904 0         0 delete $copy{MakerNotes};
905 0         0 $oldInfo = \%copy;
906             }
907             }
908 226 50 33     705 if ($oldSize > BINARY_DATA_LIMIT and $$origDirInfo{ImageData} and
    50 0        
    0 0        
909             (not defined $oldInfo or ($oldInfo and
910             (not $$oldInfo{SubDirectory} or $$oldInfo{ReadFromRAF}))))
911             {
912             # copy huge data blocks later instead of loading into memory
913 0         0 $oldValue = ''; # dummy empty value
914             # copy this value later unless writing a new value
915 0 0       0 unless (defined $set{$oldID}) {
916 0 0       0 my $pad = $oldSize & 0x01 ? 1 : 0;
917             # save block information to copy later (set directory offset later)
918 0         0 $oldImageData = [$base+$valuePtr+$dataPos, $oldSize, $pad];
919             }
920             } elsif ($raf) {
921 226   33     865 my $success = ($raf->Seek($base+$valuePtr+$dataPos, 0) and
922             $raf->Read($oldValue, $oldSize) == $oldSize);
923 226 50       740 if (defined $pos) {
924 0         0 $raf->Seek($pos, 0);
925 0         0 undef $raf;
926             # (sony A700 has 32-byte header on PreviewImage)
927 0 0 0     0 unless ($success and $oldValue =~ /^(\xff\xd8\xff|(.|.{33})\xd8\xff\xdb)/s) {
928 0         0 $invalidPreview = 1;
929 0         0 $success = 1; # continue writing directory anyway
930             }
931             }
932 226 50       575 unless ($success) {
933 0 0       0 return undef if $et->Error("Error reading value for $name entry $index", $inMakerNotes);
934 0         0 ++$index; $oldID = $newID; next; # drop this tag
  0         0  
  0         0  
935             }
936             } elsif (not $invalidPreview) {
937 0 0       0 return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
938 0         0 ++$index; $oldID = $newID; next; # drop this tag
  0         0  
  0         0  
939             }
940 226 50       493 if ($invalidPreview) {
941             # set value for invalid preview
942 0 0       0 if ($$et{FILE_TYPE} eq 'JPEG') {
943             # define dummy value for preview (or Leica MakerNote) to write later
944             # (value must be larger than 4 bytes to generate PREVIEW_INFO,
945             # and an even number of bytes so it won't be padded)
946 0         0 $oldValue = 'LOAD_PREVIEW';
947             } else {
948 0         0 $oldValue = 'none';
949 0         0 $oldSize = length $oldValue;
950             }
951 0         0 $valuePtr = 0;
952             } else {
953 226         688 UpdateTiffEnd($et, $base+$valuePtr+$dataPos+$oldSize);
954             }
955             # update pointers for value just read from file
956 226         492 $valueDataPt = \$oldValue;
957 226         419 $valueDataPos = $valuePtr + $dataPos;
958 226         375 $valueDataLen = $oldSize;
959 226         373 $valuePtr = 0;
960 226         397 $readFromFile = 1;
961             }
962 2165 100       4624 if ($suspect) {
963 2 50       7 my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf('tag 0x%.4x', $oldID);
964 2         5 my $str = "Suspicious $name offset for $tagStr";
965 2 50       6 if ($inMakerNotes) {
966 2         9 $et->Warn($str, 1);
967             } else {
968 0 0       0 return undef if $et->Error($str, 1);
969             }
970             }
971             }
972             # read value if we haven't already
973 4746 100       13564 $oldValue = substr($$valueDataPt, $valuePtr, $oldSize) unless $readFromFile;
974             # get tagInfo using value if necessary
975 4746 100 66     16165 if (defined $oldInfo and not $oldInfo) {
976 162         619 my $unk = $et->Options(Unknown => 1);
977 162         680 $oldInfo = $et->GetTagInfo($tagTablePtr, $oldID, \$oldValue, $oldFormName, $oldCount);
978 162         1096 $et->Options(Unknown => $unk);
979             # now that we have the value, we can resolve the Condition to finally
980             # determine whether we want to delete this tag or not
981 162 0 33     791 if ($mayDelete{$oldID} and $oldInfo and (not @newTags or $newTags[0] != $oldID)) {
      0        
      33        
982 0         0 my $nvHash = $et->GetNewValueHash($oldInfo, $dirName);
983 0 0 0     0 if (not $nvHash and $wrongDir) {
984             # delete from wrong directory if necessary
985 0         0 $nvHash = $et->GetNewValueHash($oldInfo, $wrongDir);
986 0 0       0 $nvHash and $xDelete{$oldID} = 1;
987             }
988 0 0       0 if ($nvHash) {
989             # we want to delete this tag after all, so insert it into our list
990 0         0 $set{$oldID} = $oldInfo;
991 0         0 unshift @newTags, $oldID;
992             }
993             }
994             }
995             # make sure we are handling the 'ifd' format properly
996 4746 50 66     16740 if (($oldFormat == 13 or $oldFormat == 18) and
      33        
      66        
997             (not $oldInfo or not $$oldInfo{SubIFD}))
998             {
999 0         0 my $str = sprintf('%s tag 0x%.4x IFD format not handled', $name, $oldID);
1000 0         0 $et->Error($str, $inMakerNotes);
1001             }
1002             # override format we use to read the value if specified
1003 4746 50       10013 if ($oldInfo) {
1004             # check for tags which must be integers
1005 4746 50 100     20959 if (($$oldInfo{IsOffset} or $$oldInfo{SubIFD}) and
      66        
1006             not $intFormat{$oldFormName})
1007             {
1008 0         0 $et->Error("Invalid format ($oldFormName) for $name $$oldInfo{Name}", $inMakerNotes);
1009 0         0 ++$index; $oldID = $newID; next; # drop this tag
  0         0  
  0         0  
1010             }
1011 4746 50 100     10442 if ($$oldInfo{Drop} and $$et{DropTags} and
      33        
      66        
1012             ($$oldInfo{Drop} == 1 or $$oldInfo{Drop} < $oldSize))
1013             {
1014 4         10 ++$index; $oldID = $newID; next; # drop this tag
  4         7  
  4         14  
1015             }
1016 4742 100       11153 if ($$oldInfo{Format}) {
1017 289         770 $readFormName = $$oldInfo{Format};
1018 289         826 $readFormat = $formatNumber{$readFormName};
1019 289 50       722 unless ($readFormat) {
1020             # we aren't reading in a standard EXIF format, so rewrite in old format
1021 0         0 $readFormName = $oldFormName;
1022 0         0 $readFormat = $oldFormat;
1023             }
1024 289 50       821 if ($$oldInfo{FixedSize}) {
1025 0 0       0 $oldSize = $$oldInfo{FixedSize} if $$oldInfo{FixedSize};
1026 0         0 $oldValue = substr($$valueDataPt, $valuePtr, $oldSize);
1027             }
1028             # adjust number of items to read if format size changed
1029 289         785 $readCount = $oldSize / $formatSize[$readFormat];
1030             }
1031             }
1032 4742 50 33     11595 if ($oldID <= $lastTagID and not ($inMakerNotes or $et->IsRawType())) {
      66        
1033 0 0       0 my $str = $oldInfo ? "$$oldInfo{Name} tag" : sprintf('tag 0x%x',$oldID);
1034 0 0       0 if ($oldID == $lastTagID) {
1035 0         0 $et->Warn("Duplicate $str in $name");
1036             # put this tag back into the newTags list if necessary
1037 0 0       0 unshift @newTags, $oldID if defined $set{$oldID};
1038             } else {
1039 0         0 $et->Warn("\u$str out of sequence in $name");
1040             }
1041             }
1042 4742         7613 $lastTagID = $oldID;
1043 4742         7572 ++$index; # increment index for next time
1044             } else {
1045 379         1000 undef $oldID; # no more existing entries
1046             }
1047             }
1048             #
1049             # write out all new tags, up to and including this one
1050             #
1051 7123         11985 $newID = $newTags[0];
1052 7123         10249 my $isNew; # -1=tag is old, 0=tag same as existing, 1=tag is new
1053 7123 100       15647 if (not defined $oldID) {
    100          
1054 2222 100       7296 last unless defined $newID;
1055 1843         2852 $isNew = 1;
1056             } elsif (not defined $newID) {
1057             # maker notes will have no new tags defined
1058 3256 100       6936 if (defined $set{$oldID}) {
1059 35         84 $newID = $oldID;
1060 35         99 $isNew = 0;
1061             } else {
1062 3221         4988 $isNew = -1;
1063             }
1064             } else {
1065 1645         2854 $isNew = $oldID <=> $newID;
1066             # special logic needed if directory has out-of-order entries
1067 1645 50 33     3543 if ($unsorted and $isNew) {
1068 0 0 0     0 if ($isNew > 0 and $hasOldID{$newID}) {
1069             # we wanted to create the new tag, but an old tag
1070             # does exist with this ID, so defer writing the new tag
1071 0         0 $isNew = -1;
1072             }
1073 0 0 0     0 if ($isNew < 0 and $hasNewID{$oldID}) {
1074             # we wanted to write the old tag, but we have
1075             # a new tag with this ID, so move it up in the order
1076 0         0 my @tmpTags = ( $oldID );
1077 0   0     0 $_ == $oldID or push @tmpTags, $_ foreach @newTags;
1078 0         0 @newTags = @tmpTags;
1079 0         0 $newID = $oldID;
1080 0         0 $isNew = 0;
1081             }
1082             }
1083             }
1084 6744         10488 my $newInfo = $oldInfo;
1085 6744         9288 my $newFormat = $oldFormat;
1086 6744         9986 my $newFormName = $oldFormName;
1087 6744         9903 my $newCount = $oldCount;
1088 6744         11014 my $ifdFormName;
1089             my $newValue;
1090 6744 100       13772 my $newValuePt = $isNew >= 0 ? \$newValue : \$oldValue;
1091 6744         10294 my $isOverwriting;
1092              
1093 6744 100       13089 if ($isNew >= 0) {
1094             # add, edit or delete this tag
1095 2285         3576 shift @newTags; # remove from list
1096 2285         5358 my $curInfo = $set{$newID};
1097 2285 100 100     5663 unless ($curInfo or $$addDirs{$newID}) {
1098             # we can finally get the specific tagInfo reference for this tag
1099             # (because we can now evaluate the Condition statement since all
1100             # DataMember's have been obtained for tags up to this one)
1101 110         460 $curInfo = $et->GetTagInfo($tagTablePtr, $newID);
1102 110 100 66     784 if (defined $curInfo and not $curInfo) {
1103             # need value to evaluate the condition
1104             # (tricky because we need the tagInfo ref to get the value,
1105             # so we must loop through all new tagInfo's...)
1106 24         78 foreach $tagInfo (@newTagInfo) {
1107 559 100       1257 next unless $$tagInfo{TagID} == $newID;
1108 24         137 my $val = $et->GetNewValue($tagInfo);
1109 24 50       81 defined $val or $mayDelete{$newID} = 1, next;
1110             # must convert to binary for evaluating in Condition
1111 24   100     127 my $fmt = $$tagInfo{Format} || $$tagInfo{Writable};
1112 24 100       79 if ($fmt) {
1113 23         134 $val = WriteValue($val, $fmt, $$tagInfo{Count});
1114 23 50       119 defined $val or $mayDelete{$newID} = 1, next;
1115             }
1116 24         110 $curInfo = $et->GetTagInfo($tagTablePtr, $newID, \$val, $oldFormName, $oldCount);
1117 24 50       110 if ($curInfo) {
1118 24 100       155 last if $curInfo eq $tagInfo;
1119 3         12 undef $curInfo;
1120             }
1121             }
1122             # may want to delete this, but we need to see the old value first
1123 24 100       98 $mayDelete{$newID} = 1 unless $curInfo;
1124             }
1125             # don't set this tag unless valid for the current condition
1126 110 100 100     705 if ($curInfo and $$et{NEW_VALUE}{$curInfo}) {
1127 83         252 $set{$newID} = $curInfo;
1128             } else {
1129 27 100       114 next if $isNew > 0;
1130 1         3 $isNew = -1;
1131 1         3 undef $curInfo;
1132             }
1133             }
1134 2259 100       4352 if ($curInfo) {
    100          
1135 2188 100       5391 if ($$curInfo{WriteCondition}) {
1136 6         15 my $self = $et; # set $self to be used in eval
1137             #### eval WriteCondition ($self)
1138 6 50       616 unless (eval $$curInfo{WriteCondition}) {
1139 0 0       0 $@ and warn $@;
1140 0         0 goto NoWrite; # GOTO !
1141             }
1142             }
1143 2188         3158 my $nvHash;
1144 2188 50       8290 $nvHash = $et->GetNewValueHash($curInfo, $dirName) if $isNew >= 0;
1145 2188 100 100     7684 unless ($nvHash or defined $$mandatory{$newID}) {
1146 1099 100       3788 goto NoWrite unless $wrongDir; # GOTO !
1147             # delete stuff from the wrong directory if setting somewhere else
1148 664         1679 $nvHash = $et->GetNewValueHash($curInfo, $wrongDir);
1149             # don't cross delete if not overwriting
1150 664 100       1991 goto NoWrite unless $et->IsOverwriting($nvHash); # GOTO !
1151             # don't cross delete if specifically deleting from the other directory
1152             # (Note: don't call GetValue() here because it shouldn't be called
1153             # if IsOverwriting returns < 0 -- eg. when shifting)
1154 636 100 100     2110 if (not defined $$nvHash{Value} and $$nvHash{WantGroup} and
      100        
1155             lc($$nvHash{WantGroup}) eq lc($wrongDir))
1156             {
1157 2         26 goto NoWrite; # GOTO !
1158             } else {
1159             # remove this tag if found in this IFD
1160 634         1498 $xDelete{$newID} = 1;
1161             }
1162             }
1163             } elsif (not $$addDirs{$newID}) {
1164 466 100       1206 NoWrite: next if $isNew > 0;
1165 3         10 delete $set{$newID};
1166 3         13 $isNew = -1;
1167             }
1168 1796 100 66     4300 if ($set{$newID}) {
    100 33        
    100 66        
    50          
1169             #
1170             # set the new tag value (or 'next' if deleting tag)
1171             #
1172 1723         3105 $newInfo = $set{$newID};
1173 1723         3294 $newCount = $$newInfo{Count};
1174 1723         2880 my ($val, $newVal, $n);
1175 1723         4177 my $nvHash = $et->GetNewValueHash($newInfo, $dirName);
1176 1723 100 66     4705 if ($isNew > 0) {
    100          
1177             # don't create new entry unless requested
1178 1473 100       2877 if ($nvHash) {
1179 601 100       1911 next unless $$nvHash{IsCreating};
1180 518 100       1426 if ($$newInfo{IsOverwriting}) {
1181 1         5 my $proc = $$newInfo{IsOverwriting};
1182 1         8 $isOverwriting = &$proc($et, $nvHash, $val, \$newVal);
1183             } else {
1184 517         1613 $isOverwriting = $et->IsOverwriting($nvHash);
1185             }
1186             } else {
1187 872 100       2451 next if $xDelete{$newID}; # don't create if cross deleting
1188 241         599 $newVal = $$mandatory{$newID}; # get value for mandatory tag
1189 241         463 $isOverwriting = 1;
1190             }
1191             # convert using new format
1192 759 100       1984 if ($$newInfo{Format}) {
1193 72         313 $newFormName = $$newInfo{Format};
1194             # use Writable flag to specify IFD format code
1195 72         228 $ifdFormName = $$newInfo{Writable};
1196             } else {
1197 687         1891 $newFormName = $$newInfo{Writable};
1198 687 50       1469 unless ($newFormName) {
1199 0         0 warn("No format for $name $$newInfo{Name}\n");
1200 0         0 next;
1201             }
1202             }
1203 759         1751 $newFormat = $formatNumber{$newFormName};
1204             } elsif ($nvHash or $xDelete{$newID}) {
1205 241 100       627 unless ($nvHash) {
1206 3         15 $nvHash = $et->GetNewValueHash($newInfo, $wrongDir);
1207             }
1208             # read value
1209 241 50       637 if (length $oldValue >= $oldSize) {
1210 241         852 $val = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize);
1211             } else {
1212 0         0 $val = '';
1213             }
1214             # determine write format (by default, use 'Writable' format)
1215 241         854 my $writable = $$newInfo{Writable};
1216             # (or use existing format if 'Writable' not specified)
1217 241 100 66     1069 $writable = $oldFormName unless $writable and $writable ne '1';
1218             # (and override write format with 'Format' if specified)
1219 241   66     868 my $writeForm = $$newInfo{Format} || $writable;
1220 241 100       619 if ($writeForm ne $newFormName) {
1221             # write in specified format
1222 8         21 $newFormName = $writeForm;
1223 8         26 $newFormat = $formatNumber{$newFormName};
1224             # use different IFD format code if necessary
1225 8 100       36 if ($inMakerNotes) {
    100          
1226             # always preserve IFD format in maker notes
1227 2         6 $ifdFormName = $oldFormName;
1228             } elsif ($writable ne $newFormName) {
1229             # use specified IFD format
1230 2         8 $ifdFormName = $writable;
1231             }
1232             }
1233 241 100 100     877 if ($inMakerNotes and $readFormName ne 'string' and $readFormName ne 'undef') {
      66        
1234             # keep same size in maker notes unless string or binary
1235 26         98 $newCount = $oldCount * $formatSize[$oldFormat] / $formatSize[$newFormat];
1236             }
1237 241 100       637 if ($$newInfo{IsOverwriting}) {
1238 1         3 my $proc = $$newInfo{IsOverwriting};
1239 1         7 $isOverwriting = &$proc($et, $nvHash, $val, \$newVal);
1240             } else {
1241 240         978 $isOverwriting = $et->IsOverwriting($nvHash, $val);
1242             }
1243             }
1244 1009 100       2154 if ($isOverwriting) {
1245 994 100       3577 $newVal = $et->GetNewValue($nvHash) unless defined $newVal;
1246             # value undefined if deleting this tag
1247             # (also delete tag if cross-deleting and this isn't a date/time shift)
1248 994 100 66     4253 if (not defined $newVal or ($xDelete{$newID} and not defined $$nvHash{Shift})) {
      100        
1249 22 50 66     157 if (not defined $newVal and $$newInfo{RawConvInv} and defined $$nvHash{Value}) {
      33        
1250             # error in RawConvInv, so rewrite existing tag
1251 0         0 goto NoOverwrite; # GOTO!
1252             }
1253 22 50       80 unless ($isNew) {
1254 22         52 ++$$et{CHANGED};
1255 22         153 $et->VerboseValue("- $dirName:$$newInfo{Name}", $val);
1256             }
1257 22         74 next;
1258             }
1259 972 100 100     2747 if ($newCount and $newCount < 0) {
1260             # set count to number of values if variable
1261 19         122 my @vals = split ' ',$newVal;
1262 19         66 $newCount = @vals;
1263             }
1264             # convert to binary format
1265 972         2873 $newValue = WriteValue($newVal, $newFormName, $newCount);
1266 972 50       2387 unless (defined $newValue) {
1267 0         0 $et->Warn("Invalid value for $dirName:$$newInfo{Name}");
1268 0         0 goto NoOverwrite; # GOTO!
1269             }
1270 972 50       2535 if (length $newValue) {
1271             # limit maximum value length in JPEG images
1272             # (max segment size is 65533 bytes and the min EXIF size is 96 incl an additional IFD entry)
1273 972 50 66     4399 if ($$et{FILE_TYPE} eq 'JPEG' and length($newValue) > 65436 and
      33        
1274             $$newInfo{Name} ne 'PreviewImage')
1275             {
1276 0 0       0 my $name = $$newInfo{MakerNotes} ? 'MakerNotes' : $$newInfo{Name};
1277 0         0 $et->Warn("Writing large value for $name",1);
1278             }
1279             # re-code if necessary
1280 972 100 100     2652 if ($strEnc and $newFormName eq 'string') {
1281 1         10 $newValue = $et->Encode($newValue, $strEnc);
1282             }
1283             } else {
1284 0         0 $et->Warn("Can't write zero length $$newInfo{Name} in $$tagTablePtr{GROUPS}{1}");
1285 0         0 goto NoOverwrite; # GOTO!
1286             }
1287 972 50       2705 if ($isNew >= 0) {
1288 972         2388 $newCount = length($newValue) / $formatSize[$newFormat];
1289 972         2026 ++$$et{CHANGED};
1290 972 100       2245 if (defined $allMandatory) {
1291             # not all mandatory if we are writing any tag specifically
1292 227 100       663 if ($nvHash) {
1293 80         204 undef $allMandatory;
1294 80         172 undef $deleteAll;
1295             } else {
1296 147         329 ++$addMandatory; # count mandatory tags that we added
1297             }
1298             }
1299 972 100       2391 if ($verbose > 1) {
1300 13 50       30 $et->VerboseValue("- $dirName:$$newInfo{Name}", $val) unless $isNew;
1301 13 50 33     42 if ($$newInfo{OffsetPair} and $newVal eq '4277010157') { # (0xfeedfeed)
1302 0         0 print { $$et{OPTIONS}{TextOut} } " + $dirName:$$newInfo{Name} = \n";
  0         0  
1303             } else {
1304 13 100       31 my $str = $nvHash ? '' : ' (mandatory)';
1305 13         69 $et->VerboseValue("+ $dirName:$$newInfo{Name}", $newVal, $str);
1306             }
1307             }
1308             }
1309             } else {
1310 15 50       55 NoOverwrite: next if $isNew > 0;
1311 15         31 $isNew = -1; # rewrite existing tag
1312             }
1313             # set format for EXIF IFD if different than conversion format
1314 987 100       2335 if ($ifdFormName) {
1315 75         216 $newFormName = $ifdFormName;
1316 75         240 $newFormat = $formatNumber{$newFormName};
1317             }
1318              
1319             } elsif ($isNew > 0) {
1320             #
1321             # create new subdirectory
1322             #
1323             # newInfo may not be defined if we try to add a mandatory tag
1324             # to a directory that doesn't support it (eg. IFD1 in RW2 images)
1325 40 50       179 $newInfo = $$addDirs{$newID} or next;
1326             # make sure we don't try to generate a new MakerNotes directory
1327             # or a SubIFD
1328 40 50 33     360 next if $$newInfo{MakerNotes} or $$newInfo{Name} eq 'SubIFD';
1329 40         114 my $subTable;
1330 40 100       170 if ($$newInfo{SubDirectory}{TagTable}) {
1331 13         70 $subTable = Image::ExifTool::GetTagTable($$newInfo{SubDirectory}{TagTable});
1332             } else {
1333 27         75 $subTable = $tagTablePtr;
1334             }
1335             # create empty source directory
1336 40         285 my %sourceDir = (
1337             Parent => $dirName,
1338             Fixup => new Image::ExifTool::Fixup,
1339             );
1340 40 100       282 $sourceDir{DirName} = $$newInfo{Groups}{1} if $$newInfo{SubIFD};
1341 40         349 $newValue = $et->WriteDirectory(\%sourceDir, $subTable);
1342             # only add new directory if it isn't empty
1343 40 100 66     332 next unless defined $newValue and length($newValue);
1344             # set the fixup start location
1345 38 100       164 if ($$newInfo{SubIFD}) {
1346             # subdirectory is referenced by an offset in value buffer
1347 34         105 my $subdir = $newValue;
1348 34         141 $newValue = Set32u(0xfeedf00d);
1349             push @subdirs, {
1350             DataPt => \$subdir,
1351             Table => $subTable,
1352             Fixup => $sourceDir{Fixup},
1353 34         446 Offset => length($dirBuff) + 8,
1354             Where => 'dirBuff',
1355             };
1356 34         120 $newFormName = 'int32u';
1357 34         156 $newFormat = $formatNumber{$newFormName};
1358             } else {
1359             # subdirectory goes directly into value buffer
1360 4         13 $sourceDir{Fixup}{Start} += length($valBuff);
1361             # use Writable to set format, otherwise 'undef'
1362 4         11 $newFormName = $$newInfo{Writable};
1363 4 50 33     46 unless ($newFormName and $formatNumber{$newFormName}) {
1364 0         0 $newFormName = 'undef';
1365             }
1366 4         10 $newFormat = $formatNumber{$newFormName};
1367 4         18 push @valFixups, $sourceDir{Fixup};
1368             }
1369             } elsif ($$newInfo{Format} and $$newInfo{Writable} and $$newInfo{Writable} ne '1') {
1370             # use specified write format
1371 4         13 $newFormName = $$newInfo{Writable};
1372 4         10 $newFormat = $formatNumber{$newFormName};
1373             } elsif ($$addDirs{$newID} and $newInfo ne $$addDirs{$newID}) {
1374             # this can happen if we are trying to add a directory that doesn't exist
1375             # in this type of file (eg. try adding a SubIFD tag to an A100 image)
1376 0         0 $isNew = -1;
1377             }
1378             }
1379 5517 100       11077 if ($isNew < 0) {
1380             # just rewrite existing tag
1381 4477         7210 $newID = $oldID;
1382 4477         7892 $newValue = $oldValue;
1383 4477         6327 $newFormat = $oldFormat; # (just in case it changed)
1384 4477         6699 $newFormName = $oldFormName;
1385             # set offset of this entry in the directory so we can update the pointer
1386             # and save block information to copy this large block later
1387 4477 50       8644 if ($oldImageData) {
1388 0         0 $$oldImageData[3] = $newStart + length($dirBuff) + 2;
1389 0         0 push @imageData, $oldImageData;
1390 0         0 $$origDirInfo{ImageData} = \@imageData;
1391             }
1392             }
1393 5517 50       10983 if ($newInfo) {
1394             #
1395             # load necessary data for this tag (thumbnail image, etc)
1396             #
1397 5517 100 100     14815 if ($$newInfo{DataTag} and $isNew >= 0) {
1398 8         28 my $dataTag = $$newInfo{DataTag};
1399             # load data for this tag
1400 8 100 66     53 unless (defined $offsetData{$dataTag} or $dataTag eq 'LeicaTrailer') {
1401             # prefer tag from Composite table if it exists (otherwise
1402             # PreviewImage data would be taken from Extra tag)
1403 4         28 my $compInfo = Image::ExifTool::GetCompositeTagInfo($dataTag);
1404 4   33     32 $offsetData{$dataTag} = $et->GetNewValue($compInfo || $dataTag);
1405 4         22 my $err;
1406 4 50       28 if (defined $offsetData{$dataTag}) {
1407 4         15 my $len = length $offsetData{$dataTag};
1408 4 100       18 if ($dataTag eq 'PreviewImage') {
1409             # must set DEL_PREVIEW flag now if preview fit into IFD
1410 2 50       24 $$et{DEL_PREVIEW} = 1 if $len <= 4;
1411             }
1412             } else {
1413 0         0 $err = "$dataTag not found";
1414             }
1415 4 50       25 if ($err) {
1416 0 0       0 $et->Warn($err) if $$newInfo{IsOffset};
1417 0         0 delete $set{$newID}; # remove from list of tags we are setting
1418 0         0 next;
1419             }
1420             }
1421             }
1422             #
1423             # write maker notes
1424             #
1425 5517 100 100     28958 if ($$newInfo{MakerNotes}) {
    100 66        
    100 100        
    100 100        
      66        
1426             # don't write new makernotes if we are deleting this group
1427 43 50 33     274 if ($$et{DEL_GROUP}{MakerNotes} and
      66        
1428             ($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
1429             {
1430 1 50       11 if ($et->IsRawType()) {
1431 0         0 $et->WarnOnce("Can't delete MakerNotes from $$et{FileType}",1);
1432             } else {
1433 1 50       6 if ($isNew <= 0) {
1434 1         5 ++$$et{CHANGED};
1435 1 50       5 $verbose and print $out " Deleting MakerNotes\n";
1436             }
1437 1         4 next;
1438             }
1439             }
1440 42         203 my $saveOrder = GetByteOrder();
1441 42 100 66     277 if ($isNew >= 0 and defined $set{$newID}) {
1442             # we are writing a whole new maker note block
1443             # --> add fixup information if necessary
1444 7         39 my $nvHash = $et->GetNewValueHash($newInfo, $dirName);
1445 7 100 66     78 if ($nvHash and $$nvHash{MAKER_NOTE_FIXUP}) {
1446             # must clone fixup because we will be shifting it
1447 6         51 my $makerFixup = $$nvHash{MAKER_NOTE_FIXUP}->Clone();
1448 6         20 my $valLen = length($valBuff);
1449 6         19 $$makerFixup{Start} += $valLen;
1450 6         24 push @valFixups, $makerFixup;
1451             }
1452             } else {
1453             # update maker notes if possible
1454             my %subdirInfo = (
1455             Base => $base,
1456             DataPt => $valueDataPt,
1457             DataPos => $valueDataPos,
1458             DataLen => $valueDataLen,
1459             DirStart => $valuePtr,
1460             DirLen => $oldSize,
1461             DirName => 'MakerNotes',
1462             Name => $$newInfo{Name},
1463 35         519 Parent => $dirName,
1464             TagInfo => $newInfo,
1465             RAF => $raf,
1466             );
1467 35         128 my ($subTable, $subdir, $loc, $writeProc, $notIFD);
1468 35 50       161 if ($$newInfo{SubDirectory}) {
1469 35         113 my $sub = $$newInfo{SubDirectory};
1470 35 100       145 $subdirInfo{FixBase} = 1 if $$sub{FixBase};
1471 35         120 $subdirInfo{FixOffsets} = $$sub{FixOffsets};
1472 35         113 $subdirInfo{EntryBased} = $$sub{EntryBased};
1473 35 100       576 $subdirInfo{NoFixBase} = 1 if defined $$sub{Base};
1474 35         109 $subdirInfo{AutoFix} = $$sub{AutoFix};
1475 35 100       204 SetByteOrder($$sub{ByteOrder}) if $$sub{ByteOrder};
1476             }
1477             # get the proper tag table for these maker notes
1478 35 50 33     244 if ($oldInfo and $$oldInfo{SubDirectory}) {
1479 35         110 $subTable = $$oldInfo{SubDirectory}{TagTable};
1480 35 50       278 $subTable and $subTable = Image::ExifTool::GetTagTable($subTable);
1481 35         126 $writeProc = $$oldInfo{SubDirectory}{WriteProc};
1482 35         98 $notIFD = $$oldInfo{NotIFD};
1483             } else {
1484 0         0 $et->Warn('Internal problem getting maker notes tag table');
1485             }
1486 35 50 66     269 $writeProc or $writeProc = $$subTable{WRITE_PROC} if $subTable;
1487 35 50       166 $subTable or $subTable = $tagTablePtr;
1488 35 50 66     422 if ($writeProc and
    100 66        
1489             $writeProc eq \&Image::ExifTool::MakerNotes::WriteUnknownOrPreview and
1490             $oldValue =~ /^\xff\xd8\xff/)
1491             {
1492 0         0 $loc = 0;
1493             } elsif (not $notIFD) {
1494             # look for IFD-style maker notes
1495 33         246 $loc = Image::ExifTool::MakerNotes::LocateIFD($et,\%subdirInfo);
1496             }
1497 35 100 66     178 if (defined $loc) {
    100          
    50          
1498             # we need fixup data for this subdirectory
1499 33         200 $subdirInfo{Fixup} = new Image::ExifTool::Fixup;
1500             # rewrite maker notes
1501 33         136 my $changed = $$et{CHANGED};
1502 33         424 $subdir = $et->WriteDirectory(\%subdirInfo, $subTable, $writeProc);
1503 33 100 100     359 if ($changed == $$et{CHANGED} and $subdirInfo{Fixup}->IsEmpty()) {
1504             # return original data if nothing changed and no fixups
1505 1         3 undef $subdir;
1506             }
1507             } elsif ($$subTable{PROCESS_PROC} and
1508             $$subTable{PROCESS_PROC} eq \&Image::ExifTool::ProcessBinaryData)
1509             {
1510 1         4 my $sub = $$oldInfo{SubDirectory};
1511 1 50       7 if (defined $$sub{Start}) {
1512             #### eval Start ($valuePtr)
1513 1         78 my $start = eval $$sub{Start};
1514 1         4 $loc = $start - $valuePtr;
1515 1         5 $subdirInfo{DirStart} = $start;
1516 1         4 $subdirInfo{DirLen} -= $loc;
1517             } else {
1518 0         0 $loc = 0;
1519             }
1520             # rewrite maker notes
1521 1         11 $subdir = $et->WriteDirectory(\%subdirInfo, $subTable);
1522             } elsif ($notIFD) {
1523 1 50       4 if ($writeProc) {
1524 1         2 $loc = 0;
1525 1         18 $subdir = $et->WriteDirectory(\%subdirInfo, $subTable);
1526             }
1527             } else {
1528 0         0 my $msg = 'Maker notes could not be parsed';
1529 0 0       0 if ($$et{FILE_TYPE} eq 'JPEG') {
1530 0         0 $et->Warn($msg, 1);
1531             } else {
1532 0         0 $et->Error($msg, 1);
1533             }
1534             }
1535 35 100       176 if (defined $subdir) {
1536 34 50       161 length $subdir or SetByteOrder($saveOrder), next;
1537 34         87 my $valLen = length($valBuff);
1538             # restore existing header and substitute the new
1539             # maker notes for the old value
1540 34         333 $newValue = substr($oldValue, 0, $loc) . $subdir;
1541 34         125 my $makerFixup = $subdirInfo{Fixup};
1542 34         122 my $previewInfo = $$et{PREVIEW_INFO};
1543 34 100       238 if ($subdirInfo{Relative}) {
    50          
1544             # apply a one-time fixup to $loc since offsets are relative
1545 5         17 $$makerFixup{Start} += $loc;
1546             # shift all offsets to be relative to new base
1547 5         21 my $baseShift = $valueDataPos + $valuePtr + $base - $subdirInfo{Base};
1548 5         19 $$makerFixup{Shift} += $baseShift;
1549 5         31 $makerFixup->ApplyFixup(\$newValue);
1550 5 100       33 if ($previewInfo) {
1551             # remove all but PreviewImage fixup (since others shouldn't change)
1552 1         3 foreach (keys %{$$makerFixup{Pointers}}) {
  1         4  
1553 2 100       13 /_PreviewImage$/ or delete $$makerFixup{Pointers}{$_};
1554             }
1555             # zero pointer so we can see how it gets shifted later
1556 1         10 $makerFixup->SetMarkerPointers(\$newValue, 'PreviewImage', 0);
1557             # set the pointer to the start of the EXIF information
1558             # add preview image fixup to list of value fixups
1559 1         3 $$makerFixup{Start} += $valLen;
1560 1         2 push @valFixups, $makerFixup;
1561 1         3 $$previewInfo{BaseShift} = $baseShift;
1562 1         4 $$previewInfo{Relative} = 1;
1563             }
1564             # don't shift anything if relative flag set to zero (Pentax patch)
1565             } elsif (not defined $subdirInfo{Relative}) {
1566             # shift offset base if shifted in the original image or if FixBase
1567             # was used, but be careful of automatic FixBase with negative shifts
1568             # since they may lead to negative (invalid) offsets (casio_edit_problem.jpg)
1569 29         109 my $baseShift = $base - $subdirInfo{Base};
1570 29 100 66     289 if ($subdirInfo{AutoFix}) {
    50 0        
      33        
1571 1         2 $baseShift = 0;
1572             } elsif ($subdirInfo{FixBase} and $baseShift < 0 and
1573             # allow negative base shift if offsets are bigger (PentaxOptioWP.jpg)
1574             (not $subdirInfo{MinOffset} or $subdirInfo{MinOffset} + $baseShift < 0))
1575             {
1576 0         0 my $fixBase = $et->Options('FixBase');
1577 0 0       0 if (not defined $fixBase) {
    0          
1578 0 0       0 my $str = $et->Options('IgnoreMinorErrors') ? 'ignored' : 'fix or ignore?';
1579 0         0 $et->Error("MakerNotes offsets may be incorrect ($str)", 1);
1580             } elsif ($fixBase eq '') {
1581 0         0 $et->Warn('Fixed incorrect MakerNotes offsets');
1582 0         0 $baseShift = 0;
1583             }
1584             }
1585 29         99 $$makerFixup{Start} += $valLen + $loc;
1586 29         100 $$makerFixup{Shift} += $baseShift;
1587             # permanently fix makernote offset errors
1588 29   50     220 $$makerFixup{Shift} += $subdirInfo{FixedBy} || 0;
1589 29         183 push @valFixups, $makerFixup;
1590 29 100 100     154 if ($previewInfo and not $$previewInfo{NoBaseShift}) {
1591 4         15 $$previewInfo{BaseShift} = $baseShift;
1592             }
1593             }
1594 34         236 $newValuePt = \$newValue; # write new value
1595             }
1596             }
1597 42         217 SetByteOrder($saveOrder);
1598              
1599             # process existing subdirectory unless we are overwriting it entirely
1600             } elsif ($$newInfo{SubDirectory} and $isNew <= 0 and not $isOverwriting
1601             # don't edit directory if Writable is set to 0
1602             and (not defined $$newInfo{Writable} or $$newInfo{Writable}) and
1603             not $$newInfo{ReadFromRAF})
1604             {
1605              
1606 442         978 my $subdir = $$newInfo{SubDirectory};
1607 442 100 66     2473 if ($$newInfo{SubIFD}) {
    50 33        
1608             #
1609             # rewrite existing sub IFD's
1610             #
1611 106         246 my $subTable = $tagTablePtr;
1612 106 100       418 if ($$subdir{TagTable}) {
1613 15         98 $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable});
1614             }
1615             # determine directory name for this IFD
1616 106   33     520 my $subdirName = $$newInfo{Groups}{1} || $$newInfo{Name};
1617             # all makernotes directory names must be 'MakerNotes'
1618 106 100       523 $subdirName = 'MakerNotes' if $$subTable{GROUPS}{0} eq 'MakerNotes';
1619             # must handle sub-IFD's specially since the values
1620             # are actually offsets to subdirectories
1621 106 50       365 unless ($readCount) { # can't have zero count
1622 0 0       0 return undef if $et->Error("$name entry $index has zero count", 2);
1623 0         0 next;
1624             }
1625 106         240 my $writeCount = 0;
1626 106         204 my $i;
1627 106         245 $newValue = ''; # reset value because we regenerate it below
1628 106         431 for ($i=0; $i<$readCount; ++$i) {
1629 109         343 my $off = $i * $formatSize[$readFormat];
1630 109         550 my $val = ReadValue($valueDataPt, $valuePtr + $off,
1631             $readFormName, 1, $oldSize - $off);
1632 109         389 my $subdirStart = $val - $dataPos;
1633 109         256 my $subdirBase = $base;
1634 109         218 my $hdrLen;
1635 109 50       399 if (defined $$subdir{Start}) {
1636             #### eval Start ($val)
1637 109         7463 my $newStart = eval $$subdir{Start};
1638 109 50       822 unless (Image::ExifTool::IsInt($newStart)) {
1639 0         0 $et->Error("Bad subdirectory start for $$newInfo{Name}");
1640 0         0 next;
1641             }
1642 109         367 $newStart -= $dataPos;
1643 109         269 $hdrLen = $newStart - $subdirStart;
1644 109         250 $subdirStart = $newStart;
1645             }
1646 109 50       451 if ($$subdir{Base}) {
1647 0         0 my $start = $subdirStart + $dataPos;
1648             #### eval Base ($start,$base)
1649 0         0 $subdirBase += eval $$subdir{Base};
1650             }
1651             # add IFD number if more than one
1652 109 100       417 $subdirName =~ s/\d*$/$i/ if $i;
1653             my %subdirInfo = (
1654             Base => $subdirBase,
1655             DataPt => $dataPt,
1656             DataPos => $dataPos - $subdirBase + $base,
1657             DataLen => $dataLen,
1658             DirStart => $subdirStart,
1659             DirName => $subdirName,
1660             Name => $$newInfo{Name},
1661 109 100       819 TagInfo => $newInfo,
1662             Parent => $dirName,
1663             Fixup => new Image::ExifTool::Fixup,
1664             RAF => $raf,
1665             Subdir => $subdir,
1666             # set ImageData only for 1st level SubIFD's
1667             ImageData=> $imageDataFlag eq 'Main' ? 'SubIFD' : undef,
1668             );
1669             # pass on header pointer only for certain sub IFD's
1670 109 100       640 $subdirInfo{HeaderPtr} = $$dirInfo{HeaderPtr} if $$newInfo{SubIFD} == 2;
1671 109 50       407 if ($$subdir{RelativeBase}) {
1672             # apply one-time fixup if offsets are relative (Sony IDC hack)
1673 0         0 delete $subdirInfo{Fixup};
1674 0         0 delete $subdirInfo{ImageData};
1675             }
1676             # is the subdirectory outside our current data?
1677 109 100 66     652 if ($subdirStart < 0 or $subdirStart + 2 > $dataLen) {
1678 15 50       62 if ($raf) {
1679             # reset SubDirectory buffer (we will load it later)
1680 15         33 my $buff = '';
1681 15         50 $subdirInfo{DataPt} = \$buff;
1682 15         45 $subdirInfo{DataLen} = 0;
1683             } else {
1684 0         0 my @err = ("Can't read $subdirName data", $inMakerNotes);
1685 0 0 0     0 if ($$subTable{VARS} and $$subTable{VARS}{MINOR_ERRORS}) {
    0          
1686 0         0 $et->Warn($err[0] . '. Ignored.');
1687             } elsif ($et->Error(@err)) {
1688 0         0 return undef;
1689             }
1690 0         0 next Entry; # don't write this directory
1691             }
1692             }
1693 109         1074 my $subdirData = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
1694 109 50       633 unless (defined $subdirData) {
1695             # WriteDirectory should have issued an error, but check just in case
1696 0 0       0 $et->Error("Error writing $subdirName") unless $$et{VALUE}{Error};
1697 0         0 return undef;
1698             }
1699             # add back original header if necessary (eg. Ricoh GR)
1700 109 0 33     473 if ($hdrLen and $hdrLen > 0 and $subdirStart <= $dataLen) {
      33        
1701 0         0 $subdirData = substr($$dataPt, $subdirStart - $hdrLen, $hdrLen) . $subdirData;
1702 0         0 $subdirInfo{Fixup}{Start} += $hdrLen;
1703             }
1704 109 100       473 unless (length $subdirData) {
1705 6 50       68 next unless $inMakerNotes;
1706             # don't delete MakerNote Sub-IFD's, write empty IFD instead
1707 0         0 $subdirData = "\0" x 6;
1708             # reset SubIFD ImageData and Fixup just to be safe
1709 0         0 delete $subdirInfo{ImageData};
1710 0         0 delete $subdirInfo{Fixup};
1711             }
1712             # handle data blocks that we will transfer later
1713 103 100       408 if (ref $subdirInfo{ImageData}) {
1714 4         9 push @imageData, @{$subdirInfo{ImageData}};
  4         12  
1715 4         13 $$origDirInfo{ImageData} = \@imageData;
1716             }
1717             # temporarily set value to subdirectory index
1718             # (will set to actual offset later when we know what it is)
1719 103         411 $newValue .= Set32u(0xfeedf00d);
1720 103         365 my ($offset, $where);
1721 103 100       353 if ($readCount > 1) {
1722 5         15 $offset = length($valBuff) + $i * 4;
1723 5         11 $where = 'valBuff';
1724             } else {
1725 98         277 $offset = length($dirBuff) + 8;
1726 98         209 $where = 'dirBuff';
1727             }
1728             # add to list of subdirectories we will append later
1729             push @subdirs, {
1730             DataPt => \$subdirData,
1731             Table => $subTable,
1732             Fixup => $subdirInfo{Fixup},
1733             Offset => $offset,
1734             Where => $where,
1735             ImageData => $subdirInfo{ImageData},
1736 103         824 };
1737 103         701 ++$writeCount; # count number of subdirs written
1738             }
1739 106 100       395 next unless length $newValue;
1740             # must change location of subdir offset if we deleted
1741             # a directory and only one remains
1742 100 50 33     398 if ($writeCount < $readCount and $writeCount == 1) {
1743 0         0 $subdirs[-1]{Where} = 'dirBuff';
1744 0         0 $subdirs[-1]{Offset} = length($dirBuff) + 8;
1745             }
1746             # set new format to int32u for IFD
1747 100   100     572 $newFormName = $$newInfo{FixFormat} || 'int32u';
1748 100         290 $newFormat = $formatNumber{$newFormName};
1749 100         296 $newValuePt = \$newValue;
1750              
1751             } elsif ((not defined $$subdir{Start} or
1752             $$subdir{Start} =~ /\$valuePtr/) and
1753             $$subdir{TagTable})
1754             {
1755             #
1756             # rewrite other existing subdirectories ('$valuePtr' type only)
1757             #
1758             # set subdirectory Start and Base
1759 336         667 my $subdirStart = $valuePtr;
1760 336 100       798 if ($$subdir{Start}) {
1761             #### eval Start ($valuePtr)
1762 4         252 $subdirStart = eval $$subdir{Start};
1763             # must adjust directory size if start changed
1764 4         28 $oldSize -= $subdirStart - $valuePtr;
1765             }
1766 336         559 my $subdirBase = $base;
1767 336 100       846 if ($$subdir{Base}) {
1768 1         4 my $start = $subdirStart + $valueDataPos;
1769             #### eval Base ($start,$base)
1770 1         41 $subdirBase += eval $$subdir{Base};
1771             }
1772 336         1475 my $subFixup = new Image::ExifTool::Fixup;
1773             my %subdirInfo = (
1774             Base => $subdirBase,
1775             DataPt => $valueDataPt,
1776             DataPos => $valueDataPos - $subdirBase + $base,
1777             DataLen => $valueDataLen,
1778             DirStart => $subdirStart,
1779             DirName => $$subdir{DirName},
1780 336         3210 DirLen => $oldSize,
1781             Parent => $dirName,
1782             Fixup => $subFixup,
1783             RAF => $raf,
1784             TagInfo => $newInfo,
1785             );
1786 336 50       924 unless ($oldSize) {
1787             # replace with dummy data if empty to prevent WriteDirectory
1788             # routines from accessing data they shouldn't
1789 0         0 my $tmp = '';
1790 0         0 $subdirInfo{DataPt} = \$tmp;
1791 0         0 $subdirInfo{DataLen} = 0;
1792 0         0 $subdirInfo{DirStart} = 0;
1793 0         0 $subdirInfo{DataPos} += $subdirStart;
1794             }
1795 336         1195 my $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable});
1796 336         1049 my $oldOrder = GetByteOrder();
1797 336 100       1022 SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder};
1798 336         2183 $newValue = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
1799 336         1484 SetByteOrder($oldOrder);
1800 336 100       995 if (defined $newValue) {
1801 274         562 my $hdrLen = $subdirStart - $valuePtr;
1802 274 100       676 if ($hdrLen) {
1803 3         47 $newValue = substr($$valueDataPt, $valuePtr, $hdrLen) . $newValue;
1804 3         28 $$subFixup{Start} += $hdrLen;
1805             }
1806 274         519 $newValuePt = \$newValue;
1807             } else {
1808 62         281 $newValuePt = \$oldValue;
1809             }
1810 336 100       1264 unless (length $$newValuePt) {
1811             # don't delete a previously empty makernote directory
1812 1 50 33     11 next if $oldSize or not $inMakerNotes;
1813             }
1814 335 100 100     1208 if ($$subFixup{Pointers} and $subdirInfo{Base} == $base) {
1815 5         11 $$subFixup{Start} += length $valBuff;
1816 5         20 push @valFixups, $subFixup;
1817             } else {
1818             # apply fixup in case we added a header ($hdrLen above)
1819 330         1412 $subFixup->ApplyFixup(\$newValue);
1820             }
1821             }
1822              
1823             } elsif ($$newInfo{OffsetPair}) {
1824             #
1825             # keep track of offsets
1826             #
1827 158   100     810 my $dataTag = $$newInfo{DataTag} || '';
1828 158 100       632 if ($dataTag eq 'CanonVRD') {
    100          
1829             # must decide now if we will write CanonVRD information
1830 10         35 my $hasVRD;
1831 10 100 33     124 if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{CanonVRD}}) {
    50          
1832             # adding or deleting as a block
1833 1 50       6 $hasVRD = $et->GetNewValue('CanonVRD') ? 1 : 0;
1834             } elsif ($$et{DEL_GROUP}{CanonVRD} or
1835             $$et{DEL_GROUP}{Trailer})
1836             {
1837 0         0 $hasVRD = 0; # deleting as a group
1838             } else {
1839 9         395 $hasVRD = ($$newValuePt ne "\0\0\0\0");
1840             }
1841 10 100       51 if ($hasVRD) {
1842             # add a fixup, and set this offset later
1843 1         8 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
1844             } else {
1845             # there is (or will soon be) no VRD information, so set pointer to zero
1846 9         45 $newValue = "\0" x length($$newValuePt);
1847 9         33 $newValuePt = \$newValue;
1848             }
1849             } elsif ($dataTag eq 'OriginalDecisionData') {
1850             # handle Canon OriginalDecisionData (no associated length tag)
1851             # - I'm going out of my way here to preserve data which is
1852             # invalidated anyway by our edits
1853 7         18 my $odd;
1854 7         62 my $oddInfo = Image::ExifTool::GetCompositeTagInfo('OriginalDecisionData');
1855 7 100 66     82 if ($oddInfo and $$et{NEW_VALUE}{$oddInfo}) {
    100          
1856 1         6 $odd = $et->GetNewValue($dataTag);
1857 1 50       5 if ($verbose > 1) {
1858 0 0       0 print $out " - $dirName:$dataTag\n" if $$newValuePt ne "\0\0\0\0";
1859 0 0       0 print $out " + $dirName:$dataTag\n" if $odd;
1860             }
1861 1         3 ++$$et{CHANGED};
1862             } elsif ($$newValuePt ne "\0\0\0\0") {
1863 1 50       4 if (length($$newValuePt) == 4) {
1864 1         15 require Image::ExifTool::Canon;
1865 1         34 my $offset = Get32u($newValuePt,0);
1866             # absolute offset in JPEG images only
1867 1 50       6 $offset += $base unless $$et{FILE_TYPE} eq 'JPEG';
1868 1         5 $odd = Image::ExifTool::Canon::ReadODD($et, $offset);
1869 1 50       6 $odd = $$odd if ref $odd;
1870             } else {
1871 0         0 $et->Error("Invalid $$newInfo{Name}",1);
1872             }
1873             }
1874 7 100       32 if ($odd) {
1875 2         7 my $newOffset = length($valBuff);
1876             # (ODD offset is absolute in JPEG, so add base offset!)
1877 2 100       10 $newOffset += $base if $$et{FILE_TYPE} eq 'JPEG';
1878 2         10 $newValue = Set32u($newOffset);
1879 2         20 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
1880 2         7 $valBuff .= $odd; # add original decision data
1881             } else {
1882 5         14 $newValue = "\0\0\0\0";
1883             }
1884 7         26 $newValuePt = \$newValue;
1885             } else {
1886 141         322 my $offsetInfo = $offsetInfo[$ifd];
1887             # save original values (for updating TIFF_END later)
1888 141         251 my @vals;
1889 141 100       412 if ($isNew <= 0) {
1890 137         458 my $oldOrder = GetByteOrder();
1891             # Minolta A200 stores these in the wrong byte order!
1892 137 50       485 SetByteOrder($$newInfo{ByteOrder}) if $$newInfo{ByteOrder};
1893 137         470 @vals = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize);
1894 137         547 SetByteOrder($oldOrder);
1895 137 100       970 $validateInfo{$newID} = [$newInfo, join(' ',@vals)] unless $$newInfo{IsOffset};
1896             }
1897             # only support int32 pointers (for now)
1898 141 0 33     510 if ($formatSize[$newFormat] != 4 and $$newInfo{IsOffset}) {
1899 0 0       0 $isNew > 0 and warn("Internal error (Offset not int32)"), return undef;
1900 0 0       0 $newCount != $readCount and warn("Wrong count!"), return undef;
1901             # change to int32
1902 0         0 $newFormName = 'int32u';
1903 0         0 $newFormat = $formatNumber{$newFormName};
1904 0         0 $newValue = WriteValue(join(' ',@vals), $newFormName, $newCount);
1905 0 0       0 unless (defined $newValue) {
1906 0         0 warn "Internal error writing offsets for $$newInfo{Name}\n";
1907 0         0 return undef;
1908             }
1909 0         0 $newValuePt = \$newValue;
1910             }
1911 141 100       489 $offsetInfo or $offsetInfo = $offsetInfo[$ifd] = { };
1912             # save location of valuePtr in new directory
1913             # (notice we add 10 instead of 8 for valuePtr because
1914             # we will put a 2-byte count at start of directory later)
1915 141         347 my $ptr = $newStart + length($dirBuff) + 10;
1916 141 50       449 $newCount or $newCount = 1; # make sure count is set for offsetInfo
1917             # save value pointer and value count for each tag
1918 141         637 $$offsetInfo{$newID} = [$newInfo, $ptr, $newCount, \@vals, $newFormat];
1919             }
1920              
1921             } elsif ($$newInfo{DataMember}) {
1922              
1923             # save any necessary data members (Make, Model, etc)
1924 272         639 my $formatStr = $newFormName;
1925 272         527 my $count = $newCount;
1926             # change to specified format if necessary
1927 272 50 33     875 if ($$newInfo{Format} and $$newInfo{Format} ne $formatStr) {
1928 0         0 $formatStr = $$newInfo{Format};
1929 0         0 my $format = $formatNumber{$formatStr};
1930             # adjust number of items for new format size
1931 0 0       0 $count = int(length($$newValuePt) / $formatSize[$format]) if $format;
1932             }
1933 272         1131 my $val = ReadValue($newValuePt,0,$formatStr,$count,length($$newValuePt));
1934 272         877 my $conv = $$newInfo{RawConv};
1935 272 50       1254 if ($conv) {
1936             # let the RawConv store the (possibly converted) data member
1937 272 50       776 if (ref $conv eq 'CODE') {
1938 0         0 &$conv($val, $et);
1939             } else {
1940 272         518 my ($priority, @grps);
1941 272         838 my ($self, $tag, $tagInfo) = ($et, $$newInfo{Name}, $newInfo);
1942             #### eval RawConv ($self, $val, $tag, $tagInfo, $priority, @grps)
1943 272         31098 eval $conv;
1944             }
1945             } else {
1946 0         0 $$et{$$newInfo{DataMember}} = $val;
1947             }
1948             }
1949             }
1950             #
1951             # write out the directory entry
1952             #
1953 5509         10403 my $newSize = length($$newValuePt);
1954 5509         9462 my $fsize = $formatSize[$newFormat];
1955 5509         7892 my $offsetVal;
1956             # set proper count
1957 5509 50 66     23671 $newCount = int(($newSize + $fsize - 1) / $fsize) unless $oldInfo and $$oldInfo{FixedSize};
1958 5509 100 100     15537 if ($saveForValidate{$newID} and $tagTablePtr eq \%Image::ExifTool::Exif::Main) {
1959 153         709 my @vals = ReadValue(\$newValue, 0, $newFormName, $newCount, $newSize);
1960 153         957 $validateInfo{$newID} = join ' ',@vals;
1961             }
1962 5509 100       10901 if ($newSize > 4) {
1963             # zero-pad to an even number of bytes (required by EXIF standard)
1964             # and make sure we are a multiple of the format size
1965 2511   100     10405 while ($newSize & 0x01 or $newSize < $newCount * $fsize) {
1966 240         706 $$newValuePt .= "\0";
1967 240         914 ++$newSize;
1968             }
1969 2511         4003 my $entryBased;
1970 2511 100 33     11673 if ($$dirInfo{EntryBased} or ($newInfo and $$newInfo{EntryBased})) {
      66        
1971 5         7 $entryBased = 1;
1972 5         17 $offsetVal = Set32u(length($valBuff) - length($dirBuff));
1973             } else {
1974 2506         7509 $offsetVal = Set32u(length $valBuff);
1975             }
1976 2511         5072 my ($dataTag, $putFirst);
1977 2511 50       8819 ($dataTag, $putFirst) = @$newInfo{'DataTag','PutFirst'} if $newInfo;
1978 2511 100       5413 if ($dataTag) {
1979 2 100 33     111 if ($dataTag eq 'PreviewImage' and ($$et{FILE_TYPE} eq 'JPEG' or
    50 66        
      33        
1980             $$et{GENERATE_PREVIEW_INFO}))
1981             {
1982             # hold onto the PreviewImage until we can determine if it fits
1983             $$et{PREVIEW_INFO} or $$et{PREVIEW_INFO} = {
1984 1 50       10 Data => $$newValuePt,
1985             Fixup => new Image::ExifTool::Fixup,
1986             };
1987 1 50       6 $$et{PREVIEW_INFO}{ChangeBase} = 1 if $$newInfo{ChangeBase};
1988 1 50 33     6 if ($$newInfo{IsOffset} and $$newInfo{IsOffset} eq '2') {
1989 0         0 $$et{PREVIEW_INFO}{NoBaseShift} = 1;
1990             }
1991             # use original preview size if we will attempt to load it later
1992 1 50       5 $newCount = $oldCount if $$newValuePt eq 'LOAD_PREVIEW';
1993 1         3 $$newValuePt = '';
1994             } elsif ($dataTag eq 'LeicaTrailer' and $$et{LeicaTrailer}) {
1995 0         0 $$newValuePt = '';
1996             }
1997             }
1998 2511 100 66     6158 if ($putFirst and $$dirInfo{HeaderPtr}) {
1999 1         6 my $hdrPtr = $$dirInfo{HeaderPtr};
2000             # place this value immediately after the TIFF header (eg. IIQ maker notes)
2001 1         8 $offsetVal = Set32u(length $$hdrPtr);
2002 1         13 $$hdrPtr .= $$newValuePt;
2003             } else {
2004 2510         6015 $valBuff .= $$newValuePt; # add value data to buffer
2005             # must save a fixup pointer for every pointer in the directory
2006 2510 100       4679 if ($entryBased) {
2007 5 100       20 $entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup;
2008 5         19 $entryBasedFixup->AddFixup(length($dirBuff) + 8, $dataTag);
2009             } else {
2010 2505         9882 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
2011             }
2012             }
2013             } else {
2014 2998         5067 $offsetVal = $$newValuePt; # save value in offset if 4 bytes or less
2015             # must pad value with zeros if less than 4 bytes
2016 2998 100       8625 $newSize < 4 and $offsetVal .= "\0" x (4 - $newSize);
2017             }
2018             # write the directory entry
2019 5509         14654 $dirBuff .= Set16u($newID) . Set16u($newFormat) .
2020             Set32u($newCount) . $offsetVal;
2021             # update flag to keep track of mandatory tags
2022 5509         16986 while (defined $allMandatory) {
2023 475 100       1652 if (defined $$mandatory{$newID}) {
2024             # values must correspond to mandatory values
2025 289   66     1389 my $form = $$newInfo{Format} || $newFormName;
2026 289         1112 my $mandVal = WriteValue($$mandatory{$newID}, $form, $newCount);
2027 289 100 66     1596 if (defined $mandVal and $mandVal eq $$newValuePt) {
2028 280         559 ++$allMandatory; # count mandatory tags
2029 280         735 last;
2030             }
2031             }
2032 195         523 undef $deleteAll;
2033 195         661 undef $allMandatory;
2034             }
2035             }
2036 379 100       1479 if (%validateInfo) {
2037 80         648 ValidateImageData($et, \%validateInfo, $dirName, 1);
2038 80         319 undef %validateInfo;
2039             }
2040 379 50       1183 if ($ignoreCount) {
2041 0 0       0 my $y = $ignoreCount > 1 ? 'ies' : 'y';
2042 0 0       0 my $verb = $$dirInfo{FixBase} ? 'Ignored' : 'Removed';
2043 0         0 $et->Warn("$verb $ignoreCount invalid entr$y from $name", 1);
2044             }
2045 379 50       1096 if ($fixCount) {
2046 0 0       0 my $s = $fixCount > 1 ? 's' : '';
2047 0         0 $et->Warn("Fixed invalid count$s for $fixCount $name tag$s", 1);
2048             }
2049             #..............................................................................
2050             # write directory counts and nextIFD pointer and add value data to end of IFD
2051             #
2052             # determine now if there is or will be another IFD after this one
2053 379         757 my $nextIfdOffset;
2054 379 100       1192 if ($dirEnd + 4 <= $dataLen) {
2055 292         967 $nextIfdOffset = Get32u($dataPt, $dirEnd);
2056             } else {
2057 87         190 $nextIfdOffset = 0;
2058             }
2059             my $isNextIFD = ($$dirInfo{Multi} and ($nextIfdOffset or
2060             # account for the case where we will create the next IFD
2061             # (IFD1 only, but not in TIFF-format images)
2062             ($dirName eq 'IFD0' and $$et{ADD_DIRS}{'IFD1'} and
2063 379   100     3122 $$et{FILE_TYPE} ne 'TIFF')));
2064             # calculate number of entries in new directory
2065 379         1122 my $newEntries = length($dirBuff) / 12;
2066             # delete entire directory if we deleted a tag and only mandatory tags remain or we
2067             # attempted to create a directory with only mandatory tags and there is no nextIFD
2068 379 100 100     4800 if ($allMandatory and not $isNextIFD and ($newEntries < $numEntries or $numEntries == 0)) {
      100        
      100        
2069 14         37 $newEntries = 0;
2070 14         40 $dirBuff = '';
2071 14         32 $valBuff = '';
2072 14         65 undef $dirFixup; # no fixups in this directory
2073 14 100       61 ++$deleteAll if defined $deleteAll;
2074 14 50       73 $verbose > 1 and print $out " - $allMandatory mandatory tag(s)\n";
2075 14         52 $$et{CHANGED} -= $addMandatory; # didn't change these after all
2076             }
2077 379 100 100     1481 if ($ifd and not $newEntries) {
2078 1 50       4 $verbose and print $out " Deleting IFD1\n";
2079 1         10 last; # don't write IFD1 if empty
2080             }
2081             # apply one-time fixup for entry-based offsets
2082 378 100       1052 if ($entryBasedFixup) {
2083 1         4 $$entryBasedFixup{Shift} = length($dirBuff) + 4;
2084 1         10 $entryBasedFixup->ApplyFixup(\$dirBuff);
2085 1         17 undef $entryBasedFixup;
2086             }
2087             # initialize next IFD pointer to zero
2088 378         1119 my $nextIFD = Set32u(0);
2089             # some cameras use a different amount of padding after the makernote IFD
2090 378 100 100     2250 if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} =~ /^(ExifIFD|IFD0)$/) {
2091 56         382 my ($rel, $pad) = Image::ExifTool::MakerNotes::GetMakerNoteOffset($et);
2092 56 100 100     691 $nextIFD = "\0" x $pad if defined $pad and ($pad==0 or ($pad>4 and $pad<=32));
      66        
2093             }
2094             # add directory entry count to start of IFD and next IFD pointer to end
2095 378         1107 $newData .= Set16u($newEntries) . $dirBuff . $nextIFD;
2096             # get position of value data in newData
2097 378         1001 my $valPos = length($newData);
2098             # go back now and set next IFD pointer if this isn't the first IFD
2099 378 100       1146 if ($nextIfdPos) {
2100             # set offset to next IFD
2101 47         274 Set32u($newStart, \$newData, $nextIfdPos);
2102 47         280 $fixup->AddFixup($nextIfdPos,'NextIFD'); # add fixup for this offset in newData
2103             }
2104             # remember position of 'next IFD' pointer so we can set it next time around
2105 378 100       1267 $nextIfdPos = length($nextIFD) ? $valPos - length($nextIFD) : undef;
2106             # add value data after IFD
2107 378         1489 $newData .= $valBuff;
2108             #
2109             # add any subdirectories, adding fixup information
2110             #
2111 378 100       1209 if (@subdirs) {
2112 120         299 my $subdir;
2113 120         376 foreach $subdir (@subdirs) {
2114 137         780 my $len = length($newData); # position of subdirectory in data
2115 137         351 my $subdirFixup = $$subdir{Fixup};
2116 137 50       433 if ($subdirFixup) {
2117 137         354 $$subdirFixup{Start} += $len;
2118 137         571 $fixup->AddFixup($subdirFixup);
2119             }
2120 137         520 my $imageData = $$subdir{ImageData};
2121 137         391 my $blockSize = 0;
2122             # must also update start position for ImageData fixups
2123 137 100       482 if (ref $imageData) {
2124 4         8 my $blockInfo;
2125 4         19 foreach $blockInfo (@$imageData) {
2126 4         16 my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo;
2127 4 50       15 if ($subFix) {
2128 4         11 $$subFix{Start} += $len;
2129             # save expected image data offset for calculating shift later
2130 4         8 $$subFix{BlockLen} = length(${$$subdir{DataPt}}) + $blockSize;
  4         13  
2131             }
2132 4         12 $blockSize += $size + $pad;
2133             }
2134             }
2135 137         278 $newData .= ${$$subdir{DataPt}}; # add subdirectory to our data
  137         894  
2136 137         323 undef ${$$subdir{DataPt}}; # free memory now
  137         460  
2137             # set the pointer
2138 137         368 my $offset = $$subdir{Offset};
2139             # if offset is in valBuff, it was added to the end of dirBuff
2140             # (plus 4 bytes for nextIFD pointer)
2141 137 100       520 $offset += length($dirBuff) + 4 if $$subdir{Where} eq 'valBuff';
2142 137         328 $offset += $newStart + 2; # get offset in newData
2143             # check to be sure we got the right offset
2144 137 50       544 unless (Get32u(\$newData, $offset) == 0xfeedf00d) {
2145 0         0 $et->Error("Internal error while rewriting $name");
2146 0         0 return undef;
2147             }
2148             # set the offset to the subdirectory data
2149 137         704 Set32u($len, \$newData, $offset);
2150 137         588 $fixup->AddFixup($offset); # add fixup for this offset in newData
2151             }
2152             }
2153             # add fixup for all offsets in directory according to value data position
2154             # (which is at the end of this directory)
2155 378 100       1185 if ($dirFixup) {
2156 365         1064 $$dirFixup{Start} = $newStart + 2;
2157 365         921 $$dirFixup{Shift} = $valPos - $$dirFixup{Start};
2158 365         1396 $fixup->AddFixup($dirFixup);
2159             }
2160             # add valueData fixups, adjusting for position of value data
2161 378         848 my $valFixup;
2162 378         1182 foreach $valFixup (@valFixups) {
2163 45         495 $$valFixup{Start} += $valPos;
2164 45         256 $fixup->AddFixup($valFixup);
2165             }
2166             # stop if no next IFD pointer
2167 378 100       3912 last unless $isNextIFD; # stop unless scanning for multiple IFD's
2168 49 100       299 if ($nextIfdOffset) {
2169             # continue with next IFD
2170 42         134 $dirStart = $nextIfdOffset - $dataPos;
2171             } else {
2172             # create IFD1 if necessary
2173 7 50       48 $verbose and print $out " Creating IFD1\n";
2174 7         28 my $ifd1 = "\0" x 2; # empty IFD1 data (zero entry count)
2175 7         20 $dataPt = \$ifd1;
2176 7         21 $dirStart = 0;
2177 7         26 $dirLen = $dataLen = 2;
2178             }
2179             # increment IFD name
2180 49 50       604 my $ifdNum = $dirName =~ s/(\d+)$// ? $1 : 0;
2181 49         220 $dirName .= $ifdNum + 1;
2182 49         240 $name =~ s/\d+$//;
2183 49         164 $name .= $ifdNum + 1;
2184 49         275 $$et{DIR_NAME} = $$et{PATH}[-1] = $dirName;
2185 49 100       294 next unless $nextIfdOffset;
2186              
2187             # guard against writing the same directory twice
2188 42         122 my $addr = $nextIfdOffset + $base;
2189 42 50       220 if ($$et{PROCESSED}{$addr}) {
2190 0         0 $et->Error("$name pointer references previous $$et{PROCESSED}{$addr} directory", 1);
2191 0         0 last;
2192             }
2193 42         175 $$et{PROCESSED}{$addr} = $name;
2194              
2195 42 50 33     233 if ($dirName eq 'SubIFD1' and not ValidateIFD($dirInfo, $dirStart)) {
2196 0 0       0 if ($$et{TIFF_TYPE} eq 'TIFF') {
    0          
2197 0         0 $et->Error('Ignored bad IFD linked from SubIFD', 1);
2198             } elsif ($verbose) {
2199 0         0 $et->Warn('Ignored bad IFD linked from SubIFD');
2200             }
2201 0         0 last; # don't write bad IFD
2202             }
2203 42 100       196 if ($$et{DEL_GROUP}{$dirName}) {
2204 1 50       6 $verbose and print $out " Deleting $dirName\n";
2205 1 50       6 $raf and $et->Error("Deleting $dirName also deletes subsequent" .
2206             " IFD's and possibly image data", 1);
2207 1         6 ++$$et{CHANGED};
2208 1 50 33     9 if ($$et{DEL_GROUP}{$dirName} == 2 and
2209             $$et{ADD_DIRS}{$dirName})
2210             {
2211 0         0 my $emptyIFD = "\0" x 2; # start with empty IFD
2212 0         0 $dataPt = \$emptyIFD;
2213 0         0 $dirStart = 0;
2214 0         0 $dirLen = $dataLen = 2;
2215             } else {
2216 1         14 last; # don't write this IFD (or any subsequent IFD)
2217             }
2218             } else {
2219 41 50       497 $verbose and print $out " Rewriting $name\n";
2220             }
2221             }
2222             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2223              
2224             # do our fixups now so we can more easily calculate offsets below
2225 331         1817 $fixup->ApplyFixup(\$newData);
2226             #
2227             # determine total block size for deferred data
2228             #
2229 331         902 my $numBlocks = scalar @imageData; # save this so we scan only existing blocks later
2230 331         821 my $blockSize = 0; # total size of blocks to copy later
2231 331         591 my $blockInfo;
2232 331         863 foreach $blockInfo (@imageData) {
2233 4         12 my ($pos, $size, $pad) = @$blockInfo;
2234 4         13 $blockSize += $size + $pad;
2235             }
2236             #
2237             # copy over image data for IFD's, starting with the last IFD first
2238             #
2239 331 100       1025 if (@offsetInfo) {
2240 60         214 my $ttwLen; # length of MRW TTW segment
2241             my @writeLater; # write image data last
2242 60         372 for ($ifd=$#offsetInfo; $ifd>=-1; --$ifd) {
2243             # build list of offsets to process
2244 162         312 my @offsetList;
2245 162 100       544 if ($ifd >= 0) {
2246 102 100       450 my $offsetInfo = $offsetInfo[$ifd] or next;
2247 70 50 66     361 if ($$offsetInfo{0x111} and $$offsetInfo{0x144}) {
2248             # SubIFD may contain double-referenced data as both strips and tiles
2249             # for Sony ARW files when SonyRawFileType is "Lossless Compressed RAW 2"
2250 0 0 0     0 if ($dirName eq 'SubIFD' and $$et{TIFF_TYPE} eq 'ARW' and
      0        
      0        
      0        
2251             $$offsetInfo{0x117} and $$offsetInfo{0x145} and
2252             $$offsetInfo{0x111}[2]==1) # (must be a single strip or the tile offsets could get out of sync)
2253             {
2254             # some Sony ARW images contain double-referenced raw data stored as both strips
2255             # and tiles. Copy the data using only the strip tags, but store the TileOffets
2256             # information for updating later (see PanasonicRaw:PatchRawDataOffset for a
2257             # description of offsetInfo elements)
2258 0         0 $$offsetInfo{0x111}[5] = $$offsetInfo{0x144}; # hack to save TileOffsets
2259             # delete tile information from offsetInfo because we will copy as strips
2260 0         0 delete $$offsetInfo{0x144};
2261 0         0 delete $$offsetInfo{0x145};
2262             } else {
2263 0         0 $et->Error("TIFF $dirName contains both strip and tile data");
2264             }
2265             }
2266             # patch Panasonic RAW/RW2 StripOffsets/StripByteCounts if necessary
2267 70         189 my $stripOffsets = $$offsetInfo{0x111};
2268 70         205 my $rawDataOffset = $$offsetInfo{0x118};
2269 70 50 100     530 if ($stripOffsets and $$stripOffsets[0]{PanasonicHack} or
      33        
      66        
2270             $rawDataOffset and $$rawDataOffset[0]{PanasonicHack})
2271             {
2272 1         11 require Image::ExifTool::PanasonicRaw;
2273 1         6 my $err = Image::ExifTool::PanasonicRaw::PatchRawDataOffset($offsetInfo, $raf, $ifd);
2274 1 50       5 $err and $et->Error($err);
2275             }
2276 70         154 my $tagID;
2277             # loop through all tags in reverse numerical order so we save thumbnail
2278             # data before main image data if both exist in the same IFD
2279 70         464 foreach $tagID (reverse sort { $a <=> $b } keys %$offsetInfo) {
  70         415  
2280 140         333 my $tagInfo = $$offsetInfo{$tagID}[0];
2281 140 100       477 next unless $$tagInfo{IsOffset}; # handle byte counts with offsets
2282 70         287 my $sizeInfo = $$offsetInfo{$$tagInfo{OffsetPair}};
2283 70 50       247 $sizeInfo or $et->Error("No size tag for $dirName:$$tagInfo{Name}"), next;
2284 70         210 my $dataTag = $$tagInfo{DataTag};
2285             # write TIFF image data (strips or tiles) later if requested
2286 70 100 100     755 if ($raf and defined $$origDirInfo{ImageData} and
      66        
      100        
      66        
      66        
2287             ($tagID == 0x111 or $tagID == 0x144 or
2288             # also defer writing of other big data such as JpgFromRaw in NEF
2289             ($$sizeInfo[3][0] and
2290             # (calculate approximate combined size of all blocks)
2291             $$sizeInfo[3][0] * scalar(@{$$sizeInfo[3]}) > 1000000)) and
2292             # but don't defer writing if replacing with new value
2293             (not defined $dataTag or not defined $offsetData{$dataTag}))
2294             {
2295 24         124 push @writeLater, [ $$offsetInfo{$tagID}, $sizeInfo ];
2296             } else {
2297 46         235 push @offsetList, [ $$offsetInfo{$tagID}, $sizeInfo ];
2298             }
2299             }
2300             } else {
2301 60 100       916 last unless @writeLater;
2302             # finally, copy all deferred data
2303 17         53 @offsetList = @writeLater;
2304             }
2305 87         192 my $offsetPair;
2306 87         230 foreach $offsetPair (@offsetList) {
2307 70         196 my ($tagInfo, $offsets, $count, $oldOffset) = @{$$offsetPair[0]};
  70         290  
2308 70         148 my ($cntInfo, $byteCounts, $count2, $oldSize, $format) = @{$$offsetPair[1]};
  70         253  
2309             # must be the same number of offset and byte count values
2310 70 50       434 unless ($count == $count2) {
2311 0         0 $et->Error("Offsets/ByteCounts disagree on count for $$tagInfo{Name}");
2312 0         0 return undef;
2313             }
2314 70         199 my $formatStr = $formatName[$format];
2315             # follow pointer to value data if necessary
2316 70 50       258 $count > 1 and $offsets = Get32u(\$newData, $offsets);
2317 70         207 my $n = $count * $formatSize[$format];
2318 70 50       230 $n > 4 and $byteCounts = Get32u(\$newData, $byteCounts);
2319 70 50 33     437 if ($byteCounts < 0 or $byteCounts + $n > length($newData)) {
2320 0         0 $et->Error("Error reading $$tagInfo{Name} byte counts");
2321 0         0 return undef;
2322             }
2323             # get offset base and data pos (abnormal for some preview images)
2324 70         172 my ($dbase, $dpos, $wrongBase, $subIfdDataFixup);
2325 70 100       260 if ($$tagInfo{IsOffset} eq '2') {
2326 2         6 $dbase = $firstBase;
2327 2         6 $dpos = $dataPos + $base - $firstBase;
2328             } else {
2329 68         168 $dbase = $base;
2330 68         153 $dpos = $dataPos;
2331             }
2332             # use different base if necessary for some offsets (Minolta A200)
2333 70 50       245 if ($$tagInfo{WrongBase}) {
2334 0         0 my $self = $et;
2335             #### eval WrongBase ($self)
2336 0   0     0 $wrongBase = eval $$tagInfo{WrongBase} || 0;
2337 0         0 $dbase += $wrongBase;
2338 0         0 $dpos -= $wrongBase;
2339             } else {
2340 70         167 $wrongBase = 0;
2341             }
2342 70         284 my $oldOrder = GetByteOrder();
2343 70         221 my $dataTag = $$tagInfo{DataTag};
2344             # use different byte order for values of this offset pair if required (Minolta A200)
2345 70 50       266 SetByteOrder($$tagInfo{ByteOrder}) if $$tagInfo{ByteOrder};
2346             # transfer the data referenced by all offsets of this tag
2347 70         308 for ($n=0; $n<$count; ++$n) {
2348 70         145 my ($oldEnd, $size);
2349 70 100 66     450 if (@$oldOffset and @$oldSize) {
2350             # calculate end offset of this block
2351 68         194 $oldEnd = $$oldOffset[$n] + $$oldSize[$n];
2352             # update TIFF_END as if we read this data from file
2353 68         313 UpdateTiffEnd($et, $oldEnd + $dbase);
2354             }
2355 70         252 my $offsetPos = $offsets + $n * 4;
2356 70         211 my $byteCountPos = $byteCounts + $n * $formatSize[$format];
2357 70 100       234 if ($$tagInfo{PanasonicHack}) {
2358             # use actual raw data length (may be different than StripByteCounts!)
2359 1         12 $size = $$oldSize[$n];
2360             } else {
2361             # use size of new data
2362 69         294 $size = ReadValue(\$newData, $byteCountPos, $formatStr, 1, 4);
2363             }
2364 70         272 my $offset = $$oldOffset[$n];
2365 70 100       249 if (defined $offset) {
    50          
2366 68         176 $offset -= $dpos;
2367             } elsif ($size != 0xfeedfeed) {
2368 0         0 $et->Error('Internal error (no offset)');
2369 0         0 return undef;
2370             }
2371 70         179 my $newOffset = length($newData) - $wrongBase;
2372 70         152 my $buff;
2373             # look for 'feed' code to use our new data
2374 70 100 66     713 if ($size == 0xfeedfeed) {
    100 66        
    100 66        
    50 33        
    100 33        
    50 33        
    50          
2375 4 50       21 unless (defined $dataTag) {
2376 0         0 $et->Error("No DataTag defined for $$tagInfo{Name}");
2377 0         0 return undef;
2378             }
2379 4 50       34 unless (defined $offsetData{$dataTag}) {
2380 0         0 $et->Error("Internal error (no $dataTag)");
2381 0         0 return undef;
2382             }
2383 4 50       26 if ($count > 1) {
2384 0         0 $et->Error("Can't modify $$tagInfo{Name} with count $count");
2385 0         0 return undef;
2386             }
2387 4         14 $buff = $offsetData{$dataTag};
2388 4 50       22 if ($formatSize[$format] != 4) {
2389 0         0 $et->Error("$$cntInfo{Name} is not int32");
2390 0         0 return undef;
2391             }
2392             # set the data size
2393 4         11 $size = length($buff);
2394 4         21 Set32u($size, \$newData, $byteCountPos);
2395             } elsif ($ifd < 0) {
2396             # hack for fixed-offset data (Panasonic GH6)
2397 24 50       106 if ($$offsetPair[0][6]) {
2398 0 0       0 if ($count > 1) {
2399 0         0 $et->Error("Can't handle fixed offsets with count > 1");
2400             } else {
2401 0         0 my $fixedOffset = Get32u(\$newData, $offsets);
2402 0         0 my $padToFixedOffset = $fixedOffset - ($newOffset + $dpos);
2403 0 0       0 if ($padToFixedOffset < 0) {
2404 0         0 $et->Error('Metadata too large to fit before fixed-offset image data');
2405             } else {
2406             # add necessary padding before raw data
2407 0         0 push @imageData, [$offset+$dbase+$dpos, 0, $padToFixedOffset];
2408 0         0 $newOffset += $padToFixedOffset;
2409 0         0 $et->Warn("Adding $padToFixedOffset bytes of padding before fixed-offset image data", 1);
2410             }
2411             }
2412             }
2413             # pad if necessary (but don't pad contiguous image blocks)
2414 24         56 my $pad = 0;
2415 24 0 33     108 ++$pad if ($blockSize + $size) & 0x01 and ($n+1 >= $count or
      66        
2416             not $oldEnd or $oldEnd != $$oldOffset[$n+1]);
2417             # preserve original image padding if specified
2418 24 0 66     122 if ($$origDirInfo{PreserveImagePadding} and $n+1 < $count and
      33        
      33        
2419             $oldEnd and $$oldOffset[$n+1] > $oldEnd)
2420             {
2421 0         0 $pad = $$oldOffset[$n+1] - $oldEnd;
2422             }
2423             # copy data later
2424 24         80 push @imageData, [$offset+$dbase+$dpos, $size, $pad];
2425 24         55 $newOffset += $blockSize; # data comes after other deferred data
2426             # create fixup for SubIFD ImageData
2427 24 100 66     112 if ($imageDataFlag eq 'SubIFD' and not $subIfdDataFixup) {
2428 4         23 $subIfdDataFixup = new Image::ExifTool::Fixup;
2429 4         16 $imageData[-1][4] = $subIfdDataFixup;
2430             }
2431 24         81 $size += $pad; # account for pad byte if necessary
2432             # return ImageData list
2433 24         72 $$origDirInfo{ImageData} = \@imageData;
2434             } elsif ($offset >= 0 and $offset+$size <= $dataLen) {
2435             # take data from old dir data buffer
2436 37         216 $buff = substr($$dataPt, $offset, $size);
2437             } elsif ($$et{TIFF_TYPE} eq 'MRW') {
2438             # TTW segment must be an even 4 bytes long, so pad now if necessary
2439 0         0 my $n = length $newData;
2440 0 0       0 $buff = ($n & 0x03) ? "\0" x (4 - ($n & 0x03)) : '';
2441 0         0 $size = length($buff);
2442             # data exists after MRW TTW segment
2443 0 0       0 $ttwLen = length($newData) + $size unless defined $ttwLen;
2444 0         0 $newOffset = $offset + $dpos + $ttwLen - $dataLen;
2445             } elsif ($raf and $raf->Seek($offset+$dbase+$dpos,0) and
2446             $raf->Read($buff,$size) == $size)
2447             {
2448             # (data was read OK)
2449             # patch incorrect ThumbnailOffset in Sony A100 1.00 ARW images
2450 4 0 33     39 if ($$et{TIFF_TYPE} eq 'ARW' and $$tagInfo{Name} eq 'ThumbnailOffset' and
      33        
      0        
2451             $$et{Model} eq 'DSLR-A100' and $buff !~ /^\xff\xd8\xff/)
2452             {
2453 0         0 my $pos = $offset + $dbase + $dpos;
2454 0         0 my $try;
2455 0 0 0     0 if ($pos < 0x10000 and $raf->Seek($pos+0x10000,0) and
      0        
      0        
2456             $raf->Read($try,$size) == $size and $try =~ /^\xff\xd8\xff/)
2457             {
2458 0         0 $buff = $try;
2459 0         0 $et->Warn('Adjusted incorrect A100 ThumbnailOffset', 1);
2460             } else {
2461 0         0 $et->Error('Invalid ThumbnailImage');
2462             }
2463             }
2464             } elsif ($$tagInfo{Name} eq 'ThumbnailOffset' and $offset>=0 and $offset<$dataLen) {
2465             # Grrr. The Canon 350D writes the thumbnail with an incorrect byte count
2466 0         0 my $diff = $offset + $size - $dataLen;
2467 0         0 $et->Warn("ThumbnailImage runs outside EXIF data by $diff bytes (truncated)",1);
2468             # set the size to the available data
2469 0         0 $size -= $diff;
2470 0 0       0 unless (WriteValue($size, $formatStr, 1, \$newData, $byteCountPos)) {
2471 0         0 warn 'Internal error writing thumbnail size';
2472             }
2473             # get the truncated image
2474 0         0 $buff = substr($$dataPt, $offset, $size);
2475             } elsif ($$tagInfo{Name} eq 'PreviewImageStart' and $$et{FILE_TYPE} eq 'JPEG') {
2476             # try to load the preview image using the specified offset
2477 1         3 undef $buff;
2478 1         4 my $r = $$et{RAF};
2479 1 50 33     8 if ($r and not $raf) {
2480 1         7 my $tell = $r->Tell();
2481             # read and validate
2482 1 50 33     6 undef $buff unless $r->Seek($offset+$base+$dataPos,0) and
      33        
2483             $r->Read($buff,$size) == $size and
2484             $buff =~ /^.\xd8\xff[\xc4\xdb\xe0-\xef]/s;
2485 1 50       5 $r->Seek($tell, 0) or $et->Error('Seek error'), return undef;
2486             }
2487             # set flag if we must load PreviewImage
2488 1 50       6 $buff = 'LOAD_PREVIEW' unless defined $buff;
2489             } else {
2490 0   0     0 my $dataName = $dataTag || $$tagInfo{Name};
2491 0 0       0 return undef if $et->Error("Error reading $dataName data in $name", $inMakerNotes);
2492 0         0 $buff = '';
2493             }
2494 70 100       354 if ($$tagInfo{Name} eq 'PreviewImageStart') {
2495 14 100 66     178 if ($$et{FILE_TYPE} eq 'JPEG' and not $$tagInfo{MakerPreview}) {
    50 33        
2496             # hold onto the PreviewImage until we can determine if it fits
2497             $$et{PREVIEW_INFO} or $$et{PREVIEW_INFO} = {
2498 8 100       71 Data => $buff,
2499             Fixup => new Image::ExifTool::Fixup,
2500             };
2501 8 100 66     96 if ($$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '2') {
2502 2         13 $$et{PREVIEW_INFO}{NoBaseShift} = 1;
2503             }
2504 8 100 66     64 if ($offset >= 0 and $offset+$size <= $dataLen) {
2505             # set flag indicating this preview wasn't in a trailer
2506 7         22 $$et{PREVIEW_INFO}{WasContained} = 1;
2507             }
2508 8         33 $buff = '';
2509             } elsif ($$et{TIFF_TYPE} eq 'ARW' and $$et{Model} eq 'DSLR-A100') {
2510             # the A100 double-references the same preview, so ignore the
2511             # second one (the offset and size will be patched later)
2512 0 0       0 next if $$et{A100PreviewLength};
2513 0 0       0 $$et{A100PreviewLength} = length $buff if defined $buff;
2514             }
2515             }
2516             # update offset accordingly and add to end of new data
2517 70         348 Set32u($newOffset, \$newData, $offsetPos);
2518             # add a pointer to fix up this offset value (marked with DataTag name)
2519 70         444 $fixup->AddFixup($offsetPos, $dataTag);
2520             # also add to subIfdDataFixup if necessary
2521 70 100       324 $subIfdDataFixup->AddFixup($offsetPos, $dataTag) if $subIfdDataFixup;
2522             # must also (sometimes) update StripOffsets in Panasonic RW2 images
2523             # and TileOffsets in Sony ARW images
2524 70         226 my $otherPos = $$offsetPair[0][5];
2525 70 50       279 if ($otherPos) {
2526 0 0       0 if ($$tagInfo{PanasonicHack}) {
    0          
2527 0         0 Set32u($newOffset, \$newData, $otherPos);
2528 0         0 $fixup->AddFixup($otherPos, $dataTag);
2529             } elsif (ref $otherPos eq 'ARRAY') {
2530             # the image data was copied as one large strip, and is double-referenced
2531             # as tile data, so all we need to do now is properly update the tile offsets
2532 0         0 my $oldRawDataOffset = $$offsetPair[0][3][0];
2533 0         0 my $count = $$otherPos[2];
2534 0         0 my $i;
2535             # point to offsets in value data if more than one pointer
2536 0 0       0 $$otherPos[1] = Get32u(\$newData, $$otherPos[1]) if $count > 1;
2537 0         0 for ($i=0; $i<$count; ++$i) {
2538 0         0 my $oldTileOffset = $$otherPos[3][$i];
2539 0         0 my $ptrPos = $$otherPos[1] + 4 * $i;
2540 0         0 Set32u($newOffset + $oldTileOffset - $oldRawDataOffset, \$newData, $ptrPos);
2541 0         0 $fixup->AddFixup($ptrPos, $dataTag);
2542 0 0       0 $subIfdDataFixup->AddFixup($ptrPos, $dataTag) if $subIfdDataFixup;
2543             }
2544             }
2545             }
2546 70 100       255 if ($ifd >= 0) {
2547             # buff length must be even (Note: may have changed since $size was set)
2548 46 100       230 $buff .= "\0" if length($buff) & 0x01;
2549 46         273 $newData .= $buff; # add this strip to the data
2550             } else {
2551 24         88 $blockSize += $size; # keep track of total size
2552             }
2553             }
2554 70         255 SetByteOrder($oldOrder);
2555             }
2556             }
2557             # verify that nothing else got written after determining TTW length
2558 60 50 33     339 if (defined $ttwLen and $ttwLen != length($newData)) {
2559 0         0 $et->Error('Internal error writing MRW TTW');
2560             }
2561             }
2562             #
2563             # set offsets and generate fixups for tag values which were too large for memory
2564             #
2565 331         746 $blockSize = 0;
2566 331         895 foreach $blockInfo (@imageData) {
2567 28         106 my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo;
2568 28 50       96 if (defined $entry) {
2569 0         0 my $format = Get16u(\$newData, $entry + 2);
2570 0 0 0     0 if ($format < 1 or $format > 13) {
2571 0         0 $et->Error('Internal error copying huge value');
2572 0         0 last;
2573             } else {
2574             # set count and offset in directory entry
2575 0         0 Set32u($size / $formatSize[$format], \$newData, $entry + 4);
2576 0         0 Set32u(length($newData)+$blockSize, \$newData, $entry + 8);
2577 0         0 $fixup->AddFixup($entry + 8);
2578             # create special fixup for SubIFD data
2579 0 0       0 if ($imageDataFlag eq 'SubIFD') {
2580 0         0 my $subIfdDataFixup = new Image::ExifTool::Fixup;
2581 0         0 $subIfdDataFixup->AddFixup($entry + 8);
2582             # save fixup in imageData list
2583 0         0 $$blockInfo[4] = $subIfdDataFixup;
2584             }
2585             # must reset entry pointer so we don't use it again in a parent IFD!
2586 0         0 $$blockInfo[3] = undef;
2587             }
2588             }
2589             # apply additional shift required for contained SubIFD image data offsets
2590 28 100 100     142 if ($subFix and defined $$subFix{BlockLen} and $numBlocks > 0) {
      66        
2591             # our offset expects the data at the end of the SubIFD block (BlockLen + Start),
2592             # but it will actually be at length($newData) + $blockSize. So adjust
2593             # accordingly (and subtract an extra Start because this shift is applied later)
2594 4         25 $$subFix{Shift} += length($newData) - $$subFix{BlockLen} - 2 * $$subFix{Start} + $blockSize;
2595 4         13 $subFix->ApplyFixup(\$newData);
2596             }
2597 28         66 $blockSize += $size + $pad;
2598 28         66 --$numBlocks;
2599             }
2600             #
2601             # apply final shift to new data position if this is the top level IFD
2602             #
2603 331 100       1306 unless ($$dirInfo{Fixup}) {
2604 124         537 my $hdrPtr = $$dirInfo{HeaderPtr};
2605 124 100 50     598 my $newDataPos = $hdrPtr ? length $$hdrPtr : $$dirInfo{NewDataPos} || 0;
2606             # adjust CanonVRD offset to point to end of regular TIFF if necessary
2607             # (NOTE: This will be incorrect if multiple trailers exist,
2608             # but it is unlikely that it could ever be correct in this case anyway.
2609             # Also, this doesn't work for JPEG images (but CanonDPP doesn't set
2610             # this when editing JPEG images anyway))
2611 124         1045 $fixup->SetMarkerPointers(\$newData, 'CanonVRD', length($newData) + $blockSize);
2612 124 50       489 if ($newDataPos) {
2613 124         380 $$fixup{Shift} += $newDataPos;
2614 124         647 $fixup->ApplyFixup(\$newData);
2615             }
2616             # save fixup for adjusting Leica trailer offset if necessary
2617 124 50       1001 $$et{LeicaTrailer}{Fixup}->AddFixup($fixup) if $$et{LeicaTrailer};
2618             # save fixup for PreviewImage in JPEG file if necessary
2619 124         434 my $previewInfo = $$et{PREVIEW_INFO};
2620 124 100 66     1291 if ($previewInfo) {
    100          
    50          
2621 6         25 my $pt = \$$previewInfo{Data}; # image data or 'LOAD_PREVIEW' flag
2622             # now that we know the size of the EXIF data, first test to see if our new image fits
2623             # inside the EXIF segment (remember about the TIFF and EXIF headers: 8+6 bytes)
2624 6 100 66     179 if (($$pt ne 'LOAD_PREVIEW' and length($$pt) + length($newData) + 14 <= 0xfffd and
      66        
      66        
2625             not $$previewInfo{IsTrailer}) or
2626             $$previewInfo{IsShort}) # must fit in this segment if using short pointers
2627             {
2628             # It fits! (or must exist in EXIF segment), so fixup the
2629             # PreviewImage pointers and stuff the preview image in here
2630 5         18 my $newPos = length($newData) + $newDataPos;
2631 5   50     38 $newPos += ($$previewInfo{BaseShift} || 0);
2632 5 50       22 if ($$previewInfo{Relative}) {
2633             # calculate our base by looking at how far the pointer got shifted
2634 0   0     0 $newPos -= ($fixup->GetMarkerPointers(\$newData, 'PreviewImage') || 0);
2635             }
2636 5         30 $fixup->SetMarkerPointers(\$newData, 'PreviewImage', $newPos);
2637 5         23 $newData .= $$pt;
2638             # set flag to delete old preview unless it was contained in the EXIF
2639 5 50       54 $$et{DEL_PREVIEW} = 1 unless $$et{PREVIEW_INFO}{WasContained};
2640 5         19 delete $$et{PREVIEW_INFO}; # done with our preview data
2641             } else {
2642             # Doesn't fit, or we still don't know, so save fixup information
2643             # and put the preview at the end of the file
2644 1 50       4 $$previewInfo{Fixup} or $$previewInfo{Fixup} = new Image::ExifTool::Fixup;
2645 1         7 $$previewInfo{Fixup}->AddFixup($fixup);
2646             }
2647             } elsif (defined $newData and $deleteAll) {
2648 6         25 $newData = ''; # delete both IFD0 and IFD1 since only mandatory tags remain
2649             } elsif ($$et{A100PreviewLength}) {
2650             # save preview image start for patching A100 quirks later
2651 0         0 $$et{A100PreviewStart} = $fixup->GetMarkerPointers(\$newData, 'PreviewImage');
2652             }
2653             # save location of last IFD for use in Canon RAW header
2654 124 100       563 if ($newDataPos == 16) {
2655 6         45 my @ifdPos = $fixup->GetMarkerPointers(\$newData,'NextIFD');
2656 6         32 $$origDirInfo{LastIFD} = pop @ifdPos;
2657             }
2658             # recrypt SR2 SubIFD data if necessary
2659 124         397 my $key = $$et{SR2SubIFDKey};
2660 124 50       447 if ($key) {
2661 0         0 my $start = $fixup->GetMarkerPointers(\$newData, 'SR2SubIFDOffset');
2662 0         0 my $len = $$et{SR2SubIFDLength};
2663             # (must subtract 8 for size of TIFF header)
2664 0 0 0     0 if ($start and $start - 8 + $len <= length $newData) {
2665 0         0 require Image::ExifTool::Sony;
2666 0         0 Image::ExifTool::Sony::Decrypt(\$newData, $start - 8, $len, $key);
2667             }
2668             }
2669             }
2670             # return empty string if no entries in directory
2671             # (could be up to 10 bytes and still be empty)
2672 331 100 66     1770 $newData = '' if defined $newData and length($newData) < 12;
2673              
2674             # set changed if ForceWrite tag was set to "EXIF"
2675 331 50 66     2469 ++$$et{CHANGED} if defined $newData and length $newData and $$et{FORCE_WRITE}{EXIF};
      66        
2676              
2677 331         3503 return $newData; # return our directory data
2678             }
2679              
2680             1; # end
2681              
2682             __END__