exiftool_vendored 12.97.0 → 12.99.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,7 +12,7 @@ require Exporter;
12
12
 
13
13
  use vars qw($VERSION @ISA @EXPORT_OK);
14
14
 
15
- $VERSION = '1.12';
15
+ $VERSION = '1.13';
16
16
  @ISA = qw(Exporter);
17
17
  @EXPORT_OK = qw(ReadCSV ReadJSON);
18
18
 
@@ -87,6 +87,7 @@ sub ReadCSV($$;$$)
87
87
  $fileInfo{$tags[$i]} =
88
88
  (defined $missingValue and $vals[$i] eq $missingValue) ? undef : $vals[$i];
89
89
  }
90
+ $fileInfo{_ordered_keys_} = \@tags;
90
91
  # figure out the file name to use
91
92
  if ($fileInfo{SourceFile}) {
92
93
  $$database{$fileInfo{SourceFile}} = \%fileInfo;
@@ -173,7 +174,7 @@ Tok: for (;;) {
173
174
  }
174
175
  # see what type of object this is
175
176
  if ($tok eq '{') { # object (hash)
176
- $rtnVal = { } unless defined $rtnVal;
177
+ $rtnVal = { _ordered_keys_ => [ ] } unless defined $rtnVal;
177
178
  for (;;) {
178
179
  # read "KEY":"VALUE" pairs
179
180
  unless (defined $key) {
@@ -189,6 +190,7 @@ Tok: for (;;) {
189
190
  $pos = pos $$buffPt;
190
191
  return undef unless defined $val;
191
192
  $$rtnVal{$key} = $val;
193
+ push @{$$rtnVal{_ordered_keys_}}, $key;
192
194
  undef $key;
193
195
  }
194
196
  # scan to delimiting ',' or bounding '}'
@@ -345,7 +347,9 @@ option for a list of valid character sets.
345
347
  These functions return an error string, or undef on success and populate the
346
348
  database hash with entries from the CSV or JSON file. Entries are keyed
347
349
  based on the SourceFile column of the CSV or JSON information, and are
348
- stored as hash lookups of tag name/value for each SourceFile.
350
+ stored as hash lookups of tag name/value for each SourceFile. The order
351
+ of the keys (CSV column order or order in a JSON object) is stored as an
352
+ ARRAY reference in a special "_ordered_keys_" element of this hash.
349
353
 
350
354
  =back
351
355
 
@@ -14,7 +14,7 @@ use strict;
14
14
  use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
 
17
- $VERSION = '1.08';
17
+ $VERSION = '1.09';
18
18
 
19
19
  # map for writing metadata to InDesign files (currently only write XMP)
20
20
  my %indMap = (
@@ -104,9 +104,10 @@ sub ProcessIND($$)
104
104
  # this must be null padding or we have a possible error
105
105
  last if $hdr =~ /^\0+$/;
106
106
  # (could be up to 4095 bytes of non-null garbage plus 4095 null bytes from ExifTool)
107
- $raf->Read($buff, 8196) and $hdr .= $buff;
107
+ $raf->Read($buff, 8192) and $hdr .= $buff;
108
+ my $n = length $hdr;
108
109
  $hdr =~ s/\0+$//; # remove trailing nulls
109
- if (length($hdr) > 4095) {
110
+ if ($n > 8190 or length($hdr) > 4095) {
110
111
  $err = 'Corrupt file or unsupported InDesign version';
111
112
  last;
112
113
  }
@@ -14,7 +14,7 @@ use vars qw($VERSION);
14
14
  use Image::ExifTool qw(:DataAccess :Utils);
15
15
  use Image::ExifTool::Import;
16
16
 
17
- $VERSION = '1.08';
17
+ $VERSION = '1.09';
18
18
 
19
19
  sub ProcessJSON($$);
20
20
  sub ProcessTag($$$$%);
@@ -92,8 +92,7 @@ sub ProcessTag($$$$%)
92
92
  return unless $et->Options('Struct') > 1;
93
93
  }
94
94
  # support hashes with ordered keys
95
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
96
- foreach (@keys) {
95
+ foreach (Image::ExifTool::OrderedKeys($val)) {
97
96
  my $tg = $tag . ((/^\d/ and $tag =~ /\d$/) ? '_' : '') . ucfirst;
98
97
  $tg =~ s/([^a-zA-Z])([a-z])/$1\U$2/g;
99
98
  ProcessTag($et, $tagTablePtr, $tg, $$val{$_}, %flags, Flat => 1);
@@ -155,7 +154,7 @@ sub ProcessJSON($$)
155
154
 
156
155
  # extract tags from JSON database
157
156
  foreach $key (sort keys %database) {
158
- foreach $tag (sort keys %{$database{$key}}) {
157
+ foreach $tag (Image::ExifTool::OrderedKeys($database{$key})) {
159
158
  my $val = $database{$key}{$tag};
160
159
  # (ignore SourceFile if generated automatically by ReadJSON)
161
160
  next if $tag eq 'SourceFile' and defined $val and $val eq '*';
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.40';
19
+ $VERSION = '1.41';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -574,6 +574,7 @@ my %j2cMarker = (
574
574
  2 => {
575
575
  Name => 'CompatibleBrands',
576
576
  Format => 'undef[$size-8]',
577
+ List => 1, # (for documentation only)
577
578
  # ignore any entry with a null, and return others as a list
578
579
  ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
579
580
  },
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::Import;
17
17
 
18
- $VERSION = '1.03';
18
+ $VERSION = '1.04';
19
19
 
20
20
  sub ExtractTags($$$);
21
21
 
@@ -106,7 +106,7 @@ sub ExtractTags($$$)
106
106
  my ($et, $meta, $parent) = @_;
107
107
  ref $meta eq 'HASH' or $et->Warn('Invalid LFP metadata'), return;
108
108
  my ($key, $val, $name, $tagTablePtr);
109
- foreach $key (sort keys %$meta) {
109
+ foreach $key (Image::ExifTool::OrderedKeys($meta)) {
110
110
  my $tag = $parent . ucfirst($key);
111
111
  foreach $val (ref $$meta{$key} eq 'ARRAY' ? @{$$meta{$key}} : $$meta{$key}) {
112
112
  ref $val eq 'HASH' and ExtractTags($et, $val, $tag), next;
@@ -328,6 +328,14 @@ sub ParsePID($$$$$)
328
328
  $more = 1; # read past unknown 0x15 packets if ExtractEmbedded > 2
329
329
  }
330
330
  }
331
+ # still have a lot of questions about how to decode this...
332
+ # (see https://exiftool.org/forum/index.php?topic=16486 and ../testpics/gps_video/forum16486.ts)
333
+ # } elsif ($type == 6) {
334
+ # my @a = unpack('x17x2NNx2nx2nx2nx2Cx2a4x2a5x2Nx2Nx2nx2Nx2Nx2Nx2nx2nx2Nx2nx2n', $$dataPt . " ");
335
+ # my $hi = shift @a;
336
+ # $a[0] = Image::ExifTool::ConvertUnixTime(($a[0] + $hi * 4294967296) * 1e-6, undef, 6);
337
+ # print "@a\n";
338
+ # $more = 1;
331
339
  } elsif ($type < 0) {
332
340
  if ($$dataPt =~ /^(.{164})?(.{24})A[NS][EW]/s) {
333
341
  # (Blueskysea B4K, Novatek NT96670)
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
48
48
  use Image::ExifTool::Exif;
49
49
  use Image::ExifTool::GPS;
50
50
 
51
- $VERSION = '3.02';
51
+ $VERSION = '3.04';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -901,6 +901,7 @@ my %userDefined = (
901
901
  Writable => 1,
902
902
  },
903
903
  # '35AX'? - seen "AT" (Yada RoadCam Pro 4K dashcam)
904
+ cust => 'CustomInfo', # 70mai A810
904
905
  );
905
906
 
906
907
  # stuff seen in 'skip' atom (70mai Pro Plus+ MP4 videos)
@@ -935,6 +936,7 @@ my %userDefined = (
935
936
  2 => {
936
937
  Name => 'CompatibleBrands',
937
938
  Format => 'undef[$size-8]',
939
+ List => 1, # (for documentation only)
938
940
  # ignore any entry with a null, and return others as a list
939
941
  ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
940
942
  },
@@ -2551,7 +2553,7 @@ my %userDefined = (
2551
2553
  TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' },
2552
2554
  TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508"
2553
2555
  # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x"
2554
- TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' },
2556
+ TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"', List => 1 },
2555
2557
  );
2556
2558
 
2557
2559
  # User-specific media data atoms (ref 11)
@@ -3350,6 +3352,7 @@ my %userDefined = (
3350
3352
  PrintConv => '"Track $val"',
3351
3353
  },
3352
3354
  # cdep (Structural Dependency QT tag?)
3355
+ # fall - ? int32u, seen: 2
3353
3356
  );
3354
3357
 
3355
3358
  # track aperture mode dimensions atoms
@@ -6743,6 +6746,13 @@ my %userDefined = (
6743
6746
  Avoid => 1,
6744
6747
  %iso8601Date,
6745
6748
  },
6749
+ # (mdta)com.apple.quicktime.scene-illuminance
6750
+ 'scene-illuminance' => {
6751
+ Name => 'SceneIlluminance',
6752
+ Notes => 'milli-lux',
6753
+ ValueConv => 'unpack("N", $val)',
6754
+ Writable => 0, # (don't make this writable because it is found in timed metadata)
6755
+ },
6746
6756
  #
6747
6757
  # seen in Apple ProRes RAW file
6748
6758
  #
@@ -7392,6 +7402,7 @@ my %userDefined = (
7392
7402
  # alac - 28 bytes
7393
7403
  # adrm - AAX DRM atom? 148 bytes
7394
7404
  # aabd - AAX unknown 17kB (contains 'aavd' strings)
7405
+ # dapa - ? 203 bytes
7395
7406
  );
7396
7407
 
7397
7408
  # AMR decode config box (ref 3)
@@ -9151,7 +9162,7 @@ sub HandleItemInfo($)
9151
9162
  $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
9152
9163
  delete $$et{DOC_NUM};
9153
9164
  }
9154
- $raf->Seek($curPos, 0); # seek back to original position
9165
+ $raf->Seek($curPos, 0) or $et->Warn('Seek error'), last; # seek back to original position
9155
9166
  pop @{$$et{PATH}};
9156
9167
  }
9157
9168
  # process the item properties now that we should know their associations and document numbers
@@ -9577,7 +9588,7 @@ sub ProcessMOV($$;$)
9577
9588
  if ($tag eq 'ftyp' and $size >= 12) {
9578
9589
  # read ftyp atom to see what type of file this is
9579
9590
  if ($raf->Read($buff, $size-8) == $size-8) {
9580
- $raf->Seek(-($size-8), 1);
9591
+ $raf->Seek(-($size-8), 1) or $et->Warn('Seek error'), return 0;
9581
9592
  my $type = substr($buff, 0, 4);
9582
9593
  $$et{save_ftyp} = $type;
9583
9594
  # see if we know the extension for this file type
@@ -9629,7 +9640,7 @@ sub ProcessMOV($$;$)
9629
9640
  # a zero size isn't legal for contained atoms, but Canon uses it to
9630
9641
  # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here
9631
9642
  my $pos = $raf->Tell() - 4;
9632
- $raf->Seek(0,2);
9643
+ $raf->Seek(0,2) or $et->Warn('Seek error'), return 0;
9633
9644
  my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes';
9634
9645
  $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]");
9635
9646
  } else {
@@ -9638,7 +9649,7 @@ sub ProcessMOV($$;$)
9638
9649
  if ($$tagTablePtr{"$tag-size"}) {
9639
9650
  my $pos = $raf->Tell();
9640
9651
  unless ($fast) {
9641
- $raf->Seek(0, 2);
9652
+ $raf->Seek(0, 2) or $et->Warn('Seek error'), return 0;
9642
9653
  $et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos);
9643
9654
  }
9644
9655
  $et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"};
@@ -109,7 +109,7 @@ my %insvLimit = (
109
109
  The tags below are extracted from timed metadata in QuickTime and other
110
110
  formats of video files when the ExtractEmbedded option is used. Although
111
111
  most of these tags are combined into the single table below, ExifTool
112
- currently reads 77 different formats of timed GPS metadata from video files.
112
+ currently reads 78 different formats of timed GPS metadata from video files.
113
113
  },
114
114
  VARS => { NO_ID => 1 },
115
115
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
@@ -2163,9 +2163,26 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2163
2163
  push(@xtra, $1 => $2), next;
2164
2164
  }
2165
2165
 
2166
+ } elsif ($$dataPt =~ m/^.{30}A.{20}VV/) {
2167
+
2168
+ $debug and $et->FoundTag(GPSType => 17);
2169
+ # 70mai A810 dashcam (note: no timestamps in the samples I have)
2170
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 ed 01 00 00 [..@.freeGPS ....]
2171
+ # 0010: 03 00 ed 01 00 00 00 0f 00 00 70 08 00 00 41 66 [..........p...Af]
2172
+ # 0020: 13 7d 1e 3c 11 dc 03 5d 01 00 00 01 00 00 00 23 [.}.<...].......#]
2173
+ # 0030: 00 00 00 56 56 00 00 00 00 00 00 00 00 00 00 00 [...VV...........]
2174
+ # 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
2175
+ SetByteOrder('II');
2176
+ SetGPSDateTime($et, $tagTbl, $$dirInfo{SampleTime});
2177
+ $lat = Get32s($dataPt, 31) / 1e5;
2178
+ $lon = Get32s($dataPt, 35) / 1e5;
2179
+ $spd = Get32s($dataPt, 43); # (seems to be km/h but not confirmed)
2180
+ # offset 475 - int16u=N string[N] - some sort of settings?:
2181
+ # eg. "\x15\x00{pA:V,rA:V,sF:0,tF:2}"
2182
+
2166
2183
  } else {
2167
2184
 
2168
- $debug and $et->FoundTag(GPSType => 17);
2185
+ $debug and $et->FoundTag(GPSType => 18);
2169
2186
  # (look for binary GPS as stored by Nextbase 512G, ref PH)
2170
2187
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
2171
2188
  # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
@@ -34,7 +34,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
34
34
  use Image::ExifTool::Exif;
35
35
  use Image::ExifTool::Minolta;
36
36
 
37
- $VERSION = '3.69';
37
+ $VERSION = '3.70';
38
38
 
39
39
  sub ProcessSRF($$$);
40
40
  sub ProcessSR2($$$);
@@ -170,6 +170,7 @@ sub PrintInvLensSpec($;$$);
170
170
  32885 => 'Sony FE 16-35mm F2.8 GM II', #JR
171
171
  32886 => 'Sony FE 300mm F2.8 GM OSS', #JR
172
172
  32887 => 'Sony E PZ 16-50mm F3.5-5.6 OSS II', #JR
173
+ 32888 => 'Sony FE 85mm F1.4 GM II', #JR
173
174
 
174
175
  # (comment this out so LensID will report the LensModel, which is more useful)
175
176
  # 32952 => 'Metabones Canon EF Speed Booster Ultra', #JR (corresponds to 184, but 'Advanced' mode, LensMount reported as E-mount)
@@ -241,6 +242,8 @@ sub PrintInvLensSpec($;$$);
241
242
  49474.9 => 'Viltrox 75mm F1.2 E', #JR
242
243
  '49474.10' => 'Viltrox 20mm F2.8 FE', #JR
243
244
  49475 => 'Tamron 50-300mm F4.5-6.3 Di III VC VXD', #JR (Model A069)
245
+ 49476 => 'Tamron 28-300mm F4-7.1 Di III VC VXD', #JR (Model A074)
246
+ 49477 => 'Tamron 90mm F2.8 Di III Macro VXD', #JR (Model F072)
244
247
 
245
248
  49712 => 'Tokina FiRIN 20mm F2 FE AF', # (firmware Ver.01)
246
249
  49713 => 'Tokina FiRIN 100mm F2.8 FE MACRO', # (firmware Ver.01)
@@ -299,6 +302,7 @@ sub PrintInvLensSpec($;$$);
299
302
  50547 => 'Sigma 10-18mm F2.8 DC DN | C', #JR (023)
300
303
  50548 => 'Sigma 15mm F1.4 DG DN DIAGONAL FISHEYE | A', #JR (024)
301
304
  50549 => 'Sigma 50mm F1.2 DG DN | A', #JR (024)
305
+ 50550 => 'Sigma 28-105mm F2.8 DG DN | A', #JR (024)
302
306
  50551 => 'Sigma 28-45mm F1.8 DG DN | A', #JR (024)
303
307
 
304
308
  50992 => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR
@@ -315,6 +319,7 @@ sub PrintInvLensSpec($;$$);
315
319
  51003 => 'Voigtlander NOKTON 35mm F1.2 Aspherical SE', #JR
316
320
  51006 => 'Voigtlander APO-LANTHAR 35mm F2 Aspherical', #JR
317
321
  51007 => 'Voigtlander NOKTON 50mm F1 Aspherical', #JR
322
+ 51008 => 'Voigtlander NOKTON 75mm F1.5 Aspherical', #JR
318
323
 
319
324
  # lenses listed in the Sigma MC-11 list, but not yet seen:
320
325
  # 504xx => 'Sigma 18-200mm F3.5-6.3 DC MACRO OS HSM | C + MC-11', # (014)
@@ -8686,7 +8686,6 @@ my %tagExists = (
8686
8686
  'cont' => 1,
8687
8687
  'contactnames' => 1,
8688
8688
  'containerversion' => 1,
8689
- 'contake' => 1,
8690
8689
  'contentbranding' => 1,
8691
8690
  'contentdescribes' => 1,
8692
8691
  'contentdescription' => 1,
@@ -8709,6 +8708,7 @@ my %tagExists = (
8709
8708
  'contrastadjustment' => 1,
8710
8709
  'contrastinfo' => 1,
8711
8710
  'controller' => 1,
8711
+ 'conttake' => 1,
8712
8712
  'convergenceangle' => 1,
8713
8713
  'convergencebaseimage' => 1,
8714
8714
  'convergencedistance' => 1,
@@ -8820,6 +8820,7 @@ my %tagExists = (
8820
8820
  'customfunctionsd30' => 1,
8821
8821
  'customfunctionsd60' => 1,
8822
8822
  'customfunctionsunknown' => 1,
8823
+ 'custominfo' => 1,
8823
8824
  'customsettingsd3' => 1,
8824
8825
  'customsettingsd300' => 1,
8825
8826
  'customsettingsd300s' => 1,
@@ -12014,6 +12015,7 @@ my %tagExists = (
12014
12015
  'scenebalancealgorithmrevision' => 1,
12015
12016
  'sceneclassification' => 1,
12016
12017
  'scenecolorimetryestimates' => 1,
12018
+ 'sceneilluminance' => 1,
12017
12019
  'scheduleitemid' => 1,
12018
12020
  'schemeinfo' => 1,
12019
12021
  'schemetype' => 1,
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
12
12
  =head1 TAG TABLES
13
13
 
14
14
  The tables listed below give the names of all tags recognized by ExifTool.
15
- They contain a total of 28148 tags, with 17486 unique tag names.
15
+ They contain a total of 28150 tags, with 17488 unique tag names.
16
16
 
17
17
  B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
18
18
  table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
@@ -26108,7 +26108,7 @@ the image undisplayable.
26108
26108
  ------ -------- --------
26109
26109
  0 MajorBrand no
26110
26110
  1 MinorVersion no
26111
- 2 CompatibleBrands no
26111
+ 2 CompatibleBrands no+
26112
26112
 
26113
26113
  =head3 Jpeg2000 ImageHeader Tags
26114
26114
 
@@ -26163,7 +26163,7 @@ from any tags found in this segment.
26163
26163
  ------ -------- --------
26164
26164
  'Aperture' Aperture no
26165
26165
  'ColorMode' ColorMode no
26166
- 'ConTake' ConTake no
26166
+ 'ContTake' ContTake no
26167
26167
  'ExpBias' ExposureCompensation no
26168
26168
  'FNumber' FNumber no
26169
26169
  'FWare' FirmwareVersion no
@@ -29846,6 +29846,7 @@ for the official QuickTime specification.
29846
29846
  'PICT' PreviewPICT no
29847
29847
  '_htc' HTCInfo QuickTime HTCInfo
29848
29848
  'ardt' ARDroneFile no
29849
+ 'cust' CustomInfo no
29849
29850
  'frea' Kodak_frea Kodak frea
29850
29851
  'free' KodakFree Kodak Free
29851
29852
  Pittasoft QuickTime Pittasoft
@@ -29897,7 +29898,7 @@ for the official QuickTime specification.
29897
29898
  The tags below are extracted from timed metadata in QuickTime and other
29898
29899
  formats of video files when the ExtractEmbedded option is used. Although
29899
29900
  most of these tags are combined into the single table below, ExifTool
29900
- currently reads 77 different formats of timed GPS metadata from video files.
29901
+ currently reads 78 different formats of timed GPS metadata from video files.
29901
29902
 
29902
29903
  Tag Name Writable
29903
29904
  -------- --------
@@ -30163,6 +30164,7 @@ changed via the config file.
30163
30164
  'producer' Producer yes
30164
30165
  'publisher' Publisher yes
30165
30166
  'rating.user' UserRating yes
30167
+ 'scene-illuminance' SceneIlluminance no
30166
30168
  'software' Software yes
30167
30169
  'still-image-time' StillImageTime no
30168
30170
  'title' Title yes
@@ -30230,7 +30232,7 @@ Tags found in Pittasoft Blackvue dashcam "free" data.
30230
30232
  ------ -------- --------
30231
30233
  0 MajorBrand no
30232
30234
  1 MinorVersion no
30233
- 2 CompatibleBrands no
30235
+ 2 CompatibleBrands no+
30234
30236
 
30235
30237
  =head3 QuickTime OtherMeta Tags
30236
30238
 
@@ -31280,7 +31282,7 @@ Tags found in TomTom Bandit Action Cam MP4 videos.
31280
31282
  'TTAD' TomTomAD QuickTime Stream
31281
31283
  'TTHL' TomTomHL? no
31282
31284
  'TTID' TomTomID no
31283
- 'TTVD' TomTomVD no
31285
+ 'TTVD' TomTomVD no+
31284
31286
  'TTVI' TomTomVI? no
31285
31287
 
31286
31288
  =head3 QuickTime HintTrackInfo Tags
@@ -184,11 +184,19 @@ sub GetFreeEntries($)
184
184
  {
185
185
  my $dict = shift;
186
186
  my %xrefFree;
187
- # from the start we have only written xref stream entries in 'CNn' format,
188
- # so we can simplify things for now and only support this type of entry
187
+ # we write xref stream entries in 'CNn' or 'CNNn' format (with 8-byte 'NN' offset),
189
188
  my $w = $$dict{W};
190
- if (ref $w eq 'ARRAY' and "@$w" eq '1 4 2') {
191
- my $size = $$dict{_entry_size}; # this will be 7 for 'CNn'
189
+ if (ref $w eq 'ARRAY') {
190
+ my $bytes = "@$w";
191
+ my $fmt;
192
+ if ($bytes eq '1 4 2') {
193
+ $fmt = 'CNn';
194
+ } elsif ($bytes eq '1 8 2') {
195
+ $fmt = 'CNNn';
196
+ } else {
197
+ return \%xrefFree;
198
+ }
199
+ my $size = $$dict{_entry_size}; # this will be 7 for 'CNn' or 11 for 'CNNn'
192
200
  my $index = $$dict{Index};
193
201
  my $len = length $$dict{_stream};
194
202
  # scan the table for free objects
@@ -200,7 +208,12 @@ sub GetFreeEntries($)
200
208
  my $count = $$index[$i*2+1];
201
209
  for ($j=0; $j<$count; ++$j) {
202
210
  last if $pos + $size > $len;
203
- my @t = unpack("x$pos CNn", $$dict{_stream});
211
+ my @t = unpack("x$pos $fmt", $$dict{_stream});
212
+ if (@t == 4) {
213
+ $t[1] = $t[1] * 4294967296 + $t[2];
214
+ $t[2] = $t[3];
215
+ @t = 3;
216
+ }
204
217
  # add entry if object was free
205
218
  $xrefFree{$start+$j} = [ $t[1], $t[2], 'f' ] if $t[0] == 0;
206
219
  $pos += $size; # step to next entry
@@ -657,24 +670,37 @@ sub WritePDF($$)
657
670
  $newXRef{$nextObject++} = [ Tell($outfile) - $$et{PDFBase} + length($/), 0, 'n' ];
658
671
  $$mainDict{Size} = $nextObject;
659
672
  # create xref stream and Index entry
660
- $$mainDict{W} = [ 1, 4, 2 ]; # int8u, int32u, int16u ('CNn')
661
- $$mainDict{Index} = [ ];
662
- $$mainDict{_stream} = '';
663
- my @ids = sort { $a <=> $b } keys %newXRef;
664
- while (@ids) {
665
- my $startID = $ids[0];
666
- for (;;) {
667
- $id = shift @ids;
668
- my ($pos, $gen, $type) = @{$newXRef{$id}};
669
- if ($pos > 0xffffffff) {
670
- $et->Error('Huge files not yet supported');
671
- last;
673
+ my $bits = 4;
674
+ Restart: for (;;) {
675
+ $$mainDict{W} = [ 1, $bits, 2 ]; # int8u, int32u/int64u, int16u ('CNn' or 'CNNn')
676
+ $$mainDict{Index} = [ ];
677
+ $$mainDict{_stream} = '';
678
+ my @ids = sort { $a <=> $b } keys %newXRef;
679
+ while (@ids) {
680
+ my $startID = $ids[0];
681
+ for (;;) {
682
+ $id = shift @ids;
683
+ my ($pos, $gen, $type) = @{$newXRef{$id}};
684
+ if ($pos > 0xffffffff) {
685
+ if ($bits == 4) {
686
+ # switch to 64-bit integer offsets
687
+ $bits = 8;
688
+ next Restart;
689
+ }
690
+ }
691
+ if ($bits == 4) {
692
+ $$mainDict{_stream} .= pack('CNn', $type eq 'f' ? 0 : 1, $pos, $gen);
693
+ } else {
694
+ my $hi = int($pos / 4294967296);
695
+ my $lo = $pos - $hi * 4294967296;
696
+ $$mainDict{_stream} .= pack('CNNn', $type eq 'f' ? 0 : 1, $hi, $lo, $gen);
697
+ }
698
+ last if not @ids or $ids[0] != $id + 1;
672
699
  }
673
- $$mainDict{_stream} .= pack('CNn', $type eq 'f' ? 0 : 1, $pos, $gen);
674
- last if not @ids or $ids[0] != $id + 1;
700
+ # add Index entries for this section of the xref stream
701
+ push @{$$mainDict{Index}}, $startID, $id - $startID + 1;
675
702
  }
676
- # add Index entries for this section of the xref stream
677
- push @{$$mainDict{Index}}, $startID, $id - $startID + 1;
703
+ last;
678
704
  }
679
705
  # write the xref stream object
680
706
  $keyExt = "$id 0 obj"; # (set anyway, but xref stream should NOT be encrypted)
@@ -925,19 +925,31 @@ sub WriteXMP($$;$)
925
925
  # get hash of all information we want to change
926
926
  # (sorted by tag name so alternate languages come last, but with structures
927
927
  # first so flattened tags may be used to override individual structure elements)
928
- my (@tagInfoList, $delLangPath, %delLangPaths, %delAllLang, $firstNewPath);
928
+ my (@tagInfoList, @structList, $delLangPath, %delLangPaths, %delAllLang, $firstNewPath, @langTags);
929
929
  my $writeGroup = $$dirInfo{WriteGroup};
930
930
  foreach $tagInfo (sort ByTagName $et->GetNewTagInfoList()) {
931
931
  next unless $et->GetGroup($tagInfo, 0) eq 'XMP';
932
932
  next if $$tagInfo{Name} eq 'XMP'; # (ignore full XMP block if we didn't write it already)
933
933
  next if $writeGroup and $writeGroup ne $$et{NEW_VALUE}{$tagInfo}{WriteGroup};
934
- if ($$tagInfo{Struct}) {
935
- unshift @tagInfoList, $tagInfo;
934
+ if ($$tagInfo{LangCode}) {
935
+ push @langTags, $tagInfo
936
+ } elsif ($$tagInfo{Struct}) {
937
+ push @structList, $tagInfo;
936
938
  } else {
937
939
  push @tagInfoList, $tagInfo;
938
940
  }
939
941
  }
940
- foreach $tagInfo (@tagInfoList) {
942
+ if (@langTags) {
943
+ # keep original order in which lang-alt entries were added
944
+ foreach $tagInfo (sort { $$et{NEW_VALUE}{$a}{Order} <=> $$et{NEW_VALUE}{$b}{Order} } @langTags) {
945
+ if ($$tagInfo{Struct}) {
946
+ push @structList, $tagInfo;
947
+ } else {
948
+ push @tagInfoList, $tagInfo;
949
+ }
950
+ }
951
+ }
952
+ foreach $tagInfo (@structList, @tagInfoList) {
941
953
  my @delPaths; # list of deleted paths
942
954
  my $tag = $$tagInfo{TagID};
943
955
  my $path = GetPropertyPath($tagInfo);
@@ -295,10 +295,11 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
295
295
  # CreateGroups - hash of all family 0 group names where tag may be created
296
296
  # WriteGroup - group name where information is being written (correct case)
297
297
  # WantGroup - group name as specified in call to function (case insensitive)
298
- # Next - pointer to next new value hash (if more than one)
298
+ # Next - pointer to next new value hash (if more than one for this tag)
299
299
  # NoReplace - set if value was created with Replace=0
300
300
  # AddBefore - number of list items added by a subsequent Replace=0 call
301
- # IsNVH - Flag indicating this is a new value hash
301
+ # IsNVH - flag indicating this is a new value hash
302
+ # Order - counter to indicate the order that new value hashes were created
302
303
  # Shift - shift value
303
304
  # Save - counter used by SaveNewValues()/RestoreNewValues()
304
305
  # MAKER_NOTE_FIXUP - pointer to fixup if necessary for a maker note value
@@ -317,7 +318,7 @@ sub SetNewValue($;$$%)
317
318
 
318
319
  unless (defined $tag) {
319
320
  delete $$self{NEW_VALUE};
320
- $$self{SAVE_COUNT} = 0;
321
+ $$self{SAVE_COUNT} = $$self{NV_COUNT} = 0;
321
322
  $$self{DEL_GROUP} = { };
322
323
  return 1;
323
324
  }
@@ -1389,8 +1390,16 @@ sub SetNewValuesFromFile($$;@)
1389
1390
  return $info if $$info{Error} and $$info{Error} eq 'Error opening file';
1390
1391
  delete $$srcExifTool{VALUE}{Error}; # delete so we can check this later
1391
1392
 
1392
- # sort tags in reverse order so we get priority tag last
1393
- my @tags = reverse sort keys %$info;
1393
+ # sort tags in file order with priority tags last
1394
+ my (@tags, @prio);
1395
+ foreach (sort { $$srcExifTool{FILE_ORDER}{$a} <=> $$srcExifTool{FILE_ORDER}{$b} } keys %$info) {
1396
+ if (/ /) {
1397
+ push @tags, $_;
1398
+ } else {
1399
+ push @prio, $_;
1400
+ }
1401
+ }
1402
+ push @tags, @prio;
1394
1403
  #
1395
1404
  # simply transfer all tags from source image if no tags specified
1396
1405
  #
@@ -3896,6 +3905,7 @@ sub GetNewValueHash($$;$$$$)
3896
3905
  TagInfo => $tagInfo,
3897
3906
  WriteGroup => $writeGroup,
3898
3907
  IsNVH => 1, # set flag so we can recognize a new value hash
3908
+ Order => $$self{NV_COUNT}++,
3899
3909
  };
3900
3910
  # add entry to our NEW_VALUE hash
3901
3911
  if ($$self{NEW_VALUE}{$tagInfo}) {
@@ -4023,7 +4033,7 @@ sub RemoveNewValuesForGroup($$)
4023
4033
  #------------------------------------------------------------------------------
4024
4034
  # Get list of tagInfo hashes for all new data
4025
4035
  # Inputs: 0) ExifTool object reference, 1) optional tag table pointer
4026
- # Returns: list of tagInfo hashes
4036
+ # Returns: list of tagInfo hashes in no particular order
4027
4037
  sub GetNewTagInfoList($;$)
4028
4038
  {
4029
4039
  my ($self, $tagTablePtr) = @_;
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
  require Exporter;
52
52
 
53
- $VERSION = '3.66';
53
+ $VERSION = '3.67';
54
54
  @ISA = qw(Exporter);
55
55
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
56
56
 
@@ -3777,8 +3777,13 @@ sub ParseXMPElement($$$;$$$$)
3777
3777
 
3778
3778
  # extract property attributes
3779
3779
  my ($parseResource, %attrs, @attrs);
3780
- while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
3781
- my ($attr, $val) = ($1, $3);
3780
+ # this hangs Perl (v5.18.4) for a specific capture string [patched in ExifTool 12.98]
3781
+ # while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
3782
+ while ($attrs =~ /(\S+?)\s*=\s*(['"])/g) {
3783
+ my ($attr, $quote) = ($1, $2);
3784
+ my $p0 = pos($attrs);
3785
+ last unless $attrs =~ /$quote/g;
3786
+ my $val = substr($attrs, $p0, pos($attrs)-$p0-1);
3782
3787
  # handle namespace prefixes (defined by xmlns:PREFIX, or used with PREFIX:tag)
3783
3788
  if ($attr =~ /(.*?):/) {
3784
3789
  if ($1 eq 'xmlns') {