exiftool_vendored 12.68.0 → 12.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +98 -15
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +10 -10
  7. data/bin/exiftool +32 -25
  8. data/bin/lib/Image/ExifTool/AAC.pm +175 -0
  9. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
  10. data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
  11. data/bin/lib/Image/ExifTool/Canon.pm +87 -20
  12. data/bin/lib/Image/ExifTool/DJI.pm +3 -2
  13. data/bin/lib/Image/ExifTool/DNG.pm +25 -2
  14. data/bin/lib/Image/ExifTool/EXE.pm +54 -6
  15. data/bin/lib/Image/ExifTool/Exif.pm +204 -22
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
  17. data/bin/lib/Image/ExifTool/GIF.pm +5 -1
  18. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  19. data/bin/lib/Image/ExifTool/ID3.pm +76 -10
  20. data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
  21. data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
  22. data/bin/lib/Image/ExifTool/JSON.pm +4 -1
  23. data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  24. data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
  25. data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
  26. data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
  27. data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
  28. data/bin/lib/Image/ExifTool/PNG.pm +8 -13
  29. data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
  30. data/bin/lib/Image/ExifTool/Pentax.pm +15 -6
  31. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
  32. data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
  33. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
  34. data/bin/lib/Image/ExifTool/README +14 -5
  35. data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
  36. data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
  37. data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
  38. data/bin/lib/Image/ExifTool/Sony.pm +177 -37
  39. data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
  40. data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
  41. data/bin/lib/Image/ExifTool/Text.pm +4 -5
  42. data/bin/lib/Image/ExifTool/Validate.pm +23 -20
  43. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  44. data/bin/lib/Image/ExifTool/WriteExif.pl +33 -8
  45. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  46. data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  47. data/bin/lib/Image/ExifTool/Writer.pl +121 -28
  48. data/bin/lib/Image/ExifTool/XMP.pm +67 -2
  49. data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
  50. data/bin/lib/Image/ExifTool.pm +94 -43
  51. data/bin/lib/Image/ExifTool.pod +28 -17
  52. data/bin/perl-Image-ExifTool.spec +9 -9
  53. data/lib/exiftool_vendored/version.rb +1 -1
  54. metadata +3 -2
@@ -25,11 +25,10 @@ $VERSION = '1.04';
25
25
  Although basic text files contain no metadata, the following tags are
26
26
  determined from a simple analysis of the data in TXT and CSV files.
27
27
  Statistics are generated only for 8-bit encodings, but the L<FastScan|../ExifTool.html#FastScan> (-fast)
28
- option may be used to limit processing to the first 64 kB in which case some
29
- tags are not produced. To avoid long processing delays, ExifTool will issue
30
- a minor warning and process only the first 64 kB of any file larger than 20
31
- MB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m)
32
- option is used.
28
+ option may be used to limit processing to the first 64 KiB in which case
29
+ some tags are not produced. To avoid long processing delays, ExifTool will
30
+ issue a minor warning and process only the first 64 KiB of any file larger
31
+ than 20 MiB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m) option is used.
33
32
  },
34
33
  MIMEEncoding => { Groups => { 2 => 'Other' } },
35
34
  Newlines => {
@@ -17,7 +17,7 @@ package Image::ExifTool::Validate;
17
17
  use strict;
18
18
  use vars qw($VERSION %exifSpec);
19
19
 
20
- $VERSION = '1.21';
20
+ $VERSION = '1.23';
21
21
 
22
22
  use Image::ExifTool qw(:Utils);
23
23
  use Image::ExifTool::Exif;
@@ -86,7 +86,7 @@ my %verCheck = (
86
86
  GPS => { GPSVersionID => \%gpsVer },
87
87
  );
88
88
 
89
- # tags standard in various RAW file formats
89
+ # tags standard in various RAW file formats or IFD's
90
90
  my %otherSpec = (
91
91
  CR2 => { 0xc5d8 => 1, 0xc5d9 => 1, 0xc5e0 => 1, 0xc640 => 1, 0xc6dc => 1, 0xc6dd => 1 },
92
92
  NEF => { 0x9216 => 1, 0x9217 => 1 },
@@ -103,6 +103,7 @@ my %otherSpec = (
103
103
  SRW => { 0xa010 => 1, 0xa011 => 1, 0xa101 => 1, 0xa102 => 1 },
104
104
  NRW => { 0x9216 => 1, 0x9217 => 1 },
105
105
  X3F => { 0xa500 => 1 },
106
+ CameraIFD => { All => 1 }, # (exists in JPG and DNG of Leica Q3 images)
106
107
  );
107
108
 
108
109
  # standard format for tags (not necessary for exifSpec or GPS tags where Writable is defined)
@@ -142,20 +143,22 @@ my %stdFormat = (
142
143
  # GeoTiff tags:
143
144
  0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string',
144
145
  0x8480 => 'double', 0x85d8 => 'double', 0x87b0 => 'double',
145
- # DNG tags:
146
- 0xc615 => '(string|int8u)', 0xc6d3 => '',
147
- 0xc61a => '(int16u|int32u|rational64u)', 0xc6f4 => '(string|int8u)',
148
- 0xc61d => 'int(16|32)u', 0xc6f6 => '(string|int8u)',
149
- 0xc61f => '(int16u|int32u|rational64u)', 0xc6f8 => '(string|int8u)',
150
- 0xc620 => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
151
- 0xc628 => '(int16u|rational64u)', 0xc716 => '(string|int8u)',
152
- 0xc634 => 'int8u', 0xc717 => '(string|int8u)',
153
- 0xc640 => '', 0xc718 => '(string|int8u)',
154
- 0xc660 => '', 0xc71e => 'int(16|32)u',
155
- 0xc68b => '(string|int8u)', 0xc71f => 'int(16|32)u',
156
- 0xc68d => 'int(16|32)u', 0xc791 => 'int(16|32)u',
157
- 0xc68e => 'int(16|32)u', 0xc792 => 'int(16|32)u',
158
- 0xc6d2 => '', 0xc793 => '(int16u|int32u|rational64u)',
146
+ # DNG tags: (use '' for non-DNG tags in the range 0xc612-0xcd48)
147
+ 0xc615 => '(string|int8u)', 0xc6f4 => '(string|int8u)',
148
+ 0xc61a => '(int16u|int32u|rational64u)', 0xc6f6 => '(string|int8u)',
149
+ 0xc61d => 'int(16|32)u', 0xc6f8 => '(string|int8u)',
150
+ 0xc61f => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
151
+ 0xc620 => '(int16u|int32u|rational64u)', 0xc716 => '(string|int8u)',
152
+ 0xc628 => '(int16u|rational64u)', 0xc717 => '(string|int8u)',
153
+ 0xc634 => 'int8u', 0xc718 => '(string|int8u)',
154
+ 0xc640 => '', 0xc71e => 'int(16|32)u',
155
+ 0xc660 => '', 0xc71f => 'int(16|32)u',
156
+ 0xc68b => '(string|int8u)', 0xc791 => 'int(16|32)u',
157
+ 0xc68d => 'int(16|32)u', 0xc792 => 'int(16|32)u',
158
+ 0xc68e => 'int(16|32)u', 0xc793 => '(int16u|int32u|rational64u)',
159
+ 0xc6d2 => '', 0xcd43 => 'int(16|32)u',
160
+ 0xc6d3 => '', 0xcd48 => '(string|int8u)',
161
+
159
162
  # Exif 3.0 spec
160
163
  0x10e => 'string|utf8', 0xa430 => 'string|utf8', 0xa439 => 'string|utf8',
161
164
  0x10f => 'string|utf8', 0xa433 => 'string|utf8', 0xa43a => 'string|utf8',
@@ -430,7 +433,7 @@ sub ValidateExif($$$$$$$$)
430
433
  my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD};
431
434
  if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and
432
435
  ($exifSpec{$tag} or $$stdFmt{$tag} or
433
- ($tag >= 0xc612 and $tag <= 0xc7b5 and not defined $$stdFmt{$tag}))) or # (DNG tags)
436
+ ($tag >= 0xc612 and $tag <= 0xcd48 and not defined $$stdFmt{$tag}))) or # (DNG tags)
434
437
  $$tagTablePtr{SHORT_NAME} eq 'GPS::Main')
435
438
  {
436
439
  my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP};
@@ -456,8 +459,8 @@ sub ValidateExif($$$$$$$$)
456
459
  } elsif (not $otherSpec{$$et{FileType}} or
457
460
  (not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
458
461
  {
459
- if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$tagInfo{Unknown}) {
460
- $et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1);
462
+ if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$ti{Unknown}) {
463
+ $et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1) unless $otherSpec{$ifd};
461
464
  }
462
465
  }
463
466
  # change expected count from read Format to Writable size
@@ -478,7 +481,7 @@ sub ValidateExif($$$$$$$$)
478
481
  } elsif (not $otherSpec{$$et{FileType}} or
479
482
  (not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
480
483
  {
481
- $et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1);
484
+ $et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1) unless $otherSpec{$ifd};
482
485
  }
483
486
  }
484
487
 
@@ -142,7 +142,6 @@ sub SaveMakerNotes($)
142
142
  }
143
143
  # save position of maker notes for pointer fixups
144
144
  $fixup->{Shift} += length($makerNotes);
145
- $$et{MAKER_NOTE_FIXUP} = $fixup;
146
145
  $$et{MAKER_NOTE_BYTE_ORDER} = GetByteOrder();
147
146
  # add value data
148
147
  $makerNotes .= $makerInfo->{ValBuff};
@@ -150,7 +149,8 @@ sub SaveMakerNotes($)
150
149
  my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Exif::Main');
151
150
  my $tagInfo = $et->GetTagInfo($tagTablePtr, 0x927c, \$makerNotes);
152
151
  # save the MakerNotes
153
- $et->FoundTag($tagInfo, $makerNotes);
152
+ my $key = $et->FoundTag($tagInfo, $makerNotes);
153
+ $$et{TAG_EXTRA}{$key}{Fixup} = $fixup;
154
154
  # save the garbage collection some work later
155
155
  delete $makerInfo->{Entries};
156
156
  delete $makerInfo->{ValBuff};
@@ -569,6 +569,7 @@ sub WriteExif($$$)
569
569
  my $imageDataFlag = $$dirInfo{ImageData} || '';
570
570
  my $verbose = $et->Options('Verbose');
571
571
  my $out = $et->Options('TextOut');
572
+ my $noMandatory = $et->Options('NoMandatory');
572
573
  my ($nextIfdPos, %offsetData, $inMakerNotes);
573
574
  my (@offsetInfo, %validateInfo, %xDelete, $strEnc);
574
575
  my $deleteAll = 0;
@@ -698,8 +699,8 @@ sub WriteExif($$$)
698
699
  }
699
700
 
700
701
  # initialize variables to handle mandatory tags
701
- my $mandatory = $mandatory{$dirName};
702
- my ($allMandatory, $addMandatory);
702
+ my ($mandatory, $allMandatory, $addMandatory);
703
+ $mandatory = $mandatory{$dirName} unless $noMandatory;
703
704
  if ($mandatory) {
704
705
  # use X/Y resolution values from JFIF if available
705
706
  if ($dirName eq 'IFD0' and defined $$et{JFIFYResolution}) {
@@ -930,8 +931,16 @@ Entry: for (;;) {
930
931
  }
931
932
  }
932
933
  unless ($success) {
933
- return undef if $et->Error("Error reading value for $name entry $index", $inMakerNotes);
934
- ++$index; $oldID = $newID; next; # drop this tag
934
+ my $wrn = sprintf("Error reading value for $name entry $index, ID 0x%.4x", $oldID);
935
+ my $truncOK;
936
+ if ($oldInfo and not $$oldInfo{Unknown}) {
937
+ $wrn .= " $$oldInfo{Name}";
938
+ $truncOK = $$oldInfo{TruncateOK};
939
+ }
940
+ return undef if $et->Error($wrn, $inMakerNotes || $truncOK);
941
+ unless ($truncOK) {
942
+ ++$index; $oldID = $newID; next; # drop this tag
943
+ }
935
944
  }
936
945
  } elsif (not $invalidPreview) {
937
946
  return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
@@ -1094,6 +1103,8 @@ Entry: for (;;) {
1094
1103
  # add, edit or delete this tag
1095
1104
  shift @newTags; # remove from list
1096
1105
  my $curInfo = $set{$newID};
1106
+ # don't allow MakerNotes to be added to ExifIFD of CR3 file
1107
+ next if $newID == 0x927c and $isNew > 0 and $$et{FileType} eq 'CR3';
1097
1108
  unless ($curInfo or $$addDirs{$newID}) {
1098
1109
  # we can finally get the specific tagInfo reference for this tag
1099
1110
  # (because we can now evaluate the Condition statement since all
@@ -1142,7 +1153,7 @@ Entry: for (;;) {
1142
1153
  }
1143
1154
  my $nvHash;
1144
1155
  $nvHash = $et->GetNewValueHash($curInfo, $dirName) if $isNew >= 0;
1145
- unless ($nvHash or defined $$mandatory{$newID}) {
1156
+ unless ($nvHash or (defined $$mandatory{$newID} and not $noMandatory)) {
1146
1157
  goto NoWrite unless $wrongDir; # GOTO !
1147
1158
  # delete stuff from the wrong directory if setting somewhere else
1148
1159
  $nvHash = $et->GetNewValueHash($curInfo, $wrongDir);
@@ -1429,8 +1440,8 @@ NoOverwrite: next if $isNew > 0;
1429
1440
  if ($$et{DEL_GROUP}{MakerNotes} and
1430
1441
  ($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
1431
1442
  {
1432
- if ($et->IsRawType()) {
1433
- $et->WarnOnce("Can't delete MakerNotes from $$et{FileType}",1);
1443
+ if ($et->IsRawType() and not ($et->IsRawType() == 2 and $dirName eq 'ExifIFD')) {
1444
+ $et->Warn("Can't delete MakerNotes from $$et{FileType}",1);
1434
1445
  } else {
1435
1446
  if ($isNew <= 0) {
1436
1447
  ++$$et{CHANGED};
@@ -2225,6 +2236,19 @@ NoOverwrite: next if $isNew > 0;
2225
2236
 
2226
2237
  # do our fixups now so we can more easily calculate offsets below
2227
2238
  $fixup->ApplyFixup(\$newData);
2239
+ # write Sony HiddenData now if this is an ARW file
2240
+ if ($$et{HiddenData} and not $$dirInfo{Fixup} and $$et{FILE_TYPE} eq 'TIFF') {
2241
+ $fixup->SetMarkerPointers(\$newData, 'HiddenData', length($newData));
2242
+ my $hbuf;
2243
+ my $hd = $$et{HiddenData};
2244
+ if ($raf->Seek($$hd{Offset}, 0) and $raf->Read($hbuf, $$hd{Size}) == $$hd{Size} and
2245
+ $hbuf =~ /^\x55\x26\x11\x05\0/)
2246
+ {
2247
+ $newData .= $hbuf;
2248
+ } else {
2249
+ $et->Error('Error copying hidden data', 1);
2250
+ }
2251
+ }
2228
2252
  #
2229
2253
  # determine total block size for deferred data
2230
2254
  #
@@ -2615,8 +2639,9 @@ NoOverwrite: next if $isNew > 0;
2615
2639
  $$fixup{Shift} += $newDataPos;
2616
2640
  $fixup->ApplyFixup(\$newData);
2617
2641
  }
2618
- # save fixup for adjusting Leica trailer offset if necessary
2642
+ # save fixup for adjusting Leica trailer and Sony HiddenData offsets if necessary
2619
2643
  $$et{LeicaTrailer}{Fixup}->AddFixup($fixup) if $$et{LeicaTrailer};
2644
+ $$et{HiddenData}{Fixup}->AddFixup($fixup) if $$et{HiddenData};
2620
2645
  # save fixup for PreviewImage in JPEG file if necessary
2621
2646
  my $previewInfo = $$et{PREVIEW_INFO};
2622
2647
  if ($previewInfo) {
@@ -1056,6 +1056,7 @@ sub WriteQuickTime($$$)
1056
1056
  Parent => $dirName,
1057
1057
  DirName => $subName,
1058
1058
  Name => $$tagInfo{Name},
1059
+ TagInfo => $tagInfo,
1059
1060
  DirID => $tag,
1060
1061
  DataPt => \$buff,
1061
1062
  DataLen => $size,
@@ -19,6 +19,8 @@ my %webpMap = (
19
19
  'XMP ' => 'RIFF', # (the RIFF chunk name is 'XMP ')
20
20
  EXIF => 'RIFF',
21
21
  ICCP => 'RIFF',
22
+ C2PA => 'RIFF',
23
+ JUMBF => 'C2PA',
22
24
  XMP => 'XMP ',
23
25
  IFD0 => 'EXIF',
24
26
  IFD1 => 'IFD0',
@@ -66,6 +68,7 @@ sub WriteRIFF($$)
66
68
  $et->InitWriteDirs(\%webpMap);
67
69
  my $addDirs = $$et{ADD_DIRS};
68
70
  my $editDirs = $$et{EDIT_DIRS};
71
+ $$addDirs{IFD0} = 'EXIF' if $$addDirs{EXIF}; # set flag to add IFD0 if adding EXIF (don't ask)
69
72
  my ($createVP8X, $deleteVP8X);
70
73
 
71
74
  # write header
@@ -142,6 +145,17 @@ sub WriteRIFF($$)
142
145
  }
143
146
  # RIFF chunks are padded to an even number of bytes
144
147
  my $len2 = $len + ($len & 0x01);
148
+ # handle incorrect "XMP\0" chunk ID written by Google software
149
+ if ($tag eq "XMP\0") {
150
+ if ($$et{DEL_GROUP}{XMP}) {
151
+ # just ignore this chunk if deleting XMP
152
+ $raf->Seek($len2, 1) or $et->Error('Seek error'), last;
153
+ ++$$et{CHANGED};
154
+ next;
155
+ } else {
156
+ $et->Warn('Incorrect XMP tag ID',1) if $pass;
157
+ }
158
+ }
145
159
  # edit/add/delete necessary metadata chunks (EXIF must come before XMP)
146
160
  if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
147
161
  my $handledTag;
@@ -156,13 +170,12 @@ sub WriteRIFF($$)
156
170
  #
157
171
  # add/edit/delete EXIF/XMP/ICCP (note: EXIF must come before XMP, and ICCP is written elsewhere)
158
172
  #
159
- my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
160
- my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
173
+ my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'JUMBF' );
174
+ my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'Jpeg2000' );
161
175
  my $dir;
162
- foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
176
+ foreach $dir ('EXIF', 'XMP ', 'ICCP', 'C2PA' ) {
163
177
  next unless $tag eq $dir or ($$addDirs{$dir} and
164
178
  ($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
165
- delete $$addDirs{$dir}; # (don't try to add again)
166
179
  my $start;
167
180
  unless ($pass) {
168
181
  # write the EXIF and save the result for the next pass
@@ -170,8 +183,15 @@ sub WriteRIFF($$)
170
183
  if ($tag eq 'EXIF') {
171
184
  # (only need to set directory $start for EXIF)
172
185
  if ($buff =~ /^Exif\0\0/) {
173
- $et->Warn('Improper EXIF header') unless $pass;
174
- $start = 6;
186
+ if ($$et{DEL_GROUP}{EXIF}) {
187
+ # remove incorrect header if rewriting anyway
188
+ $buff = substr($buff, 6);
189
+ $len -= 6;
190
+ $len2 -= 6;
191
+ } else {
192
+ $et->Warn('Improper EXIF header',1) unless $pass;
193
+ $start = 6;
194
+ }
175
195
  } else {
176
196
  $start = 0;
177
197
  }
@@ -189,11 +209,16 @@ sub WriteRIFF($$)
189
209
  Parent => $dir,
190
210
  DirName => $dirName{$dir},
191
211
  );
212
+ # must pass the TagInfo to enable deletion of C2PA information
213
+ if (ref $Image::ExifTool::RIFF::Main{$dir} eq 'HASH') {
214
+ $dirInfo{TagInfo} = $Image::ExifTool::RIFF::Main{$dir};
215
+ }
192
216
  my $tagTablePtr = GetTagTable("Image::ExifTool::$tblName{$dir}::Main");
193
217
  # (override writeProc for EXIF because it has the TIFF header)
194
218
  my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
195
219
  $dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
196
220
  }
221
+ delete $$addDirs{$dir}; # (don't try to add again)
197
222
  if (defined $dirDat{$dir}) {
198
223
  if ($dir eq $tag) {
199
224
  $handledTag = 1; # set flag indicating we edited this tag