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.
@@ -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
- if ($$srcExifTool{VALUE}{Error}) {
1573
- # pass on any error as a warning
1574
- $tag = NextFreeTagKey(\%rtnInfo, 'Warning');
1575
- $rtnInfo{$tag} = $$srcExifTool{VALUE}{Error};
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.58';
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.28';
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 (ref 4)
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 eq "Rar!\x1a\x07\0";
306
+ return 0 unless $raf->Read($buff, 7) and $buff =~ "Rar!\x1a\x07[\0\x01]";
268
307
 
269
- $et->SetFileType();
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
- for (;;) {
275
- # read block header
276
- $raf->Read($buff, 7) == 7 or last;
277
- my ($type, $flags, $size) = unpack('xxCvv', $buff);
278
- $size -= 7;
279
- if ($flags & 0x8000) {
280
- $raf->Read($buff, 4) == 4 or last;
281
- $size += unpack('V',$buff) - 4;
282
- }
283
- last if $size < 0;
284
- next unless $size; # ignore blocks with no data
285
- # don't try to read very large blocks unless LargeFileSupport is enabled
286
- if ($size >= 0x80000000 and not $et->Options('LargeFileSupport')) {
287
- $et->Warn('Large block encountered. Aborting.');
288
- last;
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
- # process the block
291
- if ($type == 0x74) { # file block
292
- # read maximum 4 KB from a file block
293
- my $n = $size > 4096 ? 4096 : $size;
294
- $raf->Read($buff, $n) == $n or last;
295
- # add compressed size to start of data so we can extract it with the other tags
296
- $buff = pack('V',$size) . $buff;
297
- $$et{DOC_NUM} = ++$docNum;
298
- $et->ProcessDirectory({ DataPt => \$buff }, $tagTablePtr);
299
- $size -= $n;
300
- } elsif ($type == 0x75 and $size > 6) { # comment block
301
- $raf->Read($buff, $size) == $size or last;
302
- # save comment, only if "Stored" (this is untested)
303
- if (Get8u(\$buff, 3) == 0x30) {
304
- $et->FoundTag('Comment', substr($buff, 6));
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
- next;
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
- # seek to the start of the next block
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