exiftool_vendored 12.06.0 → 12.08.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of exiftool_vendored might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/Changes +26 -2
- data/bin/MANIFEST +3 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +43 -42
- data/bin/exiftool +47 -43
- data/bin/lib/Image/ExifTool.pm +8 -5
- data/bin/lib/Image/ExifTool.pod +41 -40
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +3 -2
- data/bin/lib/Image/ExifTool/Canon.pm +31 -8
- data/bin/lib/Image/ExifTool/DarwinCore.pm +6 -2
- data/bin/lib/Image/ExifTool/EXE.pm +8 -5
- data/bin/lib/Image/ExifTool/Geotag.pm +2 -2
- data/bin/lib/Image/ExifTool/GoPro.pm +47 -22
- data/bin/lib/Image/ExifTool/IPTC.pm +1 -0
- data/bin/lib/Image/ExifTool/MacOS.pm +151 -37
- data/bin/lib/Image/ExifTool/Minolta.pm +4 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +7 -1
- data/bin/lib/Image/ExifTool/Olympus.pm +6 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +12 -12
- data/bin/lib/Image/ExifTool/QuickTime.pm +8 -3
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +18 -8
- data/bin/lib/Image/ExifTool/RSRC.pm +17 -11
- data/bin/lib/Image/ExifTool/Sony.pm +52 -28
- data/bin/lib/Image/ExifTool/TagLookup.pm +4 -0
- data/bin/lib/Image/ExifTool/TagNames.pod +51 -33
- data/bin/lib/Image/ExifTool/XMP.pm +1 -1
- data/bin/perl-Image-ExifTool.spec +42 -41
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +7 -7
@@ -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.
|
38
|
+
$VERSION = '3.38';
|
39
39
|
@ISA = qw(Exporter);
|
40
40
|
|
41
41
|
sub NumbersFirst($$);
|
@@ -633,7 +633,8 @@ L<http://www.metadataworkinggroup.org/> for the official MWG specification.
|
|
633
633
|
MacOS => q{
|
634
634
|
On MacOS systems, the there are additional MDItem and XAttr Finder tags that
|
635
635
|
may be extracted. These tags are not extracted by default -- they must be
|
636
|
-
specifically requested or enabled via an API option.
|
636
|
+
specifically requested or enabled via an API option. (Except when reading
|
637
|
+
MacOS "._" files directly, see below.)
|
637
638
|
|
638
639
|
The tables below list some of the tags that may be extracted, but ExifTool
|
639
640
|
will extract all available information even for tags not listed.
|
@@ -566,14 +566,27 @@ $VERSION = '4.39';
|
|
566
566
|
61494 => 'Canon CN-E 85mm T1.3 L F', #PH
|
567
567
|
61495 => 'Canon CN-E 135mm T2.2 L F', #PH
|
568
568
|
61496 => 'Canon CN-E 35mm T1.5 L F', #PH
|
569
|
-
|
570
|
-
61182
|
571
|
-
61182.
|
572
|
-
61182.
|
573
|
-
61182.
|
574
|
-
61182.
|
575
|
-
61182.
|
576
|
-
61182.
|
569
|
+
# see RFLensType tag for master list of 61182 RF lenses
|
570
|
+
61182 => 'Canon RF 50mm F1.2L USM or other Canon RF Lens',
|
571
|
+
61182.1 => 'Canon RF 24-105mm F4L IS USM',
|
572
|
+
61182.2 => 'Canon RF 28-70mm F2L USM',
|
573
|
+
61182.3 => 'Canon RF 35mm F1.8 MACRO IS STM',
|
574
|
+
61182.4 => 'Canon RF 85mm F1.2L USM',
|
575
|
+
61182.5 => 'Canon RF 85mm F1.2L USM DS',
|
576
|
+
61182.6 => 'Canon RF 24-70mm F2.8L IS USM',
|
577
|
+
61182.7 => 'Canon RF 15-35mm F2.8L IS USM',
|
578
|
+
61182.8 => 'Canon RF 24-240mm F4-6.3 IS USM',
|
579
|
+
61182.9 => 'Canon RF 70-200mm F2.8L IS USM',
|
580
|
+
61182.10 => 'Canon RF 600mm F11 IS STM',
|
581
|
+
61182.11 => 'Canon RF 600mm F11 IS STM + RF1.4x',
|
582
|
+
61182.12 => 'Canon RF 600mm F11 IS STM + RF2x',
|
583
|
+
61182.13 => 'Canon RF 800mm F11 IS STM',
|
584
|
+
61182.14 => 'Canon RF 800mm F11 IS STM + RF1.4x',
|
585
|
+
61182.15 => 'Canon RF 800mm F11 IS STM + RF2x',
|
586
|
+
61182.16 => 'Canon RF 24-105mm F4-7.1 IS STM',
|
587
|
+
61182.17 => 'Canon RF 100-500mm F4.5-7.1L IS USM',
|
588
|
+
61182.18 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF1.4x',
|
589
|
+
61182.19 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF2x',
|
577
590
|
65535 => 'n/a',
|
578
591
|
);
|
579
592
|
|
@@ -6694,7 +6707,17 @@ my %ciMaxFocal = (
|
|
6694
6707
|
264 => 'Canon RF 15-35mm F2.8L IS USM',
|
6695
6708
|
265 => 'Canon RF 24-240mm F4-6.3 IS USM',
|
6696
6709
|
266 => 'Canon RF 70-200mm F2.8L IS USM',
|
6710
|
+
268 => 'Canon RF 600mm F11 IS STM',
|
6711
|
+
269 => 'Canon RF 600mm F11 IS STM + RF1.4x',
|
6712
|
+
270 => 'Canon RF 600mm F11 IS STM + RF2x',
|
6713
|
+
271 => 'Canon RF 800mm F11 IS STM',
|
6714
|
+
272 => 'Canon RF 800mm F11 IS STM + RF1.4x',
|
6715
|
+
273 => 'Canon RF 800mm F11 IS STM + RF2x',
|
6697
6716
|
274 => 'Canon RF 24-105mm F4-7.1 IS STM',
|
6717
|
+
275 => 'Canon RF 100-500mm F4.5-7.1L IS USM',
|
6718
|
+
276 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF1.4x',
|
6719
|
+
277 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF2x',
|
6720
|
+
# Note: add new RF lenses to %canonLensTypes with ID 61182
|
6698
6721
|
},
|
6699
6722
|
},
|
6700
6723
|
);
|
@@ -44,14 +44,18 @@ my %event = (
|
|
44
44
|
Groups => { 2 => 'Time' },
|
45
45
|
Writable => 'string', # (so we can format this ourself)
|
46
46
|
Shift => 'Time',
|
47
|
-
# (
|
47
|
+
# (allow date/time or just time value)
|
48
48
|
ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
|
49
49
|
PrintConv => '$self->ConvertDateTime($val)',
|
50
50
|
ValueConvInv => 'Image::ExifTool::XMP::FormatXMPDate($val) or $val',
|
51
51
|
PrintConvInv => q{
|
52
52
|
my $v = $self->InverseDateTime($val,undef,1);
|
53
53
|
undef $Image::ExifTool::evalWarning;
|
54
|
-
return $v
|
54
|
+
return $v if $v;
|
55
|
+
my @a = ($val =~ /\d{1,2}/g); # get HH, MM and maybe SS
|
56
|
+
return undef unless @a >= 2;
|
57
|
+
$a[2] or $a[2] = 0;
|
58
|
+
return sprintf('%.2d:%.2d:%.2d', @a);
|
55
59
|
},
|
56
60
|
},
|
57
61
|
fieldNotes => { },
|
@@ -21,7 +21,7 @@ use strict;
|
|
21
21
|
use vars qw($VERSION);
|
22
22
|
use Image::ExifTool qw(:DataAccess :Utils);
|
23
23
|
|
24
|
-
$VERSION = '1.
|
24
|
+
$VERSION = '1.17';
|
25
25
|
|
26
26
|
sub ProcessPEResources($$);
|
27
27
|
sub ProcessPEVersion($$);
|
@@ -1009,7 +1009,7 @@ sub ProcessPEDict($$)
|
|
1009
1009
|
my $raf = $$dirInfo{RAF};
|
1010
1010
|
my $dataPt = $$dirInfo{DataPt};
|
1011
1011
|
my $dirLen = length($$dataPt);
|
1012
|
-
my ($pos, @sections, %dirInfo);
|
1012
|
+
my ($pos, @sections, %dirInfo, $rsrcFound);
|
1013
1013
|
|
1014
1014
|
# loop through all sections
|
1015
1015
|
for ($pos=0; $pos+40<=$dirLen; $pos+=40) {
|
@@ -1019,14 +1019,16 @@ sub ProcessPEDict($$)
|
|
1019
1019
|
my $offset = Get32u($dataPt, $pos + 20);
|
1020
1020
|
# remember the section offsets for the VirtualAddress lookup later
|
1021
1021
|
push @sections, { Base => $offset, Size => $size, VirtualAddress => $va };
|
1022
|
-
# save details of the first resource section
|
1022
|
+
# save details of the first resource section (or .text if .rsrc not found, ref forum11465)
|
1023
|
+
next unless ($name eq ".rsrc\0\0\0" and not $rsrcFound and defined($rsrcFound = 1)) or
|
1024
|
+
($name eq ".text\0\0\0" and not %dirInfo);
|
1023
1025
|
%dirInfo = (
|
1024
1026
|
RAF => $raf,
|
1025
1027
|
Base => $offset,
|
1026
1028
|
DirStart => 0, # (relative to Base)
|
1027
1029
|
DirLen => $size,
|
1028
1030
|
Sections => \@sections,
|
1029
|
-
)
|
1031
|
+
);
|
1030
1032
|
}
|
1031
1033
|
# process the first resource section
|
1032
1034
|
ProcessPEResources($et, \%dirInfo) or return 0 if %dirInfo;
|
@@ -1144,7 +1146,8 @@ sub ProcessEXE($$)
|
|
1144
1146
|
my $fileSize = ($cp - ($cblp ? 1 : 0)) * 512 + $cblp;
|
1145
1147
|
#(patch to accommodate observed 64-bit files)
|
1146
1148
|
#return 0 if $fileSize < 0x40 or $fileSize < $lfarlc;
|
1147
|
-
return 0 if $fileSize < 0x40;
|
1149
|
+
#return 0 if $fileSize < 0x40; (changed to warning in ExifTool 12.08)
|
1150
|
+
$et->Warn('Invalid file size in DOS header') if $fileSize < 0x40;
|
1148
1151
|
# read the Windows NE, PE or LE (virtual device driver) header
|
1149
1152
|
#if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and ...
|
1150
1153
|
if ($raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and $buff =~ /^(NE|PE|LE)/) {
|
@@ -27,7 +27,7 @@ use vars qw($VERSION);
|
|
27
27
|
use Image::ExifTool qw(:Public);
|
28
28
|
use Image::ExifTool::GPS;
|
29
29
|
|
30
|
-
$VERSION = '1.
|
30
|
+
$VERSION = '1.63';
|
31
31
|
|
32
32
|
sub JITTER() { return 2 } # maximum time jitter
|
33
33
|
|
@@ -217,7 +217,7 @@ sub LoadTrackLog($$;$)
|
|
217
217
|
# (don't set format yet because we want to read HFDTE first)
|
218
218
|
$nmeaStart = 'B' ;
|
219
219
|
next;
|
220
|
-
} elsif (/^HFDTE(\d{2})(\d{2})(\d{2})/) {
|
220
|
+
} elsif (/^HFDTE(?:DATE:)?(\d{2})(\d{2})(\d{2})/) {
|
221
221
|
my $year = $3 + ($3 >= 70 ? 1900 : 2000);
|
222
222
|
$dateFlarm = Time::Local::timegm(0,0,0,$1,$2-1,$year);
|
223
223
|
$nmeaStart = 'B' ;
|
@@ -16,7 +16,7 @@ use vars qw($VERSION);
|
|
16
16
|
use Image::ExifTool qw(:DataAccess :Utils);
|
17
17
|
use Image::ExifTool::QuickTime;
|
18
18
|
|
19
|
-
$VERSION = '1.
|
19
|
+
$VERSION = '1.05';
|
20
20
|
|
21
21
|
sub ProcessGoPro($$$);
|
22
22
|
sub ProcessString($$$);
|
@@ -77,6 +77,9 @@ my %addUnits = (
|
|
77
77
|
Notes => 'accelerator readings in m/s2',
|
78
78
|
Binary => 1,
|
79
79
|
},
|
80
|
+
# ANGX (GPMF-GEOC) - seen -0.05 (fmt d, Max)
|
81
|
+
# ANGY (GPMF-GEOC) - seen 179.9 (fmt d, Max)
|
82
|
+
# ANGZ (GPMF-GEOC) - seen 0.152 (fmt d, Max)
|
80
83
|
ALLD => 'AutoLowLightDuration', #1 (gpmd) (untested)
|
81
84
|
# APTO (GPMF) - seen: 'RAW', 'DYNM' (fmt c)
|
82
85
|
ATTD => { #PH (Karma)
|
@@ -105,16 +108,14 @@ my %addUnits = (
|
|
105
108
|
},
|
106
109
|
# BRID (GPMF) - seen: 0 (fmt B)
|
107
110
|
# BROD (GPMF) - seen: 'ASK','' (fmt c)
|
111
|
+
# CALH (GPMF-GEOC) - seen 3040 (fmt L, Max)
|
112
|
+
# CALW (GPMF-GEOC) - seen 4056 (fmt L, Max)
|
108
113
|
CASN => 'CameraSerialNumber', #PH (GPMF - seen: 'C3221324545448', fmt c)
|
109
|
-
# CINF (GPMF) - seen: 0x67376be7709bc8876a8baf3940908618, 0xe230988539b30cf5f016627ae8fc5395
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
# TYPE=LLLLLfffBB
|
115
|
-
# SCAL=1000 1 1 1 1 1 1 1 1 1
|
116
|
-
Binary => 1,
|
117
|
-
},
|
114
|
+
# CINF (GPMF) - seen: 0x67376be7709bc8876a8baf3940908618, 0xe230988539b30cf5f016627ae8fc5395,
|
115
|
+
# 0x8bcbe424acc5b37d7d77001635198b3b (fmt B) (Camera INFormation?)
|
116
|
+
# CMOD (GPMF) - seen: 12,13,17 [12 360 video, 13 time-laps video, 17 JPEG] (fmt B)
|
117
|
+
# CRTX (GPMF-BACK/FRNT) - double[1]
|
118
|
+
# CRTY (GPMF-BACK/FRNT) - double[1]
|
118
119
|
CSEN => { #PH (Karma)
|
119
120
|
Name => 'CoyoteSense',
|
120
121
|
# UNIT=s,rad/s,rad/s,rad/s,g,g,g,,,,
|
@@ -122,13 +123,27 @@ my %addUnits = (
|
|
122
123
|
# SCAL=1000 1 1 1 1 1 1 1 1 1 1
|
123
124
|
Binary => 1,
|
124
125
|
},
|
126
|
+
CYTS => { #PH (Karma)
|
127
|
+
Name => 'CoyoteStatus',
|
128
|
+
# UNIT=s,,,,,rad,rad,rad,,
|
129
|
+
# TYPE=LLLLLfffBB
|
130
|
+
# SCAL=1000 1 1 1 1 1 1 1 1 1
|
131
|
+
Binary => 1,
|
132
|
+
},
|
125
133
|
DEVC => { #PH (gpmd,GPMF, fmt \0)
|
126
134
|
Name => 'DeviceContainer',
|
127
135
|
SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
|
128
|
-
|
129
|
-
|
136
|
+
# (Max) DVID=1,DVNM='Global Settings',VERS,FMWR,LINF,CINF,CASN,MINF,MUID,CMOD,MTYP,OREN,
|
137
|
+
# DZOM,DZST,SMTR,PRTN,PTWB,PTSH,PTCL,EXPT,PIMX,PIMN,PTEV,RATE,SROT,ZFOV,VLTE,VLTA,
|
138
|
+
# EISE,EISA,AUPT,AUDO,BROD,BRID,PVUL,PRJT,SOFF
|
139
|
+
# (Max) DVID='GEOC',DVNM='Geometry Calibrations',SHFX,SHFY,SHFZ,ANGX,ANGY,ANGZ,CALW,CALH
|
140
|
+
# (Max) DVID='BACK',DVNM='Back Lens',KLNS,CTRX,CTRY,MFOV,SFTR
|
141
|
+
# (Max) DVID='FRNT',DVNM='Front Lens',KLNS,CTRX,CTRY,MFOV,SFTR
|
142
|
+
# (Max) DVID='HLMT',DVNM='Highlights'
|
143
|
+
},
|
144
|
+
# DVID (GPMF) - DeviceID; seen: 1 (fmt L), HLMT (fmt F), GEOC (fmt F), 'BACK' (fmt F, Max)
|
130
145
|
DVID => { Name => 'DeviceID', Unknown => 1 }, #2 (gpmd)
|
131
|
-
# DVNM (GPMF) seen: 'Video Global Settings' (fmt c), 'Highlights' (fmt c)
|
146
|
+
# DVNM (GPMF) seen: 'Video Global Settings' (fmt c), 'Highlights' (fmt c), 'Geometry Calibrations' (Max)
|
132
147
|
# DVNM (gpmd) seen: 'Camera' (Hero5), 'Hero6 Black' (Hero6), 'GoPro Karma v1.0' (Karma)
|
133
148
|
DVNM => 'DeviceName', #PH (n/c)
|
134
149
|
DZOM => { #PH (GPMF - seen: 'Y', fmt c)
|
@@ -136,10 +151,10 @@ my %addUnits = (
|
|
136
151
|
PrintConv => { N => 'No', Y => 'Yes' },
|
137
152
|
},
|
138
153
|
# DZST (GPMF) - seen: 0 (fmt L) (something to do with digital zoom maybe?)
|
139
|
-
EISA => { #PH (GPMF) - seen: 'Y','N',
|
154
|
+
EISA => { #PH (GPMF) - seen: 'Y','N','HS EIS','N/A' (fmt c) [N was for a time-lapse video]
|
140
155
|
Name => 'ElectronicImageStabilization',
|
141
156
|
},
|
142
|
-
# EISE (GPMF) - seen: 'Y' (fmt c)
|
157
|
+
# EISE (GPMF) - seen: 'Y','N' (fmt c)
|
143
158
|
EMPT => { Name => 'Empty', Unknown => 1 }, #2 (gpmd)
|
144
159
|
ESCS => { #PH (Karma)
|
145
160
|
Name => 'EscapeStatus',
|
@@ -215,7 +230,8 @@ my %addUnits = (
|
|
215
230
|
RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data
|
216
231
|
SubDirectory => { TagTable => 'Image::ExifTool::GoPro::KBAT' },
|
217
232
|
},
|
218
|
-
#
|
233
|
+
# KLNS (GPMF-BACK/FRNT) - double[5] (fmt d, Max)
|
234
|
+
# LINF (GPMF) - seen: LAJ7061916601668,C3341326002180,C33632245450981 (fmt c) (Lens INFormation?)
|
219
235
|
LNED => { #PH (Karma)
|
220
236
|
Name => 'LocalPositionNED',
|
221
237
|
# UNIT=s,m,m,m,m/s,m/s,m/s
|
@@ -224,12 +240,13 @@ my %addUnits = (
|
|
224
240
|
Binary => 1,
|
225
241
|
},
|
226
242
|
MAGN => 'Magnetometer', #1 (gpmd) (units of uT)
|
243
|
+
# MFOV (GPMF-BACK/FRNT) - seen: 100 (fmt d, Max)
|
227
244
|
MINF => { #PH (GPMF - seen: HERO6 Black, fmt c)
|
228
245
|
Name => 'Model',
|
229
246
|
Groups => { 2 => 'Camera' },
|
230
247
|
Description => 'Camera Model Name',
|
231
248
|
},
|
232
|
-
# MTYP (GPMF) - seen: 0,1,11 [1 for time-lapse video, 11 for JPEG] (fmt B)
|
249
|
+
# MTYP (GPMF) - seen: 0,1,5,11 [1 for time-lapse video, 5 for 360 video, 11 for JPEG] (fmt B)
|
233
250
|
# MUID (GPMF) - seen: 3882563431 2278071152 967805802 411471936 0 0 0 0 (fmt L)
|
234
251
|
OREN => { #PH (GPMF - seen: 'U', fmt c)
|
235
252
|
Name => 'AutoRotation',
|
@@ -245,7 +262,7 @@ my %addUnits = (
|
|
245
262
|
PIMX => 'AutoISOMax', #PH (GPMF - seen: 1600, fmt L)
|
246
263
|
# PRAW (APP6) - seen: 0, 'N', 'Y' (fmt c)
|
247
264
|
PRES => 'PhotoResolution', #PH (APP6 - seen: '12MP_W')
|
248
|
-
# PRJT (APP6) - seen: 'GPRO' (fmt F, Hero8)
|
265
|
+
# PRJT (APP6) - seen: 'GPRO','EACO' (fmt F, Hero8, Max)
|
249
266
|
PRTN => { #PH (GPMF - seen: 'N', fmt c)
|
250
267
|
Name => 'ProTune',
|
251
268
|
PrintConv => {
|
@@ -257,7 +274,7 @@ my %addUnits = (
|
|
257
274
|
PTEV => 'ExposureCompensation', #PH (GPMF - seen: '0.0', fmt c)
|
258
275
|
PTSH => 'Sharpness', #PH (GPMF - seen: 'HIGH', fmt c)
|
259
276
|
PTWB => 'WhiteBalance', #PH (GPMF - seen: 'AUTO', fmt c)
|
260
|
-
# PVUL (APP6) - seen: 'F' (fmt c, Hero8)
|
277
|
+
# PVUL (APP6) - seen: 'F' (fmt c, Hero8, Max)
|
261
278
|
RATE => 'Rate', #PH (GPMF - seen: '0_5SEC', fmt c; APP6 - seen: '4_1SEC')
|
262
279
|
RMRK => { #2 (gpmd)
|
263
280
|
Name => 'Comments',
|
@@ -274,6 +291,10 @@ my %addUnits = (
|
|
274
291
|
# SCAL=1000 0.00999999977648258 0.00999999977648258 100
|
275
292
|
%addUnits,
|
276
293
|
},
|
294
|
+
# SFTR (GPMF-BACK/FRNT) - seen 0.999,1.00004 (fmt d, Max)
|
295
|
+
# SHFX (GPMF-GEOC) - seen 22.92 (fmt d, Max)
|
296
|
+
# SHFY (GPMF-GEOC) - seen 0.123 (fmt d, Max)
|
297
|
+
# SHFZ (GPMF-GEOC) - seen 36.06 (fmt d, Max)
|
277
298
|
SHUT => { #2 (gpmd)
|
278
299
|
Name => 'ExposureTimes',
|
279
300
|
PrintConv => q{
|
@@ -295,7 +316,8 @@ my %addUnits = (
|
|
295
316
|
ValueConv => '$self->Decode($val, "Latin")',
|
296
317
|
},
|
297
318
|
# SMTR (GPMF) - seen: 'N' (fmt c)
|
298
|
-
# SOFF (APP6) - seen: 0 (fmt L, Hero8)
|
319
|
+
# SOFF (APP6) - seen: 0 (fmt L, Hero8, Max)
|
320
|
+
# SROT (GPMF) - seen 20.60 (fmt f, Max)
|
299
321
|
STMP => { #1 (gpmd)
|
300
322
|
Name => 'TimeStamp',
|
301
323
|
ValueConv => '$val / 1e6',
|
@@ -338,7 +360,10 @@ my %addUnits = (
|
|
338
360
|
Unknown => 1,
|
339
361
|
ValueConv => '$self->Decode($val, "Latin")',
|
340
362
|
},
|
341
|
-
|
363
|
+
VERS => {
|
364
|
+
Name => 'MetadataVersion',
|
365
|
+
PrintConv => '$val =~ tr/ /./; $val',
|
366
|
+
},
|
342
367
|
VFOV => { #PH (GPMF - seen: 'W', fmt c)
|
343
368
|
Name => 'FieldOfView',
|
344
369
|
PrintConv => {
|
@@ -360,7 +385,7 @@ my %addUnits = (
|
|
360
385
|
Name => 'WhiteBalanceRGB',
|
361
386
|
Binary => 1,
|
362
387
|
},
|
363
|
-
# ZFOV (APP6) - seen: 148.34 (fmt f, Hero8)
|
388
|
+
# ZFOV (APP6,GPMF) - seen: 148.34, 0 (fmt f, Hero8, Max)
|
364
389
|
);
|
365
390
|
|
366
391
|
# GoPro GPS5 tags (ref 2) (Hero5,Hero6)
|
@@ -4,6 +4,7 @@
|
|
4
4
|
# Description: Read/write MacOS system tags
|
5
5
|
#
|
6
6
|
# Revisions: 2017/03/01 - P. Harvey Created
|
7
|
+
# 2020/10/13 - PH Added ability to read MacOS "._" files
|
7
8
|
#------------------------------------------------------------------------------
|
8
9
|
|
9
10
|
package Image::ExifTool::MacOS;
|
@@ -11,15 +12,38 @@ use strict;
|
|
11
12
|
use vars qw($VERSION);
|
12
13
|
use Image::ExifTool qw(:DataAccess :Utils);
|
13
14
|
|
14
|
-
$VERSION = '1.
|
15
|
+
$VERSION = '1.10';
|
15
16
|
|
16
17
|
sub MDItemLocalTime($);
|
18
|
+
sub ProcessATTR($$$);
|
17
19
|
|
18
20
|
my %mdDateInfo = (
|
19
21
|
ValueConv => \&MDItemLocalTime,
|
20
22
|
PrintConv => '$self->ConvertDateTime($val)',
|
21
23
|
);
|
22
24
|
|
25
|
+
# Information decoded from Mac OS sidecar files
|
26
|
+
%Image::ExifTool::MacOS::Main = (
|
27
|
+
GROUPS => { 0 => 'File', 1 => 'MacOS' },
|
28
|
+
NOTES => q{
|
29
|
+
Note that on some filesystems, MacOS creates sidecar files with names that
|
30
|
+
begin with "._". ExifTool will read these files if specified, and extract
|
31
|
+
the information listed in the following table without the need for extra
|
32
|
+
options, but these files are not writable directly.
|
33
|
+
},
|
34
|
+
2 => {
|
35
|
+
Name => 'RSRC',
|
36
|
+
SubDirectory => { TagTable => 'Image::ExifTool::RSRC::Main' },
|
37
|
+
},
|
38
|
+
9 => {
|
39
|
+
Name => 'ATTR',
|
40
|
+
SubDirectory => {
|
41
|
+
TagTable => 'Image::ExifTool::MacOS::XAttr',
|
42
|
+
ProcessProc => \&ProcessATTR,
|
43
|
+
},
|
44
|
+
},
|
45
|
+
);
|
46
|
+
|
23
47
|
# "mdls" tags (ref PH)
|
24
48
|
%Image::ExifTool::MacOS::MDItem = (
|
25
49
|
WRITE_PROC => \&Image::ExifTool::DummyWriteProc,
|
@@ -221,6 +245,8 @@ my %mdDateInfo = (
|
|
221
245
|
XAttr tags are extracted using the "xattr" utility. They are extracted if
|
222
246
|
any "XAttr*" tag or the MacOS group is specifically requested, or by setting
|
223
247
|
the L<XAttrTags|../ExifTool.html#XAttrTags> API option to 1 or the L<RequestAll|../ExifTool.html#RequestAll> API option to 2 or higher.
|
248
|
+
And they extracted by default from MacOS "._" files when reading
|
249
|
+
these files directly.
|
224
250
|
},
|
225
251
|
'com.apple.FinderInfo' => {
|
226
252
|
Name => 'XAttrFinderInfo',
|
@@ -486,8 +512,50 @@ sub ExtractMDItemTags($$)
|
|
486
512
|
$$et{INDENT} =~ s/\| $//;
|
487
513
|
}
|
488
514
|
|
515
|
+
|
489
516
|
#------------------------------------------------------------------------------
|
490
|
-
#
|
517
|
+
# Read MacOS XAttr value
|
518
|
+
# Inputs: 0) ExifTool object ref, 1) file name
|
519
|
+
sub ReadXAttrValue($$$$)
|
520
|
+
{
|
521
|
+
my ($et, $tagTablePtr, $tag, $val) = @_;
|
522
|
+
# add to our table if necessary
|
523
|
+
unless ($$tagTablePtr{$tag}) {
|
524
|
+
my $name;
|
525
|
+
# generate tag name from attribute name
|
526
|
+
if ($tag =~ /^com\.apple\.(.*)$/) {
|
527
|
+
($name = $1) =~ s/^metadata:_?k//;
|
528
|
+
$name =~ s/^metadata:(com_)?//;
|
529
|
+
} else {
|
530
|
+
$name = $tag;
|
531
|
+
}
|
532
|
+
$name =~ s/[.:_]([a-z])/\U$1/g;
|
533
|
+
$name = 'XAttr' . ucfirst $name;
|
534
|
+
my %tagInfo = ( Name => $name );
|
535
|
+
$tagInfo{Groups} = { 2 => 'Time' } if $tag=~/Date$/;
|
536
|
+
$et->VPrint(0, " [adding $tag]\n");
|
537
|
+
AddTagToTable($tagTablePtr, $tag, \%tagInfo);
|
538
|
+
}
|
539
|
+
if ($val =~ /^bplist0/) {
|
540
|
+
my %dirInfo = ( DataPt => \$val );
|
541
|
+
require Image::ExifTool::PLIST;
|
542
|
+
if (Image::ExifTool::PLIST::ProcessBinaryPLIST($et, \%dirInfo, $tagTablePtr)) {
|
543
|
+
return undef if ref $dirInfo{Value} eq 'HASH';
|
544
|
+
$val = $dirInfo{Value}
|
545
|
+
} else {
|
546
|
+
$et->Warn("Error decoding $$tagTablePtr{$tag}{Name}");
|
547
|
+
return undef;
|
548
|
+
}
|
549
|
+
}
|
550
|
+
if (not ref $val and ($val =~ /\0/ or length($val) > 200) or $tag eq 'XAttrMDLabel') {
|
551
|
+
my $buff = $val;
|
552
|
+
$val = \$buff;
|
553
|
+
}
|
554
|
+
return $val;
|
555
|
+
}
|
556
|
+
|
557
|
+
#------------------------------------------------------------------------------
|
558
|
+
# Read MacOS extended attribute tags using 'xattr' utility
|
491
559
|
# Inputs: 0) ExifTool object ref, 1) file name
|
492
560
|
sub ExtractXAttrTags($$)
|
493
561
|
{
|
@@ -517,39 +585,8 @@ sub ExtractXAttrTags($$)
|
|
517
585
|
$val .= pack('H*', $_);
|
518
586
|
next;
|
519
587
|
} elsif ($tag and defined $val) {
|
520
|
-
|
521
|
-
|
522
|
-
my $name;
|
523
|
-
# generate tag name from attribute name
|
524
|
-
if ($tag =~ /^com\.apple\.(.*)$/) {
|
525
|
-
($name = $1) =~ s/^metadata:_?k//;
|
526
|
-
$name =~ s/^metadata:(com_)?//;
|
527
|
-
} else {
|
528
|
-
$name = $tag;
|
529
|
-
}
|
530
|
-
$name =~ s/[.:_]([a-z])/\U$1/g;
|
531
|
-
$name = 'XAttr' . ucfirst $name;
|
532
|
-
my %tagInfo = ( Name => $name );
|
533
|
-
$tagInfo{Groups} = { 2 => 'Time' } if $tag=~/Date$/;
|
534
|
-
$et->VPrint(0, " [adding $tag]\n");
|
535
|
-
AddTagToTable($tagTablePtr, $tag, \%tagInfo);
|
536
|
-
}
|
537
|
-
if ($val =~ /^bplist0/) {
|
538
|
-
my %dirInfo = ( DataPt => \$val );
|
539
|
-
require Image::ExifTool::PLIST;
|
540
|
-
if (Image::ExifTool::PLIST::ProcessBinaryPLIST($et, \%dirInfo, $tagTablePtr)) {
|
541
|
-
next if ref $dirInfo{Value} eq 'HASH';
|
542
|
-
$val = $dirInfo{Value}
|
543
|
-
} else {
|
544
|
-
$et->Warn("Error decoding $$tagTablePtr{$tag}{Name}");
|
545
|
-
next;
|
546
|
-
}
|
547
|
-
}
|
548
|
-
if (not ref $val and ($val =~ /\0/ or length($val) > 200) or $tag eq 'XAttrMDLabel') {
|
549
|
-
my $buff = $val;
|
550
|
-
$val = \$buff;
|
551
|
-
}
|
552
|
-
$et->HandleTag($tagTablePtr, $tag, $val);
|
588
|
+
$val = ReadXAttrValue($et, $tagTablePtr, $tag, $val);
|
589
|
+
$et->HandleTag($tagTablePtr, $tag, $val) if defined $val;
|
553
590
|
undef $tag;
|
554
591
|
undef $val;
|
555
592
|
}
|
@@ -584,6 +621,82 @@ sub GetFileCreateDate($$)
|
|
584
621
|
delete $$et{SET_GROUP1};
|
585
622
|
}
|
586
623
|
|
624
|
+
#------------------------------------------------------------------------------
|
625
|
+
# Read ATTR metadata from "._" file
|
626
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
627
|
+
# Return: 1 on success
|
628
|
+
# (ref https://www.swiftforensics.com/2018/11/the-dot-underscore-file-format.html)
|
629
|
+
sub ProcessATTR($$$)
|
630
|
+
{
|
631
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
632
|
+
my $dataPt = $$dirInfo{DataPt};
|
633
|
+
my $dataPos = $$dirInfo{DataPos};
|
634
|
+
my $dataLen = length $$dataPt;
|
635
|
+
|
636
|
+
$dataLen >= 58 and $$dataPt =~ /^.{34}ATTR/s or $et->Warn('Invalid ATTR header'), return 0;
|
637
|
+
my $entries = Get32u($dataPt, 66);
|
638
|
+
$et->VerboseDir('ATTR', $entries);
|
639
|
+
# (Note: The RAF is not in $dirInfo because it would break RSRC reading --
|
640
|
+
# the RSCR block uses relative offsets, while the ATTR block uses absolute! grrr!)
|
641
|
+
my $raf = $$et{RAF};
|
642
|
+
my $pos = 70; # first entry is after ATTR header
|
643
|
+
my $i;
|
644
|
+
for ($i=0; $i<$entries; ++$i) {
|
645
|
+
$pos + 12 > $dataLen and $et->Warn('Truncated ATTR entry'), last;
|
646
|
+
my $off = Get32u($dataPt, $pos);
|
647
|
+
my $len = Get32u($dataPt, $pos + 4);
|
648
|
+
my $n = Get8u($dataPt, $pos + 10); # number of characters in tag name
|
649
|
+
$pos + 11 + $n > $dataLen and $et->Warn('Truncated ATTR name'), last;
|
650
|
+
$off -= $dataPos; # convert to relative offset (grrr!)
|
651
|
+
$off < 0 or $off > $dataLen and $et->Warn('Invalid ATTR offset'), last;
|
652
|
+
my $tag = substr($$dataPt, $pos + 11, $n);
|
653
|
+
$tag =~ s/\0+$//; # remove null terminator
|
654
|
+
$off + $len > $dataLen and $et->Warn('Truncated ATTR value'), last;
|
655
|
+
my $val = ReadXAttrValue($et, $tagTablePtr, $tag, substr($$dataPt, $off, $len));
|
656
|
+
$et->HandleTag($tagTablePtr, $tag, $val,
|
657
|
+
DataPt => $dataPt,
|
658
|
+
DataPos => $dataPos,
|
659
|
+
Start => $off,
|
660
|
+
Size => $len,
|
661
|
+
) if defined $val;
|
662
|
+
$pos += (11 + $n + 3) & -4; # step to next entry (on even 4-byte boundary)
|
663
|
+
}
|
664
|
+
return 1;
|
665
|
+
}
|
666
|
+
|
667
|
+
#------------------------------------------------------------------------------
|
668
|
+
# Read information from a MacOS "._" sidecar file
|
669
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref
|
670
|
+
# Returns: 1 on success, 0 if this wasn't a valid "._" file
|
671
|
+
# (ref https://www.swiftforensics.com/2018/11/the-dot-underscore-file-format.html)
|
672
|
+
sub ProcessMacOS($$)
|
673
|
+
{
|
674
|
+
my ($et, $dirInfo) = @_;
|
675
|
+
my $raf = $$dirInfo{RAF};
|
676
|
+
my ($hdr, $buff, $i);
|
677
|
+
|
678
|
+
return 0 unless $raf->Read($hdr, 26) == 26 and $hdr =~ /^\0\x05\x16\x07\0(.)\0\0Mac OS X /s;
|
679
|
+
my $ver = ord $1;
|
680
|
+
# (extension may be anything, so just echo back the incoming file extension if it exists)
|
681
|
+
$et->SetFileType(undef, undef, $$et{FILE_EXT});
|
682
|
+
$ver == 2 or $et->Warn("Unsupported file version $ver"), return 1;
|
683
|
+
SetByteOrder('MM');
|
684
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::MacOS::Main');
|
685
|
+
my $entries = Get16u(\$hdr, 0x18);
|
686
|
+
$et->VerboseDir('MacOS', $entries);
|
687
|
+
$raf->Read($hdr, $entries * 12) == $entries * 12 or $et->Warn('Truncated header'), return 1;
|
688
|
+
for ($i=0; $i<$entries; ++$i) {
|
689
|
+
my $pos = $i * 12;
|
690
|
+
my $tag = Get32u(\$hdr, $pos);
|
691
|
+
my $off = Get32u(\$hdr, $pos + 4);
|
692
|
+
my $len = Get32u(\$hdr, $pos + 8);
|
693
|
+
$len > 100000000 and $et->Warn('Record size too large'), last;
|
694
|
+
$raf->Seek($off,0) and $raf->Read($buff,$len) == $len or $et->Warn('Truncated record'), last;
|
695
|
+
$et->HandleTag($tagTablePtr, $tag, undef, DataPt => \$buff, DataPos => $off, Index => $i);
|
696
|
+
}
|
697
|
+
return 1;
|
698
|
+
}
|
699
|
+
|
587
700
|
1; # end
|
588
701
|
|
589
702
|
__END__
|
@@ -600,8 +713,9 @@ This module is used by Image::ExifTool
|
|
600
713
|
|
601
714
|
This module contains definitions required by Image::ExifTool to extract
|
602
715
|
MDItem* and XAttr* tags on MacOS systems using the "mdls" and "xattr"
|
603
|
-
utilities respectively.
|
604
|
-
|
716
|
+
utilities respectively. It also reads metadata directly from the MacOS "_."
|
717
|
+
sidecar files that are used on some filesystems to store file attributes.
|
718
|
+
Writable tags use "xattr", "setfile" or "osascript" for writing.
|
605
719
|
|
606
720
|
=head1 AUTHOR
|
607
721
|
|