exiftool-vendored.pl 13.17.0 → 13.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/Changes +102 -7
- package/bin/MANIFEST +14 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +46 -46
- package/bin/config_files/example.config +1 -1
- package/bin/exiftool +211 -121
- package/bin/lib/Image/ExifTool/Apple.pm +12 -2
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -2
- package/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/DJI.pm +190 -29
- package/bin/lib/Image/ExifTool/DarwinCore.pm +22 -11
- package/bin/lib/Image/ExifTool/EXE.pm +2 -9
- package/bin/lib/Image/ExifTool/GM.pm +1 -1
- package/bin/lib/Image/ExifTool/GPS.pm +3 -3
- package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/lib/Image/ExifTool/GoPro.pm +86 -48
- package/bin/lib/Image/ExifTool/ICO.pm +2 -2
- package/bin/lib/Image/ExifTool/JPEG.pm +5 -1
- package/bin/lib/Image/ExifTool/JSON.pm +5 -1
- package/bin/lib/Image/ExifTool/Kodak.pm +3 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +943 -1237
- package/bin/lib/Image/ExifTool/Olympus.pm +2 -1
- package/bin/lib/Image/ExifTool/PCAP.pm +462 -0
- package/bin/lib/Image/ExifTool/PDF.pm +10 -1
- package/bin/lib/Image/ExifTool/PLIST.pm +92 -29
- package/bin/lib/Image/ExifTool/PNG.pm +7 -1
- package/bin/lib/Image/ExifTool/Photoshop.pm +2 -2
- package/bin/lib/Image/ExifTool/Plot.pm +713 -0
- package/bin/lib/Image/ExifTool/Protobuf.pm +24 -11
- package/bin/lib/Image/ExifTool/Qualcomm.pm +78 -1
- package/bin/lib/Image/ExifTool/QuickTime.pm +347 -318
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +75 -27
- package/bin/lib/Image/ExifTool/Sony.pm +33 -14
- package/bin/lib/Image/ExifTool/TagLookup.pm +5056 -4967
- package/bin/lib/Image/ExifTool/TagNames.pod +443 -334
- package/bin/lib/Image/ExifTool/Trailer.pm +3 -3
- package/bin/lib/Image/ExifTool/Validate.pm +4 -4
- package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteExif.pl +9 -4
- package/bin/lib/Image/ExifTool/WritePDF.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +58 -5
- package/bin/lib/Image/ExifTool/Writer.pl +14 -13
- package/bin/lib/Image/ExifTool/XMP.pm +34 -6
- package/bin/lib/Image/ExifTool/XMP2.pl +2 -0
- package/bin/lib/Image/ExifTool.pm +63 -29
- package/bin/lib/Image/ExifTool.pod +83 -86
- package/bin/perl-Image-ExifTool.spec +45 -45
- package/bin/windows_exiftool.txt +95 -71
- package/package.json +3 -3
|
@@ -12,7 +12,7 @@ use strict;
|
|
|
12
12
|
use vars qw($VERSION);
|
|
13
13
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
14
14
|
|
|
15
|
-
$VERSION = '1.
|
|
15
|
+
$VERSION = '1.01';
|
|
16
16
|
|
|
17
17
|
%Image::ExifTool::Trailer::Vivo = (
|
|
18
18
|
GROUPS => { 0 => 'Trailer', 1 => 'Vivo', 2 => 'Image' },
|
|
@@ -214,7 +214,7 @@ sub ProcessGoogle($$)
|
|
|
214
214
|
|
|
215
215
|
delete $$et{ProcessGoogleTrailer}; # reset flag to process the Google trailer
|
|
216
216
|
|
|
217
|
-
return -1 if $$dirInfo{OutFile};
|
|
217
|
+
return -1 if $$dirInfo{OutFile}; # let caller handle the writing
|
|
218
218
|
|
|
219
219
|
# sometimes DirectoryItemLength is missing the Primary entry
|
|
220
220
|
$len = [ $len ] unless ref $len eq 'ARRAY';
|
|
@@ -271,7 +271,7 @@ sub ProcessGoogle($$)
|
|
|
271
271
|
DataPos => $start + $pos,
|
|
272
272
|
DirLen => $$len[$i],
|
|
273
273
|
});
|
|
274
|
-
$et->HandleTag($tagTable, $$tag[$i], \$buff,
|
|
274
|
+
$et->HandleTag($tagTable, $$tag[$i], \$buff, DataPos => $start + $pos, DataPt => \$buff);
|
|
275
275
|
# (haven't seen non-zero padding, but I assume this is how it works
|
|
276
276
|
$pos += $$len[$i] + (($pad and $$pad[$i]) ? $$pad[$i] : 0);
|
|
277
277
|
}
|
|
@@ -188,10 +188,10 @@ my %validValue = (
|
|
|
188
188
|
0x115 => undef, # SamplesPerPixel
|
|
189
189
|
0x116 => undef, # RowsPerStrip
|
|
190
190
|
0x117 => undef, # StripByteCounts
|
|
191
|
-
0x11a => 'defined $val', # XResolution
|
|
192
|
-
0x11b => 'defined $val', # YResolution
|
|
191
|
+
# (optional as of 3.0) 0x11a => 'defined $val', # XResolution
|
|
192
|
+
# (optional as of 3.0) 0x11b => 'defined $val', # YResolution
|
|
193
193
|
0x11c => undef, # PlanarConfiguration
|
|
194
|
-
0x128 => '$val =~ /^[123]$/', # ResolutionUnit
|
|
194
|
+
# (optional as of 3.0) 0x128 => '$val =~ /^[123]$/', # ResolutionUnit
|
|
195
195
|
0x201 => undef, # JPEGInterchangeFormat
|
|
196
196
|
0x202 => undef, # JPEGInterchangeFormatLength
|
|
197
197
|
0x212 => undef, # YCbCrSubSampling
|
|
@@ -218,7 +218,7 @@ my %validValue = (
|
|
|
218
218
|
ExifIFD => {
|
|
219
219
|
0x9000 => 'defined $val and $val =~ /^\d{4}$/', # ExifVersion
|
|
220
220
|
0x9101 => 'defined $val', # ComponentsConfiguration
|
|
221
|
-
0xa000 => 'defined $val', # FlashpixVersion
|
|
221
|
+
# (optional as of 3.0) 0xa000 => 'defined $val', # FlashpixVersion
|
|
222
222
|
0xa001 => '$val == 1 or $val == 0xffff', # ColorSpace
|
|
223
223
|
0xa002 => 'defined $val', # PixelXDimension
|
|
224
224
|
0xa003 => 'defined $val', # PixelYDimension
|
|
@@ -566,7 +566,7 @@ sub WriteCRW($$)
|
|
|
566
566
|
my $trailPt;
|
|
567
567
|
while ($success) {
|
|
568
568
|
# check to see if trailer(s) exist(s)
|
|
569
|
-
my $trailInfo =
|
|
569
|
+
my $trailInfo = $et->IdentifyTrailer($raf) or last;
|
|
570
570
|
# rewrite the trailer(s)
|
|
571
571
|
$buff = '';
|
|
572
572
|
$$trailInfo{OutFile} = \$buff;
|
|
@@ -25,9 +25,9 @@ my %crossDelete = (
|
|
|
25
25
|
# mandatory tag default values
|
|
26
26
|
my %mandatory = (
|
|
27
27
|
IFD0 => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
# (optional as of 3.0) 0x011a => 72, # XResolution
|
|
29
|
+
# (optional as of 3.0) 0x011b => 72, # YResolution
|
|
30
|
+
# (optional as of 3.0) 0x0128 => 2, # ResolutionUnit (inches)
|
|
31
31
|
0x0213 => 1, # YCbCrPositioning (centered)
|
|
32
32
|
# 0x8769 => ????, # ExifOffset
|
|
33
33
|
},
|
|
@@ -40,7 +40,7 @@ my %mandatory = (
|
|
|
40
40
|
ExifIFD => {
|
|
41
41
|
0x9000 => '0232', # ExifVersion
|
|
42
42
|
0x9101 => "1 2 3 0",# ComponentsConfiguration
|
|
43
|
-
|
|
43
|
+
# (optional as of 3.0) 0xa000 => '0100', # FlashpixVersion
|
|
44
44
|
0xa001 => 0xffff, # ColorSpace (uncalibrated)
|
|
45
45
|
# 0xa002 => ????, # ExifImageWidth
|
|
46
46
|
# 0xa003 => ????, # ExifImageHeight
|
|
@@ -2269,6 +2269,11 @@ NoOverwrite: next if $isNew > 0;
|
|
|
2269
2269
|
# build list of offsets to process
|
|
2270
2270
|
my @offsetList;
|
|
2271
2271
|
if ($ifd >= 0) {
|
|
2272
|
+
$dirName = $$dirInfo{DirName} || 'unknown';
|
|
2273
|
+
if ($ifd) {
|
|
2274
|
+
$dirName =~ s/\d+$//;
|
|
2275
|
+
$dirName .= $ifd;
|
|
2276
|
+
}
|
|
2272
2277
|
my $offsetInfo = $offsetInfo[$ifd] or next;
|
|
2273
2278
|
if ($$offsetInfo{0x111} and $$offsetInfo{0x144}) {
|
|
2274
2279
|
# SubIFD may contain double-referenced data as both strips and tiles
|
|
@@ -891,7 +891,7 @@ sub WriteQuickTime($$$)
|
|
|
891
891
|
$et or return 1; # allow dummy access to autoload this package
|
|
892
892
|
my ($mdat, @mdat, @mdatEdit, $edit, $track, $outBuff, $co, $term, $delCount);
|
|
893
893
|
my (%langTags, $canCreate, $delGrp, %boxPos, %didDir, $writeLast, $err, $atomCount);
|
|
894
|
-
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2, $keysGrp, $keysPath);
|
|
894
|
+
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2, $keysGrp, $keysPath, $itemIndex);
|
|
895
895
|
my $outfile = $$dirInfo{OutFile} || return 0;
|
|
896
896
|
my $raf = $$dirInfo{RAF}; # (will be null for lower-level atoms)
|
|
897
897
|
my $dataPt = $$dirInfo{DataPt}; # (will be null for top-level atoms)
|
|
@@ -982,8 +982,25 @@ sub WriteQuickTime($$$)
|
|
|
982
982
|
$atomCount = $$tagTablePtr{VARS}{ATOM_COUNT} if $$tagTablePtr{VARS};
|
|
983
983
|
|
|
984
984
|
$tag = $lastTag = '';
|
|
985
|
-
|
|
985
|
+
$itemIndex = 0 if $dirName eq 'ItemPropertyContainer';
|
|
986
|
+
|
|
987
|
+
# read ahead to parse item property associations if this is 'iprp' ItemProperties
|
|
988
|
+
# (necessary to determine which properties belong to primary item in HEIC file)
|
|
989
|
+
if ($dirName eq 'ItemProperties') {
|
|
990
|
+
my $pos = $raf->Tell();
|
|
991
|
+
for (;;) {
|
|
992
|
+
$raf->Read($buf2, 8) == 8 or last;
|
|
993
|
+
my $size = Get32u(\$buf2, 0) - 8; # (atom size without 8-byte header)
|
|
994
|
+
$tag = substr($buf2, 4, 4);
|
|
995
|
+
last if $size < 0;
|
|
996
|
+
$tag eq 'ipma' or $raf->Seek($size, 1), next;
|
|
997
|
+
ParseItemPropAssoc($buf2,$et) if $raf->Read($buf2,$size) == $size;
|
|
998
|
+
last;
|
|
999
|
+
}
|
|
1000
|
+
$raf->Seek($pos);
|
|
1001
|
+
}
|
|
986
1002
|
for (;;) { # loop through all atoms at this level
|
|
1003
|
+
++$itemIndex if defined $itemIndex;
|
|
987
1004
|
$lastPos = $raf->Tell();
|
|
988
1005
|
# stop processing if we reached a known trailer
|
|
989
1006
|
if ($trailer and $lastPos >= $$trailer[1]) {
|
|
@@ -1186,6 +1203,36 @@ sub WriteQuickTime($$$)
|
|
|
1186
1203
|
}
|
|
1187
1204
|
undef $tagInfo if $tagInfo and $$tagInfo{AddedUnknown};
|
|
1188
1205
|
|
|
1206
|
+
# don't write this tag unless associated with the primary item
|
|
1207
|
+
# (Note: This relies on iinf and dimg coming before iprp)
|
|
1208
|
+
if (defined $itemIndex and $$et{ItemInfo}) {
|
|
1209
|
+
my $items = $$et{ItemInfo};
|
|
1210
|
+
my ($id, $prop, $isPrimary);
|
|
1211
|
+
my $primary = $$et{PrimaryItem};
|
|
1212
|
+
unless (defined $primary) {
|
|
1213
|
+
($primary) = sort { $a <=> $b } keys %{$$et{ItemInfo}} if $$et{ItemInfo};
|
|
1214
|
+
$primary = 0 unless defined $primary;
|
|
1215
|
+
}
|
|
1216
|
+
my $pitem = $$items{$primary} || { };
|
|
1217
|
+
$$pitem{RefersTo} or $$pitem{RefersTo} = { };
|
|
1218
|
+
ItemID2: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
1219
|
+
next unless $$items{$id}{Association};
|
|
1220
|
+
my $item = $$items{$id};
|
|
1221
|
+
foreach $prop (@{$$item{Association}}) {
|
|
1222
|
+
next unless $prop == $itemIndex;
|
|
1223
|
+
my $dont = $dontInherit{$tag} || 0;
|
|
1224
|
+
last unless $id == $primary or (not $dont and
|
|
1225
|
+
($$item{RefersTo} and $$item{RefersTo}{$primary})) or
|
|
1226
|
+
# special case to assume this property belongs to the primary
|
|
1227
|
+
# image if it belongs to an item referred to by the primary
|
|
1228
|
+
($dont != 1 and $$pitem{RefersTo}{$id});
|
|
1229
|
+
$isPrimary = 1;
|
|
1230
|
+
last ItemID2;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
undef $tagInfo unless $isPrimary;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1189
1236
|
if ($tagInfo and (not defined $$tagInfo{Writable} or $$tagInfo{Writable})) {
|
|
1190
1237
|
my $subdir = $$tagInfo{SubDirectory};
|
|
1191
1238
|
my ($newData, @chunkOffset);
|
|
@@ -1225,6 +1272,7 @@ sub WriteQuickTime($$$)
|
|
|
1225
1272
|
OutFile => $outfile,
|
|
1226
1273
|
NoRefTest=> 1, # don't check directory references
|
|
1227
1274
|
WriteGroup => $$tagInfo{WriteGroup},
|
|
1275
|
+
Permanent => $$tagInfo{Permanent},
|
|
1228
1276
|
# initialize array to hold details about chunk offset table
|
|
1229
1277
|
# (each entry has 3-5 items: 0=atom type, 1=table offset, 2=table size,
|
|
1230
1278
|
# 3=optional base offset, 4=optional item ID)
|
|
@@ -1468,7 +1516,10 @@ sub WriteQuickTime($$$)
|
|
|
1468
1516
|
++$$et{CHANGED};
|
|
1469
1517
|
my $grp = $et->GetGroup($langInfo, 1);
|
|
1470
1518
|
$et->VerboseValue("- $grp:$$langInfo{Name}", $val);
|
|
1471
|
-
|
|
1519
|
+
unless (defined $newData and not $$didTag{$nvHash}) {
|
|
1520
|
+
# must not delete items from iprp because it will mess up the ordering
|
|
1521
|
+
next unless defined $itemIndex;
|
|
1522
|
+
}
|
|
1472
1523
|
$et->VerboseValue("+ $grp:$$langInfo{Name}", $newData);
|
|
1473
1524
|
# add back necessary header and encode as necessary
|
|
1474
1525
|
if (defined $lang) {
|
|
@@ -1497,7 +1548,7 @@ sub WriteQuickTime($$$)
|
|
|
1497
1548
|
$newData = $et->Encode($newData, 'UTF8');
|
|
1498
1549
|
} elsif ($format and not $$tagInfo{Binary}) {
|
|
1499
1550
|
# format new value for writing
|
|
1500
|
-
$newData = WriteValue($newData, $format);
|
|
1551
|
+
$newData = WriteValue($newData, $format, $$tagInfo{Count});
|
|
1501
1552
|
}
|
|
1502
1553
|
}
|
|
1503
1554
|
$$didTag{$nvHash} = 1; # set flag so we don't add this tag again
|
|
@@ -1564,7 +1615,9 @@ sub WriteQuickTime($$$)
|
|
|
1564
1615
|
}
|
|
1565
1616
|
if ($msg) {
|
|
1566
1617
|
# (allow empty sample description for non-audio/video handler types, eg. 'url ', 'meta')
|
|
1567
|
-
|
|
1618
|
+
# (also, incorrectly written 'mett' SampleEntry by Google phones,
|
|
1619
|
+
# see https://exiftool.org/forum/index.php?msg=91158)
|
|
1620
|
+
if ($avType{$$et{MediaType}}) {
|
|
1568
1621
|
my $grp = $$et{CUR_WRITE_GROUP} || $parent;
|
|
1569
1622
|
$et->Error("$msg for $grp");
|
|
1570
1623
|
return $rtnErr;
|
|
@@ -1296,15 +1296,15 @@ sub SetNewValuesFromFile($$;@)
|
|
|
1296
1296
|
# ! option to decide how it is handled here. !
|
|
1297
1297
|
# +------------------------------------------+
|
|
1298
1298
|
foreach (qw(ByteUnit Charset CharsetEXIF CharsetFileName CharsetID3 CharsetIPTC
|
|
1299
|
-
CharsetPhotoshop Composite DateFormat Debug EncodeHangs Escape
|
|
1300
|
-
ExtractEmbedded FastScan Filter FixBase Geolocation
|
|
1301
|
-
GeolocFeature GeolocMinPop GeolocMaxDist
|
|
1302
|
-
HexTagIDs IgnoreGroups IgnoreMinorErrors
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
TimeZone Unknown UserParam
|
|
1307
|
-
XAttrTags XMPAutoConv))
|
|
1299
|
+
CharsetPhotoshop Composite DateFormat Debug EncodeHangs Escape
|
|
1300
|
+
ExtendedXMP ExtractEmbedded FastScan Filter FixBase Geolocation
|
|
1301
|
+
GeolocAltNames GeolocFeature GeolocMinPop GeolocMaxDist
|
|
1302
|
+
GlobalTimeShift GPSQuadrant HexTagIDs IgnoreGroups IgnoreMinorErrors
|
|
1303
|
+
IgnoreTags ImageHashType KeepUTCTime Lang LargeFileSupport
|
|
1304
|
+
LigoGPSScale ListItem ListSep MDItemTags MissingTagValue NoPDFList
|
|
1305
|
+
NoWarning Password PrintConv QuickTimeUTC RequestTags SaveFormat
|
|
1306
|
+
SavePath ScanForXMP StructFormat SystemTags TimeZone Unknown UserParam
|
|
1307
|
+
Validate WindowsLongPath WindowsWideFile XAttrTags XMPAutoConv))
|
|
1308
1308
|
{
|
|
1309
1309
|
$srcExifTool->Options($_ => $$options{$_});
|
|
1310
1310
|
}
|
|
@@ -4262,9 +4262,11 @@ sub WriteDirectory($$$;$)
|
|
|
4262
4262
|
if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
|
|
4263
4263
|
undef $delFlag;
|
|
4264
4264
|
}
|
|
4265
|
-
# (never delete an entire QuickTime group)
|
|
4266
4265
|
if ($delFlag) {
|
|
4267
|
-
if (
|
|
4266
|
+
if ($$dirInfo{Permanent}) {
|
|
4267
|
+
$self->Warn("Not deleting permanent $dirName directory");
|
|
4268
|
+
undef $grp1;
|
|
4269
|
+
} elsif (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
|
|
4268
4270
|
$self->IsRawType() and
|
|
4269
4271
|
# allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
|
|
4270
4272
|
(not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
|
|
@@ -5044,7 +5046,6 @@ TryLib: for ($lib=$strptimeLib; ; $lib='') {
|
|
|
5044
5046
|
last;
|
|
5045
5047
|
}
|
|
5046
5048
|
if (not $lib) {
|
|
5047
|
-
last unless $$self{OPTIONS}{StrictDate};
|
|
5048
5049
|
warn $wrn || "Install POSIX::strptime or Time::Piece for inverse date/time conversions\n";
|
|
5049
5050
|
return undef;
|
|
5050
5051
|
} elsif ($lib eq 'POSIX::strptime') {
|
|
@@ -6027,7 +6028,7 @@ sub WriteJPEG($$)
|
|
|
6027
6028
|
Write($outfile, $hdr, $s, $segData) or $err = 1;
|
|
6028
6029
|
my ($buff, $endPos, $trailInfo);
|
|
6029
6030
|
my $delPreview = $$self{DEL_PREVIEW};
|
|
6030
|
-
$trailInfo = IdentifyTrailer($raf) unless $$delGroup{Trailer};
|
|
6031
|
+
$trailInfo = $self->IdentifyTrailer($raf) unless $$delGroup{Trailer};
|
|
6031
6032
|
my $nvTrail = $self->GetNewValueHash($Image::ExifTool::Extra{Trailer});
|
|
6032
6033
|
unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail or
|
|
6033
6034
|
$$self{HiddenData})
|
|
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
|
|
|
50
50
|
use Image::ExifTool::GPS;
|
|
51
51
|
require Exporter;
|
|
52
52
|
|
|
53
|
-
$VERSION = '3.
|
|
53
|
+
$VERSION = '3.72';
|
|
54
54
|
@ISA = qw(Exporter);
|
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
|
56
56
|
|
|
@@ -165,7 +165,7 @@ my %xmpNS = (
|
|
|
165
165
|
#
|
|
166
166
|
plus => 'http://ns.useplus.org/ldf/xmp/1.0/',
|
|
167
167
|
# (prism recommendations from http://www.prismstandard.org/specifications/3.0/Image_Guide_3.0.htm)
|
|
168
|
-
prism => 'http://prismstandard.org/namespaces/basic/2.0/',
|
|
168
|
+
prism => 'http://prismstandard.org/namespaces/basic/2.0/', # (maybe left at 2.0 to avoid compatibility issues -- think hard before changing this)
|
|
169
169
|
prl => 'http://prismstandard.org/namespaces/prl/2.1/',
|
|
170
170
|
pur => 'http://prismstandard.org/namespaces/prismusagerights/2.1/',
|
|
171
171
|
pmi => 'http://prismstandard.org/namespaces/pmi/2.2/',
|
|
@@ -1247,8 +1247,22 @@ my %sPantryItem = (
|
|
|
1247
1247
|
NAMESPACE => 'pdfx',
|
|
1248
1248
|
NOTES => q{
|
|
1249
1249
|
PDF extension tags. This namespace is used to store application-defined PDF
|
|
1250
|
-
information, so there are
|
|
1251
|
-
created to enable writing of XMP-pdfx information.
|
|
1250
|
+
information, so there are few pre-defined tags. User-defined tags must be
|
|
1251
|
+
created to enable writing of other XMP-pdfx information.
|
|
1252
|
+
},
|
|
1253
|
+
SourceModified => {
|
|
1254
|
+
Name => 'SourceModified',
|
|
1255
|
+
Groups => { 2 => 'Time' },
|
|
1256
|
+
Shift => 'Time',
|
|
1257
|
+
ValueConv => 'require Image::ExifTool::PDF; $val = Image::ExifTool::PDF::ConvertPDFDate($val)',
|
|
1258
|
+
ValueConvInv => q{
|
|
1259
|
+
require Image::ExifTool::PDF;
|
|
1260
|
+
$val = Image::ExifTool::PDF::WritePDFValue($self,$val,"date");
|
|
1261
|
+
$val =~ tr/()//d;
|
|
1262
|
+
return $val;
|
|
1263
|
+
},
|
|
1264
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
1265
|
+
PrintConvInv => '$self->InverseDateTime($val)',
|
|
1252
1266
|
},
|
|
1253
1267
|
);
|
|
1254
1268
|
|
|
@@ -3804,8 +3818,22 @@ sub ParseXMPElement($$$;$$$$)
|
|
|
3804
3818
|
my ($parseResource, %attrs, @attrs);
|
|
3805
3819
|
# this hangs Perl (v5.18.4) for a specific capture string [patched in ExifTool 12.98]
|
|
3806
3820
|
# while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
|
|
3807
|
-
|
|
3808
|
-
|
|
3821
|
+
# this may hang Perl v5.26.3 (but not v5.18.4) if there is lots of garbage in the XMP [patched in 13.23]
|
|
3822
|
+
# while ($attrs =~ /(\S+?)\s*=\s*(['"])/g) {
|
|
3823
|
+
for (;;) {
|
|
3824
|
+
my ($attr, $quote);
|
|
3825
|
+
if (length($attrs) < 2000) { # (do it the easy way if attributes aren't stupid long)
|
|
3826
|
+
last unless $attrs =~ /(\S+)\s*=\s*(['"])/g;
|
|
3827
|
+
($attr, $quote) = ($1, $2);
|
|
3828
|
+
} else {
|
|
3829
|
+
# 13.23 patch to avoid capturing tons of garbage if XMP is corrupted
|
|
3830
|
+
last unless $attrs =~ /=\s*(['"])/g;
|
|
3831
|
+
$quote = $1;
|
|
3832
|
+
my $p = pos($attrs) > 1000 ? pos($attrs) - 1000 : 0;
|
|
3833
|
+
my $tmp = substr($attrs, $p, pos($attrs)-$p);
|
|
3834
|
+
last unless $tmp =~ /(\S+)\s*=\s*$quote$/;
|
|
3835
|
+
$attr = $1;
|
|
3836
|
+
}
|
|
3809
3837
|
my $p0 = pos($attrs);
|
|
3810
3838
|
last unless $attrs =~ /$quote/g;
|
|
3811
3839
|
my $val = substr($attrs, $p0, pos($attrs)-$p0-1);
|
|
@@ -402,6 +402,7 @@ my %sLocationDetails = (
|
|
|
402
402
|
STRUCT_NAME => 'LocationDetails',
|
|
403
403
|
NAMESPACE => 'Iptc4xmpExt',
|
|
404
404
|
GROUPS => { 2 => 'Location' },
|
|
405
|
+
NOTES => 'Note that the GPS elements of this structure are in the "exif" namespace.',
|
|
405
406
|
Identifier => { List => 'Bag', Namespace => 'xmp' },
|
|
406
407
|
City => { },
|
|
407
408
|
CountryCode => { },
|
|
@@ -420,6 +421,7 @@ my %sLocationDetails = (
|
|
|
420
421
|
PrintConvInv => '$val=~s/\s*m$//;$val',
|
|
421
422
|
},
|
|
422
423
|
GPSAltitudeRef => {
|
|
424
|
+
Namespace => 'exif',
|
|
423
425
|
Writable => 'integer',
|
|
424
426
|
PrintConv => {
|
|
425
427
|
OTHER => sub {
|
|
@@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
|
|
|
29
29
|
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
|
30
30
|
%static_vars $advFmtSelf);
|
|
31
31
|
|
|
32
|
-
$VERSION = '13.
|
|
32
|
+
$VERSION = '13.25';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -155,9 +155,9 @@ sub ReadValue($$$;$$$);
|
|
|
155
155
|
Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS XISF MIE JSON HTML XMP::SVG
|
|
156
156
|
Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString
|
|
157
157
|
EXE::DebugRSDS EXE::DebugNB10 EXE::Misc EXE::MachO EXE::PEF EXE::ELF EXE::AR
|
|
158
|
-
EXE::CHM LNK Font VCard Text VCard::VCalendar VCard::VNote RSRC Rawzor
|
|
159
|
-
ZIP::GZIP ZIP::RAR ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF FLIR::FPF
|
|
160
|
-
MacOS::MDItem FlashPix::DocTable
|
|
158
|
+
EXE::CHM LNK PCAP Font VCard Text VCard::VCalendar VCard::VNote RSRC Rawzor
|
|
159
|
+
ZIP ZIP::GZIP ZIP::RAR ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF FLIR::FPF
|
|
160
|
+
MacOS MacOS::MDItem FlashPix::DocTable
|
|
161
161
|
);
|
|
162
162
|
|
|
163
163
|
# alphabetical list of current Lang modules
|
|
@@ -199,8 +199,8 @@ $defaultLang = 'en'; # default language
|
|
|
199
199
|
LFP HTML VRD RTF FITS XISF XCF DSS QTIF FPX PICT ZIP GZIP PLIST
|
|
200
200
|
RAR 7Z BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font
|
|
201
201
|
JUMBF RSRC M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard
|
|
202
|
-
LRI R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3
|
|
203
|
-
NKA ICO TXT AAC);
|
|
202
|
+
LRI R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS PCAP JSON MP3
|
|
203
|
+
DICOM PCD NKA ICO TXT AAC);
|
|
204
204
|
|
|
205
205
|
# file types that we can write (edit)
|
|
206
206
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
|
@@ -263,6 +263,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
263
263
|
BPG => ['BPG', 'Better Portable Graphics'],
|
|
264
264
|
BTF => ['BTF', 'Big Tagged Image File Format'], #(unofficial)
|
|
265
265
|
BZ2 => ['BZ2', 'BZIP2 archive'],
|
|
266
|
+
CAP => 'PCAP',
|
|
266
267
|
C2PA => ['JUMBF','Coalition for Content Provenance and Authenticity'],
|
|
267
268
|
CHM => ['CHM', 'Microsoft Compiled HTML format'],
|
|
268
269
|
CIFF => ['CRW', 'Camera Image File Format'],
|
|
@@ -454,6 +455,8 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
454
455
|
PAC => ['RIFF', 'Lossless Predictive Audio Compression'],
|
|
455
456
|
PAGES => ['ZIP', 'Apple Pages document'],
|
|
456
457
|
PBM => ['PPM', 'Portable BitMap'],
|
|
458
|
+
PCAP => ['PCAP', 'Packet Capture'],
|
|
459
|
+
PCAPNG => ['PCAP', 'Packet Capture Next Generation'],
|
|
457
460
|
PCD => ['PCD', 'Kodak Photo CD Image Pac'],
|
|
458
461
|
PCT => 'PICT',
|
|
459
462
|
PCX => ['PCX', 'PC Paintbrush'],
|
|
@@ -568,7 +571,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
568
571
|
XLTX => [['ZIP','FPX'], 'Office Open XML Spreadsheet Template'],
|
|
569
572
|
XMP => ['XMP', 'Extensible Metadata Platform'],
|
|
570
573
|
WOFF => ['Font', 'Web Open Font Format'],
|
|
571
|
-
WOFF2=> ['Font', 'Web Open Font
|
|
574
|
+
WOFF2=> ['Font', 'Web Open Font Format 2'],
|
|
572
575
|
WPG => ['WPG', 'WordPerfect Graphics'],
|
|
573
576
|
WTV => ['WTV', 'Windows recorded TV show'],
|
|
574
577
|
ZIP => ['ZIP', 'ZIP archive'],
|
|
@@ -744,6 +747,7 @@ my %fileDescription = (
|
|
|
744
747
|
OTF => 'application/font-otf',
|
|
745
748
|
PAGES=> 'application/x-iwork-pages-sffpages',
|
|
746
749
|
PBM => 'image/x-portable-bitmap',
|
|
750
|
+
PCAP => 'application/vnd.tcpdump.pcap',
|
|
747
751
|
PCD => 'image/x-photo-cd',
|
|
748
752
|
PCX => 'image/pcx',
|
|
749
753
|
PDB => 'application/vnd.palm',
|
|
@@ -980,6 +984,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
980
984
|
NKA => 'NIKONADJ',
|
|
981
985
|
OGG => '(OggS|ID3)',
|
|
982
986
|
ORF => '(II|MM)',
|
|
987
|
+
PCAP => '\xa1\xb2(\xc3\xd4|\x3c\x4d)\0.\0.|(\xd4\xc3|\x4d\x3c)\xb2\xa1.\0.\0|\x0a\x0d\x0d\x0a.{4}(\x1a\x2b\x3c\x4d|\x4d\x3c\x2b\x1a)|GMBU\0\x02',
|
|
983
988
|
# PCD => signature is at byte 2048
|
|
984
989
|
PCX => '\x0a[\0-\x05]\x01[\x01\x02\x04\x08].{64}[\0-\x02]',
|
|
985
990
|
PDB => '.{60}(\.pdfADBE|TEXtREAd|BVokBDIC|DB99DBOS|PNRdPPrs|DataPPrs|vIMGView|PmDBPmDB|InfoINDB|ToGoToGo|SDocSilX|JbDbJBas|JfDbJFil|DATALSdb|Mdb1Mdb1|BOOKMOBI|DataPlkr|DataSprd|SM01SMem|TEXtTlDc|InfoTlIf|DataTlMl|DataTlPt|dataTDBP|TdatTide|ToRaTRPW|zTXTGPlm|BDOCWrdS)',
|
|
@@ -1135,6 +1140,7 @@ my @availableOptions = (
|
|
|
1135
1140
|
[ 'IgnoreMinorErrors',undef, 'ignore minor errors when reading/writing' ],
|
|
1136
1141
|
[ 'IgnoreTags', undef, 'list of tags to ignore when extracting' ],
|
|
1137
1142
|
[ 'ImageHashType', 'MD5', 'image hash algorithm' ],
|
|
1143
|
+
[ 'KeepUTCTime', undef, 'do not convert times stored as UTC' ],
|
|
1138
1144
|
[ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
|
|
1139
1145
|
[ 'LargeFileSupport', 1, 'flag indicating support of 64-bit file offsets' ],
|
|
1140
1146
|
[ 'LimitLongValues', 60, 'length limit for long values' ],
|
|
@@ -1152,6 +1158,7 @@ my @availableOptions = (
|
|
|
1152
1158
|
[ 'NoPDFList', undef, 'flag to avoid splitting PDF List-type tag values' ],
|
|
1153
1159
|
[ 'NoWarning', undef, 'regular expression for warnings to suppress' ],
|
|
1154
1160
|
[ 'Password', undef, 'password for password-protected PDF documents' ],
|
|
1161
|
+
[ 'Plot', undef, 'SVG plot settings' ],
|
|
1155
1162
|
[ 'PrintCSV', undef, 'flag to print CSV directly (selected metadata types only)' ],
|
|
1156
1163
|
[ 'PrintConv', 1, 'flag to enable print conversion' ],
|
|
1157
1164
|
[ 'QuickTimeHandler', 1, 'flag to add mdir Handler to newly created Meta box' ],
|
|
@@ -2587,6 +2594,12 @@ sub Options($$;@)
|
|
|
2587
2594
|
} else {
|
|
2588
2595
|
warn("Can't set $param to undef\n");
|
|
2589
2596
|
}
|
|
2597
|
+
} elsif ($param eq 'Plot') {
|
|
2598
|
+
# add to existing plot settings
|
|
2599
|
+
$newVal = "$oldVal,$newVal" if defined $oldVal and defined $newVal;
|
|
2600
|
+
$$options{$param} = $newVal;
|
|
2601
|
+
} elsif ($param eq 'KeepUTCTime') {
|
|
2602
|
+
$$options{$param} = $static_vars{$param} = $newVal;
|
|
2590
2603
|
} elsif (lc $param eq 'geodir') {
|
|
2591
2604
|
$Image::ExifTool::Geolocation::geoDir = $newVal;
|
|
2592
2605
|
} else {
|
|
@@ -4245,7 +4258,7 @@ sub Init($)
|
|
|
4245
4258
|
my $self = shift;
|
|
4246
4259
|
# delete all DataMember variables (lower-case names)
|
|
4247
4260
|
delete $$self{$_} foreach grep /[a-z]/, keys %$self;
|
|
4248
|
-
|
|
4261
|
+
%static_vars = ( KeepUTCTime => $$self{OPTIONS}{KeepUTCTime} ); # reset static variables
|
|
4249
4262
|
delete $$self{FOUND_TAGS}; # list of found tags
|
|
4250
4263
|
delete $$self{EXIF_DATA}; # the EXIF data block
|
|
4251
4264
|
delete $$self{EXIF_POS}; # EXIF position in file
|
|
@@ -6680,12 +6693,15 @@ sub ConvertUnixTime($;$$)
|
|
|
6680
6693
|
$time = int($time + 1e-6) if $time != int($time); # avoid round-off errors
|
|
6681
6694
|
$dec = '';
|
|
6682
6695
|
}
|
|
6683
|
-
if ($toLocal) {
|
|
6684
|
-
@tm = localtime($time);
|
|
6685
|
-
$tz = TimeZoneString(\@tm, $time);
|
|
6686
|
-
} else {
|
|
6696
|
+
if (not $toLocal) {
|
|
6687
6697
|
@tm = gmtime($time);
|
|
6688
6698
|
$tz = '';
|
|
6699
|
+
} elsif ($static_vars{KeepUTCTime}) {
|
|
6700
|
+
@tm = gmtime($time);
|
|
6701
|
+
$tz = 'Z';
|
|
6702
|
+
} else {
|
|
6703
|
+
@tm = localtime($time);
|
|
6704
|
+
$tz = TimeZoneString(\@tm, $time);
|
|
6689
6705
|
}
|
|
6690
6706
|
my $str = sprintf("%4d:%.2d:%.2d %.2d:%.2d:%.2d$dec%s",
|
|
6691
6707
|
$tm[5]+1900, $tm[4]+1, $tm[3], $tm[2], $tm[1], $tm[0], $tz);
|
|
@@ -6868,10 +6884,10 @@ sub HDump($$$$;$$$)
|
|
|
6868
6884
|
# Returns: Trailer info hash (with RAF and DirName set),
|
|
6869
6885
|
# or undef if no recognized trailer was found
|
|
6870
6886
|
# Notes: leaves file position unchanged
|
|
6871
|
-
sub IdentifyTrailer(
|
|
6887
|
+
sub IdentifyTrailer($$;$)
|
|
6872
6888
|
{
|
|
6873
|
-
my $raf =
|
|
6874
|
-
|
|
6889
|
+
my ($self, $raf, $offset) = @_;
|
|
6890
|
+
$offset or $offset = 0;
|
|
6875
6891
|
my $pos = $raf->Tell();
|
|
6876
6892
|
my ($buff, $type, $len);
|
|
6877
6893
|
while ($raf->Seek(-$offset, 2) and ($len = $raf->Tell()) > 0) {
|
|
@@ -6900,6 +6916,9 @@ sub IdentifyTrailer($;$)
|
|
|
6900
6916
|
$type = 'Vivo';
|
|
6901
6917
|
} elsif ($buff =~ /jxrs...\0$/s) {
|
|
6902
6918
|
$type = 'OnePlus';
|
|
6919
|
+
} elsif ($$self{ProcessGoogleTrailer}) {
|
|
6920
|
+
# check for Google trailer information if specific XMP tags exist
|
|
6921
|
+
$type = 'Google';
|
|
6903
6922
|
}
|
|
6904
6923
|
last;
|
|
6905
6924
|
}
|
|
@@ -7052,7 +7071,7 @@ sub ProcessTrailers($$)
|
|
|
7052
7071
|
$offset += $dirLen;
|
|
7053
7072
|
last if $dataPos and $$self{TrailerStart} and $dataPos <= $$self{TrailerStart};
|
|
7054
7073
|
# look for next trailer
|
|
7055
|
-
my $nextTrail = IdentifyTrailer($raf, $offset);
|
|
7074
|
+
my $nextTrail = $self->IdentifyTrailer($raf, $offset);
|
|
7056
7075
|
# process Google trailer after all others if necessary and not done already
|
|
7057
7076
|
unless ($nextTrail) {
|
|
7058
7077
|
last unless $$self{ProcessGoogleTrailer};
|
|
@@ -7504,11 +7523,7 @@ sub ProcessJPEG($$;$)
|
|
|
7504
7523
|
}
|
|
7505
7524
|
}
|
|
7506
7525
|
unless ($fast) {
|
|
7507
|
-
$trailInfo = IdentifyTrailer($raf);
|
|
7508
|
-
# check for Google trailer information if specific XMP tags exist
|
|
7509
|
-
if (not $trailInfo and $$self{ProcessGoogleTrailer}) {
|
|
7510
|
-
$trailInfo = { DirName => 'Google', RAF => $raf };
|
|
7511
|
-
}
|
|
7526
|
+
$trailInfo = $self->IdentifyTrailer($raf);
|
|
7512
7527
|
# process trailer now unless we are doing verbose dump
|
|
7513
7528
|
if ($trailInfo and $verbose < 3 and not $htmlDump) {
|
|
7514
7529
|
# process trailers (keep trailInfo to finish processing later
|
|
@@ -7963,6 +7978,12 @@ sub ProcessJPEG($$;$)
|
|
|
7963
7978
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7964
7979
|
undef $scalado;
|
|
7965
7980
|
}
|
|
7981
|
+
} elsif ($$segDataPt =~ /^Qualcomm Dual Camera Attributes/) {
|
|
7982
|
+
$dumpType = 'Qualcomm Dual Camera';
|
|
7983
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::Qualcomm::DualCamera');
|
|
7984
|
+
DirStart(\%dirInfo, 31);
|
|
7985
|
+
$dirInfo{DirName} = 'Qualcomm Dual Camera';
|
|
7986
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7966
7987
|
} elsif ($$segDataPt =~ /^FPXR\0/) {
|
|
7967
7988
|
next if $fast > 1; # skip processing for very fast
|
|
7968
7989
|
$dumpType = 'FPXR';
|
|
@@ -8619,7 +8640,7 @@ sub DoProcessTIFF($$;$)
|
|
|
8619
8640
|
}
|
|
8620
8641
|
# process information in recognized trailers
|
|
8621
8642
|
if ($raf) {
|
|
8622
|
-
my $trailInfo = IdentifyTrailer($raf);
|
|
8643
|
+
my $trailInfo = $self->IdentifyTrailer($raf);
|
|
8623
8644
|
if ($trailInfo) {
|
|
8624
8645
|
# scan to find AFCP if necessary (Note: we are scanning
|
|
8625
8646
|
# from a random file position in the TIFF)
|
|
@@ -8724,7 +8745,7 @@ sub DoProcessTIFF($$;$)
|
|
|
8724
8745
|
for (;;) {
|
|
8725
8746
|
last unless $extra > 12;
|
|
8726
8747
|
$raf->Seek($tiffEnd); # seek back to end of image
|
|
8727
|
-
$trailInfo = IdentifyTrailer($raf);
|
|
8748
|
+
$trailInfo = $self->IdentifyTrailer($raf);
|
|
8728
8749
|
last unless $trailInfo;
|
|
8729
8750
|
my $tbuf = '';
|
|
8730
8751
|
$$trailInfo{OutFile} = \$tbuf; # rewrite trailer(s)
|
|
@@ -8941,7 +8962,7 @@ sub ProcessDirectory($$$;$)
|
|
|
8941
8962
|
($$dirInfo{DirLen} or not defined $$dirInfo{DirLen}))
|
|
8942
8963
|
{
|
|
8943
8964
|
my $addr = $$dirInfo{DirStart} + $$dirInfo{DataPos} + ($$dirInfo{Base}||0) + $$self{BASE};
|
|
8944
|
-
if ($$self{PROCESSED}{$addr}) {
|
|
8965
|
+
if ($$self{PROCESSED}{$addr} and not $$dirInfo{NotDup}) {
|
|
8945
8966
|
$self->Warn("$dirName pointer references previous $$self{PROCESSED}{$addr} directory");
|
|
8946
8967
|
# patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
|
|
8947
8968
|
return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
|
|
@@ -9152,10 +9173,11 @@ sub AddTagToTable($$;$$)
|
|
|
9152
9173
|
# Handle simple extraction of new tag information
|
|
9153
9174
|
# Inputs: 0) ExifTool object ref, 1) tag table reference, 2) tagID, 3) value,
|
|
9154
9175
|
# 4-N) parameters hash: Index, DataPt, DataPos, Base, Start, Size, Parent,
|
|
9155
|
-
# TagInfo, ProcessProc, RAF, Format, Count
|
|
9176
|
+
# TagInfo, ProcessProc, RAF, Format, Count, MakeTagInfo
|
|
9156
9177
|
# Returns: tag key or undef if tag not found
|
|
9157
9178
|
# Notes: if value is not defined, it is extracted from DataPt using TagInfo
|
|
9158
9179
|
# Format and Count if provided
|
|
9180
|
+
# - set MakeTagInfo to add tag info for unknown tags with name made from tag ID
|
|
9159
9181
|
sub HandleTag($$$$;%)
|
|
9160
9182
|
{
|
|
9161
9183
|
my ($self, $tagTablePtr, $tag, $val, %parms) = @_;
|
|
@@ -9167,6 +9189,15 @@ sub HandleTag($$$$;%)
|
|
|
9167
9189
|
|
|
9168
9190
|
if ($tagInfo) {
|
|
9169
9191
|
$subdir = $$tagInfo{SubDirectory};
|
|
9192
|
+
} elsif ($parms{MakeTagInfo}) {
|
|
9193
|
+
$self->VPrint(0, $$self{INDENT}, "[adding $tag]\n") if $verbose;
|
|
9194
|
+
my $name = $tag;
|
|
9195
|
+
$name =~ s/([A-Z]) ([A-Z][ A-Z])/${1}_$2/g; # underline between acronyms
|
|
9196
|
+
$name =~ s/([^A-Za-z])([a-z])/$1\u$2/g; # capitalize words
|
|
9197
|
+
$name =~ tr/-_a-zA-Z0-9//dc; # remove illegal characters
|
|
9198
|
+
$name = "Tag$name" if length($name) < 2 or $name =~ /^[-0-9]/;
|
|
9199
|
+
$tagInfo = { Name => ucfirst($name) };
|
|
9200
|
+
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
|
9170
9201
|
} else {
|
|
9171
9202
|
return undef unless $verbose;
|
|
9172
9203
|
$tagInfo = { Name => "tag $tag" }; # create temporary tagInfo hash
|
|
@@ -9224,10 +9255,11 @@ sub HandleTag($$$$;%)
|
|
|
9224
9255
|
}
|
|
9225
9256
|
$self->Warn("RawConv $tag: " . CleanWarning()) if $evalWarning;
|
|
9226
9257
|
return undef unless defined $val;
|
|
9227
|
-
$
|
|
9228
|
-
$dataPt = \$val;
|
|
9258
|
+
$dataPt = ref $val eq 'SCALAR' ? $val : \$val;
|
|
9229
9259
|
$subdirStart = 0;
|
|
9230
|
-
$subdirLen = length
|
|
9260
|
+
$subdirLen = length $$dataPt;
|
|
9261
|
+
} elsif (not $dataPt) {
|
|
9262
|
+
$dataPt = ref $val eq 'SCALAR' ? $val : \$val;
|
|
9231
9263
|
}
|
|
9232
9264
|
if ($$subdir{Start}) {
|
|
9233
9265
|
my $valuePtr = 0;
|
|
@@ -9236,7 +9268,6 @@ sub HandleTag($$$$;%)
|
|
|
9236
9268
|
$subdirStart += $off;
|
|
9237
9269
|
$subdirLen -= $off;
|
|
9238
9270
|
}
|
|
9239
|
-
$dataPt or $dataPt = \$val;
|
|
9240
9271
|
# process subdirectory information
|
|
9241
9272
|
my %dirInfo = (
|
|
9242
9273
|
DirName => $$subdir{DirName} || $$tagInfo{Name},
|
|
@@ -9957,6 +9988,7 @@ sub ProcessBinaryData($$$)
|
|
|
9957
9988
|
$subdirBase = eval($$subdir{Base}) + $base;
|
|
9958
9989
|
}
|
|
9959
9990
|
my $start = $$subdir{Start} || 0;
|
|
9991
|
+
my $notDup;
|
|
9960
9992
|
if ($start =~ /\$/) {
|
|
9961
9993
|
# ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
|
|
9962
9994
|
next unless $val;
|
|
@@ -9967,6 +9999,7 @@ sub ProcessBinaryData($$$)
|
|
|
9967
9999
|
$len = $dataLen - $start unless $len and $len <= $dataLen - $start;
|
|
9968
10000
|
} else {
|
|
9969
10001
|
$start += $dirStart + $entry;
|
|
10002
|
+
$notDup = 1,
|
|
9970
10003
|
}
|
|
9971
10004
|
my %subdirInfo = (
|
|
9972
10005
|
DataPt => $dataPt,
|
|
@@ -9975,6 +10008,7 @@ sub ProcessBinaryData($$$)
|
|
|
9975
10008
|
DirStart => $start,
|
|
9976
10009
|
DirLen => $len,
|
|
9977
10010
|
Base => $subdirBase,
|
|
10011
|
+
NotDup => $notDup,
|
|
9978
10012
|
);
|
|
9979
10013
|
delete $$self{NO_UNKNOWN};
|
|
9980
10014
|
$self->ProcessDirectory(\%subdirInfo, $subTablePtr, $$subdir{ProcessProc});
|