@@ -215,7 +215,7 @@ const FileExtents = struct {
215
215
local_file_header_offset : u64 ,
216
216
};
217
217
218
- fn readZip64FileExtents (header : CentralDirectoryFileHeader , extents : * FileExtents , data : []u8 ) ! void {
218
+ fn readZip64FileExtents (comptime T : type , header : T , extents : * FileExtents , data : []u8 ) ! void {
219
219
var data_offset : usize = 0 ;
220
220
if (isMaxInt (header .uncompressed_size )) {
221
221
if (data_offset + 8 > data .len )
@@ -229,22 +229,28 @@ fn readZip64FileExtents(header: CentralDirectoryFileHeader, extents: *FileExtent
229
229
extents .compressed_size = std .mem .readInt (u64 , data [data_offset .. ][0.. 8], .little );
230
230
data_offset += 8 ;
231
231
}
232
- if (isMaxInt (header .local_file_header_offset )) {
233
- if (data_offset + 8 > data .len )
234
- return error .ZipBadCd64Size ;
235
- extents .local_file_header_offset = std .mem .readInt (u64 , data [data_offset .. ][0.. 8], .little );
236
- data_offset += 8 ;
237
- }
238
- if (isMaxInt (header .disk_number )) {
239
- if (data_offset + 4 > data .len )
240
- return error .ZipInvalid ;
241
- const disk_number = std .mem .readInt (u32 , data [data_offset .. ][0.. 4], .little );
242
- if (disk_number != 0 )
243
- return error .ZipMultiDiskUnsupported ;
244
- data_offset += 4 ;
232
+
233
+ switch (T ) {
234
+ CentralDirectoryFileHeader = > {
235
+ if (isMaxInt (header .local_file_header_offset )) {
236
+ if (data_offset + 8 > data .len )
237
+ return error .ZipBadCd64Size ;
238
+ extents .local_file_header_offset = std .mem .readInt (u64 , data [data_offset .. ][0.. 8], .little );
239
+ data_offset += 8 ;
240
+ }
241
+ if (isMaxInt (header .disk_number )) {
242
+ if (data_offset + 4 > data .len )
243
+ return error .ZipInvalid ;
244
+ const disk_number = std .mem .readInt (u32 , data [data_offset .. ][0.. 4], .little );
245
+ if (disk_number != 0 )
246
+ return error .ZipMultiDiskUnsupported ;
247
+ data_offset += 4 ;
248
+ }
249
+ if (data_offset > data .len )
250
+ return error .ZipBadCd64Size ;
251
+ },
252
+ else = > {},
245
253
}
246
- if (data_offset > data .len )
247
- return error .ZipBadCd64Size ;
248
254
}
249
255
250
256
pub fn Iterator (comptime SeekableStream : type ) type {
@@ -394,7 +400,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
394
400
return error .ZipBadExtraFieldSize ;
395
401
const data = extra [extra_offset + 4 .. end ];
396
402
switch (@as (ExtraHeader , @enumFromInt (header_id ))) {
397
- .zip64_info = > try readZip64FileExtents (header , & extents , data ),
403
+ .zip64_info = > try readZip64FileExtents (CentralDirectoryFileHeader , header , & extents , data ),
398
404
else = > {}, // ignore
399
405
}
400
406
extra_offset = end ;
@@ -466,12 +472,45 @@ pub fn Iterator(comptime SeekableStream: type) type {
466
472
return error .ZipMismatchFlags ;
467
473
if (local_header .crc32 != 0 and local_header .crc32 != self .crc32 )
468
474
return error .ZipMismatchCrc32 ;
469
- if (local_header .compressed_size != 0 and
470
- local_header .compressed_size != self .compressed_size )
475
+ var extents : FileExtents = .{
476
+ .uncompressed_size = local_header .uncompressed_size ,
477
+ .compressed_size = local_header .compressed_size ,
478
+ .local_file_header_offset = 0 ,
479
+ };
480
+ if (local_header .extra_len > 0 ) {
481
+ var extra_buf : [std .math .maxInt (u16 )]u8 = undefined ;
482
+ const extra = extra_buf [0.. local_header .extra_len ];
483
+
484
+ {
485
+ try stream .seekTo (self .file_offset + @sizeOf (LocalFileHeader ) + local_header .filename_len );
486
+ const len = try stream .context .reader ().readAll (extra );
487
+ if (len != extra .len )
488
+ return error .ZipTruncated ;
489
+ }
490
+
491
+ var extra_offset : usize = 0 ;
492
+ while (extra_offset + 4 <= local_header .extra_len ) {
493
+ const header_id = std .mem .readInt (u16 , extra [extra_offset .. ][0.. 2], .little );
494
+ const data_size = std .mem .readInt (u16 , extra [extra_offset .. ][2.. 4], .little );
495
+ const end = extra_offset + 4 + data_size ;
496
+ if (end > local_header .extra_len )
497
+ return error .ZipBadExtraFieldSize ;
498
+ const data = extra [extra_offset + 4 .. end ];
499
+ switch (@as (ExtraHeader , @enumFromInt (header_id ))) {
500
+ .zip64_info = > try readZip64FileExtents (LocalFileHeader , local_header , & extents , data ),
501
+ else = > {}, // ignore
502
+ }
503
+ extra_offset = end ;
504
+ }
505
+ }
506
+
507
+ if (extents .compressed_size != 0 and
508
+ extents .compressed_size != self .compressed_size )
471
509
return error .ZipMismatchCompLen ;
472
- if (local_header .uncompressed_size != 0 and
473
- local_header .uncompressed_size != self .uncompressed_size )
510
+ if (extents .uncompressed_size != 0 and
511
+ extents .uncompressed_size != self .uncompressed_size )
474
512
return error .ZipMismatchUncompLen ;
513
+
475
514
if (local_header .filename_len != self .filename_len )
476
515
return error .ZipMismatchFilenameLen ;
477
516
@@ -695,6 +734,20 @@ test "zip64" {
695
734
.central_directory_offset = std .math .maxInt (u32 ), // trigger zip64
696
735
},
697
736
});
737
+ try testZip (.{}, & test_files , .{
738
+ .end = .{
739
+ .zip64 = .{},
740
+ .central_directory_offset = std .math .maxInt (u32 ), // trigger zip64
741
+ },
742
+ .local_header = .{
743
+ .zip64 = .{ // trigger local header zip64
744
+ .data_size = 16 ,
745
+ },
746
+ .compressed_size = std .math .maxInt (u32 ),
747
+ .uncompressed_size = std .math .maxInt (u32 ),
748
+ .extra_len = 20 ,
749
+ },
750
+ });
698
751
}
699
752
700
753
test "bad zip files" {
0 commit comments