exiftool-vendored.exe 12.55.0 → 12.60.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/exiftool_files/Changes +97 -4
- package/bin/exiftool_files/README +19 -19
- package/bin/exiftool_files/arg_files/xmp2exif.args +4 -1
- package/bin/exiftool_files/config_files/example.config +1 -0
- package/bin/exiftool_files/config_files/rotate_regions.config +1 -1
- package/bin/exiftool_files/exiftool.pl +198 -123
- package/bin/exiftool_files/fmt_files/kml.fmt +3 -0
- package/bin/exiftool_files/fmt_files/kml_track.fmt +3 -0
- package/bin/exiftool_files/lib/Image/ExifTool/AIFF.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/APE.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +25 -19
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +33 -7
- package/bin/exiftool_files/lib/Image/ExifTool/CanonRaw.pm +5 -1
- package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +28 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +107 -20
- package/bin/exiftool_files/lib/Image/ExifTool/FlashPix.pm +92 -9
- package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +9 -4
- package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +7 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +30 -7
- package/bin/exiftool_files/lib/Image/ExifTool/InfiRay.pm +227 -0
- package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +53 -7
- package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +5 -5
- package/bin/exiftool_files/lib/Image/ExifTool/LIF.pm +10 -2
- package/bin/exiftool_files/lib/Image/ExifTool/LNK.pm +5 -4
- package/bin/exiftool_files/lib/Image/ExifTool/MIE.pm +3 -3
- package/bin/exiftool_files/lib/Image/ExifTool/MPEG.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +3 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Minolta.pm +6 -7
- package/bin/exiftool_files/lib/Image/ExifTool/MinoltaRaw.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +1199 -1325
- package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +88 -6
- package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +32 -15
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +89 -3
- package/bin/exiftool_files/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +8 -5
- package/bin/exiftool_files/lib/Image/ExifTool/PhaseOne.pm +14 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Photoshop.pm +38 -7
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +44 -13
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +63 -20
- package/bin/exiftool_files/lib/Image/ExifTool/README +19 -2
- package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +34 -13
- package/bin/exiftool_files/lib/Image/ExifTool/Rawzor.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Real.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Ricoh.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Sigma.pm +5 -4
- package/bin/exiftool_files/lib/Image/ExifTool/SigmaRaw.pm +9 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +28 -1
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +4691 -4624
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +511 -117
- package/bin/exiftool_files/lib/Image/ExifTool/VCard.pm +19 -5
- package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +5 -5
- package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +42 -0
- package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +150 -36
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +19 -4
- package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool.pm +248 -54
- package/bin/exiftool_files/lib/Image/ExifTool.pod +94 -58
- package/package.json +2 -2
|
@@ -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);
|
|
31
31
|
|
|
32
|
-
$VERSION = '12.
|
|
32
|
+
$VERSION = '12.60';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -75,6 +75,7 @@ sub GetAllGroups($;$);
|
|
|
75
75
|
sub GetNewGroups($);
|
|
76
76
|
sub GetDeleteGroups();
|
|
77
77
|
sub AddUserDefinedTags($%);
|
|
78
|
+
sub SetAlternateFile($$$);
|
|
78
79
|
# non-public routines below
|
|
79
80
|
sub InsertTagValues($$$;$$$);
|
|
80
81
|
sub IsWritable($);
|
|
@@ -113,6 +114,7 @@ sub WriteTIFF($$$);
|
|
|
113
114
|
sub PackUTF8(@);
|
|
114
115
|
sub UnpackUTF8($);
|
|
115
116
|
sub SetPreferredByteOrder($;$);
|
|
117
|
+
sub ImageDataMD5($$$;$$);
|
|
116
118
|
sub CopyBlock($$$);
|
|
117
119
|
sub CopyFileAttrs($$$);
|
|
118
120
|
sub TimeNow(;$$);
|
|
@@ -150,8 +152,8 @@ sub ReadValue($$$;$$$);
|
|
|
150
152
|
Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE
|
|
151
153
|
JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion
|
|
152
154
|
EXE::PEString EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard
|
|
153
|
-
Text VCard::VCalendar RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR RTF
|
|
154
|
-
FLIR::AFF FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable
|
|
155
|
+
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR RTF
|
|
156
|
+
OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable
|
|
155
157
|
);
|
|
156
158
|
|
|
157
159
|
# alphabetical list of current Lang modules
|
|
@@ -526,6 +528,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
526
528
|
VCARD=> ['VCard','Virtual Card'],
|
|
527
529
|
VCF => 'VCARD',
|
|
528
530
|
VOB => ['MPEG', 'Video Object'],
|
|
531
|
+
VNT => [['FPX','VCard'], 'Scene7 Vignette or V-Note text file'],
|
|
529
532
|
VRD => ['VRD', 'Canon VRD Recipe Data'],
|
|
530
533
|
VSD => ['FPX', 'Microsoft Visio Drawing'],
|
|
531
534
|
WAV => ['RIFF', 'WAVeform (Windows digital audio)'],
|
|
@@ -577,6 +580,7 @@ my %fileDescription = (
|
|
|
577
580
|
'Win32 DLL' => 'Windows 32-bit Dynamic Link Library',
|
|
578
581
|
'Win64 EXE' => 'Windows 64-bit Executable',
|
|
579
582
|
'Win64 DLL' => 'Windows 64-bit Dynamic Link Library',
|
|
583
|
+
VNote => 'V-Note document',
|
|
580
584
|
);
|
|
581
585
|
|
|
582
586
|
# MIME types for applicable file types above
|
|
@@ -977,7 +981,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
977
981
|
TAR => '.{257}ustar( )?\0', # (this doesn't catch old-style tar files)
|
|
978
982
|
TXT => '(\xff\xfe|(\0\0)?\xfe\xff|(\xef\xbb\xbf)?[\x07-\x0d\x20-\x7e\x80-\xfe]*$)',
|
|
979
983
|
TIFF => '(II|MM)', # don't test magic number (some raw formats are different)
|
|
980
|
-
VCard=> '(?i)BEGIN:(VCARD|VCALENDAR)\r\n',
|
|
984
|
+
VCard=> '(?i)BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n',
|
|
981
985
|
VRD => 'CANON OPTIONAL DATA\0',
|
|
982
986
|
WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)',
|
|
983
987
|
WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d',
|
|
@@ -1819,6 +1823,17 @@ my %systemTagsNotes = (
|
|
|
1819
1823
|
if specifically requested
|
|
1820
1824
|
},
|
|
1821
1825
|
},
|
|
1826
|
+
ImageDataMD5 => {
|
|
1827
|
+
Notes => q{
|
|
1828
|
+
MD5 of image data. Generated only if specifically requested for JPEG and
|
|
1829
|
+
TIFF-based images, PNG, CRW, CR3, MRW, RAF, X3F and AVIF images, MOV/MP4
|
|
1830
|
+
videos, and some RIFF-based files. The MD5 includes the main image data,
|
|
1831
|
+
plus JpgFromRaw/OtherImage for some formats, but does not include
|
|
1832
|
+
ThumbnailImage or PreviewImage. Includes video and audio data for MOV/MP4.
|
|
1833
|
+
The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool> provides a place to
|
|
1834
|
+
store these values in the file.
|
|
1835
|
+
},
|
|
1836
|
+
},
|
|
1822
1837
|
);
|
|
1823
1838
|
|
|
1824
1839
|
# tags defined by UserParam option (added at runtime)
|
|
@@ -2041,7 +2056,9 @@ sub new
|
|
|
2041
2056
|
$$self{DEL_GROUP} = { }; # lookup for groups to delete when writing
|
|
2042
2057
|
$$self{SAVE_COUNT} = 0; # count calls to SaveNewValues()
|
|
2043
2058
|
$$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
|
|
2059
|
+
$$self{FILES_WRITTEN} = 0; # count of files successfully written
|
|
2044
2060
|
$$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
|
|
2061
|
+
$$self{ALT_EXIFTOOL} = { }; # alternate exiftool objects
|
|
2045
2062
|
|
|
2046
2063
|
# initialize our new groups for writing
|
|
2047
2064
|
$self->SetNewGroups(@defaultWriteGroups);
|
|
@@ -2476,8 +2493,33 @@ sub ExtractInfo($;@)
|
|
|
2476
2493
|
$self->WarnOnce('Install Time::HiRes to generate ProcessingTime');
|
|
2477
2494
|
}
|
|
2478
2495
|
}
|
|
2479
|
-
|
|
2496
|
+
|
|
2497
|
+
# create MD5 object if ImageDataMD5 is requested
|
|
2498
|
+
if ($$req{imagedatamd5} and not $$self{ImageDataMD5}) {
|
|
2499
|
+
if (require Digest::MD5) {
|
|
2500
|
+
$$self{ImageDataMD5} = Digest::MD5->new;
|
|
2501
|
+
} else {
|
|
2502
|
+
$self->WarnOnce('Install Digest::MD5 to calculate image data MD5');
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2480
2505
|
++$$self{FILE_SEQUENCE}; # count files read
|
|
2506
|
+
# extract information from alternate files if necessary
|
|
2507
|
+
my ($g8, $altExifTool);
|
|
2508
|
+
foreach $g8 (keys %{$$self{ALT_EXIFTOOL}}) {
|
|
2509
|
+
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
|
2510
|
+
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
|
2511
|
+
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
|
2512
|
+
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
|
2513
|
+
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
|
2514
|
+
$altExifTool->ExtractInfo($$altExifTool{ALT_FILE});
|
|
2515
|
+
# set family 8 group name for all tags
|
|
2516
|
+
foreach (keys %{$$altExifTool{VALUE}}) {
|
|
2517
|
+
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
|
2518
|
+
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
|
2519
|
+
$$ex{G8} = $g8;
|
|
2520
|
+
}
|
|
2521
|
+
$$altExifTool{DID_EXTRACT} = 1;
|
|
2522
|
+
}
|
|
2481
2523
|
}
|
|
2482
2524
|
|
|
2483
2525
|
my $filename = $$self{FILENAME}; # image file name ('' if already open)
|
|
@@ -2867,6 +2909,10 @@ sub ExtractInfo($;@)
|
|
|
2867
2909
|
# restore necessary members when exiting re-entrant code
|
|
2868
2910
|
$$self{$_} = $$reEntry{$_} foreach keys %$reEntry;
|
|
2869
2911
|
SetByteOrder($saveOrder);
|
|
2912
|
+
} elsif ($$self{ImageDataMD5}) {
|
|
2913
|
+
my $digest = $$self{ImageDataMD5}->hexdigest;
|
|
2914
|
+
# (don't store empty digest)
|
|
2915
|
+
$self->FoundTag(ImageDataMD5 => $digest) unless $digest eq 'd41d8cd98f00b204e9800998ecf8427e';
|
|
2870
2916
|
}
|
|
2871
2917
|
|
|
2872
2918
|
# ($type may be undef without an Error when processing sub-documents)
|
|
@@ -3498,6 +3544,10 @@ sub GetGroup($$;$)
|
|
|
3498
3544
|
$groups[6] = $$ex{G6};
|
|
3499
3545
|
}
|
|
3500
3546
|
}
|
|
3547
|
+
if ($$ex{G8}) {
|
|
3548
|
+
$groups[7] = '';
|
|
3549
|
+
$groups[8] = $$ex{G8};
|
|
3550
|
+
}
|
|
3501
3551
|
# generate tag ID group names unless obviously not needed
|
|
3502
3552
|
unless ($noID) {
|
|
3503
3553
|
my $id = $$tagInfo{KeysID} || $$tagInfo{TagID};
|
|
@@ -3683,13 +3733,21 @@ COMPOSITE_TAG:
|
|
|
3683
3733
|
next COMPOSITE_TAG;
|
|
3684
3734
|
}
|
|
3685
3735
|
}
|
|
3736
|
+
my ($i, $key, @keys, $altFile);
|
|
3737
|
+
my $et = $self;
|
|
3738
|
+
# get tags from alternate file if a family 8 group was specified
|
|
3739
|
+
if ($reqTag =~ /\b(File\d+):/i and $$self{ALT_EXIFTOOL}{$1}) {
|
|
3740
|
+
$et = $$self{ALT_EXIFTOOL}{$1};
|
|
3741
|
+
$altFile = $1;
|
|
3742
|
+
}
|
|
3686
3743
|
# (CAREFUL! keys may not be sequential if one was deleted)
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
push @keys, $key if defined $$rawValue{$key};
|
|
3744
|
+
for ($key=$name, $i=$$et{DUPL_TAG}{$name} || 0; ; --$i) {
|
|
3745
|
+
push @keys, $key if defined $$et{VALUE}{$key};
|
|
3690
3746
|
last if $i <= 0;
|
|
3691
3747
|
$key = "$name ($i)";
|
|
3692
3748
|
}
|
|
3749
|
+
# make sure the necessary information is available from the alternate file
|
|
3750
|
+
$self->CopyAltInfo($altFile, \@keys) if $altFile;
|
|
3693
3751
|
# find first matching tag
|
|
3694
3752
|
$key = $self->GroupMatches($reqGroup, \@keys);
|
|
3695
3753
|
$reqTag = $key || "$name (0)";
|
|
@@ -4131,7 +4189,11 @@ sub SplitFileName($)
|
|
|
4131
4189
|
} else {
|
|
4132
4190
|
($name = $file) =~ tr/\\/\//;
|
|
4133
4191
|
# remove path
|
|
4134
|
-
|
|
4192
|
+
if ($name =~ s/(.*)\///) {
|
|
4193
|
+
$dir = length($1) ? $1 : '/';
|
|
4194
|
+
} else {
|
|
4195
|
+
$dir = '.';
|
|
4196
|
+
}
|
|
4135
4197
|
}
|
|
4136
4198
|
return ($dir, $name);
|
|
4137
4199
|
}
|
|
@@ -4294,9 +4356,9 @@ sub GetFileTime($$)
|
|
|
4294
4356
|
# on Windows, try to work around incorrect file times when daylight saving time is in effect
|
|
4295
4357
|
if ($^O eq 'MSWin32') {
|
|
4296
4358
|
if (not eval { require Win32::API }) {
|
|
4297
|
-
$self->WarnOnce('Install Win32::API for proper handling of Windows file times');
|
|
4359
|
+
$self->WarnOnce('Install Win32::API for proper handling of Windows file times', 1);
|
|
4298
4360
|
} elsif (not eval { require Win32API::File }) {
|
|
4299
|
-
$self->WarnOnce('Install Win32API::File for proper handling of Windows file times');
|
|
4361
|
+
$self->WarnOnce('Install Win32API::File for proper handling of Windows file times', 1);
|
|
4300
4362
|
} else {
|
|
4301
4363
|
# get Win32 handle, needed for GetFileTime
|
|
4302
4364
|
my $win32Handle = eval { Win32API::File::GetOsFHandle($file) };
|
|
@@ -4546,6 +4608,29 @@ sub RemoveTagsFromList($$$$;$)
|
|
|
4546
4608
|
$_[0] = \@filteredTags; # update tag list
|
|
4547
4609
|
}
|
|
4548
4610
|
|
|
4611
|
+
#------------------------------------------------------------------------------
|
|
4612
|
+
# Copy tags from alternate input file
|
|
4613
|
+
# Inputs: 0) ExifTool ref, 1) family 8 group, 2) list ref for tag keys to copy
|
|
4614
|
+
# - updates tag key list to match keys newly added to $self
|
|
4615
|
+
sub CopyAltInfo($$$)
|
|
4616
|
+
{
|
|
4617
|
+
my ($self, $g8, $tags) = @_;
|
|
4618
|
+
my ($tag, $vtag);
|
|
4619
|
+
return unless $g8 =~ /(\d+)/;
|
|
4620
|
+
my $et = $$self{ALT_EXIFTOOL}{$g8} or return;
|
|
4621
|
+
my $altOrder = ($1 + 1) * 100000; # increment file order
|
|
4622
|
+
foreach $tag (@$tags) {
|
|
4623
|
+
($vtag = $tag) =~ s/( |$)/ #[$g8]/;
|
|
4624
|
+
unless (defined $$self{VALUE}{$vtag}) {
|
|
4625
|
+
$$self{VALUE}{$vtag} = $$et{VALUE}{$tag};
|
|
4626
|
+
$$self{TAG_INFO}{$vtag} = $$et{TAG_INFO}{$tag};
|
|
4627
|
+
$$self{TAG_EXTRA}{$vtag} = $$et{TAG_EXTRA}{$tag} || { };
|
|
4628
|
+
$$self{FILE_ORDER}{$vtag} = ($$et{FILE_ORDER}{$tag} || 0) + $altOrder;
|
|
4629
|
+
}
|
|
4630
|
+
$tag = $vtag;
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
|
|
4549
4634
|
#------------------------------------------------------------------------------
|
|
4550
4635
|
# Set list of found tags from previously requested tags
|
|
4551
4636
|
# Inputs: 0) ExifTool object reference
|
|
@@ -4572,11 +4657,17 @@ sub SetFoundTags($)
|
|
|
4572
4657
|
my $tagHash = $$self{VALUE};
|
|
4573
4658
|
my $reqTag;
|
|
4574
4659
|
foreach $reqTag (@$reqTags) {
|
|
4575
|
-
my (@matches, $group, $allGrp, $allTag, $byValue);
|
|
4660
|
+
my (@matches, $group, $allGrp, $allTag, $byValue, $g8);
|
|
4661
|
+
my $et = $self;
|
|
4576
4662
|
if ($reqTag =~ /^(.*):(.+)/) {
|
|
4577
4663
|
($group, $tag) = ($1, $2);
|
|
4578
4664
|
if ($group =~ /^(\*|all)$/i) {
|
|
4579
4665
|
$allGrp = 1;
|
|
4666
|
+
} elsif ($reqTag =~ /\bfile(\d+):/i) {
|
|
4667
|
+
$g8 = "File$1";
|
|
4668
|
+
$et = $$self{ALT_EXIFTOOL}{$g8} || $self;
|
|
4669
|
+
$fileOrder = $$et{FILE_ORDER};
|
|
4670
|
+
$tagHash = $$et{VALUE};
|
|
4580
4671
|
} elsif ($group !~ /^[-\w:]*$/) {
|
|
4581
4672
|
$self->Warn("Invalid group name '${group}'");
|
|
4582
4673
|
$group = 'invalid';
|
|
@@ -4618,7 +4709,7 @@ sub SetFoundTags($)
|
|
|
4618
4709
|
}
|
|
4619
4710
|
if (defined $group and not $allGrp) {
|
|
4620
4711
|
# keep only specified group
|
|
4621
|
-
@matches = $
|
|
4712
|
+
@matches = $et->GroupMatches($group, \@matches);
|
|
4622
4713
|
next unless @matches or not $allTag;
|
|
4623
4714
|
}
|
|
4624
4715
|
if (@matches > 1) {
|
|
@@ -4627,9 +4718,9 @@ sub SetFoundTags($)
|
|
|
4627
4718
|
# return only the highest priority tag unless duplicates wanted
|
|
4628
4719
|
unless ($doDups or $allTag or $allGrp) {
|
|
4629
4720
|
$tag = shift @matches;
|
|
4630
|
-
my $oldPriority = $$
|
|
4721
|
+
my $oldPriority = $$et{PRIORITY}{$tag} || 1;
|
|
4631
4722
|
foreach (@matches) {
|
|
4632
|
-
my $priority = $$
|
|
4723
|
+
my $priority = $$et{PRIORITY}{$_};
|
|
4633
4724
|
$priority = 1 unless defined $priority;
|
|
4634
4725
|
next unless $priority >= $oldPriority;
|
|
4635
4726
|
$tag = $_;
|
|
@@ -4643,6 +4734,13 @@ sub SetFoundTags($)
|
|
|
4643
4734
|
# bogus file order entry to avoid warning if sorting in file order
|
|
4644
4735
|
$$self{FILE_ORDER}{$matches[0]} = 9999;
|
|
4645
4736
|
}
|
|
4737
|
+
# copy over necessary information for tags from alternate files
|
|
4738
|
+
if ($g8) {
|
|
4739
|
+
$self->CopyAltInfo($g8, \@matches);
|
|
4740
|
+
# restore variables to original values for main file
|
|
4741
|
+
$fileOrder = $$self{FILE_ORDER};
|
|
4742
|
+
$tagHash = $$self{VALUE};
|
|
4743
|
+
}
|
|
4646
4744
|
# save indices of tags extracted by value
|
|
4647
4745
|
push @byValue, scalar(@$rtnTags) .. (scalar(@$rtnTags)+scalar(@matches)-1) if $byValue;
|
|
4648
4746
|
# save indices of wildcard tags
|
|
@@ -5865,7 +5963,8 @@ sub ConvertTimeSpan($;$)
|
|
|
5865
5963
|
#------------------------------------------------------------------------------
|
|
5866
5964
|
# Patched timelocal() that fixes ActivePerl timezone bug
|
|
5867
5965
|
# Inputs/Returns: same as timelocal()
|
|
5868
|
-
# Notes: must 'require Time::Local' before calling this routine
|
|
5966
|
+
# Notes: must 'require Time::Local' before calling this routine.
|
|
5967
|
+
# Also note that year should be full year, and not relative to 1900 as with localtime
|
|
5869
5968
|
sub TimeLocal(@)
|
|
5870
5969
|
{
|
|
5871
5970
|
my $tm = Time::Local::timelocal(@_);
|
|
@@ -6324,7 +6423,6 @@ sub ProcessJPEG($$)
|
|
|
6324
6423
|
{
|
|
6325
6424
|
local $_;
|
|
6326
6425
|
my ($self, $dirInfo) = @_;
|
|
6327
|
-
my ($ch, $s, $length);
|
|
6328
6426
|
my $options = $$self{OPTIONS};
|
|
6329
6427
|
my $verbose = $$options{Verbose};
|
|
6330
6428
|
my $out = $$options{TextOut};
|
|
@@ -6333,10 +6431,17 @@ sub ProcessJPEG($$)
|
|
|
6333
6431
|
my $req = $$self{REQ_TAG_LOOKUP};
|
|
6334
6432
|
my $htmlDump = $$self{HTML_DUMP};
|
|
6335
6433
|
my %dumpParms = ( Out => $out );
|
|
6434
|
+
my ($ch, $s, $length, $md5, $md5size);
|
|
6336
6435
|
my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
|
|
6337
6436
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
|
6338
6437
|
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
|
6339
6438
|
|
|
6439
|
+
# get pointer to MD5 object if it exists and we are the top-level JPEG
|
|
6440
|
+
if ($$self{FILE_TYPE} eq 'JPEG' and not $$self{DOC_NUM}) {
|
|
6441
|
+
$md5 = $$self{ImageDataMD5};
|
|
6442
|
+
$md5size = 0;
|
|
6443
|
+
}
|
|
6444
|
+
|
|
6340
6445
|
# check to be sure this is a valid JPG (or J2C, or EXV) file
|
|
6341
6446
|
return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/;
|
|
6342
6447
|
if ($s eq "\xff\x01") {
|
|
@@ -6383,7 +6488,9 @@ sub ProcessJPEG($$)
|
|
|
6383
6488
|
#
|
|
6384
6489
|
# read ahead to the next segment unless we have reached EOI, SOS or SOD
|
|
6385
6490
|
#
|
|
6386
|
-
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer
|
|
6491
|
+
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $md5) or
|
|
6492
|
+
$marker==0x93))
|
|
6493
|
+
{
|
|
6387
6494
|
# read up to next marker (JPEG markers begin with 0xff)
|
|
6388
6495
|
my $buff;
|
|
6389
6496
|
$raf->ReadLine($buff) or last;
|
|
@@ -6413,6 +6520,19 @@ sub ProcessJPEG($$)
|
|
|
6413
6520
|
$nextSegPos = $raf->Tell();
|
|
6414
6521
|
$len -= 4; # subtract size of length word
|
|
6415
6522
|
last unless $raf->Seek($len, 1);
|
|
6523
|
+
} elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == 0xda or
|
|
6524
|
+
($marker >= 0xd0 and $marker <= 0xd7)))
|
|
6525
|
+
{
|
|
6526
|
+
# calculate MD5 for image data (includes leading ff d9 but not trailing ff da)
|
|
6527
|
+
$md5->add("\xff" . chr($marker));
|
|
6528
|
+
my $n = $skipped - (length($buff) - 1); # number of extra 0xff's
|
|
6529
|
+
if (not $n) {
|
|
6530
|
+
$buff = substr($buff, 0, -1); # remove trailing 0xff
|
|
6531
|
+
} elsif ($n > 1) {
|
|
6532
|
+
$buff .= "\xff" x ($n - 1); # add back extra 0xff's
|
|
6533
|
+
}
|
|
6534
|
+
$md5->add($buff);
|
|
6535
|
+
$md5size += $skipped + 2;
|
|
6416
6536
|
}
|
|
6417
6537
|
# read second segment too if this was the first
|
|
6418
6538
|
next unless defined $marker;
|
|
@@ -6623,7 +6743,7 @@ sub ProcessJPEG($$)
|
|
|
6623
6743
|
next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump;
|
|
6624
6744
|
}
|
|
6625
6745
|
# must scan to EOI if Validate or JpegCompressionFactor used
|
|
6626
|
-
next if $$options{Validate} or $calcImageLen or $$req{trailer};
|
|
6746
|
+
next if $$options{Validate} or $calcImageLen or $$req{trailer} or $md5;
|
|
6627
6747
|
# nothing interesting to parse after start of scan (SOS)
|
|
6628
6748
|
$success = 1;
|
|
6629
6749
|
last; # all done parsing file
|
|
@@ -6705,7 +6825,7 @@ sub ProcessJPEG($$)
|
|
|
6705
6825
|
} elsif ($marker == 0xe1) { # APP1 (EXIF, XMP, QVCI, PARROT)
|
|
6706
6826
|
# (some Kodak cameras don't put a second "\0", and I have seen an
|
|
6707
6827
|
# example where there was a second 4-byte APP1 segment header)
|
|
6708
|
-
if ($$segDataPt =~ /^(.{0,4})Exif\0
|
|
6828
|
+
if ($$segDataPt =~ /^(.{0,4})Exif\0./is) {
|
|
6709
6829
|
undef $dumpType; # (will be dumped here)
|
|
6710
6830
|
# this is EXIF data --
|
|
6711
6831
|
# get the data block (into a common variable)
|
|
@@ -6871,7 +6991,7 @@ sub ProcessJPEG($$)
|
|
|
6871
6991
|
$self->Warn("Ignored APP1 segment length $length (unknown header)");
|
|
6872
6992
|
}
|
|
6873
6993
|
}
|
|
6874
|
-
} elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, PreviewImage)
|
|
6994
|
+
} elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, InfiRay, PreviewImage)
|
|
6875
6995
|
if ($$segDataPt =~ /^ICC_PROFILE\0/ and $length >= 14) {
|
|
6876
6996
|
$dumpType = 'ICC_Profile';
|
|
6877
6997
|
# must concatenate profile chunks (note: handle the case where
|
|
@@ -6933,6 +7053,12 @@ sub ProcessJPEG($$)
|
|
|
6933
7053
|
# extract the MPF information (it is in standard TIFF format)
|
|
6934
7054
|
my $tagTablePtr = GetTagTable('Image::ExifTool::MPF::Main');
|
|
6935
7055
|
$self->ProcessTIFF(\%dirInfo, $tagTablePtr);
|
|
7056
|
+
} elsif ($$segDataPt =~ /^....IJPEG\0/s) {
|
|
7057
|
+
$dumpType = 'InfiRay Version';
|
|
7058
|
+
$$self{HasIJPEG} = 1;
|
|
7059
|
+
SetByteOrder('II');
|
|
7060
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Version');
|
|
7061
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
6936
7062
|
} elsif ($$segDataPt =~ /^(|QVGA\0|BGTH)\xff\xd8\xff[\xdb\xe0\xe1]/) {
|
|
6937
7063
|
# Samsung/GE/GoPro="", BenQ DC C1220/Pentacon/Polaroid="QVGA\0",
|
|
6938
7064
|
# Digilife DDC-690/Rollei="BGTH"
|
|
@@ -6973,8 +7099,8 @@ sub ProcessJPEG($$)
|
|
|
6973
7099
|
SetByteOrder('MM');
|
|
6974
7100
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::JPS');
|
|
6975
7101
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
6976
|
-
} elsif ($$self{Make} eq 'DJI') {
|
|
6977
|
-
$dumpType = 'DJI ThermalData';
|
|
7102
|
+
} elsif ($$self{HasIJPEG} or $$self{Make} eq 'DJI') {
|
|
7103
|
+
$dumpType = $$self{HasIJPEG} ? 'InfiRay ImagingData' : 'DJI ThermalData';
|
|
6978
7104
|
# add this data to the combined data if it exists
|
|
6979
7105
|
my $dataPt = $segDataPt;
|
|
6980
7106
|
if (defined $combinedSegData) {
|
|
@@ -6984,11 +7110,14 @@ sub ProcessJPEG($$)
|
|
|
6984
7110
|
if ($nextMarker == $marker) {
|
|
6985
7111
|
$combinedSegData = $$segDataPt unless defined $combinedSegData;
|
|
6986
7112
|
} else {
|
|
6987
|
-
# process DJI
|
|
7113
|
+
# process InfiRay/DJI thermal data
|
|
6988
7114
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
|
|
6989
7115
|
$self->HandleTag($tagTablePtr, 'APP3', $$dataPt);
|
|
6990
7116
|
undef $combinedSegData;
|
|
6991
7117
|
}
|
|
7118
|
+
} elsif ($$self{HasIJPEG}) {
|
|
7119
|
+
$dumpType = 'InfiRay Data',
|
|
7120
|
+
|
|
6992
7121
|
} elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) {
|
|
6993
7122
|
$dumpType = 'PreviewImage'; # (Samsung, HP, BenQ)
|
|
6994
7123
|
$preview = $$segDataPt;
|
|
@@ -6997,7 +7126,7 @@ sub ProcessJPEG($$)
|
|
|
6997
7126
|
$self->FoundTag('PreviewImage', $preview);
|
|
6998
7127
|
undef $preview;
|
|
6999
7128
|
}
|
|
7000
|
-
} elsif ($marker == 0xe4) { # APP4 ("SCALADO", FPXR, PreviewImage)
|
|
7129
|
+
} elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, DJI, PreviewImage)
|
|
7001
7130
|
if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) {
|
|
7002
7131
|
$dumpType = 'SCALADO';
|
|
7003
7132
|
my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt);
|
|
@@ -7028,6 +7157,21 @@ sub ProcessJPEG($$)
|
|
|
7028
7157
|
DirStart(\%dirInfo, 0, 0);
|
|
7029
7158
|
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams');
|
|
7030
7159
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7160
|
+
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^(.{32})?.{32}\x2c\x01\x20\0/s) {
|
|
7161
|
+
$dumpType = 'DJI ThermalParams2';
|
|
7162
|
+
DirStart(\%dirInfo, $1 ? 32 : 0, 0);
|
|
7163
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams2');
|
|
7164
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7165
|
+
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^.{32}\xaa\x55\x38\0/s) {
|
|
7166
|
+
$dumpType = 'DJI ThermalParams3';
|
|
7167
|
+
DirStart(\%dirInfo, 32, 0);
|
|
7168
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams3');
|
|
7169
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7170
|
+
} elsif ($$self{HasIJPEG} and $length >= 120) {
|
|
7171
|
+
$dumpType = 'InfiRay Factory';
|
|
7172
|
+
SetByteOrder('II');
|
|
7173
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Factory');
|
|
7174
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7031
7175
|
} elsif ($preview) {
|
|
7032
7176
|
# continued Samsung S1060 preview from APP3
|
|
7033
7177
|
$dumpType = 'PreviewImage';
|
|
@@ -7039,7 +7183,7 @@ sub ProcessJPEG($$)
|
|
|
7039
7183
|
$self->FoundTag('PreviewImage', $preview);
|
|
7040
7184
|
undef $preview;
|
|
7041
7185
|
}
|
|
7042
|
-
} elsif ($marker == 0xe5) { # APP5 (Ricoh "RMETA")
|
|
7186
|
+
} elsif ($marker == 0xe5) { # APP5 (InfiRay, Ricoh "RMETA")
|
|
7043
7187
|
if ($$segDataPt =~ /^RMETA\0/) {
|
|
7044
7188
|
# (NOTE: apparently these may span multiple segments, but I haven't seen
|
|
7045
7189
|
# a sample like this, so multi-segment support hasn't yet been implemented)
|
|
@@ -7054,13 +7198,18 @@ sub ProcessJPEG($$)
|
|
|
7054
7198
|
$dumpType = 'DJI ThermalCal';
|
|
7055
7199
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
|
|
7056
7200
|
$self->HandleTag($tagTablePtr, 'APP5', $$segDataPt);
|
|
7201
|
+
} elsif ($$self{HasIJPEG} and $length >= 38) {
|
|
7202
|
+
$dumpType = 'InfiRay Picture';
|
|
7203
|
+
SetByteOrder('II');
|
|
7204
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Picture');
|
|
7205
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7057
7206
|
} elsif ($preview) {
|
|
7058
7207
|
$dumpType = 'PreviewImage';
|
|
7059
7208
|
$preview .= $$segDataPt;
|
|
7060
7209
|
$self->FoundTag('PreviewImage', $preview);
|
|
7061
7210
|
undef $preview;
|
|
7062
7211
|
}
|
|
7063
|
-
} elsif ($marker == 0xe6) { # APP6 (Toshiba EPPIM, NITF, HP_TDHD)
|
|
7212
|
+
} elsif ($marker == 0xe6) { # APP6 (InfiRay, Toshiba EPPIM, NITF, HP_TDHD)
|
|
7064
7213
|
if ($$segDataPt =~ /^EPPIM\0/) {
|
|
7065
7214
|
undef $dumpType; # (will be dumped here)
|
|
7066
7215
|
DirStart(\%dirInfo, 6, 6);
|
|
@@ -7093,8 +7242,13 @@ sub ProcessJPEG($$)
|
|
|
7093
7242
|
$dumpType = 'DJI_DTAT';
|
|
7094
7243
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
|
|
7095
7244
|
$self->HandleTag($tagTablePtr, 'APP6', $$segDataPt);
|
|
7245
|
+
} elsif ($$self{HasIJPEG} and $length >= 129) {
|
|
7246
|
+
$dumpType = 'InfiRay MixMode';
|
|
7247
|
+
SetByteOrder('II');
|
|
7248
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::MixMode');
|
|
7249
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7096
7250
|
}
|
|
7097
|
-
} elsif ($marker == 0xe7) { # APP7 (Pentax, Huawei, Qualcomm)
|
|
7251
|
+
} elsif ($marker == 0xe7) { # APP7 (InfiRay, Pentax, Huawei, Qualcomm)
|
|
7098
7252
|
if ($$segDataPt =~ /^PENTAX \0(II|MM)/) {
|
|
7099
7253
|
# found in K-3 images (is this multi-segment??)
|
|
7100
7254
|
SetByteOrder($1);
|
|
@@ -7126,6 +7280,13 @@ sub ProcessJPEG($$)
|
|
|
7126
7280
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7127
7281
|
delete $$self{SET_GROUP0};
|
|
7128
7282
|
delete $$self{SET_GROUP1};
|
|
7283
|
+
} elsif ($$segDataPt =~ /^DJI-DBG\0/) {
|
|
7284
|
+
$dumpType = 'DJI Info';
|
|
7285
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::Info');
|
|
7286
|
+
DirStart(\%dirInfo, 8, 0);
|
|
7287
|
+
$$self{SET_GROUP0} = 'APP7';
|
|
7288
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7289
|
+
delete $$self{SET_GROUP0};
|
|
7129
7290
|
} elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) {
|
|
7130
7291
|
# found in HP iPAQ_VoiceMessenger
|
|
7131
7292
|
$dumpType = 'Qualcomm';
|
|
@@ -7133,16 +7294,26 @@ sub ProcessJPEG($$)
|
|
|
7133
7294
|
DirStart(\%dirInfo, 27);
|
|
7134
7295
|
$dirInfo{DirName} = 'Qualcomm';
|
|
7135
7296
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7297
|
+
} elsif ($$self{HasIJPEG} and $length >= 32) {
|
|
7298
|
+
$dumpType = 'InfiRay OpMode';
|
|
7299
|
+
SetByteOrder('II');
|
|
7300
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::OpMode');
|
|
7301
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7136
7302
|
}
|
|
7137
|
-
} elsif ($marker == 0xe8) { # APP8 (SPIFF)
|
|
7303
|
+
} elsif ($marker == 0xe8) { # APP8 (InfiRay, SPIFF)
|
|
7138
7304
|
# my sample SPIFF has 32 bytes of data, but spec states 30
|
|
7139
7305
|
if ($$segDataPt =~ /^SPIFF\0/ and $length == 32) {
|
|
7140
7306
|
$dumpType = 'SPIFF';
|
|
7141
7307
|
DirStart(\%dirInfo, 6);
|
|
7142
7308
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::SPIFF');
|
|
7143
7309
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7310
|
+
} elsif ($$self{HasIJPEG} and $length >= 32) {
|
|
7311
|
+
$dumpType = 'InfiRay Isothermal';
|
|
7312
|
+
SetByteOrder('II');
|
|
7313
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Isothermal');
|
|
7314
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7144
7315
|
}
|
|
7145
|
-
} elsif ($marker == 0xe9) { # APP9 (Media Jukebox)
|
|
7316
|
+
} elsif ($marker == 0xe9) { # APP9 (InfiRay, Media Jukebox)
|
|
7146
7317
|
if ($$segDataPt =~ /^Media Jukebox\0/ and $length > 22) {
|
|
7147
7318
|
$dumpType = 'MediaJukebox';
|
|
7148
7319
|
# (start parsing after the "<MJMD>")
|
|
@@ -7151,6 +7322,11 @@ sub ProcessJPEG($$)
|
|
|
7151
7322
|
require Image::ExifTool::XMP;
|
|
7152
7323
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::MediaJukebox');
|
|
7153
7324
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::XMP::ProcessXMP);
|
|
7325
|
+
} elsif ($$self{HasIJPEG} and $length >= 768) {
|
|
7326
|
+
$dumpType = 'InfiRay Sensor';
|
|
7327
|
+
SetByteOrder('II');
|
|
7328
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Sensor');
|
|
7329
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7154
7330
|
}
|
|
7155
7331
|
} elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments)
|
|
7156
7332
|
if ($$segDataPt =~ /^UNICODE\0/) {
|
|
@@ -7371,6 +7547,8 @@ sub ProcessJPEG($$)
|
|
|
7371
7547
|
delete $extendedXMP{$guid};
|
|
7372
7548
|
}
|
|
7373
7549
|
}
|
|
7550
|
+
# print verbose MD5 message if necessary
|
|
7551
|
+
print $out "$$self{INDENT}(ImageDataMD5: $md5size bytes of JPEG image data)\n" if $md5size and $verbose;
|
|
7374
7552
|
# calculate JPEGDigest if requested
|
|
7375
7553
|
if (@dqt) {
|
|
7376
7554
|
require Image::ExifTool::JPEGDigest;
|
|
@@ -7639,7 +7817,7 @@ sub DoProcessTIFF($$;$)
|
|
|
7639
7817
|
}
|
|
7640
7818
|
}
|
|
7641
7819
|
# update FileType if necessary now that we know more about the file
|
|
7642
|
-
if ($$self{DNGVersion} and $$self{
|
|
7820
|
+
if ($$self{DNGVersion} and $$self{FileType} !~ /^(DNG|GPR)$/) {
|
|
7643
7821
|
# override whatever FileType we set since we now know it is DNG
|
|
7644
7822
|
$self->OverrideFileType($$self{TIFF_TYPE} = 'DNG');
|
|
7645
7823
|
}
|
|
@@ -7947,7 +8125,7 @@ sub ProcessDirectory($$$;$)
|
|
|
7947
8125
|
# patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
|
|
7948
8126
|
return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
|
|
7949
8127
|
}
|
|
7950
|
-
$$self{PROCESSED}{$addr} = $dirName;
|
|
8128
|
+
$$self{PROCESSED}{$addr} = $dirName unless $$tagTablePtr{VARS} and $$tagTablePtr{VARS}{ALLOW_REPROCESS};
|
|
7951
8129
|
}
|
|
7952
8130
|
my $oldOrder = GetByteOrder();
|
|
7953
8131
|
my @save = @$self{'INDENT','DIR_NAME','Compression','SubfileType'};
|
|
@@ -8525,7 +8703,7 @@ sub DoEscape($$)
|
|
|
8525
8703
|
sub SetFileType($;$$$)
|
|
8526
8704
|
{
|
|
8527
8705
|
my ($self, $fileType, $mimeType, $normExt) = @_;
|
|
8528
|
-
unless ($$self{
|
|
8706
|
+
unless ($$self{FileType} and not $$self{DOC_NUM}) {
|
|
8529
8707
|
my $baseType = $$self{FILE_TYPE};
|
|
8530
8708
|
my $ext = $$self{FILE_EXT};
|
|
8531
8709
|
$fileType or $fileType = $baseType;
|
|
@@ -8544,7 +8722,8 @@ sub SetFileType($;$$$)
|
|
|
8544
8722
|
$normExt = $fileTypeExt{$fileType};
|
|
8545
8723
|
$normExt = $fileType unless defined $normExt;
|
|
8546
8724
|
}
|
|
8547
|
-
$$self{FileType}
|
|
8725
|
+
# ($$self{FileType} is the file type of the main document)
|
|
8726
|
+
$$self{FileType} = $fileType unless $$self{DOC_NUM};
|
|
8548
8727
|
$self->FoundTag('FileType', $fileType);
|
|
8549
8728
|
$self->FoundTag('FileTypeExtension', uc $normExt);
|
|
8550
8729
|
$self->FoundTag('MIMEType', $mimeType || 'application/unknown');
|
|
@@ -8708,13 +8887,16 @@ sub ProcessBinaryData($$$)
|
|
|
8708
8887
|
{
|
|
8709
8888
|
my ($self, $dirInfo, $tagTablePtr) = @_;
|
|
8710
8889
|
my $dataPt = $$dirInfo{DataPt};
|
|
8711
|
-
my $
|
|
8712
|
-
my $
|
|
8890
|
+
my $dataLen = length $$dataPt;
|
|
8891
|
+
my $dirStart = $$dirInfo{DirStart} || 0;
|
|
8892
|
+
my $maxLen = $dataLen - $dirStart;
|
|
8893
|
+
my $size = $$dirInfo{DirLen};
|
|
8713
8894
|
my $base = $$dirInfo{Base} || 0;
|
|
8714
8895
|
my $verbose = $$self{OPTIONS}{Verbose};
|
|
8715
8896
|
my $unknown = $$self{OPTIONS}{Unknown};
|
|
8716
8897
|
my $dataPos = $$dirInfo{DataPos} || 0;
|
|
8717
8898
|
|
|
8899
|
+
$size = $maxLen if not defined $size or $size > $maxLen;
|
|
8718
8900
|
# get default format ('int8u' unless specified)
|
|
8719
8901
|
my $defaultFormat = $$tagTablePtr{FORMAT} || 'int8u';
|
|
8720
8902
|
my $increment = $formatSize{$defaultFormat};
|
|
@@ -8756,6 +8938,7 @@ sub ProcessBinaryData($$$)
|
|
|
8756
8938
|
$tagInfo = $self->GetTagInfo($tagTablePtr, $index);
|
|
8757
8939
|
unless ($tagInfo) {
|
|
8758
8940
|
next unless defined $tagInfo;
|
|
8941
|
+
# $entry = offset of value relative to directory start (or end if negative)
|
|
8759
8942
|
my $entry = int($index) * $increment + $varSize;
|
|
8760
8943
|
if ($entry < 0) {
|
|
8761
8944
|
$entry += $size;
|
|
@@ -8764,7 +8947,7 @@ sub ProcessBinaryData($$$)
|
|
|
8764
8947
|
next if $entry >= $size;
|
|
8765
8948
|
my $more = $size - $entry;
|
|
8766
8949
|
$more = 128 if $more > 128;
|
|
8767
|
-
my $v = substr($$dataPt, $entry+$
|
|
8950
|
+
my $v = substr($$dataPt, $entry+$dirStart, $more);
|
|
8768
8951
|
$tagInfo = $self->GetTagInfo($tagTablePtr, $index, \$v);
|
|
8769
8952
|
next unless $tagInfo;
|
|
8770
8953
|
}
|
|
@@ -8797,7 +8980,7 @@ sub ProcessBinaryData($$$)
|
|
|
8797
8980
|
$count = $more;
|
|
8798
8981
|
} elsif ($format eq 'pstring') {
|
|
8799
8982
|
$format = 'string';
|
|
8800
|
-
$count = Get8u($dataPt, ($entry++)+$
|
|
8983
|
+
$count = Get8u($dataPt, ($entry++)+$dirStart);
|
|
8801
8984
|
--$more;
|
|
8802
8985
|
} elsif (not $formatSize{$format}) {
|
|
8803
8986
|
if ($format =~ /(.*)\[(.*)\]/) {
|
|
@@ -8826,17 +9009,17 @@ sub ProcessBinaryData($$$)
|
|
|
8826
9009
|
} elsif ($format =~ /^var_/) {
|
|
8827
9010
|
# handle variable-length string formats
|
|
8828
9011
|
$format = substr($format, 4);
|
|
8829
|
-
pos($$dataPt) = $entry + $
|
|
9012
|
+
pos($$dataPt) = $entry + $dirStart;
|
|
8830
9013
|
undef $count;
|
|
8831
9014
|
if ($format eq 'ustring') {
|
|
8832
|
-
$count = pos($$dataPt) - ($entry+$
|
|
9015
|
+
$count = pos($$dataPt) - ($entry+$dirStart) if $$dataPt =~ /\G(..)*?\0\0/sg;
|
|
8833
9016
|
$varSize -= 2; # ($count includes base size of 2 bytes)
|
|
8834
9017
|
} elsif ($format eq 'pstring') {
|
|
8835
|
-
$count = Get8u($dataPt, ($entry++)+$
|
|
9018
|
+
$count = Get8u($dataPt, ($entry++)+$dirStart);
|
|
8836
9019
|
--$more;
|
|
8837
9020
|
} elsif ($format eq 'pstr32' or $format eq 'ustr32') {
|
|
8838
9021
|
last if $more < 4;
|
|
8839
|
-
$count = Get32u($dataPt, $entry + $
|
|
9022
|
+
$count = Get32u($dataPt, $entry + $dirStart);
|
|
8840
9023
|
$count *= 2 if $format eq 'ustr32';
|
|
8841
9024
|
$entry += 4;
|
|
8842
9025
|
$more -= 4;
|
|
@@ -8844,22 +9027,22 @@ sub ProcessBinaryData($$$)
|
|
|
8844
9027
|
} elsif ($format eq 'int16u') {
|
|
8845
9028
|
# int16u size of binary data to follow
|
|
8846
9029
|
last if $more < 2;
|
|
8847
|
-
$count = Get16u($dataPt, $entry + $
|
|
9030
|
+
$count = Get16u($dataPt, $entry + $dirStart) + 2;
|
|
8848
9031
|
$varSize -= 2; # ($count includes size word)
|
|
8849
9032
|
$format = 'undef';
|
|
8850
9033
|
} elsif ($format eq 'ue7') {
|
|
8851
9034
|
require Image::ExifTool::BPG;
|
|
8852
|
-
($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $
|
|
9035
|
+
($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $dirStart);
|
|
8853
9036
|
last unless defined $val;
|
|
8854
9037
|
--$varSize; # ($count includes base size of 1 byte)
|
|
8855
9038
|
} elsif ($$dataPt =~ /\0/g) {
|
|
8856
|
-
$count = pos($$dataPt) - ($entry+$
|
|
9039
|
+
$count = pos($$dataPt) - ($entry+$dirStart);
|
|
8857
9040
|
--$varSize; # ($count includes base size of 1 byte)
|
|
8858
9041
|
}
|
|
8859
9042
|
$count = $more if not defined $count or $count > $more;
|
|
8860
9043
|
$varSize += $count; # shift subsequent indices
|
|
8861
9044
|
unless (defined $val) {
|
|
8862
|
-
$val = substr($$dataPt, $entry+$
|
|
9045
|
+
$val = substr($$dataPt, $entry+$dirStart, $count);
|
|
8863
9046
|
$val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
|
|
8864
9047
|
$val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
|
|
8865
9048
|
}
|
|
@@ -8873,7 +9056,7 @@ sub ProcessBinaryData($$$)
|
|
|
8873
9056
|
# hook to allow format, etc to be set dynamically
|
|
8874
9057
|
if (defined $$tagInfo{Hook}) {
|
|
8875
9058
|
my $oldVarSize = $varSize;
|
|
8876
|
-
my $pos = $entry + $
|
|
9059
|
+
my $pos = $entry + $dirStart;
|
|
8877
9060
|
#### eval Hook ($format, $varSize, $size, $dataPt, $pos)
|
|
8878
9061
|
eval $$tagInfo{Hook};
|
|
8879
9062
|
# save variable size data if required for writing (in case changed by Hook)
|
|
@@ -8898,7 +9081,7 @@ sub ProcessBinaryData($$$)
|
|
|
8898
9081
|
next if $$tagInfo{LargeTag} and $$self{EXCL_TAG_LOOKUP}{lc $$tagInfo{Name}};
|
|
8899
9082
|
# read value now if necessary
|
|
8900
9083
|
unless (defined $val and not $$tagInfo{SubDirectory}) {
|
|
8901
|
-
$val = ReadValue($dataPt, $entry+$
|
|
9084
|
+
$val = ReadValue($dataPt, $entry+$dirStart, $format, $count, $more, \$rational);
|
|
8902
9085
|
next unless defined $val;
|
|
8903
9086
|
$mask = $$tagInfo{Mask};
|
|
8904
9087
|
$val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
|
|
@@ -8915,8 +9098,8 @@ sub ProcessBinaryData($$$)
|
|
|
8915
9098
|
Value => $val,
|
|
8916
9099
|
DataPt => $dataPt,
|
|
8917
9100
|
Size => $len,
|
|
8918
|
-
Start => $entry+$
|
|
8919
|
-
Addr => $entry+$
|
|
9101
|
+
Start => $entry+$dirStart,
|
|
9102
|
+
Addr => $entry+$dirStart+$base+$dataPos,
|
|
8920
9103
|
Format => $format,
|
|
8921
9104
|
Count => $count,
|
|
8922
9105
|
Extra => $mask ? sprintf(', mask 0x%.2x',$mask) : undef,
|
|
@@ -8942,16 +9125,27 @@ sub ProcessBinaryData($$$)
|
|
|
8942
9125
|
my $subdirBase = $base;
|
|
8943
9126
|
if (defined $$subdir{Base}) {
|
|
8944
9127
|
#### eval Base ($start,$base)
|
|
8945
|
-
my $start = $entry + $
|
|
9128
|
+
my $start = $entry + $dirStart + $dataPos;
|
|
8946
9129
|
$subdirBase = eval($$subdir{Base}) + $base;
|
|
8947
9130
|
}
|
|
8948
9131
|
my $start = $$subdir{Start} || 0;
|
|
9132
|
+
if ($start =~ /\$/) {
|
|
9133
|
+
# ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
|
|
9134
|
+
next unless $val;
|
|
9135
|
+
#### eval Start ($val, $dirStart)
|
|
9136
|
+
$start = eval($start);
|
|
9137
|
+
next if $start < $dirStart or $start > $dataLen;
|
|
9138
|
+
$len = $$subdir{DirLen};
|
|
9139
|
+
$len = $dataLen - $start unless $len and $len <= $dataLen - $start;
|
|
9140
|
+
} else {
|
|
9141
|
+
$start += $dirStart + $entry;
|
|
9142
|
+
}
|
|
8949
9143
|
my %subdirInfo = (
|
|
8950
9144
|
DataPt => $dataPt,
|
|
8951
9145
|
DataPos => $dataPos,
|
|
8952
|
-
DataLen =>
|
|
8953
|
-
DirStart => $
|
|
8954
|
-
DirLen => $len
|
|
9146
|
+
DataLen => $dataLen,
|
|
9147
|
+
DirStart => $start,
|
|
9148
|
+
DirLen => $len,
|
|
8955
9149
|
Base => $subdirBase,
|
|
8956
9150
|
);
|
|
8957
9151
|
delete $$self{NO_UNKNOWN};
|