exiftool_vendored 12.60.0 → 12.62.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +35 -0
- data/bin/MANIFEST +7 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +45 -44
- data/bin/exiftool +100 -73
- data/bin/lib/Image/ExifTool/BMP.pm +0 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +4 -4
- data/bin/lib/Image/ExifTool/FlashPix.pm +2 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +31 -6
- data/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +3 -3
- data/bin/lib/Image/ExifTool/PDF.pm +17 -8
- data/bin/lib/Image/ExifTool/QuickTime.pm +10 -7
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +51 -21
- data/bin/lib/Image/ExifTool/Sony.pm +16 -10
- data/bin/lib/Image/ExifTool/TagLookup.pm +9 -0
- data/bin/lib/Image/ExifTool/TagNames.pod +34 -5
- data/bin/lib/Image/ExifTool/WPG.pm +296 -0
- data/bin/lib/Image/ExifTool/WritePDF.pl +7 -8
- data/bin/lib/Image/ExifTool/Writer.pl +12 -4
- data/bin/lib/Image/ExifTool/XMP.pm +17 -5
- data/bin/lib/Image/ExifTool/ZIP.pm +159 -41
- data/bin/lib/Image/ExifTool.pm +118 -50
- data/bin/lib/Image/ExifTool.pod +51 -42
- data/bin/perl-Image-ExifTool.spec +44 -43
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -11,6 +11,7 @@
|
|
11
11
|
# 4) http://DataCompression.info/ArchiveFormats/RAR202.txt
|
12
12
|
# 5) https://jira.atlassian.com/browse/CONF-21706
|
13
13
|
# 6) http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/indesign/cs55-docs/IDML/idml-specification.pdf
|
14
|
+
# 7) https://www.rarlab.com/technote.htm
|
14
15
|
#------------------------------------------------------------------------------
|
15
16
|
|
16
17
|
package Image::ExifTool::ZIP;
|
@@ -19,7 +20,7 @@ use strict;
|
|
19
20
|
use vars qw($VERSION $warnString);
|
20
21
|
use Image::ExifTool qw(:DataAccess :Utils);
|
21
22
|
|
22
|
-
$VERSION = '1.
|
23
|
+
$VERSION = '1.29';
|
23
24
|
|
24
25
|
sub WarnProc($) { $warnString = $_[0]; }
|
25
26
|
|
@@ -191,7 +192,7 @@ my %iWorkType = (
|
|
191
192
|
11 => 'Comment',
|
192
193
|
);
|
193
194
|
|
194
|
-
# RAR tags (ref 4)
|
195
|
+
# RAR v4 tags (ref 4)
|
195
196
|
%Image::ExifTool::ZIP::RAR = (
|
196
197
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
197
198
|
GROUPS => { 2 => 'Other' },
|
@@ -254,8 +255,45 @@ my %iWorkType = (
|
|
254
255
|
},
|
255
256
|
);
|
256
257
|
|
258
|
+
# RAR v5 tags (ref 7, github#203)
|
259
|
+
%Image::ExifTool::ZIP::RAR5 = (
|
260
|
+
GROUPS => { 2 => 'Other' },
|
261
|
+
VARS => { NO_ID => 1 },
|
262
|
+
NOTES => 'These tags are extracted from RAR v5 archive files.',
|
263
|
+
RARVersion => { },
|
264
|
+
CompressedSize => { },
|
265
|
+
ModifyDate => {
|
266
|
+
Groups => { 2 => 'Time' },
|
267
|
+
ValueConv => 'ConvertUnixTime($val,1)',
|
268
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
269
|
+
},
|
270
|
+
UncompressedSize => { },
|
271
|
+
OperatingSystem => {
|
272
|
+
PrintConv => { 0 => 'Win32', 1 => 'Unix' },
|
273
|
+
},
|
274
|
+
ArchivedFileName => { },
|
275
|
+
);
|
276
|
+
|
277
|
+
#------------------------------------------------------------------------------
|
278
|
+
# Read unsigned LEB (Little Endian Base) from file
|
279
|
+
# Inputs: 0) RAF ref
|
280
|
+
# Returns: integer value
|
281
|
+
sub ReadULEB($)
|
282
|
+
{
|
283
|
+
my $raf = shift;
|
284
|
+
my ($i, $buff);
|
285
|
+
my $rtnVal = 0;
|
286
|
+
for ($i=0; ; ++$i) {
|
287
|
+
$raf->Read($buff, 1) or last;
|
288
|
+
my $num = ord($buff);
|
289
|
+
$rtnVal += ($num & 0x7f) << ($i * 7);
|
290
|
+
$num & 0x80 or last;
|
291
|
+
}
|
292
|
+
return $rtnVal;
|
293
|
+
}
|
294
|
+
|
257
295
|
#------------------------------------------------------------------------------
|
258
|
-
# Extract information from a RAR file
|
296
|
+
# Extract information from a RAR file
|
259
297
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
260
298
|
# Returns: 1 on success, 0 if this wasn't a valid RAR file
|
261
299
|
sub ProcessRAR($$)
|
@@ -263,51 +301,129 @@ sub ProcessRAR($$)
|
|
263
301
|
my ($et, $dirInfo) = @_;
|
264
302
|
my $raf = $$dirInfo{RAF};
|
265
303
|
my ($flags, $buff);
|
304
|
+
my $docNum = 0;
|
266
305
|
|
267
|
-
return 0 unless $raf->Read($buff, 7) and $buff
|
306
|
+
return 0 unless $raf->Read($buff, 7) and $buff =~ "Rar!\x1a\x07[\0\x01]";
|
268
307
|
|
269
|
-
$
|
270
|
-
SetByteOrder('II');
|
271
|
-
my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR');
|
272
|
-
my $docNum = 0;
|
308
|
+
if ($buff eq "Rar!\x1a\x07\0") { # RARv4 (ref 4)
|
273
309
|
|
274
|
-
|
275
|
-
|
276
|
-
$
|
277
|
-
|
278
|
-
$
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
310
|
+
$et->SetFileType();
|
311
|
+
SetByteOrder('II');
|
312
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR5');
|
313
|
+
$et->HandleTag($tagTablePtr, 'RARVersion', 4);
|
314
|
+
$tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR');
|
315
|
+
|
316
|
+
for (;;) {
|
317
|
+
# read block header
|
318
|
+
$raf->Read($buff, 7) == 7 or last;
|
319
|
+
my ($type, $flags, $size) = unpack('xxCvv', $buff);
|
320
|
+
$size -= 7;
|
321
|
+
if ($flags & 0x8000) {
|
322
|
+
$raf->Read($buff, 4) == 4 or last;
|
323
|
+
$size += unpack('V',$buff) - 4;
|
324
|
+
}
|
325
|
+
last if $size < 0;
|
326
|
+
next unless $size; # ignore blocks with no data
|
327
|
+
# don't try to read very large blocks unless LargeFileSupport is enabled
|
328
|
+
if ($size >= 0x80000000 and not $et->Options('LargeFileSupport')) {
|
329
|
+
$et->Warn('Large block encountered. Aborting.');
|
330
|
+
last;
|
331
|
+
}
|
332
|
+
# process the block
|
333
|
+
if ($type == 0x74) { # file block
|
334
|
+
# read maximum 4 KB from a file block
|
335
|
+
my $n = $size > 4096 ? 4096 : $size;
|
336
|
+
$raf->Read($buff, $n) == $n or last;
|
337
|
+
# add compressed size to start of data so we can extract it with the other tags
|
338
|
+
$buff = pack('V',$size) . $buff;
|
339
|
+
$$et{DOC_NUM} = ++$docNum;
|
340
|
+
$et->ProcessDirectory({ DataPt => \$buff }, $tagTablePtr);
|
341
|
+
$size -= $n;
|
342
|
+
} elsif ($type == 0x75 and $size > 6) { # comment block
|
343
|
+
$raf->Read($buff, $size) == $size or last;
|
344
|
+
# save comment, only if "Stored" (this is untested)
|
345
|
+
if (Get8u(\$buff, 3) == 0x30) {
|
346
|
+
$et->FoundTag('Comment', substr($buff, 6));
|
347
|
+
}
|
348
|
+
next;
|
349
|
+
}
|
350
|
+
# seek to the start of the next block
|
351
|
+
$raf->Seek($size, 1) or last if $size;
|
289
352
|
}
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
$raf->
|
302
|
-
|
303
|
-
if
|
304
|
-
|
353
|
+
|
354
|
+
} else { # RARv5 (ref 7, github#203)
|
355
|
+
|
356
|
+
return 0 unless $raf->Read($buff, 1) and $buff eq "\0";
|
357
|
+
$et->SetFileType();
|
358
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR5');
|
359
|
+
$et->HandleTag($tagTablePtr, 'RARVersion', 5);
|
360
|
+
$$et{INDENT} .= '| ';
|
361
|
+
|
362
|
+
# loop through header blocks
|
363
|
+
for (;;) {
|
364
|
+
$raf->Seek(4, 1); # skip header CRC
|
365
|
+
my $headSize = ReadULEB($raf);
|
366
|
+
last if $headSize == 0;
|
367
|
+
# read the header and create new RAF object for reading it
|
368
|
+
my $header;
|
369
|
+
$raf->Read($header, $headSize) == $headSize or last;
|
370
|
+
my $rafHdr = new File::RandomAccess(\$header);
|
371
|
+
my $headType = ReadULEB($rafHdr); # get header type
|
372
|
+
|
373
|
+
if ($headType == 4) { # encryption block
|
374
|
+
$et->Warn("File is encrypted.", 0);
|
375
|
+
last;
|
305
376
|
}
|
306
|
-
|
377
|
+
# skip over all headers except file or service header
|
378
|
+
next unless $headType == 2 or $headType == 3;
|
379
|
+
$et->VerboseDir('RAR5 file', undef, $headSize) if $headType == 2;
|
380
|
+
|
381
|
+
my $headFlag = ReadULEB($rafHdr);
|
382
|
+
ReadULEB($rafHdr); # skip extraSize
|
383
|
+
my $dataSize;
|
384
|
+
if ($headFlag & 0x0002) {
|
385
|
+
$dataSize = ReadULEB($rafHdr); # compressed data size
|
386
|
+
if ($headType == 2) {
|
387
|
+
$et->HandleTag($tagTablePtr, 'CompressedSize', $dataSize);
|
388
|
+
} else {
|
389
|
+
$raf->Seek($dataSize, 1); # skip service data section
|
390
|
+
next;
|
391
|
+
}
|
392
|
+
} else {
|
393
|
+
next if $headType == 3; # all done with service header
|
394
|
+
$dataSize = 0;
|
395
|
+
}
|
396
|
+
my $fileFlag = ReadULEB($rafHdr);
|
397
|
+
my $uncompressedSize = ReadULEB($rafHdr);
|
398
|
+
$et->HandleTag($tagTablePtr, 'UncompressedSize', $uncompressedSize) unless $fileFlag & 0x0008;
|
399
|
+
ReadULEB($rafHdr); # skip file attributes
|
400
|
+
if ($fileFlag & 0x0002) {
|
401
|
+
$rafHdr->Read($buff, 4) == 4 or last;
|
402
|
+
# (untested)
|
403
|
+
$et->HandleTag($tagTablePtr, 'ModifyDate', unpack('V', $buff));
|
404
|
+
}
|
405
|
+
$rafHdr->Seek(4, 1) if $fileFlag & 0x0004; # skip CRC if present
|
406
|
+
|
407
|
+
ReadULEB($rafHdr); # skip compressionInfo
|
408
|
+
|
409
|
+
# get operating system
|
410
|
+
my $os = ReadULEB($rafHdr);
|
411
|
+
$et->HandleTag($tagTablePtr, 'OperatingSystem', $os);
|
412
|
+
|
413
|
+
# get filename
|
414
|
+
$rafHdr->Read($buff, 1) == 1 or last;
|
415
|
+
my $nameLen = ord($buff);
|
416
|
+
$rafHdr->Read($buff, $nameLen) == $nameLen or last;
|
417
|
+
$buff =~ s/\0+$//; # remove trailing nulls (if any)
|
418
|
+
$et->HandleTag($tagTablePtr, 'ArchivedFileName', $buff);
|
419
|
+
|
420
|
+
$$et{DOC_NUM} = ++$docNum;
|
421
|
+
|
422
|
+
$raf->Seek($dataSize, 1); # skip data section
|
307
423
|
}
|
308
|
-
|
309
|
-
$raf->Seek($size, 1) or last if $size;
|
424
|
+
$$et{INDENT} = substr($$et{INDENT}, 0, -2);
|
310
425
|
}
|
426
|
+
|
311
427
|
$$et{DOC_NUM} = 0;
|
312
428
|
if ($docNum > 1 and not $et->Options('Duplicates')) {
|
313
429
|
$et->Warn("Use the Duplicates option to extract tags for all $docNum files", 1);
|
@@ -735,6 +851,8 @@ under the same terms as Perl itself.
|
|
735
851
|
|
736
852
|
=item L<http://DataCompression.info/ArchiveFormats/RAR202.txt>
|
737
853
|
|
854
|
+
=item L<https://www.rarlab.com/technote.htm>
|
855
|
+
|
738
856
|
=back
|
739
857
|
|
740
858
|
=head1 SEE ALSO
|
data/bin/lib/Image/ExifTool.pm
CHANGED
@@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
|
|
29
29
|
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
30
30
|
%static_vars);
|
31
31
|
|
32
|
-
$VERSION = '12.
|
32
|
+
$VERSION = '12.62';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -142,8 +142,8 @@ sub ReadValue($$$;$$$);
|
|
142
142
|
@loadAllTables = qw(
|
143
143
|
PhotoMechanic Exif GeoTiff CanonRaw KyoceraRaw Lytro MinoltaRaw PanasonicRaw
|
144
144
|
SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions
|
145
|
-
ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
146
|
-
PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
|
145
|
+
WPG ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
146
|
+
PCX PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
|
147
147
|
Photoshop::Layers Photoshop::ImageData FujiFilm::RAF FujiFilm::IFD
|
148
148
|
Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD Sony::PMP ITC ID3 ID3::Lyrics3
|
149
149
|
FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible MPC MPEG::Audio
|
@@ -152,8 +152,9 @@ sub ReadValue($$$;$$$);
|
|
152
152
|
Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE
|
153
153
|
JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion
|
154
154
|
EXE::PEString EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard
|
155
|
-
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR
|
156
|
-
OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
|
155
|
+
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR
|
156
|
+
ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
|
157
|
+
FlashPix::DocTable
|
157
158
|
);
|
158
159
|
|
159
160
|
# alphabetical list of current Lang modules
|
@@ -190,12 +191,12 @@ $defaultLang = 'en'; # default language
|
|
190
191
|
# 3) PLIST must be in this list for the binary PLIST format, although it may
|
191
192
|
# cause a file to be checked twice for XML
|
192
193
|
@fileTypes = qw(JPEG EXV CRW DR4 TIFF GIF MRW RAF X3F JP2 PNG MIE MIFF PS PDF
|
193
|
-
PSD XMP BMP BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV
|
194
|
-
FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
195
|
-
HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR
|
196
|
-
CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC
|
197
|
-
MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA
|
198
|
-
PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD ICO TXT);
|
194
|
+
PSD XMP BMP WPG BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV
|
195
|
+
OGG FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
196
|
+
LFP HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR
|
197
|
+
BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC
|
198
|
+
M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA
|
199
|
+
PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD ICO TXT);
|
199
200
|
|
200
201
|
# file types that we can write (edit)
|
201
202
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
@@ -554,6 +555,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
554
555
|
XMP => ['XMP', 'Extensible Metadata Platform'],
|
555
556
|
WOFF => ['Font', 'Web Open Font Format'],
|
556
557
|
WOFF2=> ['Font', 'Web Open Font Format2'],
|
558
|
+
WPG => ['WPG', 'WordPerfect Graphics'],
|
557
559
|
WTV => ['WTV', 'Windows recorded TV show'],
|
558
560
|
ZIP => ['ZIP', 'ZIP archive'],
|
559
561
|
);
|
@@ -789,6 +791,7 @@ my %fileDescription = (
|
|
789
791
|
WMA => 'audio/x-ms-wma',
|
790
792
|
WMF => 'application/x-wmf',
|
791
793
|
WMV => 'video/x-ms-wmv',
|
794
|
+
WPG => 'image/x-wpg',
|
792
795
|
WTV => 'video/x-ms-wtv',
|
793
796
|
X3F => 'image/x-sigma-x3f',
|
794
797
|
XCF => 'image/x-xcf',
|
@@ -970,7 +973,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
970
973
|
QTIF => '.{4}(idsc|idat|iicc)',
|
971
974
|
R3D => '\0\0..RED(1|2)',
|
972
975
|
RAF => 'FUJIFILM',
|
973
|
-
RAR => 'Rar!\x1a\x07\0',
|
976
|
+
RAR => 'Rar!\x1a\x07\x01?\0',
|
974
977
|
RAW => '(.{25}ARECOYK|II|MM)',
|
975
978
|
Real => '(\.RMF|\.ra\xfd|pnm://|rtsp://|http://)',
|
976
979
|
RIFF => '(RIFF|LA0[234]|OFR |LPAC|wvpk|RF64)', # RIFF plus other variants
|
@@ -984,6 +987,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
984
987
|
VCard=> '(?i)BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n',
|
985
988
|
VRD => 'CANON OPTIONAL DATA\0',
|
986
989
|
WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)',
|
990
|
+
WPG => '\xff\x57\x50\x43',
|
987
991
|
WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d',
|
988
992
|
X3F => 'FOVb',
|
989
993
|
XCF => 'gimp xcf ',
|
@@ -1825,13 +1829,13 @@ my %systemTagsNotes = (
|
|
1825
1829
|
},
|
1826
1830
|
ImageDataMD5 => {
|
1827
1831
|
Notes => q{
|
1828
|
-
MD5 of image data. Generated only if specifically requested for JPEG
|
1829
|
-
|
1830
|
-
videos, and some RIFF-based files
|
1831
|
-
plus JpgFromRaw/OtherImage for some formats,
|
1832
|
-
ThumbnailImage or PreviewImage. Includes video and
|
1833
|
-
The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool>
|
1834
|
-
store these values in the file.
|
1832
|
+
MD5 of image data. Generated only if specifically requested for JPEG, TIFF,
|
1833
|
+
PNG, CRW, CR3, MRW, RAF, X3F, IIQ, JP2, JXL, HEIC and AVIF images, MOV/MP4
|
1834
|
+
videos, and some RIFF-based files such as AVI, WAV and WEBP. The MD5
|
1835
|
+
includes the main image data, plus JpgFromRaw/OtherImage for some formats,
|
1836
|
+
but does not include ThumbnailImage or PreviewImage. Includes video and
|
1837
|
+
audio data for MOV/MP4. The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool>
|
1838
|
+
provides a place to store these values in the file.
|
1835
1839
|
},
|
1836
1840
|
},
|
1837
1841
|
);
|
@@ -2125,8 +2129,10 @@ sub Options($$;@)
|
|
2125
2129
|
|
2126
2130
|
while (@_) {
|
2127
2131
|
my $param = shift;
|
2132
|
+
my $plus;
|
2128
2133
|
# fix parameter case if necessary
|
2129
2134
|
unless (exists $$options{$param}) {
|
2135
|
+
$plus = $param =~ s/\+$//;
|
2130
2136
|
my ($fixed) = grep /^$param$/i, keys %$options;
|
2131
2137
|
if ($fixed) {
|
2132
2138
|
$param = $fixed;
|
@@ -2291,6 +2297,23 @@ sub Options($$;@)
|
|
2291
2297
|
$compact{$p} = $val; # preserve most recent setting
|
2292
2298
|
}
|
2293
2299
|
$$options{Compact} = $$options{XMPShorthand} = \%compact;
|
2300
|
+
} elsif ($param eq 'NoWarning') {
|
2301
|
+
# validate regular expression
|
2302
|
+
undef $evalWarning;
|
2303
|
+
if (defined $newVal) {
|
2304
|
+
local $SIG{'__WARN__'} = \&SetWarning;
|
2305
|
+
eval { $param =~ /$newVal/ };
|
2306
|
+
$@ and $evalWarning = $@;
|
2307
|
+
}
|
2308
|
+
if ($evalWarning) {
|
2309
|
+
warn 'NoWarning: ' . CleanWarning() . "\n";
|
2310
|
+
next;
|
2311
|
+
}
|
2312
|
+
# add to existing expression if specified
|
2313
|
+
if ($plus and defined $oldVal) {
|
2314
|
+
$newVal = defined $newVal ? "$oldVal|$newVal" : $oldVal;
|
2315
|
+
}
|
2316
|
+
$$options{$param} = $newVal;
|
2294
2317
|
} else {
|
2295
2318
|
if ($param eq 'Escape') {
|
2296
2319
|
# set ESCAPE_PROC
|
@@ -2385,6 +2408,7 @@ sub ClearOptions($)
|
|
2385
2408
|
MissingTagValue =>undef,# value for missing tags when expanded in expressions
|
2386
2409
|
NoMultiExif => undef, # raise error when writing multi-segment EXIF
|
2387
2410
|
NoPDFList => undef, # flag to avoid splitting PDF List-type tag values
|
2411
|
+
NoWarning => undef, # regular expression for warnings to suppress
|
2388
2412
|
Password => undef, # password for password-protected PDF documents
|
2389
2413
|
PrintConv => 1, # flag to enable print conversion
|
2390
2414
|
QuickTimeHandler => 1, # flag to add mdir Handler to newly created Meta box
|
@@ -2503,23 +2527,6 @@ sub ExtractInfo($;@)
|
|
2503
2527
|
}
|
2504
2528
|
}
|
2505
2529
|
++$$self{FILE_SEQUENCE}; # count files read
|
2506
|
-
# extract information from alternate files if necessary
|
2507
|
-
my ($g8, $altExifTool);
|
2508
|
-
foreach $g8 (keys %{$$self{ALT_EXIFTOOL}}) {
|
2509
|
-
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
2510
|
-
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
2511
|
-
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
2512
|
-
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
2513
|
-
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
2514
|
-
$altExifTool->ExtractInfo($$altExifTool{ALT_FILE});
|
2515
|
-
# set family 8 group name for all tags
|
2516
|
-
foreach (keys %{$$altExifTool{VALUE}}) {
|
2517
|
-
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
2518
|
-
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
2519
|
-
$$ex{G8} = $g8;
|
2520
|
-
}
|
2521
|
-
$$altExifTool{DID_EXTRACT} = 1;
|
2522
|
-
}
|
2523
2530
|
}
|
2524
2531
|
|
2525
2532
|
my $filename = $$self{FILENAME}; # image file name ('' if already open)
|
@@ -2661,7 +2668,7 @@ sub ExtractInfo($;@)
|
|
2661
2668
|
if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) {
|
2662
2669
|
$self->FoundTag('FileType', 'DIR');
|
2663
2670
|
$self->FoundTag('FileTypeExtension', '');
|
2664
|
-
$self->
|
2671
|
+
$self->ExtractAltInfo();
|
2665
2672
|
$raf->Close() if $raf;
|
2666
2673
|
return 1;
|
2667
2674
|
}
|
@@ -2679,7 +2686,7 @@ sub ExtractInfo($;@)
|
|
2679
2686
|
} else {
|
2680
2687
|
$self->Error('Unknown file type');
|
2681
2688
|
}
|
2682
|
-
$self->
|
2689
|
+
$self->ExtractAltInfo();
|
2683
2690
|
last; # don't read the file
|
2684
2691
|
}
|
2685
2692
|
if (@fileTypeList) {
|
@@ -2845,8 +2852,7 @@ sub ExtractInfo($;@)
|
|
2845
2852
|
}
|
2846
2853
|
unless ($reEntry) {
|
2847
2854
|
$$self{PATH} = [ ]; # reset PATH
|
2848
|
-
|
2849
|
-
$self->BuildCompositeTags() if $$options{Composite};
|
2855
|
+
$self->ExtractAltInfo();
|
2850
2856
|
# do our HTML dump if requested
|
2851
2857
|
if ($$self{HTML_DUMP}) {
|
2852
2858
|
$raf->Seek(0, 2); # seek to end of file
|
@@ -3648,14 +3654,15 @@ sub SetNewGroups($;@)
|
|
3648
3654
|
|
3649
3655
|
#------------------------------------------------------------------------------
|
3650
3656
|
# Build Composite tags from Require'd/Desire'd tags
|
3651
|
-
# Inputs: 0) ExifTool object reference
|
3657
|
+
# Inputs: 0) ExifTool object reference, 1) flag to build only tags that require
|
3658
|
+
# tags from alternate files (without this, these tags are ignored)
|
3652
3659
|
# Note: Tag values are calculated in alphabetical order unless a tag Require's
|
3653
3660
|
# or Desire's another Composite tag, in which case the calculation is
|
3654
3661
|
# deferred until after the other tag is calculated.
|
3655
3662
|
sub BuildCompositeTags($)
|
3656
3663
|
{
|
3657
3664
|
local $_;
|
3658
|
-
my $self =
|
3665
|
+
my ($self, $altOnly) = @_;
|
3659
3666
|
|
3660
3667
|
$$self{BuildingComposite} = 1;
|
3661
3668
|
|
@@ -3684,7 +3691,7 @@ COMPOSITE_TAG:
|
|
3684
3691
|
# loop through sub-documents if necessary
|
3685
3692
|
my $docNum = 0;
|
3686
3693
|
for (;;) {
|
3687
|
-
my (%tagKey, $found, $index);
|
3694
|
+
my (%tagKey, $found, $index, $requireAlt);
|
3688
3695
|
# save Require'd and Desire'd tag values in list
|
3689
3696
|
for ($index=0; ; ++$index) {
|
3690
3697
|
my $reqTag = $$require{$index} || $$desire{$index} || $$inhibit{$index};
|
@@ -3739,6 +3746,8 @@ COMPOSITE_TAG:
|
|
3739
3746
|
if ($reqTag =~ /\b(File\d+):/i and $$self{ALT_EXIFTOOL}{$1}) {
|
3740
3747
|
$et = $$self{ALT_EXIFTOOL}{$1};
|
3741
3748
|
$altFile = $1;
|
3749
|
+
# set flags indicating we require tags from alternate files
|
3750
|
+
$$self{DoAltComposite} = $requireAlt = 1;
|
3742
3751
|
}
|
3743
3752
|
# (CAREFUL! keys may not be sequential if one was deleted)
|
3744
3753
|
for ($key=$name, $i=$$et{DUPL_TAG}{$name} || 0; ; --$i) {
|
@@ -3770,6 +3779,8 @@ COMPOSITE_TAG:
|
|
3770
3779
|
}
|
3771
3780
|
$tagKey{$index} = $reqTag;
|
3772
3781
|
}
|
3782
|
+
# stop now if this requires alternate tags and we aren't building them
|
3783
|
+
last if $requireAlt xor $altOnly;
|
3773
3784
|
if ($docNum) {
|
3774
3785
|
if ($found) {
|
3775
3786
|
$$self{DOC_NUM} = $docNum;
|
@@ -4067,6 +4078,49 @@ sub CombineInfo($;@)
|
|
4067
4078
|
return \%combinedInfo;
|
4068
4079
|
}
|
4069
4080
|
|
4081
|
+
#------------------------------------------------------------------------------
|
4082
|
+
# Read metadata from alternate files and build composite tags
|
4083
|
+
# Inputs: 0) ExifTool ref
|
4084
|
+
# Notes: This is called after reading the main file so the tags are available
|
4085
|
+
# for being used in the file name, but before building Composite tags
|
4086
|
+
# so tags from the alternate files may be used in the Composite tags
|
4087
|
+
sub ExtractAltInfo($)
|
4088
|
+
{
|
4089
|
+
my $self = shift;
|
4090
|
+
# extract information from alternate files if necessary
|
4091
|
+
my ($g8, $altExifTool);
|
4092
|
+
my $opts = $$self{OPTIONS};
|
4093
|
+
if ($$opts{Composite} and (not $$opts{FastScan} or $$opts{FastScan} < 5)) {
|
4094
|
+
# build all composite tags except those requiring tags from alternate files
|
4095
|
+
$self->BuildCompositeTags();
|
4096
|
+
}
|
4097
|
+
foreach $g8 (sort keys %{$$self{ALT_EXIFTOOL}}) {
|
4098
|
+
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
4099
|
+
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
4100
|
+
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
4101
|
+
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
4102
|
+
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
4103
|
+
my $fileName = $$altExifTool{ALT_FILE};
|
4104
|
+
# allow tags from the main file to be used in the alternate file names
|
4105
|
+
# (eg. -file1 '$originalfilename')
|
4106
|
+
if ($fileName =~ /\$/) {
|
4107
|
+
my @tags = reverse sort keys %{$$self{VALUE}};
|
4108
|
+
$fileName = $self->InsertTagValues(\@tags, $fileName, 'Warn');
|
4109
|
+
next unless defined $fileName;
|
4110
|
+
}
|
4111
|
+
$altExifTool->ExtractInfo($fileName);
|
4112
|
+
# set family 8 group name for all tags
|
4113
|
+
foreach (keys %{$$altExifTool{VALUE}}) {
|
4114
|
+
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
4115
|
+
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
4116
|
+
$$ex{G8} = $g8;
|
4117
|
+
}
|
4118
|
+
$$altExifTool{DID_EXTRACT} = 1;
|
4119
|
+
}
|
4120
|
+
# if necessary, build composite tags that rely on tags from alternate files
|
4121
|
+
$self->BuildCompositeTags(1) if $$self{DoAltComposite};
|
4122
|
+
}
|
4123
|
+
|
4070
4124
|
#------------------------------------------------------------------------------
|
4071
4125
|
# Get tag table name
|
4072
4126
|
# Inputs: 0) ExifTool object reference, 1) tag key
|
@@ -4917,12 +4971,14 @@ sub AUTOLOAD
|
|
4917
4971
|
sub Warn($$;$)
|
4918
4972
|
{
|
4919
4973
|
my ($self, $str, $ignorable) = @_;
|
4974
|
+
my $noWarn = $self->Options('NoWarning');
|
4920
4975
|
if ($ignorable) {
|
4921
4976
|
return 0 if $$self{OPTIONS}{IgnoreMinorErrors};
|
4922
4977
|
return 0 if $ignorable eq '3' and $$self{OPTIONS}{Validate};
|
4978
|
+
return 1 if defined $noWarn and eval { $str =~ /$noWarn/ };
|
4923
4979
|
$str = $ignorable eq '2' ? "[Minor] $str" : "[minor] $str";
|
4924
4980
|
}
|
4925
|
-
$self->FoundTag('Warning', $str);
|
4981
|
+
$self->FoundTag('Warning', $str) unless defined $noWarn and eval { $str =~ /$noWarn/ };
|
4926
4982
|
return 1;
|
4927
4983
|
}
|
4928
4984
|
|
@@ -6432,12 +6488,12 @@ sub ProcessJPEG($$)
|
|
6432
6488
|
my $htmlDump = $$self{HTML_DUMP};
|
6433
6489
|
my %dumpParms = ( Out => $out );
|
6434
6490
|
my ($ch, $s, $length, $md5, $md5size);
|
6435
|
-
my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
|
6491
|
+
my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
|
6436
6492
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
6437
6493
|
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
6438
6494
|
|
6439
|
-
# get pointer to MD5 object if it exists and we are the top-level JPEG
|
6440
|
-
if ($$self{FILE_TYPE}
|
6495
|
+
# get pointer to MD5 object if it exists and we are the top-level JPEG or JP2
|
6496
|
+
if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
|
6441
6497
|
$md5 = $$self{ImageDataMD5};
|
6442
6498
|
$md5size = 0;
|
6443
6499
|
}
|
@@ -6561,7 +6617,8 @@ sub ProcessJPEG($$)
|
|
6561
6617
|
$self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
|
6562
6618
|
$dumpEnd = $segPos + $length;
|
6563
6619
|
}
|
6564
|
-
next
|
6620
|
+
next if $length < 6 or $gotSize;
|
6621
|
+
$gotSize = 1; # (ignore subsequent SOF segments in probably corrupted JPEG)
|
6565
6622
|
# extract some useful information
|
6566
6623
|
my ($p, $h, $w, $n) = unpack('Cn2C', $$segDataPt);
|
6567
6624
|
my $sof = GetTagTable('Image::ExifTool::JPEG::SOF');
|
@@ -6751,6 +6808,11 @@ sub ProcessJPEG($$)
|
|
6751
6808
|
pop @$path;
|
6752
6809
|
$verbose and print $out "JPEG SOD\n";
|
6753
6810
|
$success = 1;
|
6811
|
+
if ($md5 and $$self{FILE_TYPE} eq 'JP2') {
|
6812
|
+
my $pos = $raf->Tell();
|
6813
|
+
$self->ImageDataMD5($raf, undef, 'SOD');
|
6814
|
+
$raf->Seek($pos, 0);
|
6815
|
+
}
|
6754
6816
|
next if $verbose > 2 or $htmlDump;
|
6755
6817
|
last; # all done parsing file
|
6756
6818
|
} elsif (defined $markerLenBytes{$marker}) {
|
@@ -7483,8 +7545,11 @@ sub ProcessJPEG($$)
|
|
7483
7545
|
}
|
7484
7546
|
} elsif ($marker == 0x51) { # SIZ (J2C)
|
7485
7547
|
my ($w, $h) = unpack('x2N2', $$segDataPt);
|
7486
|
-
|
7487
|
-
|
7548
|
+
unless ($gotSize) {
|
7549
|
+
$gotSize = 1;
|
7550
|
+
$self->FoundTag('ImageWidth', $w);
|
7551
|
+
$self->FoundTag('ImageHeight', $h);
|
7552
|
+
}
|
7488
7553
|
} elsif (($marker & 0xf0) != 0xe0) {
|
7489
7554
|
$dumpType = "$markerName segment";
|
7490
7555
|
$desc = "[JPEG $markerName]"; # (other known JPEG segments)
|
@@ -7824,6 +7889,9 @@ sub DoProcessTIFF($$;$)
|
|
7824
7889
|
if ($$self{TIFF_TYPE} eq 'TIFF') {
|
7825
7890
|
$self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage};
|
7826
7891
|
}
|
7892
|
+
if ($$self{ImageDataMD5} and $$self{A100DataOffset} and $raf->Seek($$self{A100DataOffset},0)) {
|
7893
|
+
$self->ImageDataMD5($raf, undef, 'A100');
|
7894
|
+
}
|
7827
7895
|
return 1;
|
7828
7896
|
}
|
7829
7897
|
#
|