exiftool-vendored.pl 12.45.0 → 12.49.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.
Files changed (51) hide show
  1. package/bin/Changes +84 -3
  2. package/bin/MANIFEST +9 -0
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +1 -1
  5. package/bin/README +45 -44
  6. package/bin/config_files/acdsee.config +2 -1
  7. package/bin/config_files/frameCount.config +56 -0
  8. package/bin/config_files/tiff_version.config +1 -1
  9. package/bin/exiftool +62 -54
  10. package/bin/lib/Image/ExifTool/Apple.pm +6 -2
  11. package/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -6
  12. package/bin/lib/Image/ExifTool/Canon.pm +20 -8
  13. package/bin/lib/Image/ExifTool/CanonRaw.pm +8 -1
  14. package/bin/lib/Image/ExifTool/Exif.pm +7 -3
  15. package/bin/lib/Image/ExifTool/FLAC.pm +17 -3
  16. package/bin/lib/Image/ExifTool/FlashPix.pm +4 -2
  17. package/bin/lib/Image/ExifTool/FujiFilm.pm +31 -5
  18. package/bin/lib/Image/ExifTool/ICC_Profile.pm +1 -1
  19. package/bin/lib/Image/ExifTool/ICO.pm +141 -0
  20. package/bin/lib/Image/ExifTool/ID3.pm +5 -5
  21. package/bin/lib/Image/ExifTool/M2TS.pm +55 -8
  22. package/bin/lib/Image/ExifTool/MIE.pm +9 -3
  23. package/bin/lib/Image/ExifTool/MISB.pm +494 -0
  24. package/bin/lib/Image/ExifTool/MakerNotes.pm +3 -1
  25. package/bin/lib/Image/ExifTool/Nikon.pm +34 -31
  26. package/bin/lib/Image/ExifTool/NikonSettings.pm +5 -3
  27. package/bin/lib/Image/ExifTool/Panasonic.pm +21 -4
  28. package/bin/lib/Image/ExifTool/PanasonicRaw.pm +12 -5
  29. package/bin/lib/Image/ExifTool/Photoshop.pm +29 -3
  30. package/bin/lib/Image/ExifTool/QuickTime.pm +34 -5
  31. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +42 -4
  32. package/bin/lib/Image/ExifTool/README +1 -1
  33. package/bin/lib/Image/ExifTool/RIFF.pm +106 -9
  34. package/bin/lib/Image/ExifTool/Samsung.pm +2 -2
  35. package/bin/lib/Image/ExifTool/Sigma.pm +27 -1
  36. package/bin/lib/Image/ExifTool/SigmaRaw.pm +37 -13
  37. package/bin/lib/Image/ExifTool/Sony.pm +7 -3
  38. package/bin/lib/Image/ExifTool/TagLookup.pm +176 -6
  39. package/bin/lib/Image/ExifTool/TagNames.pod +4782 -4486
  40. package/bin/lib/Image/ExifTool/Text.pm +3 -4
  41. package/bin/lib/Image/ExifTool/Torrent.pm +2 -3
  42. package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +7 -0
  43. package/bin/lib/Image/ExifTool/WriteExif.pl +19 -1
  44. package/bin/lib/Image/ExifTool/WriteRIFF.pl +359 -0
  45. package/bin/lib/Image/ExifTool/Writer.pl +6 -2
  46. package/bin/lib/Image/ExifTool/XMP.pm +70 -56
  47. package/bin/lib/Image/ExifTool.pm +75 -15
  48. package/bin/lib/Image/ExifTool.pod +55 -52
  49. package/bin/perl-Image-ExifTool.spec +43 -43
  50. package/bin/pp_build_exe.args +7 -4
  51. package/package.json +2 -2
@@ -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.48';
38
+ $VERSION = '3.49';
39
39
  @ISA = qw(Exporter);
40
40
 
41
41
  sub NumbersFirst($$);
@@ -501,11 +501,13 @@ been decoded. Use the L<Unknown|../ExifTool.html#Unknown> (-u) option to extrac
501
501
  },
502
502
  GeoTiff => q{
503
503
  ExifTool extracts the following tags from GeoTIFF images. See
504
- L<http://www.remotesensing.org/geotiff/spec/geotiffhome.html> for the
505
- complete GeoTIFF specification. Also included in the table below are
506
- ChartTIFF tags (see L<http://www.charttiff.com/whitepapers.shtml>). GeoTIFF
507
- tags are not writable individually, but they may be copied en mass via the
508
- block tags GeoTiffDirectory, GeoTiffDoubleParams and GeoTiffAsciiParams.
504
+ L<https://web.archive.org/web/20070820121549/http://www.remotesensing.org/geotiff/spec/geotiffhome.html>
505
+ for the complete GeoTIFF specification. Also included in the table below
506
+ are ChartTIFF tags (see
507
+ L<https://web.archive.org/web/20020828193928/http://www.charttiff.com/whitepapers.shtml>).
508
+ GeoTIFF tags are not writable individually, but they may be copied en mass
509
+ via the block tags GeoTiffDirectory, GeoTiffDoubleParams and
510
+ GeoTiffAsciiParams.
509
511
  },
510
512
  JFIF => q{
511
513
  The following information is extracted from the JPEG JFIF header. See
@@ -2573,6 +2575,9 @@ sub WriteTagNames($$)
2573
2575
  $tip = '';
2574
2576
  # use copyright symbol in QuickTime UserData tags
2575
2577
  $tagIDstr =~ s/^"\\xa9/"&copy;/;
2578
+ # escape necessary characters in html
2579
+ $tagIDstr =~ s/>/&gt;/g;
2580
+ $tagIDstr =~ s/</&lt;/g;
2576
2581
  }
2577
2582
  # add tooltip for special writable attributes
2578
2583
  my $wtip = '';
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '4.60';
91
+ $VERSION = '4.62';
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)
@@ -480,6 +480,7 @@ $VERSION = '4.60';
480
480
  255 => 'Sigma 24-105mm f/4 DG OS HSM | A or Other Lens', #50
481
481
  255.1 => 'Sigma 180mm f/2.8 EX DG OS HSM APO Macro', #50
482
482
  255.2 => 'Tamron SP 70-200mm f/2.8 Di VC USD', #exiv issue 1202 (A009)
483
+ 255.3 => 'Yongnuo YN 50mm f/1.8', #50
483
484
  368 => 'Sigma 14-24mm f/2.8 DG HSM | A or other Sigma Lens', #IB (A018)
484
485
  368.1 => 'Sigma 20mm f/1.4 DG HSM | A', #50 (newer firmware)
485
486
  368.2 => 'Sigma 50mm f/1.4 DG HSM | A', #50
@@ -493,6 +494,7 @@ $VERSION = '4.60';
493
494
  '368.10' => 'Sigma 35mm f/1.4 DG HSM | A', #PH (012)
494
495
  '368.11' => 'Sigma 70mm f/2.8 DG Macro', #IB (A018)
495
496
  '368.12' => 'Sigma 18-35mm f/1.8 DC HSM | A', #50
497
+ '368.13' => 'Sigma 24-105mm f/4 DG OS HSM | A', #forum3833
496
498
  # Note: LensType 488 (0x1e8) is reported as 232 (0xe8) in 7D CameraSettings
497
499
  488 => 'Canon EF-S 15-85mm f/3.5-5.6 IS USM', #PH
498
500
  489 => 'Canon EF 70-300mm f/4-5.6L IS USM', #Gerald Kapounek
@@ -602,8 +604,8 @@ $VERSION = '4.60';
602
604
  '61182.24' => 'Canon RF 14-35mm F4L IS USM', #IB
603
605
  '61182.25' => 'Canon RF-S 18-45mm F4.5-6.3 IS STM', #42
604
606
  '61182.26' => 'Canon RF 100-400mm F5.6-8 IS USM', #42
605
- '61182.27' => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
606
- '61182.28' => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
607
+ '61182.27' => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42
608
+ '61182.28' => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42
607
609
  '61182.29' => 'Canon RF-S 18-150mm F3.5-6.3 IS STM', #42
608
610
  '61182.30' => 'Canon RF 24mm F1.8 MACRO IS STM', #42
609
611
  '61182.31' => 'Canon RF 16mm F2.8 STM', #42
@@ -612,10 +614,14 @@ $VERSION = '4.60';
612
614
  '61182.34' => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB
613
615
  '61182.35' => 'Canon RF 600mm F4L IS USM', #GiaZopatti
614
616
  '61182.36' => 'Canon RF 15-30mm F4.5-6.3 IS STM', #42
617
+ '61182.37' => 'Canon RF 800mm F5.6L IS USM', #42
618
+ '61182.38' => 'Canon RF 800mm F5.6L IS USM + RF1.4x', #42
619
+ '61182.39' => 'Canon RF 800mm F5.6L IS USM + RF2x', #42
620
+ '61182.40' => 'Canon RF 1200mm F8L IS USM', #42
621
+ '61182.41' => 'Canon RF 1200mm F8L IS USM + RF1.4x', #42
622
+ '61182.42' => 'Canon RF 1200mm F8L IS USM + RF2x', #42
615
623
  # we need the RFLensType values for the following...
616
- '61182.37' => 'Canon RF 800mm F5.6L IS USM', #PH (NC)
617
- '61182.38' => 'Canon RF 1200mm F8L IS USM', #PH (NC)
618
- '61182.39' => 'Canon RF 5.2mm F2.8L Dual Fisheye 3D VR', #PH (NC)
624
+ '61182.43' => 'Canon RF 5.2mm F2.8L Dual Fisheye 3D VR', #PH (NC)
619
625
  65535 => 'n/a',
620
626
  );
621
627
 
@@ -6814,8 +6820,8 @@ my %ciMaxFocal = (
6814
6820
  281 => 'Canon RF 14-35mm F4L IS USM', #42/IB
6815
6821
  282 => 'Canon RF-S 18-45mm F4.5-6.3 IS STM', #42
6816
6822
  283 => 'Canon RF 100-400mm F5.6-8 IS USM', #42
6817
- 284 => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
6818
- 285 => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
6823
+ 284 => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42
6824
+ 285 => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42
6819
6825
  286 => 'Canon RF-S 18-150mm F3.5-6.3 IS STM', #42
6820
6826
  287 => 'Canon RF 24mm F1.8 MACRO IS STM', #42
6821
6827
  288 => 'Canon RF 16mm F2.8 STM', #42
@@ -6823,6 +6829,12 @@ my %ciMaxFocal = (
6823
6829
  290 => 'Canon RF 400mm F2.8L IS USM + RF1.4x', #IB
6824
6830
  291 => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB
6825
6831
  292 => 'Canon RF 600mm F4L IS USM', #GiaZopatti
6832
+ 295 => 'Canon RF 800mm F5.6L IS USM', #42
6833
+ 296 => 'Canon RF 800mm F5.6L IS USM + RF1.4x', #42
6834
+ 297 => 'Canon RF 800mm F5.6L IS USM + RF2x', #42
6835
+ 298 => 'Canon RF 1200mm F8L IS USM', #42
6836
+ 299 => 'Canon RF 1200mm F8L IS USM + RF1.4x', #42
6837
+ 300 => 'Canon RF 1200mm F8L IS USM + RF2x', #42
6826
6838
  302 => 'Canon RF 15-30mm F4.5-6.3 IS STM', #42
6827
6839
  # Note: add new RF lenses to %canonLensTypes with ID 61182
6828
6840
  },
@@ -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.58';
24
+ $VERSION = '1.59';
25
25
 
26
26
  sub WriteCRW($$);
27
27
  sub ProcessCanonRaw($$$);
@@ -625,6 +625,13 @@ sub ProcessCanonRaw($$$)
625
625
  $raf->Seek($blockStart+$blockSize-4, 0) or return 0;
626
626
  $raf->Read($buff, 4) == 4 or return 0;
627
627
  my $dirOffset = Get32u(\$buff,0) + $blockStart;
628
+ # avoid infinite recursion
629
+ $$et{ProcessedCanonRaw} or $$et{ProcessedCanonRaw} = { };
630
+ if ($$et{ProcessedCanonRaw}{$dirOffset}) {
631
+ $et->Warn("Not processing double-referenced $$dirInfo{DirName} directory");
632
+ return 0;
633
+ }
634
+ $$et{ProcessedCanonRaw}{$dirOffset} = 1;
628
635
  $raf->Seek($dirOffset, 0) or return 0;
629
636
  $raf->Read($buff, 2) == 2 or return 0;
630
637
  my $entries = Get16u(\$buff,0); # get number of entries in directory
@@ -56,7 +56,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
56
56
  use Image::ExifTool qw(:DataAccess :Utils);
57
57
  use Image::ExifTool::MakerNotes;
58
58
 
59
- $VERSION = '4.41';
59
+ $VERSION = '4.42';
60
60
 
61
61
  sub ProcessExif($$$);
62
62
  sub WriteExif($$$);
@@ -2080,6 +2080,7 @@ my %opcodeInfo = (
2080
2080
  Groups => { 2 => 'Time' },
2081
2081
  Notes => 'time zone for ModifyDate',
2082
2082
  Writable => 'string',
2083
+ Shift => 'Time',
2083
2084
  PrintConvInv => q{
2084
2085
  return "+00:00" if $val =~ /\d{2}Z$/;
2085
2086
  return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
@@ -2091,6 +2092,7 @@ my %opcodeInfo = (
2091
2092
  Groups => { 2 => 'Time' },
2092
2093
  Notes => 'time zone for DateTimeOriginal',
2093
2094
  Writable => 'string',
2095
+ Shift => 'Time',
2094
2096
  PrintConvInv => q{
2095
2097
  return "+00:00" if $val =~ /\d{2}Z$/;
2096
2098
  return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
@@ -2102,6 +2104,7 @@ my %opcodeInfo = (
2102
2104
  Groups => { 2 => 'Time' },
2103
2105
  Notes => 'time zone for CreateDate',
2104
2106
  Writable => 'string',
2107
+ Shift => 'Time',
2105
2108
  PrintConvInv => q{
2106
2109
  return "+00:00" if $val =~ /\d{2}Z$/;
2107
2110
  return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
@@ -4080,7 +4083,7 @@ my %opcodeInfo = (
4080
4083
  WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4081
4084
  },
4082
4085
  0xcd30 => { # DNG 1.6
4083
- Name => 'SemanticInstanceIFD',
4086
+ Name => 'SemanticInstanceID',
4084
4087
  # Writable => 'string',
4085
4088
  WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4086
4089
  },
@@ -6012,7 +6015,8 @@ sub ProcessExif($$$)
6012
6015
  my $tagID = Get16u($dataPt, $entry);
6013
6016
  my $format = Get16u($dataPt, $entry+2);
6014
6017
  my $count = Get32u($dataPt, $entry+4);
6015
- if ($format < 1 or $format > 13) {
6018
+ # (Apple uses the BigTIFF format code 16 in the maker notes of their ProRaw DNG files)
6019
+ if (($format < 1 or $format > 13) and not ($format == 16 and $$et{Make} eq 'Apple' and $inMakerNotes)) {
6016
6020
  if ($mapFmt and $$mapFmt{$format}) {
6017
6021
  $format = $$mapFmt{$format};
6018
6022
  } else {
@@ -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
  sub ProcessBitStream($$$);
20
20
 
@@ -29,7 +29,19 @@ sub ProcessBitStream($$$);
29
29
  SubDirectory => { TagTable => 'Image::ExifTool::FLAC::StreamInfo' },
30
30
  },
31
31
  1 => { Name => 'Padding', Binary => 1, Unknown => 1 },
32
- 2 => { Name => 'Application', Binary => 1, Unknown => 1 },
32
+ 2 => [{ # (see forum14064)
33
+ Name => 'Application_riff',
34
+ Condition => '$$valPt =~ /^riff(?!RIFF)/', # (all "riff" blocks but header)
35
+ SubDirectory => {
36
+ TagTable => 'Image::ExifTool::RIFF::Main',
37
+ ByteOrder => 'LittleEndian',
38
+ Start => 4,
39
+ },
40
+ },{
41
+ Name => 'ApplicationUnknown',
42
+ Binary => 1,
43
+ Unknown => 1,
44
+ }],
33
45
  3 => { Name => 'SeekTable', Binary => 1, Unknown => 1 },
34
46
  4 => {
35
47
  Name => 'VorbisComment',
@@ -255,9 +267,11 @@ sub ProcessFLAC($$)
255
267
  print $out "FLAC metadata block, type $tag:\n";
256
268
  $et->VerboseDump(\$buff, DataPos => $raf->Tell() - $size);
257
269
  }
258
- $et->HandleTag($tagTablePtr, $tag, undef,
270
+ $et->HandleTag($tagTablePtr, $tag, $buff,
259
271
  DataPt => \$buff,
260
272
  DataPos => $raf->Tell() - $size,
273
+ Start => 0,
274
+ Size => $size,
261
275
  );
262
276
  last if $last; # all done if is set
263
277
  }
@@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
21
21
  use Image::ExifTool::Exif;
22
22
  use Image::ExifTool::ASF; # for GetGUID()
23
23
 
24
- $VERSION = '1.40';
24
+ $VERSION = '1.41';
25
25
 
26
26
  sub ProcessFPX($$);
27
27
  sub ProcessFPXR($$$);
@@ -1338,7 +1338,9 @@ sub ConvertDTTM($)
1338
1338
  my $hr = ($val >> 6) & 0x1f;
1339
1339
  my $min = ($val & 0x3f);
1340
1340
  $yr += 1900 if $val;
1341
- return sprintf("%.4d:%.2d:%.2d %.2d:%.2d:00%s",$yr,$mon,$day,$hr,$min,$val ? 'Z' : '');
1341
+ # ExifTool 12.48 dropped the "Z" on the time here because a test .doc
1342
+ # file written by Word 2011 on Mac certainly used local time here
1343
+ return sprintf("%.4d:%.2d:%.2d %.2d:%.2d:00",$yr,$mon,$day,$hr,$min);
1342
1344
  }
1343
1345
 
1344
1346
  #------------------------------------------------------------------------------
@@ -31,7 +31,7 @@ use vars qw($VERSION);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
  use Image::ExifTool::Exif;
33
33
 
34
- $VERSION = '1.82';
34
+ $VERSION = '1.84';
35
35
 
36
36
  sub ProcessFujiDir($$$);
37
37
  sub ProcessFaceRec($$$);
@@ -254,6 +254,23 @@ my %faceCategories = (
254
254
  0x2e0 => '-4 (weakest)', #10 (-4)
255
255
  },
256
256
  },
257
+ 0x100f => { #PR158
258
+ Name => 'Clarity',
259
+ Writable => 'int32s', #PH
260
+ PrintConv => {
261
+ -5000 => '-5',
262
+ -4000 => '-4',
263
+ -3000 => '-3',
264
+ -2000 => '-2',
265
+ -1000 => '-1',
266
+ 0 => '0',
267
+ 1000 => '1',
268
+ 2000 => '2',
269
+ 3000 => '3',
270
+ 4000 => '4',
271
+ 5000 => '5',
272
+ },
273
+ },
257
274
  0x1010 => {
258
275
  Name => 'FujiFlashMode',
259
276
  Writable => 'int16u',
@@ -444,7 +461,7 @@ my %faceCategories = (
444
461
  PrintConv => { 0 => 'Off', 1 => 'On' },
445
462
  },
446
463
  0x1047 => { #12
447
- Name => 'GrainEffect',
464
+ Name => 'GrainEffectRoughness',
448
465
  Writable => 'int32s',
449
466
  PrintConv => {
450
467
  0 => 'Off',
@@ -469,6 +486,15 @@ my %faceCategories = (
469
486
  PrintConvInv => '$val + 0',
470
487
  },
471
488
  # 0x104b - BWAdjustment for Green->Magenta (forum10800)
489
+ 0x104c => { #PR158
490
+ Name => "GrainEffectSize",
491
+ Writable => 'int16u', #PH
492
+ PrintConv => {
493
+ 0 => 'Off',
494
+ 16 => 'Small',
495
+ 32 => 'Large',
496
+ },
497
+ },
472
498
  0x104d => { #forum9634
473
499
  Name => 'CropMode',
474
500
  Writable => 'int16u',
@@ -763,8 +789,8 @@ my %faceCategories = (
763
789
  },
764
790
  PrintConvInv => '$val=~/(0x[0-9a-f]+)/i; hex $1',
765
791
  },
766
- 0x1447 => { Name => 'FirmwareVersion', Writable => 'string' },
767
- 0x1448 => { Name => 'FirmwareVersion2', Writable => 'string' },
792
+ 0x1447 => { Name => 'FujiModel', Writable => 'string' },
793
+ 0x1448 => { Name => 'FujiModel2', Writable => 'string' },
768
794
  0x3803 => { #forum10037
769
795
  Name => 'VideoRecordingMode',
770
796
  Groups => { 2 => 'Video' },
@@ -1046,7 +1072,7 @@ my %faceCategories = (
1046
1072
  Mask => 0x000000ff,
1047
1073
  PrintConv => {
1048
1074
  0 => 'Single',
1049
- 1 => 'Continuous Low',
1075
+ 1 => 'Continuous Low', # not used by X-H2S? (see forum13777)
1050
1076
  2 => 'Continuous High',
1051
1077
  },
1052
1078
  },
@@ -627,7 +627,7 @@ my %manuSig = ( #6
627
627
  swpt => 'SpectralWhitePoint',
628
628
  s2cp => 'StandardToCustomPcc',
629
629
  smap => 'SurfaceMap',
630
- # smwp ? (seen in some v5 samples)
630
+ # smwp ? (seen in some v5 samples [was a mistake in sample production])
631
631
 
632
632
  # the following entry represents the ICC profile header, and doesn't
633
633
  # exist as a tag in the directory. It is only in this table to provide
@@ -0,0 +1,141 @@
1
+ #------------------------------------------------------------------------------
2
+ # File: ICO.pm
3
+ #
4
+ # Description: Read Windows ICO and CUR files
5
+ #
6
+ # Revisions: 2020-10-18 - P. Harvey Created
7
+ #
8
+ # References: 1) https://docs.fileformat.com/image/ico/
9
+ #------------------------------------------------------------------------------
10
+
11
+ package Image::ExifTool::ICO;
12
+
13
+ use strict;
14
+ use vars qw($VERSION);
15
+ use Image::ExifTool qw(:DataAccess :Utils);
16
+
17
+ $VERSION = '1.00';
18
+
19
+ %Image::ExifTool::ICO::Main = (
20
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
21
+ GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
22
+ NOTES => 'Information extracted from Windows ICO (icon) and CUR (cursor) files.',
23
+ 2 => {
24
+ Name => 'ImageType',
25
+ Format => 'int16u',
26
+ PrintConv => { 1 => 'Icon', 2 => 'Cursor' },
27
+ },
28
+ 4 => {
29
+ Name => 'ImageCount',
30
+ Format => 'int16u',
31
+ RawConv => '$$self{ImageCount} = $val',
32
+ },
33
+ 6 => {
34
+ Name => 'IconDir',
35
+ SubDirectory => { TagTable => 'Image::ExifTool::ICO::IconDir' },
36
+ },
37
+ );
38
+
39
+ %Image::ExifTool::ICO::IconDir = (
40
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
41
+ GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
42
+ 0 => {
43
+ Name => 'ImageWidth',
44
+ ValueConv => '$val or $val + 256',
45
+ },
46
+ 1 => {
47
+ Name => 'ImageHeight',
48
+ ValueConv => '$val or $val + 256',
49
+ },
50
+ 2 => 'NumColors',
51
+ 4 => [{
52
+ Name => 'ColorPlanes',
53
+ Condition => '$$self{FileType} eq "ICO"',
54
+ Format => 'int16u',
55
+ Notes => 'ICO files',
56
+ },{
57
+ Name => 'HotspotX',
58
+ Format => 'int16u',
59
+ Notes => 'CUR files',
60
+ }],
61
+ 6 => [{
62
+ Name => 'BitsPerPixel',
63
+ Condition => '$$self{FileType} eq "ICO"',
64
+ Format => 'int16u',
65
+ Notes => 'ICO files',
66
+ },{
67
+ Name => 'HotspotY',
68
+ Format => 'int16u',
69
+ Notes => 'CUR files',
70
+ }],
71
+ 8 => {
72
+ Name => 'ImageLength',
73
+ Format => 'int32u',
74
+ },
75
+ );
76
+
77
+ #------------------------------------------------------------------------------
78
+ # Process ICO/CUR file
79
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref
80
+ # Returns: 1 on success, 0 if this wasn't a valid ICO/CUR file
81
+ sub ProcessICO($$$)
82
+ {
83
+ my ($et, $dirInfo) = @_;
84
+ my $raf = $$dirInfo{RAF};
85
+ my ($i, $buff);
86
+ # verify this is a valid ICO/CUR file
87
+ return 0 unless $raf->Read($buff, 6) == 6;
88
+ return 0 unless $buff =~ /^\0\0([\x01\x02])\0[^0]\0/s;
89
+ $et->SetFileType($1 eq "\x01" ? 'ICO' : 'CUR');
90
+ SetByteOrder('II');
91
+ my $tagTbl = GetTagTable('Image::ExifTool::ICO::Main');
92
+ my $num = Get16u(\$buff, 4);
93
+ $et->HandleTag($tagTbl, 4, $num);
94
+ for ($i=0; $i<$num; ++$i) {
95
+ $raf->Read($buff, 16) == 16 or $et->Warn('Truncated file'), last;
96
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT} if $i;
97
+ $et->HandleTag($tagTbl, 6, $buff);
98
+ }
99
+ delete $$et{DOC_NUM};
100
+ return 1;
101
+ }
102
+
103
+ 1; # end
104
+
105
+ __END__
106
+
107
+ =head1 NAME
108
+
109
+ Image::ExifTool::ICO - Read ICO meta information
110
+
111
+ =head1 SYNOPSIS
112
+
113
+ This module is used by Image::ExifTool
114
+
115
+ =head1 DESCRIPTION
116
+
117
+ This module contains definitions required by Image::ExifTool to read
118
+ information from Windows ICO (icon) and CUR (cursor) files.
119
+
120
+ =head1 AUTHOR
121
+
122
+ Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com)
123
+
124
+ This library is free software; you can redistribute it and/or modify it
125
+ under the same terms as Perl itself.
126
+
127
+ =head1 REFERENCES
128
+
129
+ =over 4
130
+
131
+ =item L<https://docs.fileformat.com/image/ico/>
132
+
133
+ =back
134
+
135
+ =head1 SEE ALSO
136
+
137
+ L<Image::ExifTool::TagNames/ICO Tags>,
138
+ L<Image::ExifTool(3pm)|Image::ExifTool>
139
+
140
+ =cut
141
+
@@ -18,7 +18,7 @@ use strict;
18
18
  use vars qw($VERSION);
19
19
  use Image::ExifTool qw(:DataAccess :Utils);
20
20
 
21
- $VERSION = '1.57';
21
+ $VERSION = '1.58';
22
22
 
23
23
  sub ProcessID3v2($$$);
24
24
  sub ProcessPrivate($$$);
@@ -1414,13 +1414,13 @@ sub ProcessID3($$)
1414
1414
  if ($flags & 0x40) {
1415
1415
  # skip the extended header
1416
1416
  $size >= 4 or $et->Warn('Bad ID3 extended header'), last;
1417
- my $len = unpack('N', $hBuff);
1418
- if ($len > length($hBuff) - 4) {
1417
+ my $len = UnSyncSafe(unpack('N', $hBuff));
1418
+ if ($len > length($hBuff)) {
1419
1419
  $et->Warn('Truncated ID3 extended header');
1420
1420
  last;
1421
1421
  }
1422
- $hBuff = substr($hBuff, $len + 4);
1423
- $pos += $len + 4;
1422
+ $hBuff = substr($hBuff, $len);
1423
+ $pos += $len;
1424
1424
  }
1425
1425
  if ($flags & 0x10) {
1426
1426
  # ignore v2.4 footer (10 bytes long)
@@ -13,6 +13,7 @@
13
13
  # 6) http://trac.handbrake.fr/browser/trunk/libhb/stream.c
14
14
  # 7) http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=04560141
15
15
  # 8) http://www.w6rz.net/xport.zip
16
+ # 9) https://en.wikipedia.org/wiki/Program-specific_information
16
17
  #
17
18
  # Notes: Variable names containing underlines are the same as in ref 1.
18
19
  #
@@ -31,9 +32,9 @@ use strict;
31
32
  use vars qw($VERSION);
32
33
  use Image::ExifTool qw(:DataAccess :Utils);
33
34
 
34
- $VERSION = '1.21';
35
+ $VERSION = '1.22';
35
36
 
36
- # program map table "stream_type" lookup (ref 6/1)
37
+ # program map table "stream_type" lookup (ref 6/1/9)
37
38
  my %streamType = (
38
39
  0x00 => 'Reserved',
39
40
  0x01 => 'MPEG-1 Video',
@@ -56,9 +57,22 @@ my %streamType = (
56
57
  0x12 => 'MPEG-4 generic',
57
58
  0x13 => 'ISO 14496-1 SL-packetized',
58
59
  0x14 => 'ISO 13818-6 Synchronized Download Protocol',
59
- # 0x15-0x7F => 'ISO 13818-1 Reserved',
60
+ 0x15 => 'Packetized metadata',
61
+ 0x16 => 'Sectioned metadata',
62
+ 0x17 => 'ISO/IEC 13818-6 DSM CC Data Carousel metadata',
63
+ 0x18 => 'ISO/IEC 13818-6 DSM CC Object Carousel metadata',
64
+ 0x19 => 'ISO/IEC 13818-6 Synchronized Download Protocol metadata',
65
+ 0x1a => 'ISO/IEC 13818-11 IPMP',
60
66
  0x1b => 'H.264 (AVC) Video',
67
+ 0x1c => 'ISO/IEC 14496-3 (MPEG-4 raw audio)',
68
+ 0x1d => 'ISO/IEC 14496-17 (MPEG-4 text)',
69
+ 0x1e => 'ISO/IEC 23002-3 (MPEG-4 auxiliary video)',
70
+ 0x1f => 'ISO/IEC 14496-10 SVC (MPEG-4 AVC sub-bitstream)',
71
+ 0x20 => 'ISO/IEC 14496-10 MVC (MPEG-4 AVC sub-bitstream)',
72
+ 0x21 => 'ITU-T Rec. T.800 and ISO/IEC 15444 (JPEG 2000 video)',
61
73
  0x24 => 'H.265 (HEVC) Video', #PH
74
+ 0x42 => 'Chinese Video Standard',
75
+ 0x7f => 'ISO/IEC 13818-11 IPMP (DRM)',
62
76
  0x80 => 'DigiCipher II Video',
63
77
  0x81 => 'A52/AC-3 Audio',
64
78
  0x82 => 'HDMV DTS Audio',
@@ -145,6 +159,7 @@ my $knotsToKph = 1.852; # knots --> km/h
145
159
  # the following tags are for documentation purposes only
146
160
  _AC3 => { SubDirectory => { TagTable => 'Image::ExifTool::M2TS::AC3' } },
147
161
  _H264 => { SubDirectory => { TagTable => 'Image::ExifTool::H264::Main' } },
162
+ _MISB => { SubDirectory => { TagTable => 'Image::ExifTool::MISB::Main' } },
148
163
  );
149
164
 
150
165
  # information extracted from AC-3 audio streams
@@ -278,7 +293,7 @@ sub ParsePID($$$$$)
278
293
  my $verbose = $et->Options('Verbose');
279
294
  if ($verbose > 1) {
280
295
  my $out = $et->Options('TextOut');
281
- printf $out "Parsing stream 0x%.4x (%s)\n", $pid, $pidName;
296
+ printf $out "Parsing stream 0x%.4x (%s) %d bytes\n", $pid, $pidName, length($$dataPt);
282
297
  $et->VerboseDump($dataPt);
283
298
  }
284
299
  my $more = 0;
@@ -303,6 +318,16 @@ sub ParsePID($$$$$)
303
318
  } elsif ($type == 0x81 or $type == 0x87 or $type == 0x91) {
304
319
  # AC-3 audio
305
320
  ParseAC3Audio($et, $dataPt);
321
+ } elsif ($type == 0x15) {
322
+ # packetized metadata (look for MISB code starting after 5-byte header)
323
+ if ($$dataPt =~ /^.{5}\x06\x0e\x2b\x34/s) {
324
+ $more = Image::ExifTool::MISB::ParseMISB($et, $dataPt, GetTagTable('Image::ExifTool::MISB::Main'));
325
+ if (not $$et{OPTIONS}{ExtractEmbedded}) {
326
+ $more = 0; # extract from only the first packet unless ExtractEmbedded is used
327
+ } elsif ($$et{OPTIONS}{ExtractEmbedded} > 2) {
328
+ $more = 1; # read past unknown 0x15 packets if ExtractEmbedded > 2
329
+ }
330
+ }
306
331
  } elsif ($type < 0) {
307
332
  if ($$dataPt =~ /^(.{164})?(.{24})A[NS][EW]/s) {
308
333
  # (Blueskysea B4K, Novatek NT96670)
@@ -426,7 +451,7 @@ sub ProcessM2TS($$)
426
451
  my ($et, $dirInfo) = @_;
427
452
  my $raf = $$dirInfo{RAF};
428
453
  my ($buff, $pLen, $upkPrefix, $j, $fileType, $eof);
429
- my (%pmt, %pidType, %data, %sectLen);
454
+ my (%pmt, %pidType, %data, %sectLen, %packLen, %fromStart);
430
455
  my ($startTime, $endTime, $fwdTime, $backScan, $maxBack);
431
456
  my $verbose = $et->Options('Verbose');
432
457
  my $out = $et->Options('TextOut');
@@ -610,6 +635,7 @@ sub ProcessM2TS($$)
610
635
  $buf2 = $data{$pid};
611
636
  $pos = 0;
612
637
  delete $data{$pid};
638
+ delete $fromStart{$pid};
613
639
  delete $sectLen{$pid};
614
640
  }
615
641
  my $slen = length($buf2); # section length
@@ -736,6 +762,7 @@ sub ProcessM2TS($$)
736
762
  my $more = ParsePID($et, $pid, $pidType{$pid}, $pidName{$pid}, \$data{$pid});
737
763
  # start fresh even if we couldn't process this PID yet
738
764
  delete $data{$pid};
765
+ delete $fromStart{$pid};
739
766
  unless ($more) {
740
767
  delete $needPID{$pid};
741
768
  $didPID{$pid} = 1;
@@ -749,8 +776,8 @@ sub ProcessM2TS($$)
749
776
  my $start_code = Get32u(\$buff, $pos);
750
777
  next unless ($start_code & 0xffffff00) == 0x00000100;
751
778
  my $stream_id = $start_code & 0xff;
779
+ my $pes_packet_length = Get16u(\$buff, $pos + 4);
752
780
  if ($verbose > 1) {
753
- my $pes_packet_length = Get16u(\$buff, $pos + 4);
754
781
  printf $out " Stream ID: 0x%.2x\n", $stream_id;
755
782
  print $out " Packet Len: $pes_packet_length\n";
756
783
  }
@@ -766,6 +793,14 @@ sub ProcessM2TS($$)
766
793
  next if $pos >= $pEnd;
767
794
  }
768
795
  $data{$pid} = substr($buff, $pos, $pEnd-$pos);
796
+ # set flag that we read this payload from the start
797
+ $fromStart{$pid} = 1;
798
+ # save the packet length
799
+ if ($pes_packet_length > 8) {
800
+ $packLen{$pid} = $pes_packet_length - 8; # (where are the 8 extra bytes? - PH)
801
+ } else {
802
+ delete $packLen{$pid};
803
+ }
769
804
  } else {
770
805
  unless (defined $data{$pid}) {
771
806
  # (vsys a6l dashcam GPS record doesn't have a start indicator)
@@ -776,12 +811,24 @@ sub ProcessM2TS($$)
776
811
  $data{$pid} .= substr($buff, $pos, $pEnd-$pos);
777
812
  }
778
813
  # save only the first 256 bytes of most streams, except for
779
- # unknown or H.264 streams where we save 1 kB
780
- my $saveLen = (not $pidType{$pid} or $pidType{$pid} == 0x1b) ? 1024 : 256;
814
+ # unknown, H.264 or metadata streams where we save up to 1 kB
815
+ my $saveLen;
816
+ if (not $pidType{$pid} or $pidType{$pid} == 0x1b) {
817
+ $saveLen = 1024;
818
+ } elsif ($pidType{$pid} == 0x15) {
819
+ # use 1024 or actual size of metadata packet if smaller
820
+ $saveLen = 1024;
821
+ $saveLen = $packLen{$pid} if defined $packLen{$pid} and $saveLen > $packLen{$pid};
822
+ } else {
823
+ $saveLen = 256;
824
+ }
781
825
  if (length($data{$pid}) >= $saveLen) {
782
826
  my $more = ParsePID($et, $pid, $pidType{$pid}, $pidName{$pid}, \$data{$pid});
783
827
  next if $more < 0; # wait for program map table (hopefully not too long)
828
+ # don't stop parsing if we weren't successful and may have missed the start
829
+ $more = 1 if not $more and not $fromStart{$pid};
784
830
  delete $data{$pid};
831
+ delete $fromStart{$pid};
785
832
  $more and $needPID{$pid} = -1, next; # parse more of these
786
833
  delete $needPID{$pid};
787
834
  $didPID{$pid} = 1;