exiftool-vendored.exe 13.16.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/README.txt +14 -14
- package/bin/exiftool.exe +0 -0
- package/bin/exiftool_files/exiftool.pl +118 -47
- package/bin/exiftool_files/lib/Image/ExifTool/Apple.pm +12 -2
- package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +16 -10
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +3 -2
- package/bin/exiftool_files/lib/Image/ExifTool/CanonRaw.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +190 -29
- package/bin/exiftool_files/lib/Image/ExifTool/DarwinCore.pm +22 -11
- package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +2 -9
- package/bin/exiftool_files/lib/Image/ExifTool/GM.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +3 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/exiftool_files/lib/Image/ExifTool/GoPro.pm +86 -48
- package/bin/exiftool_files/lib/Image/ExifTool/ICO.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +12 -2
- package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +5 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Kodak.pm +3 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +1003 -1399
- package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +4 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/PCAP.pm +462 -0
- package/bin/exiftool_files/lib/Image/ExifTool/PDF.pm +10 -1
- package/bin/exiftool_files/lib/Image/ExifTool/PLIST.pm +92 -29
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +7 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Photoshop.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Plot.pm +713 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Protobuf.pm +24 -11
- package/bin/exiftool_files/lib/Image/ExifTool/Qualcomm.pm +78 -1
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +348 -318
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +75 -27
- package/bin/exiftool_files/lib/Image/ExifTool/Samsung.pm +4 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +34 -15
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +5061 -4967
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +8302 -8160
- package/bin/exiftool_files/lib/Image/ExifTool/Trailer.pm +318 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +4 -4
- package/bin/exiftool_files/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +9 -4
- package/bin/exiftool_files/lib/Image/ExifTool/WritePDF.pl +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +62 -5
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +14 -13
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +34 -6
- package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +5 -2
- package/bin/exiftool_files/lib/Image/ExifTool.pm +193 -92
- package/bin/exiftool_files/lib/Image/ExifTool.pod +121 -124
- package/bin/exiftool_files/windows_exiftool.txt +95 -71
- package/package.json +4 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Vivo.pm +0 -124
|
@@ -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 {
|
|
@@ -1995,7 +1997,8 @@ my %sACDSeeRegionStruct = (
|
|
|
1995
1997
|
Struct => {
|
|
1996
1998
|
STRUCT_NAME => 'DeviceItem',
|
|
1997
1999
|
NAMESPACE => { Item => 'http://ns.google.com/photos/dd/1.0/item/' },
|
|
1998
|
-
|
|
2000
|
+
# use this as a key to process Google trailer
|
|
2001
|
+
Mime => { RawConv => '$$self{ProcessGoogleTrailer} = $val' },
|
|
1999
2002
|
Length => { Writable => 'integer' },
|
|
2000
2003
|
Padding => { Writable => 'integer' },
|
|
2001
2004
|
DataURI => { },
|
|
@@ -2149,7 +2152,7 @@ my %sACDSeeRegionStruct = (
|
|
|
2149
2152
|
STRUCT_NAME => 'Item',
|
|
2150
2153
|
# (use 'GItem' to avoid conflict with Google Device Container Item)
|
|
2151
2154
|
NAMESPACE => { GItem => 'http://ns.google.com/photos/1.0/container/item/'},
|
|
2152
|
-
Mime
|
|
2155
|
+
Mime => { RawConv => '$$self{ProcessGoogleTrailer} = $val' },
|
|
2153
2156
|
Semantic => { },
|
|
2154
2157
|
Length => { Writable => 'integer' },
|
|
2155
2158
|
Label => { },
|
|
@@ -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) {
|
|
@@ -6898,6 +6914,11 @@ sub IdentifyTrailer($;$)
|
|
|
6898
6914
|
$type = 'NikonApp';
|
|
6899
6915
|
} elsif ($buff =~ /\xff{4}\x1b\*9HWfu\x84\x93\xa2\xb1$/) {
|
|
6900
6916
|
$type = 'Vivo';
|
|
6917
|
+
} elsif ($buff =~ /jxrs...\0$/s) {
|
|
6918
|
+
$type = 'OnePlus';
|
|
6919
|
+
} elsif ($$self{ProcessGoogleTrailer}) {
|
|
6920
|
+
# check for Google trailer information if specific XMP tags exist
|
|
6921
|
+
$type = 'Google';
|
|
6901
6922
|
}
|
|
6902
6923
|
last;
|
|
6903
6924
|
}
|
|
@@ -6929,18 +6950,24 @@ sub ProcessTrailers($$)
|
|
|
6929
6950
|
my $success = 1;
|
|
6930
6951
|
my $path = $$self{PATH};
|
|
6931
6952
|
|
|
6953
|
+
# get position of end of file
|
|
6954
|
+
$raf->Seek(0,2);
|
|
6955
|
+
$$self{FileEnd} = $raf->Tell();
|
|
6956
|
+
|
|
6932
6957
|
for (;;) { # loop through all trailers
|
|
6958
|
+
$raf->Seek($pos);
|
|
6933
6959
|
my ($proc, $outBuff);
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6960
|
+
# trailer-processing procs residing in modules of a different name
|
|
6961
|
+
my $module = {
|
|
6962
|
+
Insta360 => 'QuickTimeStream.pl',
|
|
6963
|
+
NikonApp => 'Nikon.pm',
|
|
6964
|
+
Vivo => 'Trailer.pm',
|
|
6965
|
+
OnePlus => 'Trailer.pm',
|
|
6966
|
+
Google => 'Trailer.pm',
|
|
6967
|
+
}->{$dirName} || "$dirName.pm";
|
|
6968
|
+
require "Image/ExifTool/$module";
|
|
6969
|
+
$module =~ s/(Stream)?\..*//; # remove extension and change QuickTimeStream to QuickTime
|
|
6970
|
+
$proc = "Image::ExifTool::${module}::Process$dirName";
|
|
6944
6971
|
if ($outfile) {
|
|
6945
6972
|
# write to local buffer so we can add trailer in proper order later
|
|
6946
6973
|
$$outfile and $$dirInfo{OutFile} = \$outBuff, $outBuff = '';
|
|
@@ -6953,11 +6980,38 @@ sub ProcessTrailers($$)
|
|
|
6953
6980
|
$$dirInfo{Trailer} = 1; # set Trailer flag in case proc cares
|
|
6954
6981
|
# add trailer and DirName to SubDirectory PATH
|
|
6955
6982
|
push @$path, 'Trailer', $dirName;
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6983
|
+
#
|
|
6984
|
+
# Call proc to read or write this trailer
|
|
6985
|
+
#
|
|
6986
|
+
# Proc inputs:
|
|
6987
|
+
# 0) ExifTool ref, with FileEnd set, and TrailerStart possibly set (start of all trailers)
|
|
6988
|
+
# 1) DirInfo with the following elements:
|
|
6989
|
+
# DirName - name of this trailer
|
|
6990
|
+
# RAF - RAF reference
|
|
6991
|
+
# Offset - positive offset from end of this trailer to the end of file
|
|
6992
|
+
# OutFile - (write mode) scalar reference for output buffer consisting of an empty string
|
|
6993
|
+
# Trailer - flag set so proc knows we are processing a trailer (if it cares)
|
|
6994
|
+
# Fixup - optional fixup for pointers in trailer
|
|
6995
|
+
# ScanForTrailer - set if we should now scan for the trailer start. For JPEG
|
|
6996
|
+
# images the ExifTool TrailerStart member will also be set, but for TIFF
|
|
6997
|
+
# images TrailerStart will only be set when writing, so the proc should
|
|
6998
|
+
# scan from the current file position when reading in a TIFF image.
|
|
6999
|
+
# Proc returns in read mode (OutFile not set):
|
|
7000
|
+
# 1 = success
|
|
7001
|
+
# 0 = error processing trailer (no warning will be issued and remaining trailers will be ignored)
|
|
7002
|
+
# -1 = must scan from TrailerStart since length can not be determined
|
|
7003
|
+
# (in which case this routine will be called again later when TrailerStart is known)
|
|
7004
|
+
# Proc returns in write mode:
|
|
7005
|
+
# 1 = success (and proc updates OutFile with the trailer to write, or empty string to delete)
|
|
7006
|
+
# 0 = error processing trailer (will issue minor error)
|
|
7007
|
+
# -1 = caller to copy or delete the trailer as-is (from TrailerStart if DataPos isn't set)
|
|
7008
|
+
# - TrailerStart will always be set in write mode
|
|
7009
|
+
# - the write routine will not be called if all trailers are being deleted
|
|
7010
|
+
# Proc sets the following elements of $dirInfo in both read and write mode:
|
|
7011
|
+
# DataPos - file position for start of this trailer
|
|
7012
|
+
# DirLen - length of this trailer (subsequent trailers are not processed if this is not set)
|
|
7013
|
+
# Fixup - for any pointers in the trailer that need adjusting
|
|
7014
|
+
#
|
|
6961
7015
|
no strict 'refs';
|
|
6962
7016
|
my $result = &$proc($self, $dirInfo);
|
|
6963
7017
|
use strict 'refs';
|
|
@@ -6965,8 +7019,27 @@ sub ProcessTrailers($$)
|
|
|
6965
7019
|
# restore PATH (pop last 2 items)
|
|
6966
7020
|
splice @$path, -2;
|
|
6967
7021
|
|
|
6968
|
-
|
|
7022
|
+
my ($dataPos, $dirLen) = @$dirInfo{'DataPos','DirLen'};
|
|
6969
7023
|
if ($outfile) {
|
|
7024
|
+
if ($result < 0) {
|
|
7025
|
+
# copy or delete the trailer ourself
|
|
7026
|
+
$result = 1;
|
|
7027
|
+
if ($$self{TrailerStart}) {
|
|
7028
|
+
$dataPos or $dataPos = $$self{TrailerStart};
|
|
7029
|
+
$dirLen or $dirLen = $$self{FileEnd} - $offset - $dataPos;
|
|
7030
|
+
}
|
|
7031
|
+
if ($$self{DEL_GROUP}{Trailer} or $$self{DEL_GROUP}{$dirName}) {
|
|
7032
|
+
my $bytes = $dirLen ? " ($dirLen bytes)" : '';
|
|
7033
|
+
$self->VPrint(0, "Deleting $dirName trailer$bytes\n");
|
|
7034
|
+
++$$self{CHANGED};
|
|
7035
|
+
} elsif ($dataPos and $dirLen) {
|
|
7036
|
+
$self->VPrint(0, "Copying $dirName trailer ($dirLen bytes)\n");
|
|
7037
|
+
$result = 0 unless $raf->Seek($dataPos) and
|
|
7038
|
+
$raf->Read(${$$dirInfo{OutFile}}, $dirLen) == $dirLen;
|
|
7039
|
+
} else {
|
|
7040
|
+
$result = 0;
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
6970
7043
|
if ($result > 0) {
|
|
6971
7044
|
if ($outBuff) {
|
|
6972
7045
|
# write trailers to OutFile in original order
|
|
@@ -6994,15 +7067,20 @@ sub ProcessTrailers($$)
|
|
|
6994
7067
|
$success = 0;
|
|
6995
7068
|
last;
|
|
6996
7069
|
}
|
|
6997
|
-
last unless $result > 0 and
|
|
7070
|
+
last unless $result > 0 and $dirLen;
|
|
7071
|
+
$offset += $dirLen;
|
|
7072
|
+
last if $dataPos and $$self{TrailerStart} and $dataPos <= $$self{TrailerStart};
|
|
6998
7073
|
# look for next trailer
|
|
6999
|
-
$
|
|
7000
|
-
|
|
7074
|
+
my $nextTrail = $self->IdentifyTrailer($raf, $offset);
|
|
7075
|
+
# process Google trailer after all others if necessary and not done already
|
|
7076
|
+
unless ($nextTrail) {
|
|
7077
|
+
last unless $$self{ProcessGoogleTrailer};
|
|
7078
|
+
$nextTrail = { DirName => 'Google', RAF => $raf };
|
|
7079
|
+
}
|
|
7001
7080
|
$dirName = $$dirInfo{DirName} = $$nextTrail{DirName};
|
|
7002
|
-
$raf->Seek($pos, 0);
|
|
7003
7081
|
}
|
|
7004
7082
|
SetByteOrder($byteOrder); # restore original byte order
|
|
7005
|
-
$raf->Seek($pos
|
|
7083
|
+
$raf->Seek($pos); # restore original file position
|
|
7006
7084
|
$$dirInfo{OutFile} = $outfile; # restore original outfile
|
|
7007
7085
|
$$dirInfo{Offset} = $offset; # return offset from EOF to start of first trailer
|
|
7008
7086
|
$$dirInfo{Fixup} = $fixup; # return fixup information
|
|
@@ -7399,12 +7477,57 @@ sub ProcessJPEG($$;$)
|
|
|
7399
7477
|
$foundSOS = 1;
|
|
7400
7478
|
# all done with meta information unless we have a trailer
|
|
7401
7479
|
$verbose and print $out "${indent}JPEG SOS\n";
|
|
7480
|
+
# process extended XMP now if it existed
|
|
7481
|
+
# (must do this before trailers because XMP is required to process Google trailer)
|
|
7482
|
+
if (%extendedXMP) {
|
|
7483
|
+
my $guid;
|
|
7484
|
+
# GUID indicated by the last main XMP segment
|
|
7485
|
+
my $goodGuid = $$self{VALUE}{HasExtendedXMP} || '';
|
|
7486
|
+
# GUID of the extended XMP that we will process ('2' for all)
|
|
7487
|
+
my $readGuid = $$options{ExtendedXMP} || 0;
|
|
7488
|
+
$readGuid = $goodGuid if $readGuid eq '1';
|
|
7489
|
+
foreach $guid (sort keys %extendedXMP) {
|
|
7490
|
+
next unless length $guid == 32; # ignore other (internal) keys
|
|
7491
|
+
my $extXMP = $extendedXMP{$guid};
|
|
7492
|
+
my ($off, @offsets, $warn);
|
|
7493
|
+
# make sure we have all chunks, and create a list of sorted offsets
|
|
7494
|
+
for ($off=0; $off<$$extXMP{Size}; ) {
|
|
7495
|
+
last unless defined $$extXMP{$off};
|
|
7496
|
+
push @offsets, $off;
|
|
7497
|
+
$off += length $$extXMP{$off};
|
|
7498
|
+
}
|
|
7499
|
+
unless ($off == $$extXMP{Size}) {
|
|
7500
|
+
$self->Warn("Incomplete extended XMP (GUID $guid)");
|
|
7501
|
+
next;
|
|
7502
|
+
}
|
|
7503
|
+
if ($guid eq $readGuid or $readGuid eq '2') {
|
|
7504
|
+
$warn = 'Reading non-' if $guid ne $goodGuid;
|
|
7505
|
+
my $buff = '';
|
|
7506
|
+
# assemble XMP all together
|
|
7507
|
+
$buff .= $$extXMP{$_} foreach @offsets;
|
|
7508
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
|
|
7509
|
+
my %dirInfo = (
|
|
7510
|
+
DataPt => \$buff,
|
|
7511
|
+
Parent => 'APP1',
|
|
7512
|
+
IsExtended => 1,
|
|
7513
|
+
);
|
|
7514
|
+
$$path[$pn] = 'APP1';
|
|
7515
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7516
|
+
pop @$path;
|
|
7517
|
+
} else {
|
|
7518
|
+
$warn = 'Ignored ';
|
|
7519
|
+
$warn .= 'non-' if $guid ne $goodGuid;
|
|
7520
|
+
}
|
|
7521
|
+
$self->Warn("${warn}standard extended XMP (GUID $guid)") if $warn;
|
|
7522
|
+
delete $extendedXMP{$guid};
|
|
7523
|
+
}
|
|
7524
|
+
}
|
|
7402
7525
|
unless ($fast) {
|
|
7403
|
-
$trailInfo = IdentifyTrailer($raf);
|
|
7526
|
+
$trailInfo = $self->IdentifyTrailer($raf);
|
|
7404
7527
|
# process trailer now unless we are doing verbose dump
|
|
7405
7528
|
if ($trailInfo and $verbose < 3 and not $htmlDump) {
|
|
7406
7529
|
# process trailers (keep trailInfo to finish processing later
|
|
7407
|
-
# only if we can't finish without scanning from
|
|
7530
|
+
# only if we can't finish without scanning from JPEG EOF)
|
|
7408
7531
|
$self->ProcessTrailers($trailInfo) and undef $trailInfo;
|
|
7409
7532
|
}
|
|
7410
7533
|
if ($wantTrailer and $$self{PreviewImageStart}) {
|
|
@@ -7577,7 +7700,7 @@ sub ProcessJPEG($$;$)
|
|
|
7577
7700
|
my $n = length($1) + 1;
|
|
7578
7701
|
$self->HDump($segPos+pos($$dataPt)-$n, $n, '[Vivo HiddenData]', undef, 0x08);
|
|
7579
7702
|
}
|
|
7580
|
-
my $tbl = GetTagTable('Image::ExifTool::Vivo
|
|
7703
|
+
my $tbl = GetTagTable('Image::ExifTool::Trailer::Vivo');
|
|
7581
7704
|
$self->HandleTag($tbl, HiddenData => $1);
|
|
7582
7705
|
}
|
|
7583
7706
|
# avoid looking for preview unless necessary because it really slows
|
|
@@ -7855,6 +7978,12 @@ sub ProcessJPEG($$;$)
|
|
|
7855
7978
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7856
7979
|
undef $scalado;
|
|
7857
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);
|
|
7858
7987
|
} elsif ($$segDataPt =~ /^FPXR\0/) {
|
|
7859
7988
|
next if $fast > 1; # skip processing for very fast
|
|
7860
7989
|
$dumpType = 'FPXR';
|
|
@@ -8237,50 +8366,6 @@ sub ProcessJPEG($$;$)
|
|
|
8237
8366
|
}
|
|
8238
8367
|
undef $$segDataPt;
|
|
8239
8368
|
}
|
|
8240
|
-
# process extended XMP now if it existed
|
|
8241
|
-
if (%extendedXMP) {
|
|
8242
|
-
my $guid;
|
|
8243
|
-
# GUID indicated by the last main XMP segment
|
|
8244
|
-
my $goodGuid = $$self{VALUE}{HasExtendedXMP} || '';
|
|
8245
|
-
# GUID of the extended XMP that we will process ('2' for all)
|
|
8246
|
-
my $readGuid = $$options{ExtendedXMP} || 0;
|
|
8247
|
-
$readGuid = $goodGuid if $readGuid eq '1';
|
|
8248
|
-
foreach $guid (sort keys %extendedXMP) {
|
|
8249
|
-
next unless length $guid == 32; # ignore other (internal) keys
|
|
8250
|
-
my $extXMP = $extendedXMP{$guid};
|
|
8251
|
-
my ($off, @offsets, $warn);
|
|
8252
|
-
# make sure we have all chunks, and create a list of sorted offsets
|
|
8253
|
-
for ($off=0; $off<$$extXMP{Size}; ) {
|
|
8254
|
-
last unless defined $$extXMP{$off};
|
|
8255
|
-
push @offsets, $off;
|
|
8256
|
-
$off += length $$extXMP{$off};
|
|
8257
|
-
}
|
|
8258
|
-
unless ($off == $$extXMP{Size}) {
|
|
8259
|
-
$self->Warn("Incomplete extended XMP (GUID $guid)");
|
|
8260
|
-
next;
|
|
8261
|
-
}
|
|
8262
|
-
if ($guid eq $readGuid or $readGuid eq '2') {
|
|
8263
|
-
$warn = 'Reading non-' if $guid ne $goodGuid;
|
|
8264
|
-
my $buff = '';
|
|
8265
|
-
# assemble XMP all together
|
|
8266
|
-
$buff .= $$extXMP{$_} foreach @offsets;
|
|
8267
|
-
my $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
|
|
8268
|
-
my %dirInfo = (
|
|
8269
|
-
DataPt => \$buff,
|
|
8270
|
-
Parent => 'APP1',
|
|
8271
|
-
IsExtended => 1,
|
|
8272
|
-
);
|
|
8273
|
-
$$path[$pn] = 'APP1';
|
|
8274
|
-
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
8275
|
-
pop @$path;
|
|
8276
|
-
} else {
|
|
8277
|
-
$warn = 'Ignored ';
|
|
8278
|
-
$warn .= 'non-' if $guid ne $goodGuid;
|
|
8279
|
-
}
|
|
8280
|
-
$self->Warn("${warn}standard extended XMP (GUID $guid)") if $warn;
|
|
8281
|
-
delete $extendedXMP{$guid};
|
|
8282
|
-
}
|
|
8283
|
-
}
|
|
8284
8369
|
# print verbose hash message if necessary
|
|
8285
8370
|
print $out "${indent}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
|
|
8286
8371
|
# calculate JPEGDigest if requested
|
|
@@ -8555,9 +8640,11 @@ sub DoProcessTIFF($$;$)
|
|
|
8555
8640
|
}
|
|
8556
8641
|
# process information in recognized trailers
|
|
8557
8642
|
if ($raf) {
|
|
8558
|
-
my $trailInfo = IdentifyTrailer($raf);
|
|
8643
|
+
my $trailInfo = $self->IdentifyTrailer($raf);
|
|
8559
8644
|
if ($trailInfo) {
|
|
8560
|
-
|
|
8645
|
+
# scan to find AFCP if necessary (Note: we are scanning
|
|
8646
|
+
# from a random file position in the TIFF)
|
|
8647
|
+
$$trailInfo{ScanForTrailer} = 1;
|
|
8561
8648
|
$self->ProcessTrailers($trailInfo);
|
|
8562
8649
|
}
|
|
8563
8650
|
# dump any other known trailer (eg. A100 RAW Data)
|
|
@@ -8658,11 +8745,12 @@ sub DoProcessTIFF($$;$)
|
|
|
8658
8745
|
for (;;) {
|
|
8659
8746
|
last unless $extra > 12;
|
|
8660
8747
|
$raf->Seek($tiffEnd); # seek back to end of image
|
|
8661
|
-
$trailInfo = IdentifyTrailer($raf);
|
|
8748
|
+
$trailInfo = $self->IdentifyTrailer($raf);
|
|
8662
8749
|
last unless $trailInfo;
|
|
8663
8750
|
my $tbuf = '';
|
|
8664
8751
|
$$trailInfo{OutFile} = \$tbuf; # rewrite trailer(s)
|
|
8665
8752
|
$$trailInfo{ScanForTrailer} = 1; # scan for AFCP if necessary
|
|
8753
|
+
$$self{TrailerStart} = $tiffEnd;
|
|
8666
8754
|
# rewrite all trailers to buffer
|
|
8667
8755
|
unless ($self->ProcessTrailers($trailInfo)) {
|
|
8668
8756
|
undef $trailInfo;
|
|
@@ -8874,7 +8962,7 @@ sub ProcessDirectory($$$;$)
|
|
|
8874
8962
|
($$dirInfo{DirLen} or not defined $$dirInfo{DirLen}))
|
|
8875
8963
|
{
|
|
8876
8964
|
my $addr = $$dirInfo{DirStart} + $$dirInfo{DataPos} + ($$dirInfo{Base}||0) + $$self{BASE};
|
|
8877
|
-
if ($$self{PROCESSED}{$addr}) {
|
|
8965
|
+
if ($$self{PROCESSED}{$addr} and not $$dirInfo{NotDup}) {
|
|
8878
8966
|
$self->Warn("$dirName pointer references previous $$self{PROCESSED}{$addr} directory");
|
|
8879
8967
|
# patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
|
|
8880
8968
|
return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
|
|
@@ -9085,10 +9173,11 @@ sub AddTagToTable($$;$$)
|
|
|
9085
9173
|
# Handle simple extraction of new tag information
|
|
9086
9174
|
# Inputs: 0) ExifTool object ref, 1) tag table reference, 2) tagID, 3) value,
|
|
9087
9175
|
# 4-N) parameters hash: Index, DataPt, DataPos, Base, Start, Size, Parent,
|
|
9088
|
-
# TagInfo, ProcessProc, RAF, Format, Count
|
|
9176
|
+
# TagInfo, ProcessProc, RAF, Format, Count, MakeTagInfo
|
|
9089
9177
|
# Returns: tag key or undef if tag not found
|
|
9090
9178
|
# Notes: if value is not defined, it is extracted from DataPt using TagInfo
|
|
9091
9179
|
# Format and Count if provided
|
|
9180
|
+
# - set MakeTagInfo to add tag info for unknown tags with name made from tag ID
|
|
9092
9181
|
sub HandleTag($$$$;%)
|
|
9093
9182
|
{
|
|
9094
9183
|
my ($self, $tagTablePtr, $tag, $val, %parms) = @_;
|
|
@@ -9100,6 +9189,15 @@ sub HandleTag($$$$;%)
|
|
|
9100
9189
|
|
|
9101
9190
|
if ($tagInfo) {
|
|
9102
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);
|
|
9103
9201
|
} else {
|
|
9104
9202
|
return undef unless $verbose;
|
|
9105
9203
|
$tagInfo = { Name => "tag $tag" }; # create temporary tagInfo hash
|
|
@@ -9157,10 +9255,11 @@ sub HandleTag($$$$;%)
|
|
|
9157
9255
|
}
|
|
9158
9256
|
$self->Warn("RawConv $tag: " . CleanWarning()) if $evalWarning;
|
|
9159
9257
|
return undef unless defined $val;
|
|
9160
|
-
$
|
|
9161
|
-
$dataPt = \$val;
|
|
9258
|
+
$dataPt = ref $val eq 'SCALAR' ? $val : \$val;
|
|
9162
9259
|
$subdirStart = 0;
|
|
9163
|
-
$subdirLen = length
|
|
9260
|
+
$subdirLen = length $$dataPt;
|
|
9261
|
+
} elsif (not $dataPt) {
|
|
9262
|
+
$dataPt = ref $val eq 'SCALAR' ? $val : \$val;
|
|
9164
9263
|
}
|
|
9165
9264
|
if ($$subdir{Start}) {
|
|
9166
9265
|
my $valuePtr = 0;
|
|
@@ -9169,7 +9268,6 @@ sub HandleTag($$$$;%)
|
|
|
9169
9268
|
$subdirStart += $off;
|
|
9170
9269
|
$subdirLen -= $off;
|
|
9171
9270
|
}
|
|
9172
|
-
$dataPt or $dataPt = \$val;
|
|
9173
9271
|
# process subdirectory information
|
|
9174
9272
|
my %dirInfo = (
|
|
9175
9273
|
DirName => $$subdir{DirName} || $$tagInfo{Name},
|
|
@@ -9890,6 +9988,7 @@ sub ProcessBinaryData($$$)
|
|
|
9890
9988
|
$subdirBase = eval($$subdir{Base}) + $base;
|
|
9891
9989
|
}
|
|
9892
9990
|
my $start = $$subdir{Start} || 0;
|
|
9991
|
+
my $notDup;
|
|
9893
9992
|
if ($start =~ /\$/) {
|
|
9894
9993
|
# ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
|
|
9895
9994
|
next unless $val;
|
|
@@ -9900,6 +9999,7 @@ sub ProcessBinaryData($$$)
|
|
|
9900
9999
|
$len = $dataLen - $start unless $len and $len <= $dataLen - $start;
|
|
9901
10000
|
} else {
|
|
9902
10001
|
$start += $dirStart + $entry;
|
|
10002
|
+
$notDup = 1,
|
|
9903
10003
|
}
|
|
9904
10004
|
my %subdirInfo = (
|
|
9905
10005
|
DataPt => $dataPt,
|
|
@@ -9908,6 +10008,7 @@ sub ProcessBinaryData($$$)
|
|
|
9908
10008
|
DirStart => $start,
|
|
9909
10009
|
DirLen => $len,
|
|
9910
10010
|
Base => $subdirBase,
|
|
10011
|
+
NotDup => $notDup,
|
|
9911
10012
|
);
|
|
9912
10013
|
delete $$self{NO_UNKNOWN};
|
|
9913
10014
|
$self->ProcessDirectory(\%subdirInfo, $subTablePtr, $$subdir{ProcessProc});
|