exiftool-vendored.pl 13.0.1 → 13.16.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 +254 -20
- package/bin/MANIFEST +10 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +3 -3
- package/bin/arg_files/exif2xmp.args +4 -0
- package/bin/arg_files/xmp2exif.args +2 -1
- package/bin/build_geolocation +1 -1
- package/bin/exiftool +356 -213
- package/bin/lib/File/RandomAccess.pm +1 -1
- package/bin/lib/File/RandomAccess.pod +2 -2
- package/bin/lib/Image/ExifTool/AAC.pm +1 -1
- package/bin/lib/Image/ExifTool/AES.pm +1 -1
- package/bin/lib/Image/ExifTool/AFCP.pm +6 -6
- package/bin/lib/Image/ExifTool/AIFF.pm +2 -2
- package/bin/lib/Image/ExifTool/APE.pm +2 -2
- package/bin/lib/Image/ExifTool/APP12.pm +1 -1
- package/bin/lib/Image/ExifTool/ASF.pm +2 -2
- package/bin/lib/Image/ExifTool/Apple.pm +11 -9
- package/bin/lib/Image/ExifTool/Audible.pm +1 -1
- package/bin/lib/Image/ExifTool/BMP.pm +1 -1
- package/bin/lib/Image/ExifTool/BPG.pm +1 -1
- package/bin/lib/Image/ExifTool/BZZ.pm +1 -1
- package/bin/lib/Image/ExifTool/BigTIFF.pm +1 -1
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +36 -22
- package/bin/lib/Image/ExifTool/CBOR.pm +5 -2
- package/bin/lib/Image/ExifTool/Canon.pm +66 -27
- package/bin/lib/Image/ExifTool/CanonCustom.pm +1 -1
- package/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
- package/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
- package/bin/lib/Image/ExifTool/Casio.pm +1 -1
- package/bin/lib/Image/ExifTool/Charset.pm +1 -1
- package/bin/lib/Image/ExifTool/DICOM.pm +1 -1
- package/bin/lib/Image/ExifTool/DJI.pm +196 -30
- package/bin/lib/Image/ExifTool/DNG.pm +1 -1
- package/bin/lib/Image/ExifTool/DPX.pm +1 -1
- package/bin/lib/Image/ExifTool/DV.pm +1 -1
- package/bin/lib/Image/ExifTool/DarwinCore.pm +1 -1
- package/bin/lib/Image/ExifTool/DjVu.pm +1 -1
- package/bin/lib/Image/ExifTool/EXE.pm +138 -33
- package/bin/lib/Image/ExifTool/Exif.pm +29 -16
- package/bin/lib/Image/ExifTool/FITS.pm +3 -3
- package/bin/lib/Image/ExifTool/FLAC.pm +1 -1
- package/bin/lib/Image/ExifTool/FLIF.pm +3 -3
- package/bin/lib/Image/ExifTool/FLIR.pm +1 -1
- package/bin/lib/Image/ExifTool/Fixup.pm +1 -1
- package/bin/lib/Image/ExifTool/Flash.pm +1 -1
- package/bin/lib/Image/ExifTool/FlashPix.pm +17 -21
- package/bin/lib/Image/ExifTool/Font.pm +2 -2
- package/bin/lib/Image/ExifTool/FotoStation.pm +1 -1
- package/bin/lib/Image/ExifTool/FujiFilm.pm +1 -1
- package/bin/lib/Image/ExifTool/GE.pm +1 -1
- package/bin/lib/Image/ExifTool/GIF.pm +144 -93
- package/bin/lib/Image/ExifTool/GIMP.pm +1 -1
- package/bin/lib/Image/ExifTool/GM.pm +1 -1
- package/bin/lib/Image/ExifTool/GPS.pm +34 -30
- package/bin/lib/Image/ExifTool/GeoTiff.pm +1 -1
- package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/lib/Image/ExifTool/Geolocation.pm +19 -9
- package/bin/lib/Image/ExifTool/Geotag.pm +46 -12
- package/bin/lib/Image/ExifTool/GoPro.pm +120 -8
- package/bin/lib/Image/ExifTool/H264.pm +1 -1
- package/bin/lib/Image/ExifTool/HP.pm +2 -2
- package/bin/lib/Image/ExifTool/HTML.pm +1 -1
- package/bin/lib/Image/ExifTool/HtmlDump.pm +1 -1
- package/bin/lib/Image/ExifTool/ICC_Profile.pm +81 -2
- package/bin/lib/Image/ExifTool/ICO.pm +1 -1
- package/bin/lib/Image/ExifTool/ID3.pm +8 -8
- package/bin/lib/Image/ExifTool/IPTC.pm +10 -7
- package/bin/lib/Image/ExifTool/ISO.pm +1 -1
- package/bin/lib/Image/ExifTool/ITC.pm +1 -1
- package/bin/lib/Image/ExifTool/Import.pm +5 -4
- package/bin/lib/Image/ExifTool/InDesign.pm +2 -2
- package/bin/lib/Image/ExifTool/InfiRay.pm +1 -1
- package/bin/lib/Image/ExifTool/JPEG.pm +32 -5
- package/bin/lib/Image/ExifTool/JPEGDigest.pm +1 -1
- package/bin/lib/Image/ExifTool/JSON.pm +1 -1
- package/bin/lib/Image/ExifTool/JVC.pm +1 -1
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +10 -9
- package/bin/lib/Image/ExifTool/Kodak.pm +1 -1
- package/bin/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/LIF.pm +1 -1
- package/bin/lib/Image/ExifTool/LNK.pm +2 -2
- package/bin/lib/Image/ExifTool/Lang/cs.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/de.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/en_ca.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/en_gb.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/fi.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/fr.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/it.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/ja.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/ko.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/nl.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/pl.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/ru.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/sk.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/sv.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/tr.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
- package/bin/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
- package/bin/lib/Image/ExifTool/Leaf.pm +1 -1
- package/bin/lib/Image/ExifTool/LigoGPS.pm +409 -0
- package/bin/lib/Image/ExifTool/Lytro.pm +1 -1
- package/bin/lib/Image/ExifTool/M2TS.pm +57 -18
- package/bin/lib/Image/ExifTool/MIE.pm +15 -6
- package/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
- package/bin/lib/Image/ExifTool/MIFF.pm +1 -1
- package/bin/lib/Image/ExifTool/MISB.pm +1 -1
- package/bin/lib/Image/ExifTool/MNG.pm +1 -1
- package/bin/lib/Image/ExifTool/MOI.pm +1 -1
- package/bin/lib/Image/ExifTool/MPC.pm +1 -1
- package/bin/lib/Image/ExifTool/MPEG.pm +1 -1
- package/bin/lib/Image/ExifTool/MPF.pm +1 -1
- package/bin/lib/Image/ExifTool/MRC.pm +1 -1
- package/bin/lib/Image/ExifTool/MWG.pm +1 -1
- package/bin/lib/Image/ExifTool/MXF.pm +3 -3
- package/bin/lib/Image/ExifTool/MacOS.pm +3 -2
- package/bin/lib/Image/ExifTool/MakerNotes.pm +1 -1
- package/bin/lib/Image/ExifTool/Matroska.pm +22 -6
- package/bin/lib/Image/ExifTool/Microsoft.pm +2 -2
- package/bin/lib/Image/ExifTool/Minolta.pm +1 -1
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/Motorola.pm +1 -1
- package/bin/lib/Image/ExifTool/Nikon.pm +495 -39
- package/bin/lib/Image/ExifTool/NikonCapture.pm +1 -1
- package/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
- package/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
- package/bin/lib/Image/ExifTool/Nintendo.pm +1 -1
- package/bin/lib/Image/ExifTool/OOXML.pm +8 -8
- package/bin/lib/Image/ExifTool/Ogg.pm +1 -1
- package/bin/lib/Image/ExifTool/Olympus.pm +1 -1
- package/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
- package/bin/lib/Image/ExifTool/Opus.pm +1 -1
- package/bin/lib/Image/ExifTool/Other.pm +1 -1
- package/bin/lib/Image/ExifTool/PCX.pm +1 -1
- package/bin/lib/Image/ExifTool/PDF.pm +49 -18
- package/bin/lib/Image/ExifTool/PGF.pm +1 -1
- package/bin/lib/Image/ExifTool/PICT.pm +1 -1
- package/bin/lib/Image/ExifTool/PLIST.pm +4 -4
- package/bin/lib/Image/ExifTool/PLUS.pm +1 -1
- package/bin/lib/Image/ExifTool/PNG.pm +20 -8
- package/bin/lib/Image/ExifTool/PPM.pm +12 -3
- package/bin/lib/Image/ExifTool/PSP.pm +1 -1
- package/bin/lib/Image/ExifTool/Palm.pm +1 -1
- package/bin/lib/Image/ExifTool/Panasonic.pm +27 -3
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/Parrot.pm +1 -1
- package/bin/lib/Image/ExifTool/Pentax.pm +1 -1
- package/bin/lib/Image/ExifTool/PhaseOne.pm +4 -4
- package/bin/lib/Image/ExifTool/PhotoCD.pm +1 -1
- package/bin/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
- package/bin/lib/Image/ExifTool/Photoshop.pm +65 -4
- package/bin/lib/Image/ExifTool/PostScript.pm +1 -1
- package/bin/lib/Image/ExifTool/PrintIM.pm +1 -1
- package/bin/lib/Image/ExifTool/Protobuf.pm +270 -0
- package/bin/lib/Image/ExifTool/Qualcomm.pm +1 -1
- package/bin/lib/Image/ExifTool/QuickTime.pm +326 -88
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +199 -195
- package/bin/lib/Image/ExifTool/README +12 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +21 -6
- package/bin/lib/Image/ExifTool/RSRC.pm +1 -1
- package/bin/lib/Image/ExifTool/RTF.pm +2 -2
- package/bin/lib/Image/ExifTool/Radiance.pm +1 -1
- package/bin/lib/Image/ExifTool/Rawzor.pm +1 -1
- package/bin/lib/Image/ExifTool/Real.pm +1 -1
- package/bin/lib/Image/ExifTool/Reconyx.pm +1 -1
- package/bin/lib/Image/ExifTool/Red.pm +1 -1
- package/bin/lib/Image/ExifTool/Ricoh.pm +4 -4
- package/bin/lib/Image/ExifTool/Samsung.pm +2 -2
- package/bin/lib/Image/ExifTool/Sanyo.pm +1 -1
- package/bin/lib/Image/ExifTool/Scalado.pm +1 -1
- package/bin/lib/Image/ExifTool/Shift.pl +1 -1
- package/bin/lib/Image/ExifTool/Shortcuts.pm +1 -1
- package/bin/lib/Image/ExifTool/Sigma.pm +1 -1
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/Sony.pm +5 -4
- package/bin/lib/Image/ExifTool/SonyIDC.pm +1 -1
- package/bin/lib/Image/ExifTool/Stim.pm +1 -1
- package/bin/lib/Image/ExifTool/TagInfoXML.pm +6 -5
- package/bin/lib/Image/ExifTool/TagLookup.pm +7023 -6968
- package/bin/lib/Image/ExifTool/TagNames.pod +445 -29
- package/bin/lib/Image/ExifTool/Text.pm +4 -3
- package/bin/lib/Image/ExifTool/Theora.pm +1 -1
- package/bin/lib/Image/ExifTool/Torrent.pm +3 -3
- package/bin/lib/Image/ExifTool/Unknown.pm +1 -1
- package/bin/lib/Image/ExifTool/VCard.pm +3 -3
- package/bin/lib/Image/ExifTool/Validate.pm +6 -6
- package/bin/lib/Image/ExifTool/Vivo.pm +124 -0
- package/bin/lib/Image/ExifTool/Vorbis.pm +1 -1
- package/bin/lib/Image/ExifTool/WPG.pm +1 -1
- package/bin/lib/Image/ExifTool/WTV.pm +1 -1
- package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteExif.pl +3 -3
- package/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
- package/bin/lib/Image/ExifTool/WritePDF.pl +1 -1
- package/bin/lib/Image/ExifTool/WritePNG.pl +1 -1
- package/bin/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
- package/bin/lib/Image/ExifTool/WritePostScript.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +166 -79
- package/bin/lib/Image/ExifTool/WriteRIFF.pl +17 -6
- package/bin/lib/Image/ExifTool/WriteXMP.pl +3 -3
- package/bin/lib/Image/ExifTool/Writer.pl +89 -96
- package/bin/lib/Image/ExifTool/XISF.pm +1 -1
- package/bin/lib/Image/ExifTool/XMP.pm +28 -13
- package/bin/lib/Image/ExifTool/XMP2.pl +103 -1
- package/bin/lib/Image/ExifTool/XMPStruct.pl +2 -3
- package/bin/lib/Image/ExifTool/ZIP.pm +2 -2
- package/bin/lib/Image/ExifTool/ZISRAW.pm +1 -1
- package/bin/lib/Image/ExifTool/iWork.pm +1 -1
- package/bin/lib/Image/ExifTool.pm +335 -163
- package/bin/lib/Image/ExifTool.pod +119 -73
- package/bin/perl-Image-ExifTool.spec +1 -1
- package/bin/windows_exiftool.txt +96 -51
- package/package.json +6 -6
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# Revisions: Nov. 12/2003 - P. Harvey Created
|
|
9
9
|
# (See html/history.html for revision history)
|
|
10
10
|
#
|
|
11
|
-
# Legal: Copyright (c) 2003-
|
|
11
|
+
# Legal: Copyright (c) 2003-2025, Phil Harvey (philharvey66 at gmail.com)
|
|
12
12
|
# This library is free software; you can redistribute it and/or
|
|
13
13
|
# modify it under the same terms as Perl itself.
|
|
14
14
|
#------------------------------------------------------------------------------
|
|
@@ -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.16';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -126,6 +126,7 @@ sub MakeTiffHeader($$$$;$$);
|
|
|
126
126
|
# other subroutine definitions
|
|
127
127
|
sub SplitFileName($);
|
|
128
128
|
sub EncodeFileName($$;$);
|
|
129
|
+
sub WindowsLongPath($$);
|
|
129
130
|
sub Open($*$;$);
|
|
130
131
|
sub Exists($$;$);
|
|
131
132
|
sub IsDirectory($$);
|
|
@@ -153,10 +154,10 @@ sub ReadValue($$$;$$$);
|
|
|
153
154
|
Matroska::StdTag MOI MXF DV Flash Flash::FLV Real::Media Real::Audio
|
|
154
155
|
Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS XISF MIE JSON HTML XMP::SVG
|
|
155
156
|
Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString
|
|
156
|
-
EXE::
|
|
157
|
-
VCard::VCalendar VCard::VNote RSRC Rawzor ZIP
|
|
158
|
-
RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS
|
|
159
|
-
FlashPix::DocTable
|
|
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 ZIP
|
|
159
|
+
ZIP::GZIP ZIP::RAR ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS
|
|
160
|
+
MacOS::MDItem FlashPix::DocTable
|
|
160
161
|
);
|
|
161
162
|
|
|
162
163
|
# alphabetical list of current Lang modules
|
|
@@ -1081,6 +1082,7 @@ my %xmpShorthandOpt = ( 0 => 'None', 1 => 'Shorthand', 2 => ['Shorthand','OneDes
|
|
|
1081
1082
|
# +-----------------------------------------------------+
|
|
1082
1083
|
# (Note: All options must exist in this lookup, even if undefined,
|
|
1083
1084
|
# to facilitate case-insensitive options. 'Group#' is handled specially)
|
|
1085
|
+
# (item 3 is a flag indicating the option is undocumented)
|
|
1084
1086
|
my @availableOptions = (
|
|
1085
1087
|
[ 'Binary', undef, 'flag to extract binary values even if tag not specified' ],
|
|
1086
1088
|
[ 'ByteOrder', undef, 'default byte order when creating EXIF information' ],
|
|
@@ -1098,7 +1100,12 @@ my @availableOptions = (
|
|
|
1098
1100
|
[ 'Compress', undef, 'flag to write new values as compressed if possible' ],
|
|
1099
1101
|
[ 'CoordFormat', undef, 'GPS lat/long coordinate format' ],
|
|
1100
1102
|
[ 'DateFormat', undef, 'format for date/time' ],
|
|
1103
|
+
[ 'Debug', undef, 'enable debugging output', 1 ], # (undocumented)
|
|
1101
1104
|
[ 'Duplicates', 1, 'flag to save duplicate tag values' ],
|
|
1105
|
+
# ("require Encode" hangs on my Windows 10 virtual machine running under MacOS if
|
|
1106
|
+
# the current working directory has a long path name. This problem hasn't been
|
|
1107
|
+
# seen on other Windows systems, so I'm leaving this option undocumented for now)
|
|
1108
|
+
[ 'EncodeHangs', undef, 'flag set to avoid using Encode if it hangs on your system', 1 ], # (undocumented)
|
|
1102
1109
|
[ 'Escape', undef, 'escape special characters' ],
|
|
1103
1110
|
[ 'Exclude', undef, 'tags to exclude' ],
|
|
1104
1111
|
[ 'ExtendedXMP', 1, 'strategy for reading extended XMP' ],
|
|
@@ -1119,6 +1126,7 @@ my @availableOptions = (
|
|
|
1119
1126
|
[ 'GeoMinSats', undef, 'geotag minimum satellites' ],
|
|
1120
1127
|
[ 'GeoSpeedRef', undef, 'geotag GPSSpeedRef' ],
|
|
1121
1128
|
[ 'GlobalTimeShift', undef, 'apply time shift to all extracted date/time values' ],
|
|
1129
|
+
[ 'GPSQuadrant', undef, 'quadrant for GPS if not otherwise known' ],
|
|
1122
1130
|
[ 'Group#', undef, 'return tags for specified groups in family #' ],
|
|
1123
1131
|
[ 'HexTagIDs', 0, 'use hex tag ID\'s in family 7 group names' ],
|
|
1124
1132
|
[ 'HtmlDump', 0, 'HTML dump (0-3, higher # = bigger limit)' ],
|
|
@@ -1130,11 +1138,12 @@ my @availableOptions = (
|
|
|
1130
1138
|
[ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
|
|
1131
1139
|
[ 'LargeFileSupport', 1, 'flag indicating support of 64-bit file offsets' ],
|
|
1132
1140
|
[ 'LimitLongValues', 60, 'length limit for long values' ],
|
|
1133
|
-
[ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]' ],
|
|
1141
|
+
[ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]', 1 ],
|
|
1134
1142
|
[ 'ListItem', undef, 'used to return a specific item from lists' ],
|
|
1135
1143
|
[ 'ListJoin', ', ', 'join lists together with this separator' ],
|
|
1136
|
-
[ 'ListSep', ', ', '[deprecated, use ListSplit and ListJoin instead]' ],
|
|
1144
|
+
[ 'ListSep', ', ', '[deprecated, use ListSplit and ListJoin instead]', 1 ],
|
|
1137
1145
|
[ 'ListSplit', undef, 'regex for splitting list-type tag values when writing' ],
|
|
1146
|
+
# LigoGPSScale - undocumented scale for unfuzzing LIGO GPS: 1,2,3 for standard scales (1 default), or scale value
|
|
1138
1147
|
[ 'MakerNotes', undef, 'extract maker notes as a block' ],
|
|
1139
1148
|
[ 'MDItemTags', undef, 'extract MacOS metadata item tags' ],
|
|
1140
1149
|
[ 'MissingTagValue', undef, 'value for missing tags when expanded in expressions' ],
|
|
@@ -1150,6 +1159,7 @@ my @availableOptions = (
|
|
|
1150
1159
|
[ 'QuickTimeUTC', undef, 'assume that QuickTime date/time tags are stored as UTC' ],
|
|
1151
1160
|
[ 'RequestAll', undef, 'extract all tags that must be specifically requested' ],
|
|
1152
1161
|
[ 'RequestTags', undef, 'extra tags to request (on top of those in the tag list)' ],
|
|
1162
|
+
[ 'SaveBin', undef, 'save binary values of tags' ],
|
|
1153
1163
|
[ 'SaveFormat', undef, 'save family 6 tag TIFF format' ],
|
|
1154
1164
|
[ 'SavePath', undef, 'save family 5 location path' ],
|
|
1155
1165
|
[ 'ScanForXMP', undef, 'flag to scan for XMP information in all files' ],
|
|
@@ -1165,11 +1175,12 @@ my @availableOptions = (
|
|
|
1165
1175
|
[ 'UserParam', { }, 'user parameters for additional user-defined tag values' ],
|
|
1166
1176
|
[ 'Validate', undef, 'perform additional validation' ],
|
|
1167
1177
|
[ 'Verbose', 0, 'print verbose messages (0-5, higher # = more verbose)' ],
|
|
1178
|
+
[ 'WindowsLongPath', 1, 'enable support for long pathnames (enables WindowsWideFile)' ],
|
|
1168
1179
|
[ 'WindowsWideFile', undef, 'force the use of Windows wide-character file routines' ], # (see forum15208)
|
|
1169
1180
|
[ 'WriteMode', 'wcg', 'enable all write modes by default' ],
|
|
1170
1181
|
[ 'XAttrTags', undef, 'extract MacOS extended attribute tags' ],
|
|
1171
1182
|
[ 'XMPAutoConv', 1, 'automatic conversion of unknown XMP tag values' ],
|
|
1172
|
-
[ 'XMPShorthand', 0, '[deprecated, use Compact=Shorthand instead]' ],
|
|
1183
|
+
[ 'XMPShorthand', 0, '[deprecated, use Compact=Shorthand instead]', 1 ],
|
|
1173
1184
|
);
|
|
1174
1185
|
|
|
1175
1186
|
# default family 0 group priority for writing
|
|
@@ -1256,7 +1267,9 @@ my %systemTagsNotes = (
|
|
|
1256
1267
|
Use the -a or L<Duplicates|../ExifTool.html#Duplicates> option to see all warnings if more than one
|
|
1257
1268
|
occurred. Minor warnings may be ignored with the -m or L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors>
|
|
1258
1269
|
option. Minor warnings with a capital "M" in the "[Minor]" designation
|
|
1259
|
-
indicate that the processing is affected by ignoring the warning
|
|
1270
|
+
indicate that the processing is affected by ignoring the warning. Multiple
|
|
1271
|
+
identical warnings are indicated by a count after the warning message, eg.
|
|
1272
|
+
"[x2]" if the same warning occurred twice
|
|
1260
1273
|
},
|
|
1261
1274
|
},
|
|
1262
1275
|
Comment => {
|
|
@@ -2488,6 +2501,7 @@ sub Options($$;@)
|
|
|
2488
2501
|
}
|
|
2489
2502
|
} elsif ($param =~ /^(IgnoreTags|IgnoreGroups)$/) {
|
|
2490
2503
|
if (defined $newVal) {
|
|
2504
|
+
ref $newVal eq 'HASH' and $$options{$param} = $newVal, next;
|
|
2491
2505
|
# parse list from delimited string if necessary
|
|
2492
2506
|
my @ignoreList = (ref $newVal eq 'ARRAY') ? @$newVal : ($newVal =~ /[-\w?*:#]+/g);
|
|
2493
2507
|
ExpandShortcuts(\@ignoreList) if $param eq 'IgnoreTags';
|
|
@@ -2574,7 +2588,7 @@ sub Options($$;@)
|
|
|
2574
2588
|
warn("Can't set $param to undef\n");
|
|
2575
2589
|
}
|
|
2576
2590
|
} elsif (lc $param eq 'geodir') {
|
|
2577
|
-
$Image::ExifTool::Geolocation::geoDir = $newVal;
|
|
2591
|
+
$Image::ExifTool::Geolocation::geoDir = $newVal;
|
|
2578
2592
|
} else {
|
|
2579
2593
|
if ($param eq 'Escape') {
|
|
2580
2594
|
# set ESCAPE_PROC
|
|
@@ -2652,7 +2666,7 @@ sub ExtractInfo($;@)
|
|
|
2652
2666
|
my $fast = $$options{FastScan} || 0;
|
|
2653
2667
|
my $req = $$self{REQ_TAG_LOOKUP};
|
|
2654
2668
|
my $reqAll = $$options{RequestAll} || 0;
|
|
2655
|
-
my (%saveOptions, $reEntry, $rsize, $zid, $type, @startTime, $saveOrder, $isDir);
|
|
2669
|
+
my (%saveOptions, $reEntry, $rsize, $zid, $type, @startTime, $saveOrder, $isDir, $i);
|
|
2656
2670
|
|
|
2657
2671
|
# check for internal ReEntry option to allow recursive calls to ExtractInfo
|
|
2658
2672
|
if (ref $_[1] eq 'HASH' and $_[1]{ReEntry} and
|
|
@@ -2709,7 +2723,7 @@ sub ExtractInfo($;@)
|
|
|
2709
2723
|
if ($$req{processingtime} or $reqAll) {
|
|
2710
2724
|
eval { require Time::HiRes; @startTime = Time::HiRes::gettimeofday() };
|
|
2711
2725
|
if (not @startTime and $$req{processingtime}) {
|
|
2712
|
-
$self->
|
|
2726
|
+
$self->Warn('Install Time::HiRes to generate ProcessingTime');
|
|
2713
2727
|
}
|
|
2714
2728
|
}
|
|
2715
2729
|
|
|
@@ -2720,12 +2734,12 @@ sub ExtractInfo($;@)
|
|
|
2720
2734
|
if (require Digest::SHA) {
|
|
2721
2735
|
$$self{ImageDataHash} = Digest::SHA->new($1);
|
|
2722
2736
|
} else {
|
|
2723
|
-
$self->
|
|
2737
|
+
$self->Warn("Install Digest::SHA to calculate image data SHA$1");
|
|
2724
2738
|
}
|
|
2725
2739
|
} elsif (require Digest::MD5) {
|
|
2726
2740
|
$$self{ImageDataHash} = Digest::MD5->new;
|
|
2727
2741
|
} else {
|
|
2728
|
-
$self->
|
|
2742
|
+
$self->Warn('Install Digest::MD5 to calculate image data MD5');
|
|
2729
2743
|
}
|
|
2730
2744
|
}
|
|
2731
2745
|
++$$self{FILE_SEQUENCE}; # count files read
|
|
@@ -2754,12 +2768,18 @@ sub ExtractInfo($;@)
|
|
|
2754
2768
|
if ($$req{filepath} or
|
|
2755
2769
|
($reqAll and not $$self{EXCL_TAG_LOOKUP}{filepath}))
|
|
2756
2770
|
{
|
|
2771
|
+
my $path;
|
|
2757
2772
|
local $SIG{'__WARN__'} = \&SetWarning;
|
|
2758
|
-
if (
|
|
2759
|
-
|
|
2760
|
-
|
|
2773
|
+
if ($^O eq 'MSWin32' and $$options{WindowsLongPath}) {
|
|
2774
|
+
$path = $self->WindowsLongPath($filename);
|
|
2775
|
+
} elsif (eval { require Cwd }) {
|
|
2776
|
+
$path = eval { Cwd::abs_path($filename) };
|
|
2777
|
+
}
|
|
2778
|
+
if (defined $path) {
|
|
2779
|
+
$path =~ tr/\\/\// if $^O eq 'MSWin32'; # return forward slashes
|
|
2780
|
+
$self->FoundTag('FilePath', $path);
|
|
2761
2781
|
} elsif ($$req{filepath}) {
|
|
2762
|
-
$self->
|
|
2782
|
+
$self->Warn('The Perl Cwd module must be installed to use FilePath');
|
|
2763
2783
|
}
|
|
2764
2784
|
}
|
|
2765
2785
|
# get size of resource fork on Mac OS
|
|
@@ -3098,6 +3118,15 @@ sub ExtractInfo($;@)
|
|
|
3098
3118
|
# and as such it can't be used in user-defined Composite tags
|
|
3099
3119
|
@startTime and $self->FoundTag('ProcessingTime', Time::HiRes::tv_interval(\@startTime));
|
|
3100
3120
|
|
|
3121
|
+
# add numbers to warnings with multiple occurrences
|
|
3122
|
+
if (%{$$self{WAS_WARNED}}) {
|
|
3123
|
+
my ($tag, $val) = ( 'Warning', $$self{VALUE} );
|
|
3124
|
+
for ($i=1; $$val{$tag}; ++$i) {
|
|
3125
|
+
my $n = $$self{WAS_WARNED}{$$val{$tag}};
|
|
3126
|
+
$$val{$tag} .= " [x$n]" if $n and $n > 1;
|
|
3127
|
+
$tag = "Warning ($i)";
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3101
3130
|
# restore original options
|
|
3102
3131
|
%saveOptions and $$self{OPTIONS} = \%saveOptions;
|
|
3103
3132
|
|
|
@@ -3328,8 +3357,8 @@ sub GetRequestedTags($)
|
|
|
3328
3357
|
# Inputs: 0) ExifTool object reference
|
|
3329
3358
|
# 1) tag key or tag name with optional group names (case sensitive)
|
|
3330
3359
|
# (or flattened tagInfo for getting field values, not part of public API)
|
|
3331
|
-
# 2) [optional] Value type: PrintConv, ValueConv, Both, Raw or Rational, the
|
|
3332
|
-
# is PrintConv or ValueConv, depending on the PrintConv option setting
|
|
3360
|
+
# 2) [optional] Value type: PrintConv, ValueConv, Both, Raw, Bin or Rational, the
|
|
3361
|
+
# default is PrintConv or ValueConv, depending on the PrintConv option setting
|
|
3333
3362
|
# 3) raw field value (not part of public API)
|
|
3334
3363
|
# Returns: Scalar context: tag value or undefined
|
|
3335
3364
|
# List context: list of values or empty list
|
|
@@ -3358,7 +3387,8 @@ sub GetValue($$;$)
|
|
|
3358
3387
|
}
|
|
3359
3388
|
# figure out what conversions to do
|
|
3360
3389
|
if ($type) {
|
|
3361
|
-
return $$self{
|
|
3390
|
+
return $$self{TAG_EXTRA}{$tag}{Rational} if $type eq 'Rational';
|
|
3391
|
+
return $$self{TAG_EXTRA}{$tag}{BinVal} if $type eq 'Bin';
|
|
3362
3392
|
} else {
|
|
3363
3393
|
$type = $$self{OPTIONS}{PrintConv} ? 'PrintConv' : 'ValueConv';
|
|
3364
3394
|
}
|
|
@@ -3702,9 +3732,10 @@ sub GetGroup($$;$)
|
|
|
3702
3732
|
$tag = $$tagInfo{Name};
|
|
3703
3733
|
# set flag so we don't get extra information for an extracted tag
|
|
3704
3734
|
$byTagInfo = 1;
|
|
3735
|
+
$ex = { };
|
|
3705
3736
|
} else {
|
|
3706
3737
|
$tagInfo = $$self{TAG_INFO}{$tag} || { };
|
|
3707
|
-
$ex = $$self{TAG_EXTRA}{$tag};
|
|
3738
|
+
$ex = $$self{TAG_EXTRA}{$tag} || { };
|
|
3708
3739
|
}
|
|
3709
3740
|
my $groups = $$tagInfo{Groups};
|
|
3710
3741
|
# fill in default groups unless already done
|
|
@@ -3723,32 +3754,30 @@ sub GetGroup($$;$)
|
|
|
3723
3754
|
if (defined $family and $family ne '-1') {
|
|
3724
3755
|
if ($family =~ /[^\d]/) {
|
|
3725
3756
|
@families = ($family =~ /\d+/g);
|
|
3726
|
-
return(
|
|
3757
|
+
return($$ex{G0} || $$groups{0}) unless @families;
|
|
3727
3758
|
$simplify = 1 unless $family =~ /^:/;
|
|
3728
3759
|
undef $family;
|
|
3729
3760
|
foreach (0..2) { $groups[$_] = $$groups{$_}; }
|
|
3730
3761
|
$noID = 1 if @families == 1 and $families[0] != 7;
|
|
3731
3762
|
} else {
|
|
3732
|
-
return(
|
|
3763
|
+
return($$ex{"G$family"} || $$groups{$family}) if $family == 0 or $family == 2;
|
|
3733
3764
|
$groups[1] = $$groups{1};
|
|
3734
3765
|
}
|
|
3735
3766
|
} else {
|
|
3736
|
-
return(
|
|
3767
|
+
return($$ex{G0} || $$groups{0}) unless wantarray;
|
|
3737
3768
|
foreach (0..2) { $groups[$_] = $$groups{$_}; }
|
|
3738
3769
|
}
|
|
3739
3770
|
$groups[3] = 'Main';
|
|
3740
|
-
$groups[4] = ($tag =~ /\((\d+)\)$/) ? "Copy$1" : '';
|
|
3771
|
+
$groups[4] = ($tag =~ /\((\d+)\)$/ and $1 ne '0') ? "Copy$1" : '';
|
|
3741
3772
|
# handle dynamic group names if necessary
|
|
3742
3773
|
unless ($byTagInfo) {
|
|
3743
|
-
if
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
$groups[6] = $$ex{G6};
|
|
3751
|
-
}
|
|
3774
|
+
$groups[0] = $$ex{G0} if $$ex{G0};
|
|
3775
|
+
$groups[1] = $$ex{G1} =~ /^\+(.*)/ ? "$groups[1]$1" : $$ex{G1} if $$ex{G1};
|
|
3776
|
+
$groups[3] = 'Doc' . $$ex{G3} if $$ex{G3};
|
|
3777
|
+
$groups[5] = $$ex{G5} || $groups[1] if defined $$ex{G5};
|
|
3778
|
+
if (defined $$ex{G6}) {
|
|
3779
|
+
$groups[5] = '' unless defined $groups[5]; # (can't leave a hole in the array)
|
|
3780
|
+
$groups[6] = $$ex{G6};
|
|
3752
3781
|
}
|
|
3753
3782
|
if ($$ex{G8}) {
|
|
3754
3783
|
$groups[7] = '';
|
|
@@ -3921,12 +3950,9 @@ COMPOSITE_TAG:
|
|
|
3921
3950
|
$key = "$reqTag ($i)";
|
|
3922
3951
|
}
|
|
3923
3952
|
@keys = $self->GroupMatches($reqGroup, \@keys) if defined $reqGroup;
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
# priority tag will win in the case of duplicates within a doc
|
|
3928
|
-
$$cacheTag[$$ex{$_} ? $$ex{$_}{G3} || 0 : 0] = $_ foreach reverse @keys;
|
|
3929
|
-
}
|
|
3953
|
+
# loop through tags in reverse order of precedence so the higher
|
|
3954
|
+
# priority tag will win in the case of duplicates within a doc
|
|
3955
|
+
$$cacheTag[$$self{TAG_EXTRA}{$_}{G3} || 0] = $_ foreach reverse @keys;
|
|
3930
3956
|
}
|
|
3931
3957
|
# (set $reqTag to a bogus key if not found)
|
|
3932
3958
|
$reqTag = $$cacheTag[$doc] || "$reqTag (0)";
|
|
@@ -4140,7 +4166,7 @@ sub GetFileType(;$$)
|
|
|
4140
4166
|
$desc = $$fileType[1];
|
|
4141
4167
|
}
|
|
4142
4168
|
} else {
|
|
4143
|
-
$desc = $fileDescription{$file};
|
|
4169
|
+
$desc = $fileDescription{$file} || $file;
|
|
4144
4170
|
}
|
|
4145
4171
|
$desc .= ", $subType" if $subType;
|
|
4146
4172
|
return $desc;
|
|
@@ -4218,9 +4244,7 @@ sub Init($)
|
|
|
4218
4244
|
local $_;
|
|
4219
4245
|
my $self = shift;
|
|
4220
4246
|
# delete all DataMember variables (lower-case names)
|
|
4221
|
-
foreach
|
|
4222
|
-
/[a-z]/ and delete $$self{$_};
|
|
4223
|
-
}
|
|
4247
|
+
delete $$self{$_} foreach grep /[a-z]/, keys %$self;
|
|
4224
4248
|
undef %static_vars; # clear all static variables
|
|
4225
4249
|
delete $$self{FOUND_TAGS}; # list of found tags
|
|
4226
4250
|
delete $$self{EXIF_DATA}; # the EXIF data block
|
|
@@ -4235,7 +4259,6 @@ sub Init($)
|
|
|
4235
4259
|
$$self{FILE_ORDER} = { }; # * hash of tag order in file ('*' = based on tag key)
|
|
4236
4260
|
$$self{VALUE} = { }; # * hash of raw tag values
|
|
4237
4261
|
$$self{BOTH} = { }; # * hash for Value/PrintConv values of Require'd tags
|
|
4238
|
-
$$self{RATIONAL} = { }; # * hash of original rational components
|
|
4239
4262
|
$$self{TAG_INFO} = { }; # * hash of tag information
|
|
4240
4263
|
$$self{TAG_EXTRA} = { }; # * hash of extra tag information (dynamic group names)
|
|
4241
4264
|
$$self{PRIORITY} = { }; # * priority of current tags
|
|
@@ -4243,7 +4266,7 @@ sub Init($)
|
|
|
4243
4266
|
$$self{PROCESSED} = { }; # hash of processed directory start positions
|
|
4244
4267
|
$$self{DIR_COUNT} = { }; # count various types of directories
|
|
4245
4268
|
$$self{DUPL_TAG} = { }; # last-used index for duplicate-tag keys
|
|
4246
|
-
$$self{
|
|
4269
|
+
$$self{WAS_WARNED} = { }; # number of times each warning was issued
|
|
4247
4270
|
$$self{WRITTEN} = { }; # list of tags written (selected tags only)
|
|
4248
4271
|
$$self{FORCE_WRITE}= { }; # ForceWrite lookup (set from ForceWrite tag)
|
|
4249
4272
|
$$self{FOUND_DIR} = { }; # hash of directory names found in file
|
|
@@ -4401,6 +4424,7 @@ sub DoneExtract($)
|
|
|
4401
4424
|
local $SIG{'__WARN__'} = \&SetWarning;
|
|
4402
4425
|
undef $evalWarning;
|
|
4403
4426
|
$$opts{GeolocMulti} = $$opts{Duplicates};
|
|
4427
|
+
$self->VPrint(0, "Geolocation arguments: '${arg}'\n");
|
|
4404
4428
|
my ($cities, $dist) = Image::ExifTool::Geolocation::Geolocate($arg, $opts);
|
|
4405
4429
|
delete $$opts{GeolocMulti};
|
|
4406
4430
|
if ($cities and (@$cities < 2 or $dist or not $self->Warn('Multiple Geolocation cities are possible',2))) {
|
|
@@ -4468,13 +4492,9 @@ sub DoneExtract($)
|
|
|
4468
4492
|
my $err = $$altExifTool{VALUE}{Error};
|
|
4469
4493
|
$err and $self->Warn(qq{$err "$fileName"});
|
|
4470
4494
|
# set family 8 group name for all tags
|
|
4471
|
-
foreach
|
|
4472
|
-
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
|
4473
|
-
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
|
4474
|
-
$$ex{G8} = $g8;
|
|
4475
|
-
}
|
|
4495
|
+
$$altExifTool{TAG_EXTRA}{$_}{G8} = $g8 foreach keys %{$$altExifTool{VALUE}};
|
|
4476
4496
|
# prepare our sorted list of found tags
|
|
4477
|
-
$$altExifTool{FoundTags} =
|
|
4497
|
+
$$altExifTool{FoundTags} = $altExifTool->SetFoundTags();
|
|
4478
4498
|
$$altExifTool{DID_EXTRACT} = 1;
|
|
4479
4499
|
}
|
|
4480
4500
|
# if necessary, build composite tags that rely on tags from alternate files
|
|
@@ -4614,36 +4634,124 @@ sub SplitFileName($)
|
|
|
4614
4634
|
|
|
4615
4635
|
#------------------------------------------------------------------------------
|
|
4616
4636
|
# Encode file name for calls to system i/o routines
|
|
4617
|
-
# Inputs: 0) ExifTool ref, 1) file name in
|
|
4637
|
+
# Inputs: 0) ExifTool ref, 1) file name in CharsetFileName encoding, 2) flag to force conversion
|
|
4618
4638
|
# Returns: true if Windows Unicode routines should be used (in which case
|
|
4619
4639
|
# the file name will be encoded as a null-terminated UTF-16LE string)
|
|
4620
4640
|
sub EncodeFileName($$;$)
|
|
4621
4641
|
{
|
|
4622
4642
|
my ($self, $file, $force) = @_;
|
|
4643
|
+
return 0 if $file eq '-'; # special case for stdin pipe
|
|
4623
4644
|
my $enc = $$self{OPTIONS}{CharsetFileName};
|
|
4624
|
-
$
|
|
4625
|
-
if ($
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
if (
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
# recode as UTF-16LE and add null terminator
|
|
4632
|
-
$_[1] = $self->Decode($file, $enc, undef, 'UTF16', 'II') . "\0\0";
|
|
4633
|
-
return 1;
|
|
4634
|
-
}
|
|
4635
|
-
$self->WarnOnce('Install Win32API::File for Windows Unicode file support');
|
|
4645
|
+
my $hasSpecialChars;
|
|
4646
|
+
if ($file =~ /[\x80-\xff]/) {
|
|
4647
|
+
$hasSpecialChars = 1;
|
|
4648
|
+
if (not $enc and $^O eq 'MSWin32') {
|
|
4649
|
+
if (IsUTF8(\$file) < 0) {
|
|
4650
|
+
$self->Warn('FileName encoding must be specified') if not defined $enc;
|
|
4651
|
+
return 0;
|
|
4636
4652
|
} else {
|
|
4637
|
-
|
|
4638
|
-
$_[1] = $self->Decode($file, $enc, undef, 'UTF8') unless $enc eq 'UTF8';
|
|
4653
|
+
$enc = 'UTF8'; # assume UTF8
|
|
4639
4654
|
}
|
|
4640
4655
|
}
|
|
4641
|
-
}
|
|
4642
|
-
|
|
4656
|
+
}
|
|
4657
|
+
if ($hasSpecialChars or $force or $$self{OPTIONS}{WindowsLongPath} or $$self{OPTIONS}{WindowsWideFile}) {
|
|
4658
|
+
$enc or $enc = 'UTF8';
|
|
4659
|
+
if ($^O eq 'MSWin32') {
|
|
4660
|
+
local $SIG{'__WARN__'} = \&SetWarning;
|
|
4661
|
+
if (eval { require Win32API::File }) {
|
|
4662
|
+
$file = $self->WindowsLongPath($file) if $$self{OPTIONS}{WindowsLongPath};
|
|
4663
|
+
# recode as UTF-16LE and add null terminator
|
|
4664
|
+
$_[1] = $self->Decode($file, $enc, undef, 'UTF16', 'II') . "\0\0";
|
|
4665
|
+
return 1;
|
|
4666
|
+
}
|
|
4667
|
+
$self->Warn('Install Win32API::File for Windows wide/long file name support');
|
|
4668
|
+
} elsif ($enc ne 'UTF8') {
|
|
4669
|
+
# recode as UTF-8 for other platforms if necessary
|
|
4670
|
+
$_[1] = $self->Decode($file, $enc, undef, 'UTF8');
|
|
4671
|
+
}
|
|
4643
4672
|
}
|
|
4644
4673
|
return 0;
|
|
4645
4674
|
}
|
|
4646
4675
|
|
|
4676
|
+
#------------------------------------------------------------------------------
|
|
4677
|
+
# Rebuild a path as an absolute long path to be usable in Windows system calls
|
|
4678
|
+
# Inputs: 0) ExifTool ref, 1) path string (CharsetFileName)
|
|
4679
|
+
# Returns: normalized long path (CharsetFileName)
|
|
4680
|
+
# Note: this should only be called for Windows systems
|
|
4681
|
+
# References:
|
|
4682
|
+
# - https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
|
|
4683
|
+
# - https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
|
|
4684
|
+
# GetFullPathName supported by Windows XP and later. It handles:
|
|
4685
|
+
# full path names EG: c:\foto\sub\abc.jpg
|
|
4686
|
+
# relative EG: .\abc.jpg, ..\abc.jpg
|
|
4687
|
+
# full UNC paths EG: \\server\share\abc.jpg
|
|
4688
|
+
# relative UNC paths EG: .\abc.jpg, ..\abc.jpg
|
|
4689
|
+
# Dos device paths EG: \\.\c:\fotoabc.jpg
|
|
4690
|
+
# relative path on other drives EG: z:abc.jpg (working dir on z: z:\foto called from c:\foto)
|
|
4691
|
+
# Wide chars EG: Chars that need UTF8.
|
|
4692
|
+
my $k32GetFullPathName;
|
|
4693
|
+
sub WindowsLongPath($$)
|
|
4694
|
+
{
|
|
4695
|
+
my ($self, $path) = @_;
|
|
4696
|
+
my $debug = $$self{OPTIONS}{Debug};
|
|
4697
|
+
my $out = $$self{OPTIONS}{TextOut};
|
|
4698
|
+
my $suffix = '';
|
|
4699
|
+
my $longPath;
|
|
4700
|
+
|
|
4701
|
+
# remove common suffixes to make cache more effective
|
|
4702
|
+
if ($path =~ s/(_original|_exiftool_tmp|:Zone\.Identifier)$//) {
|
|
4703
|
+
$suffix = $1;
|
|
4704
|
+
if (not length $path or $path =~ m([:./\\]$)) {
|
|
4705
|
+
# don't remove suffix if it could be the whole file name
|
|
4706
|
+
$path .= $suffix;
|
|
4707
|
+
$suffix = '';
|
|
4708
|
+
}
|
|
4709
|
+
}
|
|
4710
|
+
return $$self{LONG_PATH_OUT}.$suffix if defined $$self{LONG_PATH_IN} and $$self{LONG_PATH_IN} eq $path;
|
|
4711
|
+
|
|
4712
|
+
$debug and print $out "WindowsLongPath input : $path$suffix\n";
|
|
4713
|
+
|
|
4714
|
+
for (;;) { # (cheap goto)
|
|
4715
|
+
($longPath = $path) =~ tr(/)(\\); # convert slashes to backslashes
|
|
4716
|
+
last if $longPath =~ /^\\\\\?\\/; # already a device path in the format we want
|
|
4717
|
+
|
|
4718
|
+
unless ($k32GetFullPathName) { # need to import (once) GetFullPathNameW
|
|
4719
|
+
last if defined $k32GetFullPathName;
|
|
4720
|
+
unless (eval { require Win32::API }) {
|
|
4721
|
+
$self->Warn('Install Win32::API to use WindowsLongPath option');
|
|
4722
|
+
last;
|
|
4723
|
+
}
|
|
4724
|
+
$k32GetFullPathName = Win32::API->new('KERNEL32', 'GetFullPathNameW', 'PNPP', 'I');
|
|
4725
|
+
unless ($k32GetFullPathName) {
|
|
4726
|
+
$k32GetFullPathName = 0;
|
|
4727
|
+
$self->Warn('Error loading Win32::API GetFullPathNameW');
|
|
4728
|
+
last;
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
my $enc = $$self{OPTIONS}{CharsetFileName} || 'UTF8';
|
|
4732
|
+
my $encPath = $self->Decode($longPath, $enc, undef, 'UTF16', 'II');# need to encode to UTF16
|
|
4733
|
+
my $lenReq = $k32GetFullPathName->Call($encPath,0,0,0) + 1; # first pass gets length required, +1 for safety (null?)
|
|
4734
|
+
my $fullPath = "\0" x $lenReq x 2; # create buffer to hold full path
|
|
4735
|
+
$k32GetFullPathName->Call($encPath, $lenReq, $fullPath, 0); # fullPath is UTF16 now
|
|
4736
|
+
$longPath = $self->Decode($fullPath, 'UTF16', 'II', $enc);
|
|
4737
|
+
|
|
4738
|
+
last if length($longPath) <= 247 - length($suffix);
|
|
4739
|
+
|
|
4740
|
+
if ($longPath =~ /^\\\\/) {
|
|
4741
|
+
$longPath = '\\\\?\\UNC' . substr($longPath, 1);
|
|
4742
|
+
} else {
|
|
4743
|
+
$longPath = '\\\\?\\' . $longPath;
|
|
4744
|
+
}
|
|
4745
|
+
last;
|
|
4746
|
+
}
|
|
4747
|
+
# this may be called repeatedly for the same file file (exists, stat, open),
|
|
4748
|
+
# so cache the last return value (without any of the suffixes that we use)
|
|
4749
|
+
$$self{LONG_PATH_IN} = $path;
|
|
4750
|
+
$$self{LONG_PATH_OUT} = $longPath;
|
|
4751
|
+
$debug and print $out "WindowsLongPath return: $longPath$suffix\n";
|
|
4752
|
+
return $longPath . $suffix;
|
|
4753
|
+
}
|
|
4754
|
+
|
|
4647
4755
|
#------------------------------------------------------------------------------
|
|
4648
4756
|
# Modified perl open() routine to properly handle special characters in file names
|
|
4649
4757
|
# Inputs: 0) ExifTool ref, 1) filehandle, 2) filename,
|
|
@@ -4773,16 +4881,16 @@ sub CreateDirectory($$)
|
|
|
4773
4881
|
my $d2 = $dir; # (must make a copy in case EncodeFileName recodes it)
|
|
4774
4882
|
if ($self->EncodeFileName($d2)) {
|
|
4775
4883
|
# handle Windows Unicode directory names
|
|
4776
|
-
unless (eval { require Win32::API }) {
|
|
4777
|
-
$err = 'Install Win32::API to create directories with Unicode names';
|
|
4778
|
-
last;
|
|
4779
|
-
}
|
|
4780
4884
|
unless (defined $k32CreateDir) {
|
|
4885
|
+
unless (eval { require Win32::API }) {
|
|
4886
|
+
$err = 'Install Win32::API to create directories with Unicode names';
|
|
4887
|
+
last;
|
|
4888
|
+
}
|
|
4781
4889
|
$k32CreateDir = Win32::API->new('KERNEL32', 'CreateDirectoryW', 'PP', 'I');
|
|
4782
4890
|
unless ($k32CreateDir) {
|
|
4783
4891
|
$k32CreateDir = 0;
|
|
4784
4892
|
# give this error once, then just "Error creating" for subsequent attempts
|
|
4785
|
-
return 'Error
|
|
4893
|
+
return 'Error loading Win32::API CreateDirectoryW';
|
|
4786
4894
|
}
|
|
4787
4895
|
}
|
|
4788
4896
|
$success = $k32CreateDir->Call($d2, 0) if $k32CreateDir;
|
|
@@ -4823,9 +4931,9 @@ sub GetFileTime($$)
|
|
|
4823
4931
|
# on Windows, try to work around incorrect file times when daylight saving time is in effect
|
|
4824
4932
|
if ($^O eq 'MSWin32') {
|
|
4825
4933
|
if (not eval { require Win32::API }) {
|
|
4826
|
-
$self->
|
|
4934
|
+
$self->Warn('Install Win32::API for proper handling of Windows file times', 1);
|
|
4827
4935
|
} elsif (not eval { require Win32API::File }) {
|
|
4828
|
-
$self->
|
|
4936
|
+
$self->Warn('Install Win32API::File for proper handling of Windows file times', 1);
|
|
4829
4937
|
} else {
|
|
4830
4938
|
# get Win32 handle, needed for GetFileTime
|
|
4831
4939
|
my $win32Handle = eval { Win32API::File::GetOsFHandle($file) };
|
|
@@ -4840,13 +4948,13 @@ sub GetFileTime($$)
|
|
|
4840
4948
|
return () if defined $k32GetFileTime;
|
|
4841
4949
|
$k32GetFileTime = Win32::API->new('KERNEL32', 'GetFileTime', 'NPPP', 'I');
|
|
4842
4950
|
unless ($k32GetFileTime) {
|
|
4843
|
-
$self->Warn('Error
|
|
4951
|
+
$self->Warn('Error loading Win32::API GetFileTime');
|
|
4844
4952
|
$k32GetFileTime = 0;
|
|
4845
4953
|
return ();
|
|
4846
4954
|
}
|
|
4847
4955
|
}
|
|
4848
4956
|
unless ($k32GetFileTime->Call($win32Handle, $ctime, $atime, $mtime)) {
|
|
4849
|
-
$self->Warn("Win32::API
|
|
4957
|
+
$self->Warn("Win32::API GetFileTime returned " . Win32::GetLastError());
|
|
4850
4958
|
return ();
|
|
4851
4959
|
}
|
|
4852
4960
|
# convert FILETIME structs to Unix seconds
|
|
@@ -4910,11 +5018,13 @@ sub ParseArguments($;@)
|
|
|
4910
5018
|
next if defined $$self{RAF};
|
|
4911
5019
|
# convert image data from UTF-8 to character stream if necessary
|
|
4912
5020
|
# (patches RHEL 3 UTF8 LANG problem)
|
|
4913
|
-
if (ref $arg eq 'SCALAR' and $] >= 5.006 and
|
|
4914
|
-
|
|
5021
|
+
if (ref $arg eq 'SCALAR' and $] >= 5.006 and ($$self{OPTIONS}{EncodeHangs} or
|
|
5022
|
+
eval { require Encode; Encode::is_utf8($$arg) } or $@))
|
|
4915
5023
|
{
|
|
5024
|
+
local $SIG{'__WARN__'} = \&SetWarning;
|
|
4916
5025
|
# repack by hand if Encode isn't available
|
|
4917
|
-
my $buff = $@ ? pack('C*',unpack($] < 5.010000 ?
|
|
5026
|
+
my $buff = ($$self{OPTIONS}{EncodeHangs} or $@) ? pack('C*',unpack($] < 5.010000 ?
|
|
5027
|
+
'U0C*' : 'C0C*', $$arg)) : Encode::encode('utf8', $$arg);
|
|
4918
5028
|
$arg = \$buff;
|
|
4919
5029
|
}
|
|
4920
5030
|
$$self{RAF} = File::RandomAccess->new($arg);
|
|
@@ -4995,7 +5105,7 @@ sub IsSameID($$)
|
|
|
4995
5105
|
|
|
4996
5106
|
#------------------------------------------------------------------------------
|
|
4997
5107
|
# Get list of tags in specified group
|
|
4998
|
-
# Inputs: 0) ExifTool ref, 1) group spec, 2) tag key or reference to list of tag keys
|
|
5108
|
+
# Inputs: 0) ExifTool ref, 1) group spec (case insensitive), 2) tag key or reference to list of tag keys
|
|
4999
5109
|
# Returns: list of matching tags in list context, or first match in scalar context
|
|
5000
5110
|
# Notes: Group spec may contain multiple groups separated by colons, each
|
|
5001
5111
|
# possibly with a leading family number
|
|
@@ -5399,28 +5509,21 @@ sub AddCleanup($)
|
|
|
5399
5509
|
sub Warn($$;$)
|
|
5400
5510
|
{
|
|
5401
5511
|
my ($self, $str, $ignorable) = @_;
|
|
5402
|
-
my $noWarn =
|
|
5512
|
+
my $noWarn = $$self{OPTIONS}{NoWarning};
|
|
5403
5513
|
if ($ignorable) {
|
|
5404
5514
|
return 0 if $$self{OPTIONS}{IgnoreMinorErrors};
|
|
5405
5515
|
return 0 if $ignorable eq '3' and $$self{OPTIONS}{Validate};
|
|
5406
5516
|
return 1 if defined $noWarn and eval { $str =~ /$noWarn/ };
|
|
5407
5517
|
$str = $ignorable eq '2' ? "[Minor] $str" : "[minor] $str";
|
|
5408
5518
|
}
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
}
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
sub WarnOnce($$;$)
|
|
5418
|
-
{
|
|
5419
|
-
my ($self, $str, $ignorable) = @_;
|
|
5420
|
-
return 0 if $ignorable and $$self{OPTIONS}{IgnoreMinorErrors};
|
|
5421
|
-
unless ($$self{WARNED_ONCE}{$str}) {
|
|
5422
|
-
$self->Warn($str, $ignorable);
|
|
5423
|
-
$$self{WARNED_ONCE}{$str} = 1;
|
|
5519
|
+
unless (defined $noWarn and eval { $str =~ /$noWarn/ }) {
|
|
5520
|
+
# add each warning only once but count number of occurrences
|
|
5521
|
+
if ($$self{WAS_WARNED}{$str}) {
|
|
5522
|
+
++$$self{WAS_WARNED}{$str};
|
|
5523
|
+
} else {
|
|
5524
|
+
$self->FoundTag('Warning', $str);
|
|
5525
|
+
$$self{WAS_WARNED}{$str} = 1;
|
|
5526
|
+
}
|
|
5424
5527
|
}
|
|
5425
5528
|
return 1;
|
|
5426
5529
|
}
|
|
@@ -6151,7 +6254,7 @@ sub Decode($$$;$$$)
|
|
|
6151
6254
|
}
|
|
6152
6255
|
|
|
6153
6256
|
#------------------------------------------------------------------------------
|
|
6154
|
-
# Encode string
|
|
6257
|
+
# Encode string (in Charset encoding) to specified encoding
|
|
6155
6258
|
# Inputs: 0) ExifTool object ref, 1) string, 2) destination character set name,
|
|
6156
6259
|
# 3) optional destination byte order (2-byte and 4-byte fixed-width sets only)
|
|
6157
6260
|
# Returns: string in specified encoding
|
|
@@ -6322,10 +6425,12 @@ sub Filter($$$)
|
|
|
6322
6425
|
# Return printable value
|
|
6323
6426
|
# Inputs: 0) ExifTool object reference
|
|
6324
6427
|
# 1) value to print, 2) line length limit (undef defaults to 60, 0=unlimited)
|
|
6428
|
+
# Returns: Printable string
|
|
6325
6429
|
sub Printable($;$)
|
|
6326
6430
|
{
|
|
6327
6431
|
my ($self, $outStr, $maxLen) = @_;
|
|
6328
6432
|
return '(undef)' unless defined $outStr;
|
|
6433
|
+
ref $outStr eq 'SCALAR' and return '(Binary data '.length($$outStr).' bytes)';
|
|
6329
6434
|
$outStr =~ tr/\x01-\x1f\x7f-\xff/./;
|
|
6330
6435
|
$outStr =~ s/\x00//g;
|
|
6331
6436
|
my $verbose = $$self{OPTIONS}{Verbose};
|
|
@@ -6358,9 +6463,45 @@ sub ConvertDateTime($$)
|
|
|
6358
6463
|
my $fmt = $$self{OPTIONS}{DateFormat};
|
|
6359
6464
|
my $shift = $$self{OPTIONS}{GlobalTimeShift};
|
|
6360
6465
|
if ($shift) {
|
|
6361
|
-
my $dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
|
6362
6466
|
my $offset = $$self{GLOBAL_TIME_OFFSET};
|
|
6363
|
-
$
|
|
6467
|
+
my ($g, $t, $dir, @matches);
|
|
6468
|
+
if ($shift =~ s/^((\d?[A-Z][-\w]*\w:)*)([A-Z][-\w]*\w)([-+])//i) {
|
|
6469
|
+
($g, $t, $dir) = ($1, $3, ($4 eq '-' ? -1 : 1));
|
|
6470
|
+
} else {
|
|
6471
|
+
$dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
|
6472
|
+
}
|
|
6473
|
+
unless ($offset) {
|
|
6474
|
+
$offset = $$self{GLOBAL_TIME_OFFSET} = { };
|
|
6475
|
+
# (see forum16692 for a discussion about why this code was added)
|
|
6476
|
+
if ($t) {
|
|
6477
|
+
# determine initial shift from specified tag
|
|
6478
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
|
6479
|
+
if ($g and @matches) {
|
|
6480
|
+
$g =~ s/:$//;
|
|
6481
|
+
@matches = $self->GroupMatches($g, \@matches);
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
if (not @matches and $$self{TAGS_FROM_FILE} and $$self{OPTIONS}{RequestTags}) {
|
|
6485
|
+
# determine initial shift from first requested date/time tag
|
|
6486
|
+
my @reqDate = grep /date/i, @{$$self{OPTIONS}{RequestTags}};
|
|
6487
|
+
while (@reqDate) {
|
|
6488
|
+
$t = shift @reqDate;
|
|
6489
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
|
6490
|
+
my $ti = $$self{TAG_INFO};
|
|
6491
|
+
for (; @matches; shift @matches) {
|
|
6492
|
+
# select the first tag that calls this routine in its PrintConv
|
|
6493
|
+
next unless $$ti{$matches[0]}{PrintConv};
|
|
6494
|
+
next unless $$ti{$matches[0]}{PrintConv} =~ /ConvertDateTime/;
|
|
6495
|
+
undef @reqDate;
|
|
6496
|
+
last;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
if (@matches) {
|
|
6501
|
+
my $val = $self->GetValue($matches[0], 'ValueConv');
|
|
6502
|
+
ShiftTime($val, $shift, $dir, $offset) if defined $val;
|
|
6503
|
+
}
|
|
6504
|
+
}
|
|
6364
6505
|
ShiftTime($date, $shift, $dir, $offset);
|
|
6365
6506
|
}
|
|
6366
6507
|
# only convert date if a format was specified and the date is recognizable
|
|
@@ -6412,11 +6553,13 @@ sub ConvertDateTime($$)
|
|
|
6412
6553
|
$fmt =~ s/(^|[^%])((%%)*)%-?\.?\d*f/$1$2$frac/g;
|
|
6413
6554
|
}
|
|
6414
6555
|
# parse %z and %s ourself (to handle time zones properly)
|
|
6415
|
-
if ($fmt =~
|
|
6556
|
+
if ($fmt =~ /%:?[sz]/) {
|
|
6416
6557
|
# use system time zone unless otherwise specified
|
|
6417
6558
|
$tz = TimeZoneString(\@a, TimeLocal(@a)) if not $tz and eval { require Time::Local };
|
|
6418
6559
|
# remove colon, setting to UTC if time zone is not numeric
|
|
6419
|
-
$tz =
|
|
6560
|
+
$tz = '+00:00' unless $tz and $tz=~/^[-+]\d{2}:\d{2}$/;
|
|
6561
|
+
$fmt =~ s/(^|[^%])((%%)*)%:z/$1$2$tz/g; # convert '%:z' format codes
|
|
6562
|
+
$tz =~ s/://;
|
|
6420
6563
|
$fmt =~ s/(^|[^%])((%%)*)%z/$1$2$tz/g; # convert '%z' format codes
|
|
6421
6564
|
if ($fmt =~ /%s/ and eval { require Time::Local }) {
|
|
6422
6565
|
# calculate seconds since the Epoch, UTC
|
|
@@ -6753,6 +6896,8 @@ sub IdentifyTrailer($;$)
|
|
|
6753
6896
|
$type = 'Insta360';
|
|
6754
6897
|
} elsif ($buff =~ m(\0{6}/NIKON APP$)) {
|
|
6755
6898
|
$type = 'NikonApp';
|
|
6899
|
+
} elsif ($buff =~ /\xff{4}\x1b\*9HWfu\x84\x93\xa2\xb1$/) {
|
|
6900
|
+
$type = 'Vivo';
|
|
6756
6901
|
}
|
|
6757
6902
|
last;
|
|
6758
6903
|
}
|
|
@@ -6765,7 +6910,8 @@ sub IdentifyTrailer($;$)
|
|
|
6765
6910
|
# Inputs: 0) ExifTool object ref, 1) DirInfo ref:
|
|
6766
6911
|
# - requires RAF and DirName
|
|
6767
6912
|
# - OutFile is a scalar reference for writing
|
|
6768
|
-
# - scans from current file position if
|
|
6913
|
+
# - scans from current file position for each trailer if ScanForTrailer is set
|
|
6914
|
+
# (current file position is just after JPEG EOF for a JPEG image)
|
|
6769
6915
|
# Returns: 1 if trailer was processed or couldn't be processed (or written OK)
|
|
6770
6916
|
# 0 if trailer was recognized but offsets need fixing (or write error)
|
|
6771
6917
|
# - DirName, DirLen, DataPos, Offset, Fixup and OutFile are updated
|
|
@@ -6811,7 +6957,7 @@ sub ProcessTrailers($$)
|
|
|
6811
6957
|
# read or write this trailer
|
|
6812
6958
|
# (proc takes Offset as positive offset from end of trailer to end of file,
|
|
6813
6959
|
# and returns DataPos and DirLen, and Fixup if applicable, and updates
|
|
6814
|
-
# OutFile when writing)
|
|
6960
|
+
# OutFile when writing. Returns < 0 if we must scan for this trailer)
|
|
6815
6961
|
no strict 'refs';
|
|
6816
6962
|
my $result = &$proc($self, $dirInfo);
|
|
6817
6963
|
use strict 'refs';
|
|
@@ -7221,7 +7367,7 @@ sub ProcessJPEG($$;$)
|
|
|
7221
7367
|
# and scan for AFCP if necessary
|
|
7222
7368
|
my $fromEnd = 0;
|
|
7223
7369
|
if ($trailInfo) {
|
|
7224
|
-
$$trailInfo{
|
|
7370
|
+
$$trailInfo{ScanForTrailer} = 1; # scan now if necessary
|
|
7225
7371
|
$self->ProcessTrailers($trailInfo);
|
|
7226
7372
|
# save offset from end of file to start of first trailer
|
|
7227
7373
|
$fromEnd = $$trailInfo{Offset};
|
|
@@ -7322,7 +7468,7 @@ sub ProcessJPEG($$;$)
|
|
|
7322
7468
|
}
|
|
7323
7469
|
# handle all other markers
|
|
7324
7470
|
my $dumpType = '';
|
|
7325
|
-
my ($desc, $tip, $xtra);
|
|
7471
|
+
my ($desc, $tip, $xtra, $useJpegMain);
|
|
7326
7472
|
$length = length $$segDataPt;
|
|
7327
7473
|
$appBytes += $length + 4 if ($marker & 0xf0) == 0xe0; # total size of APP segments
|
|
7328
7474
|
if ($verbose) {
|
|
@@ -7421,6 +7567,19 @@ sub ProcessJPEG($$;$)
|
|
|
7421
7567
|
$$self{SkipData} = \@skipData if @skipData;
|
|
7422
7568
|
# extract the EXIF information (it is in standard TIFF format)
|
|
7423
7569
|
$self->ProcessTIFF(\%dirInfo) or $self->Warn('Malformed APP1 EXIF segment');
|
|
7570
|
+
# scan for Vivo HiddenData if necessary
|
|
7571
|
+
if ($$self{Make} eq 'vivo' and
|
|
7572
|
+
# (stored as UserComment by some models)
|
|
7573
|
+
not ($$self{VALUE}{UserComment} and $$self{VALUE}{UserComment} =~ /^filter:/) and
|
|
7574
|
+
$$dataPt =~ /(filter: .*?; \n)\0/sg)
|
|
7575
|
+
{
|
|
7576
|
+
if ($htmlDump) {
|
|
7577
|
+
my $n = length($1) + 1;
|
|
7578
|
+
$self->HDump($segPos+pos($$dataPt)-$n, $n, '[Vivo HiddenData]', undef, 0x08);
|
|
7579
|
+
}
|
|
7580
|
+
my $tbl = GetTagTable('Image::ExifTool::Vivo::Main');
|
|
7581
|
+
$self->HandleTag($tbl, HiddenData => $1);
|
|
7582
|
+
}
|
|
7424
7583
|
# avoid looking for preview unless necessary because it really slows
|
|
7425
7584
|
# us down -- only look for it if we found pointer, and preview is
|
|
7426
7585
|
# outside EXIF, and PreviewImage is specifically requested
|
|
@@ -7457,13 +7616,13 @@ sub ProcessJPEG($$;$)
|
|
|
7457
7616
|
my ($size, $off) = unpack('x67N2', $$segDataPt);
|
|
7458
7617
|
my $guid = substr($$segDataPt, 35, 32);
|
|
7459
7618
|
if ($guid =~ /[^A-Za-z0-9]/) { # (technically, should be uppercase)
|
|
7460
|
-
$self->
|
|
7619
|
+
$self->Warn($tip = 'Invalid extended XMP GUID');
|
|
7461
7620
|
} else {
|
|
7462
7621
|
my $extXMP = $extendedXMP{$guid};
|
|
7463
7622
|
if (not $extXMP) {
|
|
7464
7623
|
$extXMP = $extendedXMP{$guid} = { };
|
|
7465
7624
|
} elsif ($size != $$extXMP{Size}) {
|
|
7466
|
-
$self->
|
|
7625
|
+
$self->Warn('Inconsistent extended XMP size');
|
|
7467
7626
|
}
|
|
7468
7627
|
$$extXMP{Size} = $size;
|
|
7469
7628
|
$$extXMP{$off} = substr($$segDataPt, 75);
|
|
@@ -7472,7 +7631,7 @@ sub ProcessJPEG($$;$)
|
|
|
7472
7631
|
# (delay processing extended XMP until after reading all segments)
|
|
7473
7632
|
}
|
|
7474
7633
|
} else {
|
|
7475
|
-
$self->
|
|
7634
|
+
$self->Warn($tip = 'Invalid extended XMP segment');
|
|
7476
7635
|
}
|
|
7477
7636
|
} elsif ($$segDataPt =~ /^QVCI\0/) {
|
|
7478
7637
|
$dumpType = 'QVCI';
|
|
@@ -7495,7 +7654,7 @@ sub ProcessJPEG($$;$)
|
|
|
7495
7654
|
}
|
|
7496
7655
|
if (defined $flirCount) {
|
|
7497
7656
|
if (defined $flirChunk[$chunkNum]) {
|
|
7498
|
-
$self->
|
|
7657
|
+
$self->Warn('Duplicate FLIR chunk number(s)');
|
|
7499
7658
|
$flirChunk[$chunkNum] .= substr($$segDataPt, 8);
|
|
7500
7659
|
} else {
|
|
7501
7660
|
$flirChunk[$chunkNum] = substr($$segDataPt, 8);
|
|
@@ -7515,7 +7674,7 @@ sub ProcessJPEG($$;$)
|
|
|
7515
7674
|
undef $flirCount; # prevent reprocessing
|
|
7516
7675
|
}
|
|
7517
7676
|
} else {
|
|
7518
|
-
$self->
|
|
7677
|
+
$self->Warn('Invalid or extraneous FLIR chunk(s)');
|
|
7519
7678
|
}
|
|
7520
7679
|
} elsif ($$segDataPt =~ /^PARROT\0(II\x2a\0|MM\0\x2a)/) {
|
|
7521
7680
|
# (don't know if this could span multiple segments)
|
|
@@ -7542,7 +7701,7 @@ sub ProcessJPEG($$;$)
|
|
|
7542
7701
|
$self->Warn("Ignored APP1 segment length $length (unknown header)");
|
|
7543
7702
|
}
|
|
7544
7703
|
}
|
|
7545
|
-
} elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, InfiRay, PreviewImage)
|
|
7704
|
+
} elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, InfiRay, URN, PreviewImage)
|
|
7546
7705
|
if ($$segDataPt =~ /^ICC_PROFILE\0/ and $length >= 14) {
|
|
7547
7706
|
$dumpType = 'ICC_Profile';
|
|
7548
7707
|
# must concatenate profile chunks (note: handle the case where
|
|
@@ -7560,7 +7719,7 @@ sub ProcessJPEG($$;$)
|
|
|
7560
7719
|
}
|
|
7561
7720
|
if (defined $iccChunkCount) {
|
|
7562
7721
|
if (defined $iccChunk[$chunkNum]) {
|
|
7563
|
-
$self->
|
|
7722
|
+
$self->Warn('Duplicate ICC_Profile chunk number(s)');
|
|
7564
7723
|
$iccChunk[$chunkNum] .= substr($$segDataPt, 14);
|
|
7565
7724
|
} else {
|
|
7566
7725
|
$iccChunk[$chunkNum] = substr($$segDataPt, 14);
|
|
@@ -7583,7 +7742,7 @@ sub ProcessJPEG($$;$)
|
|
|
7583
7742
|
undef $iccChunkCount; # prevent reprocessing
|
|
7584
7743
|
}
|
|
7585
7744
|
} else {
|
|
7586
|
-
$self->
|
|
7745
|
+
$self->Warn('Invalid or extraneous ICC_Profile chunk(s)');
|
|
7587
7746
|
}
|
|
7588
7747
|
} elsif ($$segDataPt =~ /^FPXR\0/) {
|
|
7589
7748
|
next if $fast > 1; # skip processing for very fast
|
|
@@ -7615,6 +7774,9 @@ sub ProcessJPEG($$;$)
|
|
|
7615
7774
|
# Digilife DDC-690/Rollei="BGTH"
|
|
7616
7775
|
$dumpType = 'Preview Image';
|
|
7617
7776
|
$preview = substr($$segDataPt, length($1));
|
|
7777
|
+
} elsif ($$segDataPt =~ /^urn:/) { # (found in Apple HDR images)
|
|
7778
|
+
$dumpType = 'URN';
|
|
7779
|
+
$useJpegMain = 1;
|
|
7618
7780
|
} elsif ($preview) {
|
|
7619
7781
|
$dumpType = 'Preview Image';
|
|
7620
7782
|
$preview .= $$segDataPt;
|
|
@@ -7860,6 +8022,10 @@ sub ProcessJPEG($$;$)
|
|
|
7860
8022
|
SetByteOrder('II');
|
|
7861
8023
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Isothermal');
|
|
7862
8024
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
8025
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
|
8026
|
+
$dumpType = 'SEAL';
|
|
8027
|
+
DirStart(\%dirInfo, 5);
|
|
8028
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
|
7863
8029
|
}
|
|
7864
8030
|
} elsif ($marker == 0xe9) { # APP9 (InfiRay, Media Jukebox)
|
|
7865
8031
|
if ($$segDataPt =~ /^Media Jukebox\0/ and $length > 22) {
|
|
@@ -7875,18 +8041,19 @@ sub ProcessJPEG($$;$)
|
|
|
7875
8041
|
SetByteOrder('II');
|
|
7876
8042
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Sensor');
|
|
7877
8043
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
8044
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
|
8045
|
+
$dumpType = 'SEAL';
|
|
8046
|
+
DirStart(\%dirInfo, 5);
|
|
8047
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
|
7878
8048
|
}
|
|
7879
|
-
} elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments)
|
|
8049
|
+
} elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments, HDR gain curve)
|
|
7880
8050
|
if ($$segDataPt =~ /^UNICODE\0/) {
|
|
7881
8051
|
$dumpType = 'PhotoStudio';
|
|
7882
8052
|
my $comment = $self->Decode(substr($$segDataPt,8), 'UCS2', 'MM');
|
|
7883
8053
|
$self->FoundTag('Comment', $comment);
|
|
7884
|
-
} elsif ($$segDataPt =~ /^AROT\0/
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
# "Absolute ROTational difference between two frames"
|
|
7888
|
-
# (see https://www.hackerfactor.com/blog/index.php?/archives/822-Apple-Rot.html)
|
|
7889
|
-
$xtra = 'segment (N=' . unpack('x6N', $$segDataPt) . ')';
|
|
8054
|
+
} elsif ($$segDataPt =~ /^AROT\0\0.{4}/s) {
|
|
8055
|
+
$dumpType = 'AROT', # (HDR gain curve? PH guess)
|
|
8056
|
+
$useJpegMain = 1;
|
|
7890
8057
|
}
|
|
7891
8058
|
} elsif ($marker == 0xeb) { # APP11 (JPEG-HDR, JUMBF)
|
|
7892
8059
|
if ($$segDataPt =~ /^HDR_RI /) {
|
|
@@ -7919,7 +8086,7 @@ sub ProcessJPEG($$;$)
|
|
|
7919
8086
|
my $type = substr($$segDataPt, 12, 4);
|
|
7920
8087
|
# a Microsoft bug writes $len and $type incorrectly as little-endian
|
|
7921
8088
|
if ($type eq 'bmuj') {
|
|
7922
|
-
$self->
|
|
8089
|
+
$self->Warn('Wrong byte order in C2PA APP11 JUMBF header');
|
|
7923
8090
|
$type = 'jumb';
|
|
7924
8091
|
$len = unpack('x8V', $$segDataPt);
|
|
7925
8092
|
# fix the header
|
|
@@ -8053,6 +8220,10 @@ sub ProcessJPEG($$;$)
|
|
|
8053
8220
|
$desc = "[JPEG $markerName]"; # (other known JPEG segments)
|
|
8054
8221
|
}
|
|
8055
8222
|
if (defined $dumpType) {
|
|
8223
|
+
if ($useJpegMain) {
|
|
8224
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
|
|
8225
|
+
$self->HandleTag($tagTablePtr, $markerName, $$segDataPt);
|
|
8226
|
+
}
|
|
8056
8227
|
if (not $dumpType and ($$options{Unknown} or $$options{Validate})) {
|
|
8057
8228
|
my $str = ($$segDataPt =~ /^([\x20-\x7e]{1,20})\0/) ? " '${1}'" : '';
|
|
8058
8229
|
$xtra = 'segment' unless $xtra;
|
|
@@ -8223,7 +8394,11 @@ sub DoProcessTIFF($$;$)
|
|
|
8223
8394
|
# save a copy of the EXIF data
|
|
8224
8395
|
my $dirStart = $$dirInfo{DirStart} || 0;
|
|
8225
8396
|
my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
|
|
8226
|
-
|
|
8397
|
+
if ($dirLen > 0 or not $outfile) {
|
|
8398
|
+
$$self{EXIF_DATA} = substr($$dataPt, $dirStart, $dirLen);
|
|
8399
|
+
} else {
|
|
8400
|
+
delete $$self{EXIF_DATA}; # create from scratch;
|
|
8401
|
+
}
|
|
8227
8402
|
$self->VerboseDir('TIFF') if $$self{OPTIONS}{Verbose} and length($$self{INDENT}) > 2;
|
|
8228
8403
|
} elsif ($outfile) {
|
|
8229
8404
|
delete $$self{EXIF_DATA}; # create from scratch
|
|
@@ -8382,7 +8557,7 @@ sub DoProcessTIFF($$;$)
|
|
|
8382
8557
|
if ($raf) {
|
|
8383
8558
|
my $trailInfo = IdentifyTrailer($raf);
|
|
8384
8559
|
if ($trailInfo) {
|
|
8385
|
-
$$trailInfo{
|
|
8560
|
+
$$trailInfo{ScanForTrailer} = 1; # scan to find AFCP if necessary
|
|
8386
8561
|
$self->ProcessTrailers($trailInfo);
|
|
8387
8562
|
}
|
|
8388
8563
|
# dump any other known trailer (eg. A100 RAW Data)
|
|
@@ -8487,7 +8662,7 @@ sub DoProcessTIFF($$;$)
|
|
|
8487
8662
|
last unless $trailInfo;
|
|
8488
8663
|
my $tbuf = '';
|
|
8489
8664
|
$$trailInfo{OutFile} = \$tbuf; # rewrite trailer(s)
|
|
8490
|
-
$$trailInfo{
|
|
8665
|
+
$$trailInfo{ScanForTrailer} = 1; # scan for AFCP if necessary
|
|
8491
8666
|
# rewrite all trailers to buffer
|
|
8492
8667
|
unless ($self->ProcessTrailers($trailInfo)) {
|
|
8493
8668
|
undef $trailInfo;
|
|
@@ -8592,23 +8767,18 @@ sub GetTagTable($)
|
|
|
8592
8767
|
# try to load module for this table
|
|
8593
8768
|
if ($tableName =~ /(.*)::/) {
|
|
8594
8769
|
my $module = $1;
|
|
8595
|
-
if (eval "require $module") {
|
|
8770
|
+
if (not eval "require $module") {
|
|
8771
|
+
$@ and warn $@;
|
|
8772
|
+
} elsif (not %$tableName) {
|
|
8596
8773
|
# load additional modules if required
|
|
8597
|
-
if (
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
require 'Image/ExifTool/QuickTimeStream.pl';
|
|
8602
|
-
}
|
|
8774
|
+
if ($module eq 'Image::ExifTool::XMP') {
|
|
8775
|
+
require 'Image/ExifTool/XMP2.pl';
|
|
8776
|
+
} elsif ($tableName eq 'Image::ExifTool::QuickTime::Stream') {
|
|
8777
|
+
require 'Image/ExifTool/QuickTimeStream.pl';
|
|
8603
8778
|
}
|
|
8604
|
-
} else {
|
|
8605
|
-
$@ and warn $@;
|
|
8606
8779
|
}
|
|
8607
8780
|
}
|
|
8608
|
-
|
|
8609
|
-
warn "Can't find table $tableName\n";
|
|
8610
|
-
return undef;
|
|
8611
|
-
}
|
|
8781
|
+
%$tableName or warn("Can't find table $tableName\n"), return undef;
|
|
8612
8782
|
}
|
|
8613
8783
|
no strict 'refs';
|
|
8614
8784
|
$table = \%$tableName;
|
|
@@ -8797,6 +8967,7 @@ sub GetTagInfo($$$;$$$)
|
|
|
8797
8967
|
my ($valPt, $format, $count);
|
|
8798
8968
|
|
|
8799
8969
|
my @infoArray = GetTagInfoList($tagTablePtr, $tagID);
|
|
8970
|
+
my $options = $$self{OPTIONS};
|
|
8800
8971
|
# evaluate condition
|
|
8801
8972
|
my $tagInfo;
|
|
8802
8973
|
foreach $tagInfo (@infoArray) {
|
|
@@ -8814,10 +8985,11 @@ sub GetTagInfo($$$;$$$)
|
|
|
8814
8985
|
next;
|
|
8815
8986
|
}
|
|
8816
8987
|
}
|
|
8817
|
-
# don't return Unknown tags unless that option is set (also see forum13716)
|
|
8818
|
-
if ($$tagInfo{Unknown} and not $$
|
|
8819
|
-
($$self{
|
|
8820
|
-
($$
|
|
8988
|
+
# don't return Unknown tags unless that option is set or we are writing (also see forum13716)
|
|
8989
|
+
if ($$tagInfo{Unknown} and not $$options{Unknown} and
|
|
8990
|
+
(not $$self{IsWriting} or $$tagInfo{AddedUnknown}) and not
|
|
8991
|
+
($$options{Verbose} or $$self{HTML_DUMP} or
|
|
8992
|
+
($$options{Validate} and not $$tagInfo{AddedUnknown})))
|
|
8821
8993
|
{
|
|
8822
8994
|
return undef;
|
|
8823
8995
|
}
|
|
@@ -8825,7 +8997,7 @@ sub GetTagInfo($$$;$$$)
|
|
|
8825
8997
|
return $tagInfo;
|
|
8826
8998
|
}
|
|
8827
8999
|
# generate information for unknown tags (numerical only) if required
|
|
8828
|
-
if (not $tagInfo and ($$
|
|
9000
|
+
if (not $tagInfo and ($$options{Unknown} or $$options{Verbose} or $$self{HTML_DUMP}) and
|
|
8829
9001
|
$tagID =~ /^\d+$/ and not $$self{NO_UNKNOWN})
|
|
8830
9002
|
{
|
|
8831
9003
|
my $printConv;
|
|
@@ -8924,7 +9096,7 @@ sub HandleTag($$$$;%)
|
|
|
8924
9096
|
my $pfmt = $parms{Format};
|
|
8925
9097
|
my $tagInfo = $parms{TagInfo} || $self->GetTagInfo($tagTablePtr, $tag, \$val, $pfmt, $parms{Count});
|
|
8926
9098
|
my $dataPt = $parms{DataPt};
|
|
8927
|
-
my ($subdir, $format, $noTagInfo, $rational);
|
|
9099
|
+
my ($subdir, $format, $noTagInfo, $rational, $binVal);
|
|
8928
9100
|
|
|
8929
9101
|
if ($tagInfo) {
|
|
8930
9102
|
$subdir = $$tagInfo{SubDirectory};
|
|
@@ -8948,6 +9120,7 @@ sub HandleTag($$$$;%)
|
|
|
8948
9120
|
} else {
|
|
8949
9121
|
$val = substr($$dataPt, $start, $size);
|
|
8950
9122
|
}
|
|
9123
|
+
$binVal = substr($$dataPt, $start, $size) if $$self{OPTIONS}{SaveBin};
|
|
8951
9124
|
} else {
|
|
8952
9125
|
$self->Warn("Error extracting value for $$tagInfo{Name}");
|
|
8953
9126
|
return undef;
|
|
@@ -9009,6 +9182,7 @@ sub HandleTag($$$$;%)
|
|
|
9009
9182
|
Base => $parms{Base},
|
|
9010
9183
|
Multi => $$subdir{Multi},
|
|
9011
9184
|
TagInfo => $tagInfo,
|
|
9185
|
+
IgnoreProp => $$subdir{IgnoreProp},
|
|
9012
9186
|
RAF => $parms{RAF},
|
|
9013
9187
|
);
|
|
9014
9188
|
my $oldOrder = GetByteOrder();
|
|
@@ -9030,8 +9204,11 @@ sub HandleTag($$$$;%)
|
|
|
9030
9204
|
return undef unless $$tagInfo{Writable};
|
|
9031
9205
|
}
|
|
9032
9206
|
my $key = $self->FoundTag($tagInfo, $val);
|
|
9033
|
-
|
|
9034
|
-
|
|
9207
|
+
if (defined $key) {
|
|
9208
|
+
# save original components of rational numbers and original binary value
|
|
9209
|
+
$$self{TAG_EXTRA}{$key}{Rational} = $rational if defined $rational;
|
|
9210
|
+
$$self{TAG_EXTRA}{$key}{BinVal} = $binVal if defined $binVal;
|
|
9211
|
+
}
|
|
9035
9212
|
return $key;
|
|
9036
9213
|
}
|
|
9037
9214
|
return undef;
|
|
@@ -9142,9 +9319,7 @@ sub FoundTag($$$;@)
|
|
|
9142
9319
|
# a Warning tag because they may be added by ValueConv, which could be confusing)
|
|
9143
9320
|
my $oldPriority = $$self{PRIORITY}{$tag};
|
|
9144
9321
|
unless ($oldPriority) {
|
|
9145
|
-
if ($$self{DOC_NUM} or not $$self{TAG_EXTRA}{$tag}
|
|
9146
|
-
not $$self{TAG_EXTRA}{$tag}{G3})
|
|
9147
|
-
{
|
|
9322
|
+
if ($$self{DOC_NUM} or $tag eq 'Warning' or not $$self{TAG_EXTRA}{$tag}{G3}) {
|
|
9148
9323
|
$oldPriority = 1;
|
|
9149
9324
|
} else {
|
|
9150
9325
|
$oldPriority = 0; # don't promote sub-document tag over main document
|
|
@@ -9162,8 +9337,7 @@ sub FoundTag($$$;@)
|
|
|
9162
9337
|
} else {
|
|
9163
9338
|
$priority = 1; # the normal default
|
|
9164
9339
|
}
|
|
9165
|
-
if ($priority >= $oldPriority and (not $$self{DOC_NUM} or
|
|
9166
|
-
($$self{TAG_EXTRA}{$tag} and $$self{TAG_EXTRA}{$tag}{G3} and
|
|
9340
|
+
if ($priority >= $oldPriority and (not $$self{DOC_NUM} or ($$self{TAG_EXTRA}{$tag}{G3} and
|
|
9167
9341
|
$$self{DOC_NUM} eq $$self{TAG_EXTRA}{$tag}{G3})) and not $noListDel)
|
|
9168
9342
|
{
|
|
9169
9343
|
# move existing tag out of the way since this tag is higher priority
|
|
@@ -9172,12 +9346,8 @@ sub FoundTag($$$;@)
|
|
|
9172
9346
|
$$valueHash{$nextTag} = $$valueHash{$tag};
|
|
9173
9347
|
$$self{FILE_ORDER}{$nextTag} = $$self{FILE_ORDER}{$tag};
|
|
9174
9348
|
my $oldInfo = $$self{TAG_INFO}{$nextTag} = $$self{TAG_INFO}{$tag};
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
$$self{$_}{$nextTag} = $$self{$_}{$tag};
|
|
9178
|
-
delete $$self{$_}{$tag};
|
|
9179
|
-
}
|
|
9180
|
-
}
|
|
9349
|
+
$$self{TAG_EXTRA}{$nextTag} = $$self{TAG_EXTRA}{$tag};
|
|
9350
|
+
$$self{TAG_EXTRA}{$tag} = { };
|
|
9181
9351
|
delete $$self{BOTH}{$tag};
|
|
9182
9352
|
# update tag key for list if necessary
|
|
9183
9353
|
$$self{LIST_TAGS}{$oldInfo} = $nextTag if $$self{LIST_TAGS}{$oldInfo};
|
|
@@ -9202,6 +9372,7 @@ sub FoundTag($$$;@)
|
|
|
9202
9372
|
$$valueHash{$tag} = $value;
|
|
9203
9373
|
$$self{FILE_ORDER}{$tag} = ++$$self{NUM_FOUND};
|
|
9204
9374
|
$$self{TAG_INFO}{$tag} = $tagInfo;
|
|
9375
|
+
$$self{TAG_EXTRA}{$tag} = { } unless $$self{TAG_EXTRA}{$tag};
|
|
9205
9376
|
# set dynamic groups 0, 1 and 3 if necessary
|
|
9206
9377
|
$$self{TAG_EXTRA}{$tag}{G0} = $grps[0] if $grps[0];
|
|
9207
9378
|
$$self{TAG_EXTRA}{$tag}{G1} = $grps[1] if $grps[1];
|
|
@@ -9260,7 +9431,6 @@ sub DeleteTag($$)
|
|
|
9260
9431
|
delete $$self{TAG_INFO}{$tag};
|
|
9261
9432
|
delete $$self{TAG_EXTRA}{$tag};
|
|
9262
9433
|
delete $$self{PRIORITY}{$tag};
|
|
9263
|
-
delete $$self{RATIONAL}{$tag};
|
|
9264
9434
|
delete $$self{BOTH}{$tag};
|
|
9265
9435
|
}
|
|
9266
9436
|
|
|
@@ -9496,7 +9666,7 @@ sub ProcessBinaryData($$$)
|
|
|
9496
9666
|
$increment = $formatSize{$defaultFormat};
|
|
9497
9667
|
}
|
|
9498
9668
|
# prepare list of tag numbers to extract
|
|
9499
|
-
my (@tags, $topIndex);
|
|
9669
|
+
my (@tags, $topIndex, $binVal);
|
|
9500
9670
|
if ($unknown > 1 and defined $$tagTablePtr{FIRST_ENTRY}) {
|
|
9501
9671
|
# don't create a stupid number of tags if data is huge
|
|
9502
9672
|
my $sizeLimit = $size < 65536 ? $size : 65536;
|
|
@@ -9636,6 +9806,7 @@ sub ProcessBinaryData($$$)
|
|
|
9636
9806
|
$val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
|
|
9637
9807
|
$val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
|
|
9638
9808
|
}
|
|
9809
|
+
$binVal = substr($$dataPt, $entry+$dirStart, $count) if $$self{OPTIONS}{SaveBin};
|
|
9639
9810
|
$wasVar = 1;
|
|
9640
9811
|
# save variable size data if required for writing
|
|
9641
9812
|
if ($$dirInfo{VarFormatData}) {
|
|
@@ -9757,7 +9928,8 @@ sub ProcessBinaryData($$$)
|
|
|
9757
9928
|
my $key = $self->FoundTag($tagInfo,$val);
|
|
9758
9929
|
$$self{BASE} = $oldBase if defined $oldBase;
|
|
9759
9930
|
if ($key) {
|
|
9760
|
-
$$self{
|
|
9931
|
+
$$self{TAG_EXTRA}{$key}{Rational} = $rational if defined $rational;
|
|
9932
|
+
$$self{TAG_EXTRA}{$key}{BinVal} = $binVal if defined $binVal;
|
|
9761
9933
|
} else {
|
|
9762
9934
|
# don't increment nextIndex if we didn't extract a tag
|
|
9763
9935
|
$nextIndex = $saveNextIndex if defined $saveNextIndex;
|