exiftool_vendored 13.47.0 → 13.50.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47f8feb5a44a6bb4ae7c01fc5283a6b0407be026ac355bdfd28249e5b9118d96
4
- data.tar.gz: c4f5c0cc1862c2fad3dc1c79bc7c0fbd546534018ce380a8abfb2fdb16f3d48b
3
+ metadata.gz: 119da28d5499012533651a09438cf1c0b551bb65e4b97815bc86190c7b439beb
4
+ data.tar.gz: 11292b43f6d89879e7eef760270799f803ec5bc15cdcaf8eb9c57fdeb7d9f9cc
5
5
  SHA512:
6
- metadata.gz: f66737b1a83f6e4c4c493a9845fb6f9eae5813fb08733fb3cda7d572ea58a0ad94c136deff3c0e73bc79e2f1b02871679b49fbd00da2d98d33986b7bf4ec8dce
7
- data.tar.gz: f0f87c67bacd26a6047039f9ee95ef8a6a695fcaf9c0d3be5ed7c5130118814cf2263a374f4c598a4c10fb2b1145179a0d8cb81c3b93f3e3c17c1f0622313fa4
6
+ metadata.gz: 36b76bee5489e79558b03b5eabf21f0e59d9d60c4702818468f82dd50141f652caa8395a791d117d502d3e7aff95d6ceb139e741fa5351c0cf5925936331d45b
7
+ data.tar.gz: 39b786e84e02df42bc8021b97084fa899810a4b8207e5bb91fc92dc990e4768efb1600bfc83497f7ae0d1db2cab02677633e054cc23fe693e30490778dd09f23
data/bin/Changes CHANGED
@@ -4,14 +4,44 @@ ExifTool Version History
4
4
 
5
5
  RSS feed: https://exiftool.org/rss.xml
6
6
 
7
- Note: The most recent production release is Version 13.44. (Other versions are
7
+ Note: The most recent production release is Version 13.50. (Other versions are
8
8
  considered development releases, and are not uploaded to MetaCPAN.)
9
9
 
10
+ Feb. 7, 2026 - Version 13.50 (production release)
11
+
12
+ - Added a few new Sony lenses (thanks Jos Roost)
13
+ - Added a couple of new Canon lenses (thanks Norbert Wasser)
14
+ - Decode another Samsung trailer tag
15
+ - Decode BlackLevels from some Canon CRW files (github #387)
16
+ - Updated Sony maker note decoding for the ILCE-7M5 (thanks Jos Roost)
17
+ - Patched potential MacOS security issue (thanks Tay Kiat Loong)
18
+ - Fixed -list options so reading image files beforehand doesn't add tags to
19
+ the output when running multiple commands using the -execute feature
20
+
21
+ Feb. 3, 2026 - Version 13.49
22
+
23
+ - Decode a couple of new Samsung trailer tags
24
+ - Disabled decoding of MenuSettings for the Nikon Z6III firmware 2.0 until the
25
+ changes can be worked through in detail
26
+ - Fixed problem where Google Photos had problems displaying ExifTool-edited
27
+ HEIC MotionPhoto images. Files written by older versions of ExifTool may be
28
+ repaired by re-writing with 13.49 or later
29
+
30
+ Jan. 31, 2026 - Version 13.48
31
+
32
+ - Added a new Nikon LensID (github #385)
33
+ - Added support for quoted entries in input -geotag CSV files
34
+ - Fixed decoding of Nikon Z6III menu settings for firmware 2.0 update
35
+ - Fixed -fast2 to avoid processing maker notes in some QuickTime-based files
36
+ - Fixed bug introduced in version 13.46 where some tags may be associated with
37
+ the next fix when geotagging from GPX files
38
+
10
39
  Jan. 27, 2026 - Version 13.47
11
40
 
12
41
  - Enhanced -fast option to avoid scanning QuickTime MediaData for metadata
13
42
  (improves performance when reading CR3 files from slow media, github #384)
14
43
  and -fast2 to avoid reading HDRP maker notes
44
+ - Fixed hang problem when reading HDRPMakerNotes from some Google phones
15
45
  - API Changes:
16
46
  - Added CSV support to GeoUserTag option
17
47
 
data/bin/META.json CHANGED
@@ -50,6 +50,6 @@
50
50
  }
51
51
  },
52
52
  "release_status" : "stable",
53
- "version" : "13.47",
53
+ "version" : "13.50",
54
54
  "x_serialization_backend" : "JSON::PP version 4.06"
55
55
  }
data/bin/META.yml CHANGED
@@ -31,5 +31,5 @@ recommends:
31
31
  Time::HiRes: '0'
32
32
  requires:
33
33
  perl: '5.004'
34
- version: '13.47'
34
+ version: '13.50'
35
35
  x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
data/bin/README CHANGED
@@ -111,8 +111,8 @@ your home directory, then you would type the following commands in a
111
111
  terminal window to extract and run ExifTool:
112
112
 
113
113
  cd ~/Desktop
114
- gzip -dc Image-ExifTool-13.47.tar.gz | tar -xf -
115
- cd Image-ExifTool-13.47
114
+ gzip -dc Image-ExifTool-13.50.tar.gz | tar -xf -
115
+ cd Image-ExifTool-13.50
116
116
  ./exiftool t/images/ExifTool.jpg
117
117
 
118
118
  Note: These commands extract meta information from one of the test images.
data/bin/exiftool CHANGED
@@ -11,7 +11,7 @@ use strict;
11
11
  use warnings;
12
12
  require 5.004;
13
13
 
14
- my $version = '13.47';
14
+ my $version = '13.50';
15
15
 
16
16
  $^W = 1; # enable global warnings
17
17
 
@@ -6136,7 +6136,7 @@ with this command:
6136
6136
 
6137
6137
  produces output like this:
6138
6138
 
6139
- -- Generated by ExifTool 13.47 --
6139
+ -- Generated by ExifTool 13.50 --
6140
6140
  File: a.jpg - 2003:10:31 15:44:19
6141
6141
  (f/5.6, 1/60s, ISO 100)
6142
6142
  File: b.jpg - 2006:05:23 11:57:38
@@ -35,7 +35,7 @@ use Image::ExifTool::Sony;
35
35
  use Image::ExifTool::Validate;
36
36
  use Image::ExifTool::MacOS;
37
37
 
38
- $VERSION = '3.64';
38
+ $VERSION = '3.65';
39
39
  @ISA = qw(Exporter);
40
40
 
41
41
  sub NumbersFirst($$);
@@ -71,6 +71,7 @@ my %tweakOrder = (
71
71
  CBOR => 'JSON',
72
72
  GeoTiff => 'GPS',
73
73
  CanonVRD=> 'CanonCustom',
74
+ CaptureOne => 'CanonVRD',
74
75
  DJI => 'Casio',
75
76
  FLIR => 'DJI',
76
77
  FujiFilm => 'FLIR',
@@ -977,7 +978,7 @@ TagID: foreach $tagID (@keys) {
977
978
  if ($format and $format =~ /^var_/) {
978
979
  $datamember{$tagID} = $name;
979
980
  unless (defined $$tagInfo{Writable} and not $$tagInfo{Writable}) {
980
- warn "Warning: Var-format tag is writable - $short $name\n"
981
+ warn "Warning: Var-format tag is writable - $short $name\n";
981
982
  }
982
983
  # also need DATAMEMBER for tags used in length of var-sized value
983
984
  while ($format =~ /\$val\{(.*?)\}/g) {
@@ -996,10 +997,15 @@ TagID: foreach $tagID (@keys) {
996
997
  if ($format and $format =~ /\$val\{/ and
997
998
  ($$tagInfo{Writable} or not defined $$tagInfo{Writable}))
998
999
  {
999
- warn "Warning: \$val{} used in Format of writable tag - $short $name\n"
1000
+ warn "Warning: \$val{} used in Format of writable tag - $short $name\n";
1000
1001
  }
1001
1002
  }
1002
1003
  if ($$tagInfo{Hidden}) {
1004
+ if ($$tagInfo{Hidden} ne '2' and not $$tagInfo{Unknown} and
1005
+ (not $$tagInfo{RawConv} or $$tagInfo{RawConv} !~ /Unknown|undef/))
1006
+ {
1007
+ warn "Warning: $short $name is Hidden contrary to guidelines\n";
1008
+ }
1003
1009
  if ($tagInfo == $infoArray[0]) {
1004
1010
  next TagID; # hide all tags with this ID if first tag in list is hidden
1005
1011
  } else {
@@ -1011,7 +1017,7 @@ TagID: foreach $tagID (@keys) {
1011
1017
  $writable = $$tagInfo{Writable};
1012
1018
  # validate Writable
1013
1019
  unless ($formatOK{$writable} or ($writable =~ /(.*)\[/ and $formatOK{$1})) {
1014
- warn "Warning: Unknown Writable ($writable) - $short $name\n",
1020
+ warn "Warning: Unknown Writable ($writable) - $short $name\n";
1015
1021
  }
1016
1022
  } elsif (not $$tagInfo{SubDirectory}) {
1017
1023
  $writable = $$table{WRITABLE};
@@ -1021,7 +1027,7 @@ TagID: foreach $tagID (@keys) {
1021
1027
  undef $writable;
1022
1028
  }
1023
1029
  #if ($writable and $$tagInfo{Unknown} and $$table{GROUPS}{0} ne 'MakerNotes') {
1024
- # warn "Warning: Writable Unknown tag - $short $name\n",
1030
+ # warn "Warning: Writable Unknown tag - $short $name\n";
1025
1031
  #}
1026
1032
  # validate some characteristics of obvious date/time tags
1027
1033
  my @g = $et->GetGroup($tagInfo);
@@ -2096,7 +2102,7 @@ sub CloseHtmlFiles($)
2096
2102
  if ($htmlFile =~ /index\.html$/) {
2097
2103
  print HTMLFILE "'../index.html'>&lt;-- Back to ExifTool home page</a></p>\n";
2098
2104
  } else {
2099
- print HTMLFILE "'index.html'>&lt;-- ExifTool Tag Names</a></p>\n"
2105
+ print HTMLFILE "'index.html'>&lt;-- ExifTool Tag Names</a></p>\n";
2100
2106
  }
2101
2107
  print HTMLFILE "</body>\n</html>\n" or $success = 0;
2102
2108
  close HTMLFILE or $success = 0;
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '5.02';
91
+ $VERSION = '5.03';
92
92
 
93
93
  # Note: Removed 'USM' from 'L' lenses since it is redundant - PH
94
94
  # (or is it? Ref 32 shows 5 non-USM L-type lenses)
@@ -645,6 +645,8 @@ $VERSION = '5.02';
645
645
  '61182.64' => 'Canon RF 20mm F1.4 L VCM', #42
646
646
  '61182.65' => 'Canon RF 85mm F1.4 L VCM', #github350
647
647
  '61182.66' => 'Canon RF 45mm F1.2 STM', #42
648
+ '61182.67' => 'Canon RF 7-14mm F2.8-3.5 L FISHEYE STM', #42
649
+ '61182.68' => 'Canon RF 14mm F1.4 L VCM', #42
648
650
  65535 => 'n/a',
649
651
  );
650
652
 
@@ -7081,6 +7083,8 @@ my %ciMaxFocal = (
7081
7083
  327 => 'Canon RF 20mm F1.4 L VCM', #42
7082
7084
  328 => 'Canon RF 85mm F1.4 L VCM', #42/github350
7083
7085
  330 => 'Canon RF 45mm F1.2 STM', #42
7086
+ 331 => 'Canon RF 7-14mm F2.8-3.5 L FISHEYE STM', #42
7087
+ 332 => 'Canon RF 14mm F1.4 L VCM', #42
7084
7088
  # Note: add new RF lenses to %canonLensTypes with ID 61182
7085
7089
  },
7086
7090
  },
@@ -9728,6 +9732,7 @@ my %filterConv = (
9728
9732
  },
9729
9733
  0x927c => {
9730
9734
  Name => 'MakerNoteCanon',
9735
+ MakerNotes => 1,
9731
9736
  SubDirectory => {
9732
9737
  TagTable => 'Image::ExifTool::Canon::Main',
9733
9738
  ProcessProc => \&Image::ExifTool::ProcessTIFF,
@@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
21
21
  use Image::ExifTool::Exif;
22
22
  use Image::ExifTool::Canon;
23
23
 
24
- $VERSION = '1.61';
24
+ $VERSION = '1.62';
25
25
 
26
26
  sub WriteCRW($$);
27
27
  sub ProcessCanonRaw($$$);
@@ -595,7 +595,9 @@ sub BuildMakerNotes($$$$$$);
595
595
  3 => 'WhiteSampleLeftBorder',
596
596
  4 => 'WhiteSampleTopBorder',
597
597
  5 => 'WhiteSampleBits',
598
- # this is followed by the encrypted white sample values (ref 1)
598
+ # (followed by the encrypted white sample values, ref 1)
599
+ # BlackLevels seem valid for D30 and D60, but not sure about PowerShot models
600
+ 0x37 => { Name => 'BlackLevels', Format => 'int16u[4]' }, #github387
599
601
  );
600
602
 
601
603
  #------------------------------------------------------------------------------
@@ -17,7 +17,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
17
17
  use Image::ExifTool::XMP;
18
18
  use Image::ExifTool::ZIP;
19
19
 
20
- $VERSION = '1.04';
20
+ $VERSION = '1.05';
21
21
 
22
22
  # CaptureOne COS XML tags
23
23
  # - tags are added dynamically when encountered
@@ -26,7 +26,7 @@ $VERSION = '1.04';
26
26
  GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
27
27
  PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP,
28
28
  VARS => { ID_FMT => 'none' },
29
- ColorCorrections => { ValueConv => '\$val' }, # (long list of floating point numbers)
29
+ ColorCorrections => { ValueConv => '\$val', Hidden => 1 }, # (long list of floating point numbers)
30
30
  );
31
31
 
32
32
  #------------------------------------------------------------------------------
@@ -20,7 +20,7 @@ use strict;
20
20
  use vars qw($VERSION %uid);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
 
23
- $VERSION = '1.23';
23
+ $VERSION = '1.24';
24
24
 
25
25
  # DICOM VR (Value Representation) format conversions
26
26
  my %dicomFormat = (
@@ -3794,7 +3794,10 @@ sub ProcessDICOM($$)
3794
3794
  } elsif ($vr eq 'UI') {
3795
3795
  # add PrintConv to translate registered UID's
3796
3796
  $val =~ s/\0.*//s; # truncate at null
3797
- $$tagInfo{PrintConv} = \%uid if $uid{$val} and $tagInfo;
3797
+ if ($tagInfo) {
3798
+ $$tagInfo{PrintConv} = \%uid if $uid{$val};
3799
+ $$tagInfo{Hidden} = '' unless defined $$tagInfo{Hidden}; # (don't add PrintConv to -listx output)
3800
+ }
3798
3801
  } elsif ($vr =~ /^(AE|CS|DS|IS|LO|PN|SH)$/) {
3799
3802
  $val =~ s/ +$//; # leading/trailing spaces not significant
3800
3803
  $val =~ s/^ +//;
@@ -2118,8 +2118,16 @@ my %opcodeInfo = (
2118
2118
  0x8827 => {
2119
2119
  Name => 'ISO',
2120
2120
  Notes => q{
2121
- called ISOSpeedRatings by EXIF 2.2, then PhotographicSensitivity by the EXIF
2122
- 2.3 spec.
2121
+ called ISOSpeedRatings by EXIF 2.2, then PhotographicSensitivity by EXIF
2122
+ 2.3. This tag has a maximum value of 65535 because the brain-dead EXIF
2123
+ specification limits it to a short integer, and while they can change the
2124
+ name of the tag in an updated EXIF specification, they can't allow a larger
2125
+ storage format for some reason. For higher ISO settings, see the other
2126
+ ISO-related tags StandardOutputSensitivity, RecommendedExposureIndex,
2127
+ ISOSpeed, ISOSpeedLatitudeyyy and ISOSpeedLatitudezzz. But the meanings of
2128
+ these new tags are anyone's guess since the defining specification, ISO
2129
+ 12232, is imprisoned by the ISO organization who extort a ransom for the
2130
+ release of this information
2123
2131
  },
2124
2132
  Writable => 'int16u',
2125
2133
  Count => -1,
@@ -23,7 +23,7 @@ use Image::ExifTool::Exif;
23
23
  use Image::ExifTool::ASF; # for GetGUID()
24
24
  use Image::ExifTool::Microsoft; # for %codePage
25
25
 
26
- $VERSION = '1.50';
26
+ $VERSION = '1.51';
27
27
 
28
28
  sub ProcessFPX($$);
29
29
  sub ProcessFPXR($$$);
@@ -290,12 +290,12 @@ my %fpxFileType = (
290
290
  # save these tables until after the WordDocument was processed
291
291
  '0Table' => {
292
292
  Name => 'Table0',
293
- Hidden => 1, # (used only as temporary storage until table is processed)
293
+ Hidden => 2, # (used only as temporary storage until table is processed)
294
294
  Binary => 1,
295
295
  },
296
296
  '1Table' => {
297
297
  Name => 'Table1',
298
- Hidden => 1, # (used only as temporary storage until table is processed)
298
+ Hidden => 2, # (used only as temporary storage until table is processed)
299
299
  Binary => 1,
300
300
  },
301
301
  Preview => {
@@ -1117,20 +1117,20 @@ my %fpxFileType = (
1117
1117
  #
1118
1118
  # tags below are used internally in intermediate steps to extract the tags above
1119
1119
  #
1120
- TableOffsets => { Hidden => 1 }, # stores offsets to extract data from document table
1120
+ TableOffsets => { Hidden => 2 }, # stores offsets to extract data from document table
1121
1121
  CommentByBlock => { # entire block of CommentBy entries
1122
1122
  SubDirectory => {
1123
1123
  TagTable => 'Image::ExifTool::FlashPix::DocTable',
1124
1124
  ProcessProc => \&ProcessCommentBy,
1125
1125
  },
1126
- Hidden => 1,
1126
+ Hidden => 2,
1127
1127
  },
1128
1128
  LastSavedByBlock => { # entire block of LastSavedBy entries
1129
1129
  SubDirectory => {
1130
1130
  TagTable => 'Image::ExifTool::FlashPix::DocTable',
1131
1131
  ProcessProc => \&ProcessLastSavedBy,
1132
1132
  },
1133
- Hidden => 1,
1133
+ Hidden => 2,
1134
1134
  },
1135
1135
  );
1136
1136
 
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::GPS;
17
17
 
18
- $VERSION = '1.01';
18
+ $VERSION = '1.02';
19
19
 
20
20
  sub Process_marl($$$);
21
21
  sub Process_mrld($$$);
@@ -344,7 +344,7 @@ sub Process_mrld($$$)
344
344
 
345
345
  $et->VerboseDir('mrld', undef, $dirLen);
346
346
  require 'Image/ExifTool/XMPStruct.pl';
347
- Image::ExifTool::XMP::AddFlattenedTags($tagTablePtr);
347
+ Image::ExifTool::XMP::AddFlattenedTags($tagTablePtr, undef, undef, 1);
348
348
  $csv = [ ] if $et->Options('PrintCSV');
349
349
 
350
350
  for ($pos=0; $pos+448<=$dirLen; $pos+=448) {
@@ -375,7 +375,7 @@ sub Process_mrld($$$)
375
375
  my $hash = { map { $channel[$_] => $a[$_] } 1..$#a };
376
376
  unless ($tagInfo) {
377
377
  $tagInfo = AddTagToTable($tagTablePtr, $tag, { Name => $tag, Struct => \%channelStruct });
378
- Image::ExifTool::XMP::AddFlattenedTags($tagTablePtr, $tag);
378
+ Image::ExifTool::XMP::AddFlattenedTags($tagTablePtr, $tag, undef, 1);
379
379
  }
380
380
  # extract channel structure if specified
381
381
  if ($struct) {
Binary file
@@ -36,7 +36,7 @@ use vars qw($VERSION);
36
36
  use Image::ExifTool qw(:Public);
37
37
  use Image::ExifTool::GPS;
38
38
 
39
- $VERSION = '1.86';
39
+ $VERSION = '1.87';
40
40
 
41
41
  sub JITTER() { return 2 } # maximum time jitter
42
42
 
@@ -137,6 +137,31 @@ my %otherConv = (
137
137
 
138
138
  my $secPerDay = 24 * 3600; # a useful constant
139
139
 
140
+ #------------------------------------------------------------------------------
141
+ # Split a line of CSV
142
+ # Inputs: 0) line to split, 1) delimiter
143
+ # Returns: list of items
144
+ sub SplitCSV($$)
145
+ {
146
+ my ($line, $delim) = @_;
147
+ my @toks = split /\Q$delim/, $line;
148
+ my (@vals, $v);
149
+ while (@toks) {
150
+ ($v = shift @toks) =~ s/^ +//; # remove leading spaces
151
+ if ($v =~ s/^"//) {
152
+ # quoted value must end in an odd number of quotes
153
+ while ($v !~ /("+)\s*$/ or not length($1) & 1) {
154
+ last unless @toks;
155
+ $v .= $delim . shift @toks;
156
+ }
157
+ $v =~ s/"\s*$//; # remove trailing quote and whitespace
158
+ $v =~ s/""/"/g; # un-escape quotes
159
+ }
160
+ push @vals, $v;
161
+ }
162
+ return @vals;
163
+ }
164
+
140
165
  #------------------------------------------------------------------------------
141
166
  # Load GPS track log file
142
167
  # Inputs: 0) ExifTool ref, 1) track log data or file name
@@ -281,7 +306,7 @@ sub LoadTrackLog($$;$)
281
306
  $format = 'Bramor';
282
307
  } elsif (((/\b(GPS)?Date/i and /\b(GPS)?(Date)?Time/i) or /\bTime\(seconds\)/i) and /\Q$csvDelim/) {
283
308
  chomp;
284
- @csvHeadings = split /\Q$csvDelim/;
309
+ @csvHeadings = SplitCSV($_, $csvDelim);
285
310
  my $isColumbus = ($csvHeadings[0] and $csvHeadings[0] eq 'INDEX'); # (Columbus GPS logger)
286
311
  $format = 'CSV';
287
312
  # convert recognized headings to our parameter names
@@ -382,7 +407,8 @@ sub LoadTrackLog($$;$)
382
407
  # parse attributes (eg. GPX 'lat' and 'lon')
383
408
  # (note: ignore namespace prefixes if they exist)
384
409
  if ($arg =~ /^(\w+:)?(\w+)=(['"])(.*?)\3/g) {
385
- my $tag = $xmlTag{lc $2} || $userTag{lc $2};
410
+ my $tag = $xmlTag{lc $2};
411
+ $tag = $userTag{lc $2} unless defined $tag;
386
412
  if ($tag) {
387
413
  $$fix{$tag} = $4;
388
414
  if ($keyCategory{$tag}) {
@@ -399,7 +425,8 @@ sub LoadTrackLog($$;$)
399
425
  # loop through XML elements
400
426
  while ($arg =~ m{([^<>]*)<(/)?(\w+:)?(\w+)(>|$)}g) {
401
427
  $tok = lc $4;
402
- my $tag = $xmlTag{$tok} || $userTag{$tok};
428
+ my $tag = $xmlTag{$tok};
429
+ $tag = $userTag{$tok} unless defined $tag;
403
430
  # parse as a simple property if this element has a value
404
431
  if (defined $tag and not $tag) {
405
432
  # a containing property was opened or closed
@@ -530,7 +557,7 @@ DoneFix: $isDate = 1;
530
557
  goto DoneFix; # save this fix
531
558
  } elsif ($format eq 'CSV') {
532
559
  chomp;
533
- my @vals = split /\Q$csvDelim/;
560
+ my @vals = SplitCSV($_, $csvDelim);
534
561
  #
535
562
  # CSV format output of GPS/IMU POS system
536
563
  # Date* - date in DD/MM/YYYY format
@@ -1557,8 +1584,7 @@ sub ConvertGeosync($$)
1557
1584
  # Returns: UTC time string with fractional seconds
1558
1585
  sub PrintFixTime($)
1559
1586
  {
1560
- my $time = $_[0] + 0.0005; # round off to nearest ms
1561
- my $fsec = int(($time - int($time)) * 1000);
1587
+ my $time = shift;
1562
1588
  return Image::ExifTool::ConvertUnixTime($time, undef, 3) . ' UTC';
1563
1589
  }
1564
1590
 
@@ -12,7 +12,7 @@ use strict;
12
12
  use vars qw($VERSION);
13
13
  use Image::ExifTool qw(:DataAccess :Utils);
14
14
 
15
- $VERSION = '1.14';
15
+ $VERSION = '1.15';
16
16
 
17
17
  sub MDItemLocalTime($);
18
18
  sub ProcessATTR($$$);
@@ -364,6 +364,23 @@ sub MDItemLocalTime($)
364
364
  return $val;
365
365
  }
366
366
 
367
+ #------------------------------------------------------------------------------
368
+ # Call system command, redirecting all I/O to /dev/null
369
+ # Inputs: system arguments
370
+ # Returns: system return code
371
+ sub System
372
+ {
373
+ my ($oldout, $olderr);
374
+ open($oldout, ">&STDOUT");
375
+ open($olderr, ">&STDERR");
376
+ open(STDOUT, '>', '/dev/null');
377
+ open(STDERR, '>', '/dev/null');
378
+ my $result = system(@_);
379
+ open(STDOUT, ">&", $oldout);
380
+ open(STDERR, ">&", $olderr);
381
+ return $result;
382
+ }
383
+
367
384
  #------------------------------------------------------------------------------
368
385
  # Set MacOS MDItem and XAttr tags from new tag values
369
386
  # Inputs: 0) ExifTool ref, 1) file name, 2) list of tags to set
@@ -376,7 +393,7 @@ sub SetMacOSTags($$$)
376
393
  my $tag;
377
394
 
378
395
  foreach $tag (@$setTags) {
379
- my ($nvHash, $f, $v, $attr, $cmd, $err, $silentErr);
396
+ my ($nvHash, $attr, @cmd, $err, $silentErr);
380
397
  my $val = $et->GetNewValue($tag, \$nvHash);
381
398
  next unless $nvHash;
382
399
  my $overwrite = $et->IsOverwriting($nvHash);
@@ -389,7 +406,6 @@ sub SetMacOSTags($$$)
389
406
  }
390
407
  }
391
408
  if ($tag eq 'MDItemFSCreationDate' or $tag eq 'FileCreateDate') {
392
- ($f = $file) =~ s/'/'\\''/g;
393
409
  # convert to local time if value has a time zone
394
410
  if ($val =~ /[-+Z]/) {
395
411
  my $time = Image::ExifTool::GetUnixTime($val, 1);
@@ -397,17 +413,15 @@ sub SetMacOSTags($$$)
397
413
  $val =~ s/[-+].*//; # remove time zone
398
414
  }
399
415
  $val =~ s{(\d{4}):(\d{2}):(\d{2})}{$2/$3/$1}; # reformat for setfile
400
- $cmd = "/usr/bin/setfile -d '${val}' '${f}'";
416
+ push @cmd, '/usr/bin/setfile', '-d', $val, $file;
401
417
  } elsif ($tag eq 'MDItemUserTags') {
402
418
  # (tested with "tag" version 0.9.0)
403
- ($f = $file) =~ s/'/'\\''/g;
404
419
  my @vals = $et->GetNewValue($nvHash);
405
420
  if ($overwrite < 0 and @{$$nvHash{DelValue}}) {
406
421
  # delete specified tags
407
422
  my @dels = @{$$nvHash{DelValue}};
408
- s/'/'\\''/g foreach @dels;
409
423
  my $del = join ',', @dels;
410
- $err = system "/usr/local/bin/tag -r '${del}' '${f}'>/dev/null 2>&1";
424
+ $err = System('/usr/local/bin/tag', '-r', $del, $file);
411
425
  unless ($err) {
412
426
  $et->VerboseValue("- $tag", $del);
413
427
  $result = 1;
@@ -416,43 +430,39 @@ sub SetMacOSTags($$$)
416
430
  }
417
431
  unless (defined $err) {
418
432
  # add new tags, or overwrite or delete existing tags
419
- s/'/'\\''/g foreach @vals;
420
433
  my $opt = $overwrite > 0 ? '-s' : '-a';
421
434
  $val = @vals ? join(',', @vals) : '';
422
- $cmd = "/usr/local/bin/tag $opt '${val}' '${f}'";
435
+ push @cmd, '/usr/local/bin/tag', $opt, $val, $file;
423
436
  $et->VPrint(1," - $tag = (all)\n") if $overwrite > 0;
424
437
  undef $val if $val eq '';
425
438
  }
426
439
  } elsif ($delXAttr{$tag}) {
427
- ($f = $file) =~ s/'/'\\''/g;
428
- $cmd = "/usr/bin/xattr -d $delXAttr{$tag} '${f}'";
440
+ push @cmd, '/usr/bin/xattr', '-d', $delXAttr{$tag}, $file;
429
441
  $silentErr = 256; # (will get this error if attribute doesn't exist)
430
442
  } else {
431
- ($f = $file) =~ s/(["\\])/\\$1/g; # escape necessary characters for script
432
- $f =~ s/'/'"'"'/g;
443
+ my ($f, $v);
444
+ ($f = $file) =~ s/([\\"])/\\$1/g; # escape backslashes and quotes for AppleScript
433
445
  if ($tag eq 'MDItemFinderComment') {
434
446
  # (write finder comment using osascript instead of xattr
435
447
  # because it is more work to construct the necessary bplist)
436
448
  $val = '' unless defined $val; # set to empty string instead of deleting
437
449
  $v = $et->Encode($val, 'UTF8');
438
- $v =~ s/(["\\])/\\$1/g;
439
- $v =~ s/'/'"'"'/g;
450
+ $v =~ s/([\\"])/\\$1/g;
440
451
  $attr = 'comment';
441
452
  } else { # $tag eq 'MDItemFSLabel'
442
453
  $v = $val ? 8 - $val : 0; # convert from label to label index (0 for no label)
443
454
  $attr = 'label index';
444
455
  }
445
- $cmd = qq(/usr/bin/osascript -e 'set fp to POSIX file "$f" as alias' -e \\
446
- 'tell application "Finder" to set $attr of file fp to "$v"');
447
- }
448
- if (defined $cmd) {
449
- $err = system $cmd . '>/dev/null 2>&1'; # (pipe all output to /dev/null)
456
+ push @cmd, '/usr/bin/osascript', '-e', qq(set fp to POSIX file "$f" as alias),
457
+ '-e', qq(tell application "Finder" to set $attr of file fp to "$v");
450
458
  }
459
+ $err = System(@cmd) if @cmd;
451
460
  if (not $err) {
452
461
  $et->VerboseValue("+ $tag", $val) if defined $val;
453
462
  $result = 1;
454
463
  } elsif (not $silentErr or $err != $silentErr) {
455
- $cmd =~ s/ .*//s;
464
+ my $cmd = $cmd[0] || 'tag';
465
+ $cmd =~ s(.*/)();
456
466
  $et->Warn(qq{Error $err running "$cmd" to set $tag});
457
467
  $result = -1 unless $result;
458
468
  }
@@ -498,6 +508,7 @@ sub ExtractMDItemTags($$)
498
508
  $_ = '' if $_ eq '(null)';
499
509
  s/^"// and s/"$//; # remove quotes if they exist
500
510
  s/\\"/"/g; # un-escape quotes
511
+ s/\\\\/\\/g; # un-escape backslashes
501
512
  $_ = $et->Decode($_, 'UTF8');
502
513
  push @$val, $_;
503
514
  next;