exiftool_vendored 12.61.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 +12 -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 +56 -54
- 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/PDF.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +10 -7
- data/bin/lib/Image/ExifTool/TagLookup.pm +9 -0
- data/bin/lib/Image/ExifTool/TagNames.pod +33 -5
- data/bin/lib/Image/ExifTool/WPG.pm +296 -0
- data/bin/lib/Image/ExifTool/Writer.pl +12 -4
- data/bin/lib/Image/ExifTool/XMP.pm +4 -1
- data/bin/lib/Image/ExifTool/ZIP.pm +159 -41
- data/bin/lib/Image/ExifTool.pm +62 -28
- 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
@@ -0,0 +1,296 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: WPG.pm
|
3
|
+
#
|
4
|
+
# Description: Read WordPerfect Graphics meta information
|
5
|
+
#
|
6
|
+
# Revisions: 2023-05-01 - P. Harvey Created
|
7
|
+
#
|
8
|
+
# References: 1) https://www.fileformat.info/format/wpg/egff.htm
|
9
|
+
# 2) https://archive.org/details/mac_Graphics_File_Formats_Second_Edition_1996/page/n991/mode/2up
|
10
|
+
# 3) http://libwpg.sourceforge.net/
|
11
|
+
#------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
package Image::ExifTool::WPG;
|
14
|
+
|
15
|
+
use strict;
|
16
|
+
use vars qw($VERSION);
|
17
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
18
|
+
|
19
|
+
$VERSION = '1.00';
|
20
|
+
|
21
|
+
sub PrintRecord($$$);
|
22
|
+
|
23
|
+
# WPG metadata
|
24
|
+
%Image::ExifTool::WPG::Main = (
|
25
|
+
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
26
|
+
VARS => { NO_ID => 1 },
|
27
|
+
NOTES => 'Tags extracted from WordPerfect Graphics (WPG) images.',
|
28
|
+
WPGVersion => { },
|
29
|
+
ImageWidthInches => { PrintConv => 'sprintf("%.2f",$val)' },
|
30
|
+
ImageHeightInches => { PrintConv => 'sprintf("%.2f",$val)' },
|
31
|
+
Records => {
|
32
|
+
Notes => 'records for version 1.0 files',
|
33
|
+
List => 1,
|
34
|
+
PrintHex => 2,
|
35
|
+
PrintConvColumns => 2,
|
36
|
+
PrintConv => {
|
37
|
+
OTHER => \&PrintRecord,
|
38
|
+
0x01 => 'Fill Attributes',
|
39
|
+
0x02 => 'Line Attributes',
|
40
|
+
0x03 => 'Marker Attributes',
|
41
|
+
0x04 => 'Polymarker',
|
42
|
+
0x05 => 'Line',
|
43
|
+
0x06 => 'Polyline',
|
44
|
+
0x07 => 'Rectangle',
|
45
|
+
0x08 => 'Polygon',
|
46
|
+
0x09 => 'Ellipse',
|
47
|
+
0x0a => 'Reserved',
|
48
|
+
0x0b => 'Bitmap (Type 1)',
|
49
|
+
0x0c => 'Graphics Text (Type 1)',
|
50
|
+
0x0d => 'Graphics Text Attributes',
|
51
|
+
0x0e => 'Color Map',
|
52
|
+
0x0f => 'Start WPG (Type 1)',
|
53
|
+
0x10 => 'End WPG',
|
54
|
+
0x11 => 'PostScript Data (Type 1)',
|
55
|
+
0x12 => 'Output Attributes',
|
56
|
+
0x13 => 'Curved Polyline',
|
57
|
+
0x14 => 'Bitmap (Type 2)',
|
58
|
+
0x15 => 'Start Figure',
|
59
|
+
0x16 => 'Start Chart',
|
60
|
+
0x17 => 'PlanPerfect Data',
|
61
|
+
0x18 => 'Graphics Text (Type 2)',
|
62
|
+
0x19 => 'Start WPG (Type 2)',
|
63
|
+
0x1a => 'Graphics Text (Type 3)',
|
64
|
+
0x1b => 'PostScript Data (Type 2)',
|
65
|
+
},
|
66
|
+
},
|
67
|
+
RecordsV2 => {
|
68
|
+
Notes => 'records for version 2.0 files',
|
69
|
+
List => 1,
|
70
|
+
PrintHex => 2,
|
71
|
+
PrintConvColumns => 2,
|
72
|
+
PrintConv => {
|
73
|
+
OTHER => \&PrintRecord,
|
74
|
+
0x00 => 'End Marker',
|
75
|
+
0x01 => 'Start WPG',
|
76
|
+
0x02 => 'End WPG',
|
77
|
+
0x03 => 'Form Settings',
|
78
|
+
0x04 => 'Ruler Settings',
|
79
|
+
0x05 => 'Grid Settings',
|
80
|
+
0x06 => 'Layer',
|
81
|
+
0x08 => 'Pen Style Definition',
|
82
|
+
0x09 => 'Pattern Definition',
|
83
|
+
0x0a => 'Comment',
|
84
|
+
0x0b => 'Color Transfer',
|
85
|
+
0x0c => 'Color Palette',
|
86
|
+
0x0d => 'DP Color Palette',
|
87
|
+
0x0e => 'Bitmap Data',
|
88
|
+
0x0f => 'Text Data',
|
89
|
+
0x10 => 'Chart Style',
|
90
|
+
0x11 => 'Chart Data',
|
91
|
+
0x12 => 'Object Image',
|
92
|
+
0x15 => 'Polyline',
|
93
|
+
0x16 => 'Polyspline',
|
94
|
+
0x17 => 'Polycurve',
|
95
|
+
0x18 => 'Rectangle',
|
96
|
+
0x19 => 'Arc',
|
97
|
+
0x1a => 'Compound Polygon',
|
98
|
+
0x1b => 'Bitmap',
|
99
|
+
0x1c => 'Text Line',
|
100
|
+
0x1d => 'Text Block',
|
101
|
+
0x1e => 'Text Path',
|
102
|
+
0x1f => 'Chart',
|
103
|
+
0x20 => 'Group',
|
104
|
+
0x21 => 'Object Capsule',
|
105
|
+
0x22 => 'Font Settings',
|
106
|
+
0x25 => 'Pen Fore Color',
|
107
|
+
0x26 => 'DP Pen Fore Color',
|
108
|
+
0x27 => 'Pen Back Color',
|
109
|
+
0x28 => 'DP Pen Back Color',
|
110
|
+
0x29 => 'Pen Style',
|
111
|
+
0x2a => 'Pen Pattern',
|
112
|
+
0x2b => 'Pen Size',
|
113
|
+
0x2c => 'DP Pen Size',
|
114
|
+
0x2d => 'Line Cap',
|
115
|
+
0x2e => 'Line Join',
|
116
|
+
0x2f => 'Brush Gradient',
|
117
|
+
0x30 => 'DP Brush Gradient',
|
118
|
+
0x31 => 'Brush Fore Color',
|
119
|
+
0x32 => 'DP Brush Fore Color',
|
120
|
+
0x33 => 'Brush Back Color',
|
121
|
+
0x34 => 'DP Brush Back Color',
|
122
|
+
0x35 => 'Brush Pattern',
|
123
|
+
0x36 => 'Horizontal Line',
|
124
|
+
0x37 => 'Vertical Line',
|
125
|
+
0x38 => 'Poster Settings',
|
126
|
+
0x39 => 'Image State',
|
127
|
+
0x3a => 'Envelope Definition',
|
128
|
+
0x3b => 'Envelope',
|
129
|
+
0x3c => 'Texture Definition',
|
130
|
+
0x3d => 'Brush Texture',
|
131
|
+
0x3e => 'Texture Alignment',
|
132
|
+
0x3f => 'Pen Texture ',
|
133
|
+
}
|
134
|
+
},
|
135
|
+
);
|
136
|
+
|
137
|
+
#------------------------------------------------------------------------------
|
138
|
+
# Print record type
|
139
|
+
# Inputs: 0) record type and count, 1) inverse flag, 2) PrintConv hash ref
|
140
|
+
# Returns: converted record name
|
141
|
+
sub PrintRecord($$$)
|
142
|
+
{
|
143
|
+
my ($val, $inv, $printConv) = @_;
|
144
|
+
my ($type, $count) = split 'x', $val;
|
145
|
+
my $prt = $$printConv{$type} || sprintf('Unknown (0x%.2x)', $type);
|
146
|
+
$prt .= " x $count" if $count;
|
147
|
+
return $prt;
|
148
|
+
}
|
149
|
+
|
150
|
+
#------------------------------------------------------------------------------
|
151
|
+
# Read variable-length integer
|
152
|
+
# Inputs: 0) RAF ref
|
153
|
+
# Returns: integer value
|
154
|
+
sub ReadVarInt($)
|
155
|
+
{
|
156
|
+
my $raf = shift;
|
157
|
+
my $buff;
|
158
|
+
$raf->Read($buff, 1) or return 0;
|
159
|
+
my $val = ord($buff);
|
160
|
+
if ($val == 0xff) {
|
161
|
+
$raf->Read($buff, 2) == 2 or return 0;
|
162
|
+
$val = unpack('v', $buff);
|
163
|
+
if ($val & 0x8000) {
|
164
|
+
$raf->Read($buff, 2) == 2 or return 0;
|
165
|
+
$val = (($val & 0x7fff) << 16) | unpack('v', $buff);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
return $val;
|
169
|
+
}
|
170
|
+
|
171
|
+
#------------------------------------------------------------------------------
|
172
|
+
# Read WPG version 1 or 2 image
|
173
|
+
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
174
|
+
# Returns: 1 on success, 0 if this wasn't a valid WPG file
|
175
|
+
sub ProcessWPG($$)
|
176
|
+
{
|
177
|
+
my ($et, $dirInfo) = @_;
|
178
|
+
my $raf = $$dirInfo{RAF};
|
179
|
+
my ($buff, $lastType, $count);
|
180
|
+
|
181
|
+
# verify this is a valid WPG file
|
182
|
+
return 0 unless $raf->Read($buff, 16) == 16;
|
183
|
+
return 0 unless $buff =~ /^\xff\x57\x50\x43/;
|
184
|
+
$et->SetFileType();
|
185
|
+
SetByteOrder('II');
|
186
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::WPG::Main');
|
187
|
+
my $offset = Get32u(\$buff, 4);
|
188
|
+
my ($ver, $rev) = unpack('x10CC', $buff);
|
189
|
+
$et->HandleTag($tagTablePtr, WPGVersion => "$ver.$rev");
|
190
|
+
if ($ver < 1 or $ver > 2) {
|
191
|
+
# currently support only version 1 and 2 formats
|
192
|
+
$et->Warn('Unsupported WPG version');
|
193
|
+
return 1;
|
194
|
+
}
|
195
|
+
my $tag = $ver == 1 ? 'Records' : 'RecordsV2';
|
196
|
+
$raf->Seek($offset - 16, 1) or return 1 if $offset > 16;
|
197
|
+
# loop through records
|
198
|
+
for (;;) {
|
199
|
+
my ($type, $len, $getSize);
|
200
|
+
if ($raf->Read($buff, $ver) == $ver) { # read 1 or 2 bytes, based on version
|
201
|
+
if ($ver == 1) {
|
202
|
+
# read version 1 record header
|
203
|
+
$type = ord($buff);
|
204
|
+
$len = ReadVarInt($raf);
|
205
|
+
$getSize = 1 if $type == 0x0f; # Start WPG (Type 1)
|
206
|
+
} else {
|
207
|
+
# read version 2 record header
|
208
|
+
$type = unpack('xC', $buff);
|
209
|
+
ReadVarInt($raf); # skip extensions
|
210
|
+
$len = ReadVarInt($raf);
|
211
|
+
$getSize = 1 if $type == 0x01; # Start WPG
|
212
|
+
undef $type if $type > 0x3f;
|
213
|
+
}
|
214
|
+
if ($getSize) {
|
215
|
+
# read Start record to obtain image size
|
216
|
+
$raf->Read($buff, $len) == $len or $et->Warn('File format error'), last;
|
217
|
+
my ($w, $h, $xres, $yres);
|
218
|
+
if ($ver == 1) {
|
219
|
+
($w, $h) = unpack('x2vv', $buff);
|
220
|
+
} else {
|
221
|
+
my ($precision, $format);
|
222
|
+
($xres, $yres, $precision) = unpack('vvC', $buff);
|
223
|
+
if ($precision == 0 and $len >= 21) {
|
224
|
+
$format = 'int16s';
|
225
|
+
} elsif ($precision == 1 and $len >= 29) {
|
226
|
+
$format = 'int32s';
|
227
|
+
} else {
|
228
|
+
$et->Warn('Invalid integer precision');
|
229
|
+
next;
|
230
|
+
}
|
231
|
+
my ($x1,$y1,$x2,$y2) = ReadValue(\$buff, 13, $format, 4, $len-13);
|
232
|
+
$w = abs($x2 - $x1);
|
233
|
+
$h = abs($y2 - $y1);
|
234
|
+
}
|
235
|
+
$et->HandleTag($tagTablePtr, ImageWidthInches => $w / ($xres || 1200));
|
236
|
+
$et->HandleTag($tagTablePtr, ImageHeightInches => $h / ($yres || 1200));
|
237
|
+
} else {
|
238
|
+
$raf->Seek($len, 1) or last; # skip to the next record
|
239
|
+
}
|
240
|
+
}
|
241
|
+
# go to some trouble to collapse identical sequential entries in record list
|
242
|
+
# (trying to keep the length of the list managable for complex images)
|
243
|
+
$lastType and $type and $type == $lastType and ++$count, next;
|
244
|
+
if ($lastType) {
|
245
|
+
my $val = $count > 1 ? "${lastType}x$count" : $lastType;
|
246
|
+
$et->HandleTag($tagTablePtr, $tag => $val);
|
247
|
+
}
|
248
|
+
last unless $type;
|
249
|
+
$lastType = $type;
|
250
|
+
$count = 1;
|
251
|
+
}
|
252
|
+
return 1;
|
253
|
+
}
|
254
|
+
|
255
|
+
1; # end
|
256
|
+
|
257
|
+
__END__
|
258
|
+
|
259
|
+
=head1 NAME
|
260
|
+
|
261
|
+
Image::ExifTool::WPG - Read WPG meta information
|
262
|
+
|
263
|
+
=head1 SYNOPSIS
|
264
|
+
|
265
|
+
This module is used by Image::ExifTool
|
266
|
+
|
267
|
+
=head1 DESCRIPTION
|
268
|
+
|
269
|
+
This module contains definitions required by Image::ExifTool to read WPG
|
270
|
+
(WordPerfect Graphics) images.
|
271
|
+
|
272
|
+
=head1 AUTHOR
|
273
|
+
|
274
|
+
Copyright 2003-2023, Phil Harvey (philharvey66 at gmail.com)
|
275
|
+
|
276
|
+
This library is free software; you can redistribute it and/or modify it
|
277
|
+
under the same terms as Perl itself.
|
278
|
+
|
279
|
+
=head1 REFERENCES
|
280
|
+
|
281
|
+
=over 4
|
282
|
+
|
283
|
+
=item L<https://www.fileformat.info/format/wpg/egff.htm>
|
284
|
+
|
285
|
+
=item L<https://archive.org/details/mac_Graphics_File_Formats_Second_Edition_1996/page/n991/mode/2up>
|
286
|
+
|
287
|
+
=item L<http://libwpg.sourceforge.net/>
|
288
|
+
|
289
|
+
=back
|
290
|
+
|
291
|
+
=head1 SEE ALSO
|
292
|
+
|
293
|
+
L<Image::ExifTool::TagNames/WPG Tags>,
|
294
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
295
|
+
|
296
|
+
=cut
|
@@ -1302,6 +1302,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1302
1302
|
MDItemTags => $$options{MDItemTags},
|
1303
1303
|
MissingTagValue => $$options{MissingTagValue},
|
1304
1304
|
NoPDFList => $$options{NoPDFList},
|
1305
|
+
NoWarning => $$options{NoWarning},
|
1305
1306
|
Password => $$options{Password},
|
1306
1307
|
PrintConv => $$options{PrintConv},
|
1307
1308
|
QuickTimeUTC => $$options{QuickTimeUTC},
|
@@ -1569,10 +1570,17 @@ SET: foreach $set (@setList) {
|
|
1569
1570
|
# handle expressions
|
1570
1571
|
if ($$opts{EXPR}) {
|
1571
1572
|
my $val = $srcExifTool->InsertTagValues(\@tags, $$set[1], 'Error');
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
$
|
1573
|
+
my $err = $$srcExifTool{VALUE}{Error};
|
1574
|
+
if ($err) {
|
1575
|
+
# pass on any error as a warning unless it is suppressed
|
1576
|
+
my $noWarn = $$srcExifTool{OPTIONS}{NoWarning};
|
1577
|
+
unless ($noWarn and (eval { $err =~ /$noWarn/ } or
|
1578
|
+
# (also apply expression to warning without "[minor] " prefix)
|
1579
|
+
($err =~ s/^\[minor\] //i and eval { $err =~ /$noWarn/ })))
|
1580
|
+
{
|
1581
|
+
$tag = NextFreeTagKey(\%rtnInfo, 'Warning');
|
1582
|
+
$rtnInfo{$tag} = $$srcExifTool{VALUE}{Error};
|
1583
|
+
}
|
1576
1584
|
delete $$srcExifTool{VALUE}{Error};
|
1577
1585
|
next unless defined $val;
|
1578
1586
|
}
|
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
|
|
50
50
|
use Image::ExifTool::GPS;
|
51
51
|
require Exporter;
|
52
52
|
|
53
|
-
$VERSION = '3.
|
53
|
+
$VERSION = '3.59';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -2489,6 +2489,9 @@ my %sPantryItem = (
|
|
2489
2489
|
EnhanceSuperResolutionAlreadyApplied => { Writable => 'boolean' },
|
2490
2490
|
EnhanceSuperResolutionVersion => { }, # integer?
|
2491
2491
|
EnhanceSuperResolutionScale => { Writable => 'rational' },
|
2492
|
+
EnhanceDenoiseAlreadyApplied => { Writable => 'boolean' }, #forum14760
|
2493
|
+
EnhanceDenoiseVersion => { }, #forum14760 integer?
|
2494
|
+
EnhanceDenoiseLumaAmount => { }, #forum14760 integer?
|
2492
2495
|
);
|
2493
2496
|
|
2494
2497
|
# IPTC Core namespace properties (Iptc4xmpCore) (ref 4)
|
@@ -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
|