exiftool_vendored 12.55.0 → 12.57.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +38 -1
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +19 -19
  7. data/bin/arg_files/xmp2exif.args +4 -1
  8. data/bin/exiftool +97 -53
  9. data/bin/fmt_files/kml.fmt +3 -0
  10. data/bin/fmt_files/kml_track.fmt +3 -0
  11. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +13 -6
  12. data/bin/lib/Image/ExifTool/Canon.pm +8 -2
  13. data/bin/lib/Image/ExifTool/Exif.pm +31 -2
  14. data/bin/lib/Image/ExifTool/FlashPix.pm +73 -8
  15. data/bin/lib/Image/ExifTool/FujiFilm.pm +2 -1
  16. data/bin/lib/Image/ExifTool/GPS.pm +7 -2
  17. data/bin/lib/Image/ExifTool/InfiRay.pm +227 -0
  18. data/bin/lib/Image/ExifTool/JPEG.pm +40 -6
  19. data/bin/lib/Image/ExifTool/Jpeg2000.pm +5 -5
  20. data/bin/lib/Image/ExifTool/MIE.pm +3 -3
  21. data/bin/lib/Image/ExifTool/Nikon.pm +862 -1264
  22. data/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
  23. data/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
  24. data/bin/lib/Image/ExifTool/Olympus.pm +3 -1
  25. data/bin/lib/Image/ExifTool/OpenEXR.pm +32 -15
  26. data/bin/lib/Image/ExifTool/PNG.pm +80 -2
  27. data/bin/lib/Image/ExifTool/Photoshop.pm +36 -5
  28. data/bin/lib/Image/ExifTool/QuickTime.pm +18 -2
  29. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +25 -14
  30. data/bin/lib/Image/ExifTool/README +11 -2
  31. data/bin/lib/Image/ExifTool/Real.pm +2 -2
  32. data/bin/lib/Image/ExifTool/Sigma.pm +2 -1
  33. data/bin/lib/Image/ExifTool/Sony.pm +5 -1
  34. data/bin/lib/Image/ExifTool/TagLookup.pm +4667 -4624
  35. data/bin/lib/Image/ExifTool/TagNames.pod +400 -90
  36. data/bin/lib/Image/ExifTool/VCard.pm +19 -5
  37. data/bin/lib/Image/ExifTool/Writer.pl +36 -16
  38. data/bin/lib/Image/ExifTool.pm +92 -35
  39. data/bin/lib/Image/ExifTool.pod +54 -53
  40. data/bin/perl-Image-ExifTool.spec +18 -18
  41. data/lib/exiftool_vendored/version.rb +1 -1
  42. metadata +3 -2
@@ -17,7 +17,7 @@ use strict;
17
17
  use vars qw($VERSION);
18
18
  use Image::ExifTool qw(:DataAccess :Utils);
19
19
 
20
- $VERSION = '1.06';
20
+ $VERSION = '1.07';
21
21
 
22
22
  my %unescapeVCard = ( '\\'=>'\\', ','=>',', 'n'=>"\n", 'N'=>"\n" );
23
23
 
@@ -190,6 +190,15 @@ my %timeInfo = (
190
190
  'X-wr-alarmuid' => 'AlarmUID',
191
191
  );
192
192
 
193
+ %Image::ExifTool::VCard::VNote = (
194
+ GROUPS => { 1 => 'VNote', 2 => 'Document' },
195
+ NOTES => 'Tags extracted from V-Note VNT files.',
196
+ Version => { },
197
+ Body => { },
198
+ Dcreated => { Name => 'CreateDate', Groups => { 2 => 'Time' }, %timeInfo },
199
+ 'Last-modified' => { Name => 'ModifyDate', Groups => { 2 => 'Time' }, %timeInfo },
200
+ );
201
+
193
202
  #------------------------------------------------------------------------------
194
203
  # Get vCard tag, creating if necessary
195
204
  # Inputs: 0) ExifTool ref, 1) tag table ref, 2) tag ID, 3) tag Name,
@@ -254,9 +263,14 @@ sub ProcessVCard($$)
254
263
  my $raf = $$dirInfo{RAF};
255
264
  my ($buff, $val, $ok, $component, %compNum, @count);
256
265
 
257
- return 0 unless $raf->Read($buff, 24) and $raf->Seek(0,0) and $buff=~/^BEGIN:(VCARD|VCALENDAR)\r\n/i;
258
- my ($type, $lbl, $tbl, $ext) = uc($1) eq 'VCARD' ? qw(VCard vCard Main VCF) : qw(ICS iCalendar VCalendar ICS);
259
- $et->SetFileType($type, undef, $ext);
266
+ return 0 unless $raf->Read($buff, 24) and $raf->Seek(0,0) and $buff=~/^BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n/i;
267
+ my %info = (
268
+ VCARD => [ qw(VCard vCard Main VCF) ],
269
+ VCALENDAR => [ qw(ICS iCalendar VCalendar ICS) ],
270
+ VNOTE => [ qw(VNote vNote VNote VNT text/v-note) ],
271
+ );
272
+ my ($type, $lbl, $tbl, $ext, $mime) = @{$info{uc($1)}};
273
+ $et->SetFileType($type, $mime, $ext);
260
274
  return 1 if $$et{OPTIONS}{FastScan} and $$et{OPTIONS}{FastScan} == 3;
261
275
  local $/ = "\r\n";
262
276
  my $tagTablePtr = GetTagTable("Image::ExifTool::VCard::$tbl");
@@ -274,7 +288,7 @@ sub ProcessVCard($$)
274
288
  }
275
289
  if ($val =~ /^(BEGIN|END):(V?)(\w+)$/i) {
276
290
  my ($begin, $v, $what) = ((lc($1) eq 'begin' ? 1 : 0), $2, ucfirst lc $3);
277
- if ($what eq 'Card' or $what eq 'Calendar') {
291
+ if ($what eq 'Card' or $what eq 'Calendar' or $what eq 'Note') {
278
292
  if ($begin) {
279
293
  @count = ( { } ); # reset group counters
280
294
  } else {
@@ -2727,8 +2727,10 @@ sub GetAllGroups($;$)
2727
2727
 
2728
2728
  my @tableNames = keys %allTables;
2729
2729
 
2730
- # loop through all tag tables and get all group names
2731
2730
  my %allGroups;
2731
+ # add family 1 groups not in tables
2732
+ $family == 1 and map { $allGroups{$_} = 1 } qw(Garmin);
2733
+ # loop through all tag tables and get all group names
2732
2734
  while (@tableNames) {
2733
2735
  my $table = GetTagTable(pop @tableNames);
2734
2736
  my ($grps, $grp, $tag, $tagInfo);
@@ -4267,7 +4269,7 @@ sub WriteDirectory($$$;$)
4267
4269
  if ($out) {
4268
4270
  print $out " Deleting $name\n" if defined $newData and not length $newData;
4269
4271
  if ($$self{CHANGED} == $oldChanged and $$self{OPTIONS}{Verbose} > 2) {
4270
- print $out "$$self{INDENT} [nothing changed in $dirName]\n";
4272
+ print $out "$$self{INDENT} [nothing changed in $name]\n";
4271
4273
  }
4272
4274
  }
4273
4275
  return $newData;
@@ -5432,7 +5434,6 @@ sub WriteJPEG($$)
5432
5434
  my $verbose = $$self{OPTIONS}{Verbose};
5433
5435
  my $out = $$self{OPTIONS}{TextOut};
5434
5436
  my $rtnVal = 0;
5435
- my %dumpParms = ( Out => $out );
5436
5437
  my ($writeBuffer, $oldOutfile); # used to buffer writing until PreviewImage position is known
5437
5438
 
5438
5439
  # check to be sure this is a valid JPG or EXV file
@@ -5447,7 +5448,6 @@ sub WriteJPEG($$)
5447
5448
  Write($outfile,"\xff\x01") or $err = 1;
5448
5449
  $isEXV = 1;
5449
5450
  }
5450
- $dumpParms{MaxLen} = 128 unless $verbose > 3;
5451
5451
 
5452
5452
  delete $$self{PREVIEW_INFO}; # reset preview information
5453
5453
  delete $$self{DEL_PREVIEW}; # reset flag to delete preview
@@ -6017,12 +6017,7 @@ sub WriteJPEG($$)
6017
6017
  #
6018
6018
  my $segDataPt = \$segData;
6019
6019
  $length = length($segData);
6020
- if ($verbose) {
6021
- print $out "JPEG $markerName ($length bytes):\n";
6022
- if ($verbose > 2 and $markerName =~ /^APP/) {
6023
- HexDump($segDataPt, undef, %dumpParms);
6024
- }
6025
- }
6020
+ print $out "JPEG $markerName ($length bytes)\n" if $verbose;
6026
6021
  # group delete of APP segments
6027
6022
  if ($$delGroup{$dirName}) {
6028
6023
  $verbose and print $out " Deleting $dirName segment\n";
@@ -6870,6 +6865,7 @@ sub WriteBinaryData($$$)
6870
6865
 
6871
6866
  # get default format ('int8u' unless specified)
6872
6867
  my $dataPt = $$dirInfo{DataPt} or return undef;
6868
+ my $dataLen = length $$dataPt;
6873
6869
  my $defaultFormat = $$tagTablePtr{FORMAT} || 'int8u';
6874
6870
  my $increment = FormatSize($defaultFormat);
6875
6871
  unless ($increment) {
@@ -6886,7 +6882,8 @@ sub WriteBinaryData($$$)
6886
6882
  delete $$dirInfo{VarFormatData};
6887
6883
  }
6888
6884
  my $dirStart = $$dirInfo{DirStart} || 0;
6889
- my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart;
6885
+ my $dirLen = $$dirInfo{DirLen};
6886
+ $dirLen = $dataLen - $dirStart if not defined $dirLen or $dirLen > $dataLen - $dirStart;
6890
6887
  my $newData = substr($$dataPt, $dirStart, $dirLen) or return undef;
6891
6888
  my $dirName = $$dirInfo{DirName};
6892
6889
  my $varSize = 0;
@@ -7022,11 +7019,34 @@ sub WriteBinaryData($$$)
7022
7019
  $tagInfo = $self->GetTagInfo($tagTablePtr, $tagID, \$v);
7023
7020
  next unless $tagInfo;
7024
7021
  }
7025
- next unless $$tagInfo{SubDirectory}; # (just to be safe)
7026
- my %subdirInfo = ( DataPt => \$newData, DirStart => $entry );
7027
- my $subTablePtr = GetTagTable($$tagInfo{SubDirectory}{TagTable});
7028
- my $dat = $self->WriteDirectory(\%subdirInfo, $subTablePtr);
7029
- substr($newData, $entry) = $dat if defined $dat and length $dat;
7022
+ my $subdir = $$tagInfo{SubDirectory} or next;
7023
+ my $start = $$subdir{Start};
7024
+ my $len;
7025
+ if (not $start) {
7026
+ $start = $entry;
7027
+ $len = $dirLen - $start;
7028
+ } elsif ($start =~ /\$/) {
7029
+ my $count = 1;
7030
+ my $format = $$tagInfo{Format} || $defaultFormat;
7031
+ $format =~ /(.*)\[(.*)\]/ and ($format, $count) = ($1, $2);
7032
+ my $val = ReadValue($dataPt, $entry, $format, $count, $dirLen - $entry);
7033
+ # ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
7034
+ next unless $val;
7035
+ my $dirStart = 0;
7036
+ #### eval Start ($val, $dirStart)
7037
+ $start = eval($start);
7038
+ next if $start < $dirStart or $start > $dataLen;
7039
+ $len = $$subdir{DirLen};
7040
+ $len = $dataLen - $start unless $len and $len <= $dataLen - $start;
7041
+ }
7042
+ my %subdirInfo = (
7043
+ DataPt => \$newData,
7044
+ DirStart => $start,
7045
+ DirLen => $len,
7046
+ TagInfo => $tagInfo,
7047
+ );
7048
+ my $dat = $self->WriteDirectory(\%subdirInfo, GetTagTable($$subdir{TagTable}));
7049
+ substr($newData, $start, $len) = $dat if defined $dat and length $dat;
7030
7050
  }
7031
7051
  }
7032
7052
  return $newData;
@@ -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.55';
32
+ $VERSION = '12.57';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -150,8 +150,8 @@ sub ReadValue($$$;$$$);
150
150
  Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE
151
151
  JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion
152
152
  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 OOXML iWork ISO
154
- FLIR::AFF FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable
153
+ Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR RTF
154
+ OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable
155
155
  );
156
156
 
157
157
  # alphabetical list of current Lang modules
@@ -526,6 +526,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
526
526
  VCARD=> ['VCard','Virtual Card'],
527
527
  VCF => 'VCARD',
528
528
  VOB => ['MPEG', 'Video Object'],
529
+ VNT => [['FPX','VCard'], 'Scene7 Vignette or V-Note text file'],
529
530
  VRD => ['VRD', 'Canon VRD Recipe Data'],
530
531
  VSD => ['FPX', 'Microsoft Visio Drawing'],
531
532
  WAV => ['RIFF', 'WAVeform (Windows digital audio)'],
@@ -577,6 +578,7 @@ my %fileDescription = (
577
578
  'Win32 DLL' => 'Windows 32-bit Dynamic Link Library',
578
579
  'Win64 EXE' => 'Windows 64-bit Executable',
579
580
  'Win64 DLL' => 'Windows 64-bit Dynamic Link Library',
581
+ VNote => 'V-Note document',
580
582
  );
581
583
 
582
584
  # MIME types for applicable file types above
@@ -977,7 +979,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
977
979
  TAR => '.{257}ustar( )?\0', # (this doesn't catch old-style tar files)
978
980
  TXT => '(\xff\xfe|(\0\0)?\xfe\xff|(\xef\xbb\xbf)?[\x07-\x0d\x20-\x7e\x80-\xfe]*$)',
979
981
  TIFF => '(II|MM)', # don't test magic number (some raw formats are different)
980
- VCard=> '(?i)BEGIN:(VCARD|VCALENDAR)\r\n',
982
+ VCard=> '(?i)BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n',
981
983
  VRD => 'CANON OPTIONAL DATA\0',
982
984
  WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)',
983
985
  WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d',
@@ -2041,6 +2043,7 @@ sub new
2041
2043
  $$self{DEL_GROUP} = { }; # lookup for groups to delete when writing
2042
2044
  $$self{SAVE_COUNT} = 0; # count calls to SaveNewValues()
2043
2045
  $$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
2046
+ $$self{FILES_WRITTEN} = 0; # count of files successfully written
2044
2047
  $$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
2045
2048
 
2046
2049
  # initialize our new groups for writing
@@ -6871,7 +6874,7 @@ sub ProcessJPEG($$)
6871
6874
  $self->Warn("Ignored APP1 segment length $length (unknown header)");
6872
6875
  }
6873
6876
  }
6874
- } elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, PreviewImage)
6877
+ } elsif ($marker == 0xe2) { # APP2 (ICC Profile, FPXR, MPF, InfiRay, PreviewImage)
6875
6878
  if ($$segDataPt =~ /^ICC_PROFILE\0/ and $length >= 14) {
6876
6879
  $dumpType = 'ICC_Profile';
6877
6880
  # must concatenate profile chunks (note: handle the case where
@@ -6933,6 +6936,12 @@ sub ProcessJPEG($$)
6933
6936
  # extract the MPF information (it is in standard TIFF format)
6934
6937
  my $tagTablePtr = GetTagTable('Image::ExifTool::MPF::Main');
6935
6938
  $self->ProcessTIFF(\%dirInfo, $tagTablePtr);
6939
+ } elsif ($$segDataPt =~ /^....IJPEG\0/s) {
6940
+ $dumpType = 'InfiRay Version';
6941
+ $$self{HasIJPEG} = 1;
6942
+ SetByteOrder('II');
6943
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Version');
6944
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
6936
6945
  } elsif ($$segDataPt =~ /^(|QVGA\0|BGTH)\xff\xd8\xff[\xdb\xe0\xe1]/) {
6937
6946
  # Samsung/GE/GoPro="", BenQ DC C1220/Pentacon/Polaroid="QVGA\0",
6938
6947
  # Digilife DDC-690/Rollei="BGTH"
@@ -6973,8 +6982,8 @@ sub ProcessJPEG($$)
6973
6982
  SetByteOrder('MM');
6974
6983
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::JPS');
6975
6984
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
6976
- } elsif ($$self{Make} eq 'DJI') {
6977
- $dumpType = 'DJI ThermalData';
6985
+ } elsif ($$self{HasIJPEG} or $$self{Make} eq 'DJI') {
6986
+ $dumpType = $$self{HasIJPEG} ? 'InfiRay ImagingData' : 'DJI ThermalData';
6978
6987
  # add this data to the combined data if it exists
6979
6988
  my $dataPt = $segDataPt;
6980
6989
  if (defined $combinedSegData) {
@@ -6984,11 +6993,14 @@ sub ProcessJPEG($$)
6984
6993
  if ($nextMarker == $marker) {
6985
6994
  $combinedSegData = $$segDataPt unless defined $combinedSegData;
6986
6995
  } else {
6987
- # process DJI FLIR thermal data
6996
+ # process InfiRay/DJI thermal data
6988
6997
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
6989
6998
  $self->HandleTag($tagTablePtr, 'APP3', $$dataPt);
6990
6999
  undef $combinedSegData;
6991
7000
  }
7001
+ } elsif ($$self{HasIJPEG}) {
7002
+ $dumpType = 'InfiRay Data',
7003
+
6992
7004
  } elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) {
6993
7005
  $dumpType = 'PreviewImage'; # (Samsung, HP, BenQ)
6994
7006
  $preview = $$segDataPt;
@@ -6997,7 +7009,7 @@ sub ProcessJPEG($$)
6997
7009
  $self->FoundTag('PreviewImage', $preview);
6998
7010
  undef $preview;
6999
7011
  }
7000
- } elsif ($marker == 0xe4) { # APP4 ("SCALADO", FPXR, PreviewImage)
7012
+ } elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, PreviewImage)
7001
7013
  if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) {
7002
7014
  $dumpType = 'SCALADO';
7003
7015
  my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt);
@@ -7028,6 +7040,11 @@ sub ProcessJPEG($$)
7028
7040
  DirStart(\%dirInfo, 0, 0);
7029
7041
  my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams');
7030
7042
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7043
+ } elsif ($$self{HasIJPEG} and $length >= 120) {
7044
+ $dumpType = 'InfiRay Factory';
7045
+ SetByteOrder('II');
7046
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Factory');
7047
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7031
7048
  } elsif ($preview) {
7032
7049
  # continued Samsung S1060 preview from APP3
7033
7050
  $dumpType = 'PreviewImage';
@@ -7039,7 +7056,7 @@ sub ProcessJPEG($$)
7039
7056
  $self->FoundTag('PreviewImage', $preview);
7040
7057
  undef $preview;
7041
7058
  }
7042
- } elsif ($marker == 0xe5) { # APP5 (Ricoh "RMETA")
7059
+ } elsif ($marker == 0xe5) { # APP5 (InfiRay, Ricoh "RMETA")
7043
7060
  if ($$segDataPt =~ /^RMETA\0/) {
7044
7061
  # (NOTE: apparently these may span multiple segments, but I haven't seen
7045
7062
  # a sample like this, so multi-segment support hasn't yet been implemented)
@@ -7054,13 +7071,18 @@ sub ProcessJPEG($$)
7054
7071
  $dumpType = 'DJI ThermalCal';
7055
7072
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
7056
7073
  $self->HandleTag($tagTablePtr, 'APP5', $$segDataPt);
7074
+ } elsif ($$self{HasIJPEG} and $length >= 38) {
7075
+ $dumpType = 'InfiRay Picture';
7076
+ SetByteOrder('II');
7077
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Picture');
7078
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7057
7079
  } elsif ($preview) {
7058
7080
  $dumpType = 'PreviewImage';
7059
7081
  $preview .= $$segDataPt;
7060
7082
  $self->FoundTag('PreviewImage', $preview);
7061
7083
  undef $preview;
7062
7084
  }
7063
- } elsif ($marker == 0xe6) { # APP6 (Toshiba EPPIM, NITF, HP_TDHD)
7085
+ } elsif ($marker == 0xe6) { # APP6 (InfiRay, Toshiba EPPIM, NITF, HP_TDHD)
7064
7086
  if ($$segDataPt =~ /^EPPIM\0/) {
7065
7087
  undef $dumpType; # (will be dumped here)
7066
7088
  DirStart(\%dirInfo, 6, 6);
@@ -7093,8 +7115,13 @@ sub ProcessJPEG($$)
7093
7115
  $dumpType = 'DJI_DTAT';
7094
7116
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main');
7095
7117
  $self->HandleTag($tagTablePtr, 'APP6', $$segDataPt);
7118
+ } elsif ($$self{HasIJPEG} and $length >= 129) {
7119
+ $dumpType = 'InfiRay MixMode';
7120
+ SetByteOrder('II');
7121
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::MixMode');
7122
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7096
7123
  }
7097
- } elsif ($marker == 0xe7) { # APP7 (Pentax, Huawei, Qualcomm)
7124
+ } elsif ($marker == 0xe7) { # APP7 (InfiRay, Pentax, Huawei, Qualcomm)
7098
7125
  if ($$segDataPt =~ /^PENTAX \0(II|MM)/) {
7099
7126
  # found in K-3 images (is this multi-segment??)
7100
7127
  SetByteOrder($1);
@@ -7133,16 +7160,26 @@ sub ProcessJPEG($$)
7133
7160
  DirStart(\%dirInfo, 27);
7134
7161
  $dirInfo{DirName} = 'Qualcomm';
7135
7162
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7163
+ } elsif ($$self{HasIJPEG} and $length >= 32) {
7164
+ $dumpType = 'InfiRay OpMode';
7165
+ SetByteOrder('II');
7166
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::OpMode');
7167
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7136
7168
  }
7137
- } elsif ($marker == 0xe8) { # APP8 (SPIFF)
7169
+ } elsif ($marker == 0xe8) { # APP8 (InfiRay, SPIFF)
7138
7170
  # my sample SPIFF has 32 bytes of data, but spec states 30
7139
7171
  if ($$segDataPt =~ /^SPIFF\0/ and $length == 32) {
7140
7172
  $dumpType = 'SPIFF';
7141
7173
  DirStart(\%dirInfo, 6);
7142
7174
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::SPIFF');
7143
7175
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7176
+ } elsif ($$self{HasIJPEG} and $length >= 32) {
7177
+ $dumpType = 'InfiRay Isothermal';
7178
+ SetByteOrder('II');
7179
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Isothermal');
7180
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7144
7181
  }
7145
- } elsif ($marker == 0xe9) { # APP9 (Media Jukebox)
7182
+ } elsif ($marker == 0xe9) { # APP9 (InfiRay, Media Jukebox)
7146
7183
  if ($$segDataPt =~ /^Media Jukebox\0/ and $length > 22) {
7147
7184
  $dumpType = 'MediaJukebox';
7148
7185
  # (start parsing after the "<MJMD>")
@@ -7151,6 +7188,11 @@ sub ProcessJPEG($$)
7151
7188
  require Image::ExifTool::XMP;
7152
7189
  my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::MediaJukebox');
7153
7190
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::XMP::ProcessXMP);
7191
+ } elsif ($$self{HasIJPEG} and $length >= 768) {
7192
+ $dumpType = 'InfiRay Sensor';
7193
+ SetByteOrder('II');
7194
+ my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Sensor');
7195
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7154
7196
  }
7155
7197
  } elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments)
7156
7198
  if ($$segDataPt =~ /^UNICODE\0/) {
@@ -7947,7 +7989,7 @@ sub ProcessDirectory($$$;$)
7947
7989
  # patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
7948
7990
  return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
7949
7991
  }
7950
- $$self{PROCESSED}{$addr} = $dirName;
7992
+ $$self{PROCESSED}{$addr} = $dirName unless $$tagTablePtr{VARS} and $$tagTablePtr{VARS}{ALLOW_REPROCESS};
7951
7993
  }
7952
7994
  my $oldOrder = GetByteOrder();
7953
7995
  my @save = @$self{'INDENT','DIR_NAME','Compression','SubfileType'};
@@ -8708,13 +8750,16 @@ sub ProcessBinaryData($$$)
8708
8750
  {
8709
8751
  my ($self, $dirInfo, $tagTablePtr) = @_;
8710
8752
  my $dataPt = $$dirInfo{DataPt};
8711
- my $offset = $$dirInfo{DirStart} || 0;
8712
- my $size = $$dirInfo{DirLen} || (length($$dataPt) - $offset);
8753
+ my $dataLen = length $$dataPt;
8754
+ my $dirStart = $$dirInfo{DirStart} || 0;
8755
+ my $maxLen = $dataLen - $dirStart;
8756
+ my $size = $$dirInfo{DirLen};
8713
8757
  my $base = $$dirInfo{Base} || 0;
8714
8758
  my $verbose = $$self{OPTIONS}{Verbose};
8715
8759
  my $unknown = $$self{OPTIONS}{Unknown};
8716
8760
  my $dataPos = $$dirInfo{DataPos} || 0;
8717
8761
 
8762
+ $size = $maxLen if not defined $size or $size > $maxLen;
8718
8763
  # get default format ('int8u' unless specified)
8719
8764
  my $defaultFormat = $$tagTablePtr{FORMAT} || 'int8u';
8720
8765
  my $increment = $formatSize{$defaultFormat};
@@ -8756,6 +8801,7 @@ sub ProcessBinaryData($$$)
8756
8801
  $tagInfo = $self->GetTagInfo($tagTablePtr, $index);
8757
8802
  unless ($tagInfo) {
8758
8803
  next unless defined $tagInfo;
8804
+ # $entry = offset of value relative to directory start (or end if negative)
8759
8805
  my $entry = int($index) * $increment + $varSize;
8760
8806
  if ($entry < 0) {
8761
8807
  $entry += $size;
@@ -8764,7 +8810,7 @@ sub ProcessBinaryData($$$)
8764
8810
  next if $entry >= $size;
8765
8811
  my $more = $size - $entry;
8766
8812
  $more = 128 if $more > 128;
8767
- my $v = substr($$dataPt, $entry+$offset, $more);
8813
+ my $v = substr($$dataPt, $entry+$dirStart, $more);
8768
8814
  $tagInfo = $self->GetTagInfo($tagTablePtr, $index, \$v);
8769
8815
  next unless $tagInfo;
8770
8816
  }
@@ -8797,7 +8843,7 @@ sub ProcessBinaryData($$$)
8797
8843
  $count = $more;
8798
8844
  } elsif ($format eq 'pstring') {
8799
8845
  $format = 'string';
8800
- $count = Get8u($dataPt, ($entry++)+$offset);
8846
+ $count = Get8u($dataPt, ($entry++)+$dirStart);
8801
8847
  --$more;
8802
8848
  } elsif (not $formatSize{$format}) {
8803
8849
  if ($format =~ /(.*)\[(.*)\]/) {
@@ -8826,17 +8872,17 @@ sub ProcessBinaryData($$$)
8826
8872
  } elsif ($format =~ /^var_/) {
8827
8873
  # handle variable-length string formats
8828
8874
  $format = substr($format, 4);
8829
- pos($$dataPt) = $entry + $offset;
8875
+ pos($$dataPt) = $entry + $dirStart;
8830
8876
  undef $count;
8831
8877
  if ($format eq 'ustring') {
8832
- $count = pos($$dataPt) - ($entry+$offset) if $$dataPt =~ /\G(..)*?\0\0/sg;
8878
+ $count = pos($$dataPt) - ($entry+$dirStart) if $$dataPt =~ /\G(..)*?\0\0/sg;
8833
8879
  $varSize -= 2; # ($count includes base size of 2 bytes)
8834
8880
  } elsif ($format eq 'pstring') {
8835
- $count = Get8u($dataPt, ($entry++)+$offset);
8881
+ $count = Get8u($dataPt, ($entry++)+$dirStart);
8836
8882
  --$more;
8837
8883
  } elsif ($format eq 'pstr32' or $format eq 'ustr32') {
8838
8884
  last if $more < 4;
8839
- $count = Get32u($dataPt, $entry + $offset);
8885
+ $count = Get32u($dataPt, $entry + $dirStart);
8840
8886
  $count *= 2 if $format eq 'ustr32';
8841
8887
  $entry += 4;
8842
8888
  $more -= 4;
@@ -8844,22 +8890,22 @@ sub ProcessBinaryData($$$)
8844
8890
  } elsif ($format eq 'int16u') {
8845
8891
  # int16u size of binary data to follow
8846
8892
  last if $more < 2;
8847
- $count = Get16u($dataPt, $entry + $offset) + 2;
8893
+ $count = Get16u($dataPt, $entry + $dirStart) + 2;
8848
8894
  $varSize -= 2; # ($count includes size word)
8849
8895
  $format = 'undef';
8850
8896
  } elsif ($format eq 'ue7') {
8851
8897
  require Image::ExifTool::BPG;
8852
- ($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $offset);
8898
+ ($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $dirStart);
8853
8899
  last unless defined $val;
8854
8900
  --$varSize; # ($count includes base size of 1 byte)
8855
8901
  } elsif ($$dataPt =~ /\0/g) {
8856
- $count = pos($$dataPt) - ($entry+$offset);
8902
+ $count = pos($$dataPt) - ($entry+$dirStart);
8857
8903
  --$varSize; # ($count includes base size of 1 byte)
8858
8904
  }
8859
8905
  $count = $more if not defined $count or $count > $more;
8860
8906
  $varSize += $count; # shift subsequent indices
8861
8907
  unless (defined $val) {
8862
- $val = substr($$dataPt, $entry+$offset, $count);
8908
+ $val = substr($$dataPt, $entry+$dirStart, $count);
8863
8909
  $val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
8864
8910
  $val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
8865
8911
  }
@@ -8873,7 +8919,7 @@ sub ProcessBinaryData($$$)
8873
8919
  # hook to allow format, etc to be set dynamically
8874
8920
  if (defined $$tagInfo{Hook}) {
8875
8921
  my $oldVarSize = $varSize;
8876
- my $pos = $entry + $offset;
8922
+ my $pos = $entry + $dirStart;
8877
8923
  #### eval Hook ($format, $varSize, $size, $dataPt, $pos)
8878
8924
  eval $$tagInfo{Hook};
8879
8925
  # save variable size data if required for writing (in case changed by Hook)
@@ -8898,7 +8944,7 @@ sub ProcessBinaryData($$$)
8898
8944
  next if $$tagInfo{LargeTag} and $$self{EXCL_TAG_LOOKUP}{lc $$tagInfo{Name}};
8899
8945
  # read value now if necessary
8900
8946
  unless (defined $val and not $$tagInfo{SubDirectory}) {
8901
- $val = ReadValue($dataPt, $entry+$offset, $format, $count, $more, \$rational);
8947
+ $val = ReadValue($dataPt, $entry+$dirStart, $format, $count, $more, \$rational);
8902
8948
  next unless defined $val;
8903
8949
  $mask = $$tagInfo{Mask};
8904
8950
  $val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
@@ -8915,8 +8961,8 @@ sub ProcessBinaryData($$$)
8915
8961
  Value => $val,
8916
8962
  DataPt => $dataPt,
8917
8963
  Size => $len,
8918
- Start => $entry+$offset,
8919
- Addr => $entry+$offset+$base+$dataPos,
8964
+ Start => $entry+$dirStart,
8965
+ Addr => $entry+$dirStart+$base+$dataPos,
8920
8966
  Format => $format,
8921
8967
  Count => $count,
8922
8968
  Extra => $mask ? sprintf(', mask 0x%.2x',$mask) : undef,
@@ -8942,16 +8988,27 @@ sub ProcessBinaryData($$$)
8942
8988
  my $subdirBase = $base;
8943
8989
  if (defined $$subdir{Base}) {
8944
8990
  #### eval Base ($start,$base)
8945
- my $start = $entry + $offset + $dataPos;
8991
+ my $start = $entry + $dirStart + $dataPos;
8946
8992
  $subdirBase = eval($$subdir{Base}) + $base;
8947
8993
  }
8948
8994
  my $start = $$subdir{Start} || 0;
8995
+ if ($start =~ /\$/) {
8996
+ # ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
8997
+ next unless $val;
8998
+ #### eval Start ($val, $dirStart)
8999
+ $start = eval($start);
9000
+ next if $start < $dirStart or $start > $dataLen;
9001
+ $len = $$subdir{DirLen};
9002
+ $len = $dataLen - $start unless $len and $len <= $dataLen - $start;
9003
+ } else {
9004
+ $start += $dirStart + $entry;
9005
+ }
8949
9006
  my %subdirInfo = (
8950
9007
  DataPt => $dataPt,
8951
9008
  DataPos => $dataPos,
8952
- DataLen => length $$dataPt,
8953
- DirStart => $entry + $offset + $start,
8954
- DirLen => $len - $start,
9009
+ DataLen => $dataLen,
9010
+ DirStart => $start,
9011
+ DirLen => $len,
8955
9012
  Base => $subdirBase,
8956
9013
  );
8957
9014
  delete $$self{NO_UNKNOWN};