exiftool_vendored 12.99.0 → 13.02.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 = '12.99';
32
+ $VERSION = '13.02';
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($$);
@@ -740,7 +741,7 @@ my %fileDescription = (
740
741
  OGV => 'video/ogg',
741
742
  ONP => 'application/on1',
742
743
  ORF => 'image/x-olympus-orf',
743
- OTF => 'application/x-font-otf',
744
+ OTF => 'application/font-otf',
744
745
  PAGES=> 'application/x-iwork-pages-sffpages',
745
746
  PBM => 'image/x-portable-bitmap',
746
747
  PCD => 'image/x-photo-cd',
@@ -798,8 +799,8 @@ my %fileDescription = (
798
799
  THMX => 'application/vnd.ms-officetheme',
799
800
  TIFF => 'image/tiff',
800
801
  Torrent => 'application/x-bittorrent',
801
- TTC => 'application/x-font-ttf',
802
- TTF => 'application/x-font-ttf',
802
+ TTC => 'application/font-ttf',
803
+ TTF => 'application/font-ttf',
803
804
  TXT => 'text/plain',
804
805
  VCard=> 'text/vcard',
805
806
  VRD => 'application/octet-stream', #PH (NC)
@@ -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' ],
@@ -1130,10 +1137,10 @@ my @availableOptions = (
1130
1137
  [ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
1131
1138
  [ 'LargeFileSupport', 1, 'flag indicating support of 64-bit file offsets' ],
1132
1139
  [ 'LimitLongValues', 60, 'length limit for long values' ],
1133
- [ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]' ],
1140
+ [ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]', 1 ],
1134
1141
  [ 'ListItem', undef, 'used to return a specific item from lists' ],
1135
1142
  [ 'ListJoin', ', ', 'join lists together with this separator' ],
1136
- [ 'ListSep', ', ', '[deprecated, use ListSplit and ListJoin instead]' ],
1143
+ [ 'ListSep', ', ', '[deprecated, use ListSplit and ListJoin instead]', 1 ],
1137
1144
  [ 'ListSplit', undef, 'regex for splitting list-type tag values when writing' ],
1138
1145
  [ 'MakerNotes', undef, 'extract maker notes as a block' ],
1139
1146
  [ 'MDItemTags', undef, 'extract MacOS metadata item tags' ],
@@ -1150,6 +1157,7 @@ my @availableOptions = (
1150
1157
  [ 'QuickTimeUTC', undef, 'assume that QuickTime date/time tags are stored as UTC' ],
1151
1158
  [ 'RequestAll', undef, 'extract all tags that must be specifically requested' ],
1152
1159
  [ 'RequestTags', undef, 'extra tags to request (on top of those in the tag list)' ],
1160
+ [ 'SaveBin', undef, 'save binary values of tags' ],
1153
1161
  [ 'SaveFormat', undef, 'save family 6 tag TIFF format' ],
1154
1162
  [ 'SavePath', undef, 'save family 5 location path' ],
1155
1163
  [ 'ScanForXMP', undef, 'flag to scan for XMP information in all files' ],
@@ -1165,11 +1173,12 @@ my @availableOptions = (
1165
1173
  [ 'UserParam', { }, 'user parameters for additional user-defined tag values' ],
1166
1174
  [ 'Validate', undef, 'perform additional validation' ],
1167
1175
  [ 'Verbose', 0, 'print verbose messages (0-5, higher # = more verbose)' ],
1176
+ [ 'WindowsLongPath', undef, 'enable support for long pathnames (enables WindowsWideFile)' ],
1168
1177
  [ 'WindowsWideFile', undef, 'force the use of Windows wide-character file routines' ], # (see forum15208)
1169
1178
  [ 'WriteMode', 'wcg', 'enable all write modes by default' ],
1170
1179
  [ 'XAttrTags', undef, 'extract MacOS extended attribute tags' ],
1171
1180
  [ 'XMPAutoConv', 1, 'automatic conversion of unknown XMP tag values' ],
1172
- [ 'XMPShorthand', 0, '[deprecated, use Compact=Shorthand instead]' ],
1181
+ [ 'XMPShorthand', 0, '[deprecated, use Compact=Shorthand instead]', 1 ],
1173
1182
  );
1174
1183
 
1175
1184
  # default family 0 group priority for writing
@@ -3328,8 +3337,8 @@ sub GetRequestedTags($)
3328
3337
  # Inputs: 0) ExifTool object reference
3329
3338
  # 1) tag key or tag name with optional group names (case sensitive)
3330
3339
  # (or flattened tagInfo for getting field values, not part of public API)
3331
- # 2) [optional] Value type: PrintConv, ValueConv, Both, Raw or Rational, the default
3332
- # is PrintConv or ValueConv, depending on the PrintConv option setting
3340
+ # 2) [optional] Value type: PrintConv, ValueConv, Both, Raw, Bin or Rational, the
3341
+ # default is PrintConv or ValueConv, depending on the PrintConv option setting
3333
3342
  # 3) raw field value (not part of public API)
3334
3343
  # Returns: Scalar context: tag value or undefined
3335
3344
  # List context: list of values or empty list
@@ -3358,7 +3367,8 @@ sub GetValue($$;$)
3358
3367
  }
3359
3368
  # figure out what conversions to do
3360
3369
  if ($type) {
3361
- return $$self{RATIONAL}{$tag} if $type eq 'Rational';
3370
+ return $$self{TAG_EXTRA}{$tag}{Rational} if $type eq 'Rational';
3371
+ return $$self{TAG_EXTRA}{$tag}{BinVal} if $type eq 'Bin';
3362
3372
  } else {
3363
3373
  $type = $$self{OPTIONS}{PrintConv} ? 'PrintConv' : 'ValueConv';
3364
3374
  }
@@ -3702,9 +3712,10 @@ sub GetGroup($$;$)
3702
3712
  $tag = $$tagInfo{Name};
3703
3713
  # set flag so we don't get extra information for an extracted tag
3704
3714
  $byTagInfo = 1;
3715
+ $ex = { };
3705
3716
  } else {
3706
3717
  $tagInfo = $$self{TAG_INFO}{$tag} || { };
3707
- $ex = $$self{TAG_EXTRA}{$tag};
3718
+ $ex = $$self{TAG_EXTRA}{$tag} || { };
3708
3719
  }
3709
3720
  my $groups = $$tagInfo{Groups};
3710
3721
  # fill in default groups unless already done
@@ -3723,32 +3734,30 @@ sub GetGroup($$;$)
3723
3734
  if (defined $family and $family ne '-1') {
3724
3735
  if ($family =~ /[^\d]/) {
3725
3736
  @families = ($family =~ /\d+/g);
3726
- return(($ex && $$ex{G0}) || $$groups{0}) unless @families;
3737
+ return($$ex{G0} || $$groups{0}) unless @families;
3727
3738
  $simplify = 1 unless $family =~ /^:/;
3728
3739
  undef $family;
3729
3740
  foreach (0..2) { $groups[$_] = $$groups{$_}; }
3730
3741
  $noID = 1 if @families == 1 and $families[0] != 7;
3731
3742
  } else {
3732
- return(($ex && $$ex{"G$family"}) || $$groups{$family}) if $family == 0 or $family == 2;
3743
+ return($$ex{"G$family"} || $$groups{$family}) if $family == 0 or $family == 2;
3733
3744
  $groups[1] = $$groups{1};
3734
3745
  }
3735
3746
  } else {
3736
- return(($ex && $$ex{G0}) || $$groups{0}) unless wantarray;
3747
+ return($$ex{G0} || $$groups{0}) unless wantarray;
3737
3748
  foreach (0..2) { $groups[$_] = $$groups{$_}; }
3738
3749
  }
3739
3750
  $groups[3] = 'Main';
3740
- $groups[4] = ($tag =~ /\((\d+)\)$/) ? "Copy$1" : '';
3751
+ $groups[4] = ($tag =~ /\((\d+)\)$/ and $1 ne '0') ? "Copy$1" : '';
3741
3752
  # handle dynamic group names if necessary
3742
3753
  unless ($byTagInfo) {
3743
- if ($ex) {
3744
- $groups[0] = $$ex{G0} if $$ex{G0};
3745
- $groups[1] = $$ex{G1} =~ /^\+(.*)/ ? "$groups[1]$1" : $$ex{G1} if $$ex{G1};
3746
- $groups[3] = 'Doc' . $$ex{G3} if $$ex{G3};
3747
- $groups[5] = $$ex{G5} || $groups[1] if defined $$ex{G5};
3748
- if (defined $$ex{G6}) {
3749
- $groups[5] = '' unless defined $groups[5]; # (can't leave a hole in the array)
3750
- $groups[6] = $$ex{G6};
3751
- }
3754
+ $groups[0] = $$ex{G0} if $$ex{G0};
3755
+ $groups[1] = $$ex{G1} =~ /^\+(.*)/ ? "$groups[1]$1" : $$ex{G1} if $$ex{G1};
3756
+ $groups[3] = 'Doc' . $$ex{G3} if $$ex{G3};
3757
+ $groups[5] = $$ex{G5} || $groups[1] if defined $$ex{G5};
3758
+ if (defined $$ex{G6}) {
3759
+ $groups[5] = '' unless defined $groups[5]; # (can't leave a hole in the array)
3760
+ $groups[6] = $$ex{G6};
3752
3761
  }
3753
3762
  if ($$ex{G8}) {
3754
3763
  $groups[7] = '';
@@ -3921,12 +3930,9 @@ COMPOSITE_TAG:
3921
3930
  $key = "$reqTag ($i)";
3922
3931
  }
3923
3932
  @keys = $self->GroupMatches($reqGroup, \@keys) if defined $reqGroup;
3924
- if (@keys) {
3925
- my $ex = $$self{TAG_EXTRA};
3926
- # loop through tags in reverse order of precedence so the higher
3927
- # priority tag will win in the case of duplicates within a doc
3928
- $$cacheTag[$$ex{$_} ? $$ex{$_}{G3} || 0 : 0] = $_ foreach reverse @keys;
3929
- }
3933
+ # loop through tags in reverse order of precedence so the higher
3934
+ # priority tag will win in the case of duplicates within a doc
3935
+ $$cacheTag[$$self{TAG_EXTRA}{$_}{G3} || 0] = $_ foreach reverse @keys;
3930
3936
  }
3931
3937
  # (set $reqTag to a bogus key if not found)
3932
3938
  $reqTag = $$cacheTag[$doc] || "$reqTag (0)";
@@ -4218,9 +4224,7 @@ sub Init($)
4218
4224
  local $_;
4219
4225
  my $self = shift;
4220
4226
  # delete all DataMember variables (lower-case names)
4221
- foreach (keys %$self) {
4222
- /[a-z]/ and delete $$self{$_};
4223
- }
4227
+ delete $$self{$_} foreach grep /[a-z]/, keys %$self;
4224
4228
  undef %static_vars; # clear all static variables
4225
4229
  delete $$self{FOUND_TAGS}; # list of found tags
4226
4230
  delete $$self{EXIF_DATA}; # the EXIF data block
@@ -4235,7 +4239,6 @@ sub Init($)
4235
4239
  $$self{FILE_ORDER} = { }; # * hash of tag order in file ('*' = based on tag key)
4236
4240
  $$self{VALUE} = { }; # * hash of raw tag values
4237
4241
  $$self{BOTH} = { }; # * hash for Value/PrintConv values of Require'd tags
4238
- $$self{RATIONAL} = { }; # * hash of original rational components
4239
4242
  $$self{TAG_INFO} = { }; # * hash of tag information
4240
4243
  $$self{TAG_EXTRA} = { }; # * hash of extra tag information (dynamic group names)
4241
4244
  $$self{PRIORITY} = { }; # * priority of current tags
@@ -4468,11 +4471,7 @@ sub DoneExtract($)
4468
4471
  my $err = $$altExifTool{VALUE}{Error};
4469
4472
  $err and $self->Warn(qq{$err "$fileName"});
4470
4473
  # set family 8 group name for all tags
4471
- foreach (keys %{$$altExifTool{VALUE}}) {
4472
- my $ex = $$altExifTool{TAG_EXTRA}{$_};
4473
- $ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
4474
- $$ex{G8} = $g8;
4475
- }
4474
+ $$altExifTool{TAG_EXTRA}{$_}{G8} = $g8 foreach keys %{$$altExifTool{VALUE}};
4476
4475
  # prepare our sorted list of found tags
4477
4476
  $$altExifTool{FoundTags} = [ reverse sort keys %{$$altExifTool{VALUE}} ];
4478
4477
  $$altExifTool{DID_EXTRACT} = 1;
@@ -4614,36 +4613,125 @@ sub SplitFileName($)
4614
4613
 
4615
4614
  #------------------------------------------------------------------------------
4616
4615
  # Encode file name for calls to system i/o routines
4617
- # Inputs: 0) ExifTool ref, 1) file name in CharSetFileName, 2) flag to force conversion
4616
+ # Inputs: 0) ExifTool ref, 1) file name in CharsetFileName encoding, 2) flag to force conversion
4618
4617
  # Returns: true if Windows Unicode routines should be used (in which case
4619
4618
  # the file name will be encoded as a null-terminated UTF-16LE string)
4620
4619
  sub EncodeFileName($$;$)
4621
4620
  {
4622
4621
  my ($self, $file, $force) = @_;
4623
4622
  my $enc = $$self{OPTIONS}{CharsetFileName};
4624
- $force = 1 if $$self{OPTIONS}{WindowsWideFile};
4625
- if ($enc) {
4626
- if ($file =~ /[\x80-\xff]/ or $force) {
4627
- # encode for use in Windows Unicode functions if necessary
4628
- if ($^O eq 'MSWin32') {
4629
- local $SIG{'__WARN__'} = \&SetWarning;
4630
- if (eval { require Win32API::File }) {
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');
4623
+ my $hasSpecialChars;
4624
+ if ($file =~ /[\x80-\xff]/) {
4625
+ $hasSpecialChars = 1;
4626
+ if (not $enc and $^O eq 'MSWin32') {
4627
+ if (IsUTF8(\$file) < 0) {
4628
+ $self->WarnOnce('FileName encoding must be specified') if not defined $enc;
4629
+ return 0;
4636
4630
  } else {
4637
- # recode as UTF-8 for other platforms if necessary
4638
- $_[1] = $self->Decode($file, $enc, undef, 'UTF8') unless $enc eq 'UTF8';
4631
+ $enc = 'UTF8'; # assume UTF8
4632
+ }
4633
+ }
4634
+ }
4635
+ $force = 1 if $$self{OPTIONS}{WindowsWideFile} or $$self{OPTIONS}{WindowsLongPath};
4636
+ if ($hasSpecialChars or $force) {
4637
+ $enc or $enc = 'UTF8';
4638
+ if ($^O eq 'MSWin32') {
4639
+ local $SIG{'__WARN__'} = \&SetWarning;
4640
+ if (eval { require Win32API::File }) {
4641
+ $file = $self->WindowsLongPath($file) if $$self{OPTIONS}{WindowsLongPath};
4642
+ # recode as UTF-16LE and add null terminator
4643
+ $_[1] = $self->Decode($file, $enc, undef, 'UTF16', 'II') . "\0\0";
4644
+ return 1;
4639
4645
  }
4646
+ $self->WarnOnce('Install Win32API::File for Windows wide/long file name support');
4647
+ } elsif ($enc ne 'UTF8') {
4648
+ # recode as UTF-8 for other platforms if necessary
4649
+ $_[1] = $self->Decode($file, $enc, undef, 'UTF8');
4640
4650
  }
4641
- } elsif ($^O eq 'MSWin32' and $file =~ /[\x80-\xff]/ and not defined $enc) {
4642
- $self->WarnOnce('FileName encoding not specified') if IsUTF8(\$file) < 0;
4643
4651
  }
4644
4652
  return 0;
4645
4653
  }
4646
4654
 
4655
+ #------------------------------------------------------------------------------
4656
+ # Rebuild a path as an absolute long path to be usable in Windows system calls
4657
+ # Inputs: 0) ExifTool ref, 1) path string
4658
+ # Returns: normalized long path
4659
+ # Note: this should only be called for Windows systems
4660
+ # References:
4661
+ # - https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
4662
+ # - https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
4663
+ sub WindowsLongPath($$)
4664
+ {
4665
+ my ($self, $path) = @_;
4666
+ my $debug = $$self{OPTIONS}{Debug};
4667
+ my $out = $$self{OPTIONS}{TextOut};
4668
+ my @fullParts;
4669
+ my $prefixLen = 0;
4670
+
4671
+ $debug and print $out "WindowsLongPath input : $path\n";
4672
+ $path =~ tr(/)(\\); # convert slashes to backslashes
4673
+ my @pathParts = split /\\/, $path;
4674
+
4675
+ if ($path =~ /^\\\\\?\\/ or # already a device path in the format we want
4676
+ $path =~ s/^\\\\\.\\/\\\\?\\/) # convert //./ to //?/
4677
+ {
4678
+ # path is already long-path compatible
4679
+ $prefixLen = 3; # path already contains prefix of 3 parts ('', '' and '?')
4680
+ } elsif ($path =~ /[*?]/) {
4681
+ return $path; # do nothing because we don't support wildcards
4682
+ } elsif ($path =~ /^\\\\/) {
4683
+ # UNC path starts with two slashes change to "\\?\UNC\"
4684
+ splice @pathParts, 2, 0, '?', 'UNC';
4685
+ $prefixLen = (@pathParts > 6 ? 6 : @pathParts); # ('', '', '?', 'UNC', <server>, <share>)
4686
+ } elsif ($path =~ /^[a-z]:\\/i) {
4687
+ # path is already absolute but we need to add the device path prefix
4688
+ unshift @pathParts, '', '', '?';
4689
+ $prefixLen = 4;
4690
+ } elsif ({ eval { require Cwd } }) {
4691
+ my $drive;
4692
+ $drive = $1 if $pathParts[0] =~ s/^([a-z]:)//;
4693
+ my $cwd = Cwd::getdcwd($drive); # ($drive is undef for current working drive)
4694
+ $debug and print $out "WindowsLongPath getcwd: $cwd\n";
4695
+ @fullParts = split /[\\\/]/, $cwd;
4696
+ # UNC path starts with "\\", so first 2 elements are empty
4697
+ # --> shift and put UNC in first element.
4698
+ if (@fullParts > 1 and $fullParts[0] eq '' and $fullParts[1] eq '') {
4699
+ shift @fullParts;
4700
+ $fullParts[0] = 'UNC';
4701
+ unshift @fullParts, '', '', '?';
4702
+ $prefixLen = (@fullParts > 6 ? 6 : @fullParts);
4703
+ } else {
4704
+ $prefixLen = 1; # drive designator only
4705
+ }
4706
+ # if absolute path on current drive starts with "\"
4707
+ # just keep prefix and drop the rest of the cwd
4708
+ $#fullParts = $prefixLen - 1 if $pathParts[0] eq '';
4709
+ } else {
4710
+ $prefixLen = @pathParts; # (nothing more we can do)
4711
+ }
4712
+ # remove "." and ".." from path (not handled for device paths)
4713
+ my $part;
4714
+ foreach $part (@pathParts) {
4715
+ if ($part eq '.') {
4716
+ next;
4717
+ } elsif ($part eq '') {
4718
+ # only allow double slashes at start of path name (max 2)
4719
+ push @fullParts, $part if not @fullParts or (@fullParts == 1 and $fullParts[0] eq '');
4720
+ } elsif ($part eq '..') {
4721
+ # step up one directory, but not into the prefix
4722
+ pop @fullParts if @fullParts > $prefixLen;
4723
+ } else {
4724
+ push @fullParts, $part;
4725
+ }
4726
+ }
4727
+ $path = join '\\', @fullParts;
4728
+ # add device path prefix ("\\?\") if path length near the limit (the most
4729
+ # conservative limit I can find is 247, which is the limit on the directory name)
4730
+ $path = '\\\\?\\' . $path unless $prefixLen > 1 or length($path) <= 247;
4731
+ $debug and print $out "WindowsLongPath return: $path\n";
4732
+ return $path;
4733
+ }
4734
+
4647
4735
  #------------------------------------------------------------------------------
4648
4736
  # Modified perl open() routine to properly handle special characters in file names
4649
4737
  # Inputs: 0) ExifTool ref, 1) filehandle, 2) filename,
@@ -4910,11 +4998,13 @@ sub ParseArguments($;@)
4910
4998
  next if defined $$self{RAF};
4911
4999
  # convert image data from UTF-8 to character stream if necessary
4912
5000
  # (patches RHEL 3 UTF8 LANG problem)
4913
- if (ref $arg eq 'SCALAR' and $] >= 5.006 and
4914
- (eval { require Encode; Encode::is_utf8($$arg) } or $@))
5001
+ if (ref $arg eq 'SCALAR' and $] >= 5.006 and ($$self{OPTIONS}{EncodeHangs} or
5002
+ eval { require Encode; Encode::is_utf8($$arg) } or $@))
4915
5003
  {
5004
+ local $SIG{'__WARN__'} = \&SetWarning;
4916
5005
  # repack by hand if Encode isn't available
4917
- my $buff = $@ ? pack('C*',unpack($] < 5.010000 ? 'U0C*' : 'C0C*',$$arg)) : Encode::encode('utf8',$$arg);
5006
+ my $buff = ($$self{OPTIONS}{EncodeHangs} or $@) ? pack('C*',unpack($] < 5.010000 ?
5007
+ 'U0C*' : 'C0C*', $$arg)) : Encode::encode('utf8', $$arg);
4918
5008
  $arg = \$buff;
4919
5009
  }
4920
5010
  $$self{RAF} = File::RandomAccess->new($arg);
@@ -6322,10 +6412,12 @@ sub Filter($$$)
6322
6412
  # Return printable value
6323
6413
  # Inputs: 0) ExifTool object reference
6324
6414
  # 1) value to print, 2) line length limit (undef defaults to 60, 0=unlimited)
6415
+ # Returns: Printable string
6325
6416
  sub Printable($;$)
6326
6417
  {
6327
6418
  my ($self, $outStr, $maxLen) = @_;
6328
6419
  return '(undef)' unless defined $outStr;
6420
+ ref $outStr eq 'SCALAR' and return '(Binary data '.length($$outStr).' bytes)';
6329
6421
  $outStr =~ tr/\x01-\x1f\x7f-\xff/./;
6330
6422
  $outStr =~ s/\x00//g;
6331
6423
  my $verbose = $$self{OPTIONS}{Verbose};
@@ -8924,7 +9016,7 @@ sub HandleTag($$$$;%)
8924
9016
  my $pfmt = $parms{Format};
8925
9017
  my $tagInfo = $parms{TagInfo} || $self->GetTagInfo($tagTablePtr, $tag, \$val, $pfmt, $parms{Count});
8926
9018
  my $dataPt = $parms{DataPt};
8927
- my ($subdir, $format, $noTagInfo, $rational);
9019
+ my ($subdir, $format, $noTagInfo, $rational, $binVal);
8928
9020
 
8929
9021
  if ($tagInfo) {
8930
9022
  $subdir = $$tagInfo{SubDirectory};
@@ -8948,6 +9040,7 @@ sub HandleTag($$$$;%)
8948
9040
  } else {
8949
9041
  $val = substr($$dataPt, $start, $size);
8950
9042
  }
9043
+ $binVal = substr($$dataPt, $start, $size) if $$self{OPTIONS}{SaveBin};
8951
9044
  } else {
8952
9045
  $self->Warn("Error extracting value for $$tagInfo{Name}");
8953
9046
  return undef;
@@ -9030,8 +9123,11 @@ sub HandleTag($$$$;%)
9030
9123
  return undef unless $$tagInfo{Writable};
9031
9124
  }
9032
9125
  my $key = $self->FoundTag($tagInfo, $val);
9033
- # save original components of rational numbers
9034
- $$self{RATIONAL}{$key} = $rational if defined $rational and defined $key;
9126
+ if (defined $key) {
9127
+ # save original components of rational numbers and original binary value
9128
+ $$self{TAG_EXTRA}{$key}{Rational} = $rational if defined $rational;
9129
+ $$self{TAG_EXTRA}{$key}{BinVal} = $binVal if defined $binVal;
9130
+ }
9035
9131
  return $key;
9036
9132
  }
9037
9133
  return undef;
@@ -9142,9 +9238,7 @@ sub FoundTag($$$;@)
9142
9238
  # a Warning tag because they may be added by ValueConv, which could be confusing)
9143
9239
  my $oldPriority = $$self{PRIORITY}{$tag};
9144
9240
  unless ($oldPriority) {
9145
- if ($$self{DOC_NUM} or not $$self{TAG_EXTRA}{$tag} or $tag eq 'Warning' or
9146
- not $$self{TAG_EXTRA}{$tag}{G3})
9147
- {
9241
+ if ($$self{DOC_NUM} or $tag eq 'Warning' or not $$self{TAG_EXTRA}{$tag}{G3}) {
9148
9242
  $oldPriority = 1;
9149
9243
  } else {
9150
9244
  $oldPriority = 0; # don't promote sub-document tag over main document
@@ -9162,8 +9256,7 @@ sub FoundTag($$$;@)
9162
9256
  } else {
9163
9257
  $priority = 1; # the normal default
9164
9258
  }
9165
- if ($priority >= $oldPriority and (not $$self{DOC_NUM} or
9166
- ($$self{TAG_EXTRA}{$tag} and $$self{TAG_EXTRA}{$tag}{G3} and
9259
+ if ($priority >= $oldPriority and (not $$self{DOC_NUM} or ($$self{TAG_EXTRA}{$tag}{G3} and
9167
9260
  $$self{DOC_NUM} eq $$self{TAG_EXTRA}{$tag}{G3})) and not $noListDel)
9168
9261
  {
9169
9262
  # move existing tag out of the way since this tag is higher priority
@@ -9172,12 +9265,8 @@ sub FoundTag($$$;@)
9172
9265
  $$valueHash{$nextTag} = $$valueHash{$tag};
9173
9266
  $$self{FILE_ORDER}{$nextTag} = $$self{FILE_ORDER}{$tag};
9174
9267
  my $oldInfo = $$self{TAG_INFO}{$nextTag} = $$self{TAG_INFO}{$tag};
9175
- foreach ('TAG_EXTRA','RATIONAL') {
9176
- if ($$self{$_}{$tag}) {
9177
- $$self{$_}{$nextTag} = $$self{$_}{$tag};
9178
- delete $$self{$_}{$tag};
9179
- }
9180
- }
9268
+ $$self{TAG_EXTRA}{$nextTag} = $$self{TAG_EXTRA}{$tag};
9269
+ $$self{TAG_EXTRA}{$tag} = { };
9181
9270
  delete $$self{BOTH}{$tag};
9182
9271
  # update tag key for list if necessary
9183
9272
  $$self{LIST_TAGS}{$oldInfo} = $nextTag if $$self{LIST_TAGS}{$oldInfo};
@@ -9202,6 +9291,7 @@ sub FoundTag($$$;@)
9202
9291
  $$valueHash{$tag} = $value;
9203
9292
  $$self{FILE_ORDER}{$tag} = ++$$self{NUM_FOUND};
9204
9293
  $$self{TAG_INFO}{$tag} = $tagInfo;
9294
+ $$self{TAG_EXTRA}{$tag} = { } unless $$self{TAG_EXTRA}{$tag};
9205
9295
  # set dynamic groups 0, 1 and 3 if necessary
9206
9296
  $$self{TAG_EXTRA}{$tag}{G0} = $grps[0] if $grps[0];
9207
9297
  $$self{TAG_EXTRA}{$tag}{G1} = $grps[1] if $grps[1];
@@ -9260,7 +9350,6 @@ sub DeleteTag($$)
9260
9350
  delete $$self{TAG_INFO}{$tag};
9261
9351
  delete $$self{TAG_EXTRA}{$tag};
9262
9352
  delete $$self{PRIORITY}{$tag};
9263
- delete $$self{RATIONAL}{$tag};
9264
9353
  delete $$self{BOTH}{$tag};
9265
9354
  }
9266
9355
 
@@ -9496,7 +9585,7 @@ sub ProcessBinaryData($$$)
9496
9585
  $increment = $formatSize{$defaultFormat};
9497
9586
  }
9498
9587
  # prepare list of tag numbers to extract
9499
- my (@tags, $topIndex);
9588
+ my (@tags, $topIndex, $binVal);
9500
9589
  if ($unknown > 1 and defined $$tagTablePtr{FIRST_ENTRY}) {
9501
9590
  # don't create a stupid number of tags if data is huge
9502
9591
  my $sizeLimit = $size < 65536 ? $size : 65536;
@@ -9636,6 +9725,7 @@ sub ProcessBinaryData($$$)
9636
9725
  $val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
9637
9726
  $val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
9638
9727
  }
9728
+ $binVal = substr($$dataPt, $entry+$dirStart, $count) if $$self{OPTIONS}{SaveBin};
9639
9729
  $wasVar = 1;
9640
9730
  # save variable size data if required for writing
9641
9731
  if ($$dirInfo{VarFormatData}) {
@@ -9757,7 +9847,8 @@ sub ProcessBinaryData($$$)
9757
9847
  my $key = $self->FoundTag($tagInfo,$val);
9758
9848
  $$self{BASE} = $oldBase if defined $oldBase;
9759
9849
  if ($key) {
9760
- $$self{RATIONAL}{$key} = $rational if defined $rational;
9850
+ $$self{TAG_EXTRA}{$key}{Rational} = $rational if defined $rational;
9851
+ $$self{TAG_EXTRA}{$key}{BinVal} = $binVal if defined $binVal;
9761
9852
  } else {
9762
9853
  # don't increment nextIndex if we didn't extract a tag
9763
9854
  $nextIndex = $saveNextIndex if defined $saveNextIndex;
@@ -520,9 +520,9 @@ set to undef to pass through EXIF "ASCII" values without recoding. Set to
520
520
  =item CharsetFileName
521
521
 
522
522
  External character set used for file names passed to ExifTool functions.
523
- When set in Windows, this triggers use of Windows wide-character i/o library
524
- routines (requires Win32API::File). Default is undef. May also be set to
525
- an empty string to avoid "encoding not specified" warnings on Windows.
523
+ Default is undef but "UTF8" is assumed in Windows if the file name contains
524
+ special characters and is valid UTF8. May also be set to an empty string to
525
+ avoid "encoding must be specified" warnings on Windows.
526
526
 
527
527
  =item CharsetID3
528
528
 
@@ -981,7 +981,7 @@ normally. Currently this feature applies only to GM PDR data (see
981
981
  L<Image::ExifTool::TagNames/GM Tags>). Setting this option automatically
982
982
  sets L</IgnoreTags> to "all", and L</ExtractEmbedded> to 1. Default is
983
983
  undef.
984
-
984
+
985
985
  =item QuickTimeHandler
986
986
 
987
987
  Flag set to add an 'mdir' Handler to a newly created Meta box when adding
@@ -1028,6 +1028,11 @@ current RequestTags list. Groups are requested by adding a colon after the
1028
1028
  name (eg. "MacOS:"). Names are converted to lower case as they are added to
1029
1029
  the list. Default is undef.
1030
1030
 
1031
+ =item SaveBin
1032
+
1033
+ Flag to save binary values of tags, accessible through calls to L</GetValue>
1034
+ with a value type of "Bin".
1035
+
1031
1036
  =item SaveFormat
1032
1037
 
1033
1038
  Flag to save EXIF/TIFF format type as the family 6 group name when
@@ -1176,13 +1181,17 @@ details about the tags. Level 3 adds a hex dump of the tag data, but with
1176
1181
  limits on the number of bytes dumped. Levels 4 and 5 remove the dump limit
1177
1182
  on tag values and JPEG segment data respectively.
1178
1183
 
1184
+ =item WindowsLongPath
1185
+
1186
+ Support long path names in Windows. Enabling this option automatically
1187
+ enables the WindowsWideFile feature.
1188
+
1179
1189
  =item WindowsWideFile
1180
1190
 
1181
- Force the use of wide-character Windows I/O functions when the
1182
- L</CharsetFileName> option is used. This may be necessary when files are on
1183
- a network drive and the current directory name contains Unicode characters.
1184
- By default, the wide-character functions are used only if the specified file
1185
- path contains Unicode characters.
1191
+ Force the use of wide-character Windows I/O functions. This may be
1192
+ necessary when files are on a network drive and the current directory name
1193
+ contains Unicode characters. By default, the wide-character functions are
1194
+ used only if the specified file path contains Unicode characters.
1186
1195
 
1187
1196
  =item WriteMode
1188
1197
 
@@ -1257,8 +1266,9 @@ CharsetPhotoshop, CharsetQuickTime, CharsetRIFF, Composite, ExtendedXMP,
1257
1266
  ExtractEmbedded, FastScan, FixBase, HtmlDump, HtmlDumpBase, IgnoreGroups,
1258
1267
  IgnoreMinorErrors, IgnoreTags, Lang, LargeFileSupport, MakerNotes,
1259
1268
  MDItemTags, NoPDFList, Password, QuickTimeUTC (enforced 1904 time zero),
1260
- RequestAll, RequestTags, SaveFormat, SavePath, ScanForXMP, Struct, TextOut,
1261
- Unknown, Verbose, WindowsWideFile, XAttrTags and XMPAutoConv.
1269
+ RequestAll, RequestTags, SaveBin, SaveFormat, SavePath, ScanForXMP, Struct,
1270
+ TextOut, Unknown, Verbose, WindowsLongPath, WindowsWideFile, XAttrTags and
1271
+ XMPAutoConv.
1262
1272
 
1263
1273
  =item Return Value:
1264
1274
 
@@ -1397,7 +1407,8 @@ The following ExifTool options are effective in the call to L</WriteInfo>:
1397
1407
 
1398
1408
  ByteOrder, Charset, CharsetEXIF, CharsetFileName, CharsetIPTC, Compact,
1399
1409
  Compress, FixBase, IgnoreMinorErrors, NoMultiExif, NoPDFList, Password,
1400
- QuickTimeHandler, QuickTimePad, Verbose, WindowsWideFile and WriteMode.
1410
+ QuickTimeHandler, QuickTimePad, Verbose, WindowsLongPath, WindowsWideFile
1411
+ and WriteMode.
1401
1412
 
1402
1413
  =head2 GetTagList
1403
1414
 
@@ -1535,14 +1546,15 @@ StrictDate and TimeZone.
1535
1546
 
1536
1547
  1) Tag key, or case-sensitive tag name with optional group prefix(es)
1537
1548
 
1538
- 2) [optional] Value type: 'PrintConv', 'ValueConv', 'Both', 'Raw' or
1549
+ 2) [optional] Value type: 'PrintConv', 'ValueConv', 'Both', 'Raw', 'Bin' or
1539
1550
  'Rational'
1540
1551
 
1541
1552
  The default value type is 'PrintConv' if the PrintConv option is set,
1542
1553
  otherwise the default is 'ValueConv'. A value type of 'Both' returns both
1543
- ValueConv and PrintConv values as a list. 'Rational' returns the raw
1544
- rational value as a string fraction for rational types, or undef for other
1545
- types.
1554
+ ValueConv and PrintConv values as a list. 'Raw' returns the raw decoded tag
1555
+ value. 'Bin' returns the original binary data for EXIF tags if the
1556
+ L</SaveBin> option was set. 'Rational' returns the raw rational value as a
1557
+ string fraction for rational types, or undef for other types.
1546
1558
 
1547
1559
  =item Return Values:
1548
1560
 
@@ -2394,7 +2406,8 @@ Get a list of available API options. (See L</Options> for option details.)
2394
2406
  =item Return Values:
2395
2407
 
2396
2408
  Reference to list of available options. Each entry in the list is a list
2397
- reference with 3 items: 0=Option name, 1=Default value, 2=Description.
2409
+ reference with 4 items: 0=Option name, 1=Default value, 2=Description,
2410
+ 3=flag set if option is undocumented.
2398
2411
 
2399
2412
  my $opts = Image::ExifTool::<b>AvailableOptions</b>();
2400
2413
  foreach (@$opts) {
@@ -2553,17 +2566,18 @@ Real-PROP, Real-RA3, Real-RA4, Real-RA5, Real-RJMD, Reconyx, Red, Ricoh,
2553
2566
  SPIFF, SR2, SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado,
2554
2567
  Sigma, SigmaRaw, Sony, SonyIDC, Stim, SubIFD, System, Theora, Torrent,
2555
2568
  Track#, UserData, VCalendar, VCard, VNote, Version0, Vorbis, WTV, XML, XMP,
2556
- XMP-DICOM, XMP-Device, XMP-GAudio, XMP-GCamera, XMP-GCreations, XMP-GDepth,
2557
- XMP-GFocus, XMP-GImage, XMP-GPano, XMP-GSpherical, XMP-LImage, XMP-MP,
2558
- XMP-MP1, XMP-PixelLive, XMP-aas, XMP-acdsee, XMP-album, XMP-apple-fi,
2559
- XMP-ast, XMP-aux, XMP-cc, XMP-cell, XMP-crd, XMP-creatorAtom, XMP-crs,
2560
- XMP-dc, XMP-dex, XMP-digiKam, XMP-drone-dji, XMP-dwc, XMP-et, XMP-exif,
2561
- XMP-exifEX, XMP-expressionmedia, XMP-extensis, XMP-fpv, XMP-getty, XMP-hdr,
2562
- XMP-hdrgm, XMP-ics, XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro,
2563
- XMP-microsoft, XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-nine, XMP-panorama,
2564
- XMP-pdf, XMP-pdfx, XMP-photomech, XMP-photoshop, XMP-plus, XMP-pmi,
2565
- XMP-prism, XMP-prl, XMP-prm, XMP-pur, XMP-rdf, XMP-sdc, XMP-swf, XMP-tiff,
2566
- XMP-x, XMP-xmp, XMP-xmpBJ, XMP-xmpDM, XMP-xmpDSA, XMP-xmpMM, XMP-xmpNote,
2569
+ XMP-DICOM, XMP-Device, XMP-GAudio, XMP-GCamera, XMP-GContainer,
2570
+ XMP-GCreations, XMP-GDepth, XMP-GFocus, XMP-GImage, XMP-GPano,
2571
+ XMP-GSpherical, XMP-LImage, XMP-MP, XMP-MP1, XMP-PixelLive, XMP-aas,
2572
+ XMP-acdsee, XMP-acdsee-rs, XMP-album, XMP-apple-fi, XMP-ast, XMP-aux,
2573
+ XMP-cc, XMP-cell, XMP-crd, XMP-creatorAtom, XMP-crs, XMP-dc, XMP-dex,
2574
+ XMP-digiKam, XMP-drone-dji, XMP-dwc, XMP-et, XMP-exif, XMP-exifEX,
2575
+ XMP-expressionmedia, XMP-extensis, XMP-fpv, XMP-getty, XMP-hdr, XMP-hdrgm,
2576
+ XMP-ics, XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro, XMP-microsoft,
2577
+ XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-nine, XMP-panorama, XMP-pdf,
2578
+ XMP-pdfx, XMP-photomech, XMP-photoshop, XMP-plus, XMP-pmi, XMP-prism,
2579
+ XMP-prl, XMP-prm, XMP-pur, XMP-rdf, XMP-sdc, XMP-swf, XMP-tiff, XMP-x,
2580
+ XMP-xmp, XMP-xmpBJ, XMP-xmpDM, XMP-xmpDSA, XMP-xmpMM, XMP-xmpNote,
2567
2581
  XMP-xmpPLUS, XMP-xmpRights, XMP-xmpTPg, ZIP, iTunes
2568
2582
 
2569
2583
  =item Family 2 (Category):
@@ -1,6 +1,6 @@
1
1
  Summary: perl module for image data extraction
2
2
  Name: perl-Image-ExifTool
3
- Version: 12.99
3
+ Version: 13.02
4
4
  Release: 1
5
5
  License: Artistic/GPL
6
6
  Group: Development/Libraries/Perl
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExiftoolVendored
4
- VERSION = Gem::Version.new('12.99.0')
4
+ VERSION = Gem::Version.new('13.02.0')
5
5
  end