exiftool_vendored 12.60.0 → 12.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
#
|