use crate::raw::{
ArchiveExtraDataRecord, ArchiveExtraDataRecordFixed, CentralDirectoryHeader, CentralDirectoryHeaderFixed,
DigitalSignature, DigitalSignatureFixed, EndOfCentralDirectory, EndOfCentralDirectoryFixed, ExtensibleData,
ExtensibleDataFixed, LocalFileHeader, LocalFileHeaderFixed, Zip64EndOfCentralDirectory,
Zip64EndOfCentralDirectoryFixed,
};
pub trait PartialRecord {
type Partial;
fn get_partial(&self) -> &Self::Partial;
fn is_valid_sizes(&self) -> bool;
}
impl PartialRecord for LocalFileHeader {
type Partial = LocalFileHeaderFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool {
self.file_name.len() == self.fixed.file_name_length as usize
&& self.extra_field.len() == self.fixed.extra_field_length as usize
}
}
impl PartialRecord for ArchiveExtraDataRecord {
type Partial = ArchiveExtraDataRecordFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool { self.extra_field_data.len() == self.fixed.extra_field_length as usize }
}
impl PartialRecord for CentralDirectoryHeader {
type Partial = CentralDirectoryHeaderFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool {
self.file_name.len() == self.fixed.file_name_length as usize
&& self.extra_field.len() == self.fixed.extra_field_length as usize
&& self.file_comment.len() == self.fixed.file_comment_length as usize
}
}
impl PartialRecord for DigitalSignature {
type Partial = DigitalSignatureFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool { self.signature_data.len() == self.fixed.size_of_data as usize }
}
impl PartialRecord for Zip64EndOfCentralDirectory {
type Partial = Zip64EndOfCentralDirectoryFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool {
const MIN_SIZE: usize = Zip64EndOfCentralDirectoryFixed::SIZE_IN_BYTES - 12;
if (self.fixed.size_of_zip64_end_of_central_directory_record as usize) < MIN_SIZE {
return false;
}
let length = self.fixed.size_of_zip64_end_of_central_directory_record as usize - MIN_SIZE;
self.zip64_extensible_data_sector.len() == length
}
}
impl PartialRecord for EndOfCentralDirectory {
type Partial = EndOfCentralDirectoryFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool { self.zip_file_comment.len() == self.fixed.zip_file_comment_length as usize }
}
impl PartialRecord for ExtensibleData {
type Partial = ExtensibleDataFixed;
fn get_partial(&self) -> &Self::Partial { &self.fixed }
fn is_valid_sizes(&self) -> bool { self.data.len() == self.fixed.data_size as usize }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partial_local_file_header() {
let file_name = vec![48, 49, 32, 50];
let extra_field = vec![61, 62, 32, 63, 64];
let lf = LocalFileHeader {
fixed: LocalFileHeaderFixed {
local_file_header_signature: LocalFileHeaderFixed::LOCAL_FILE_HEADER_SIGNATURE,
version_needed_to_extract: 1,
general_purpose_bit_flag: 2,
compression_method: 3,
last_mod_file_time: 4,
last_mod_file_date: 5,
crc_32: 6,
compressed_size: 7,
uncompressed_size: 8,
file_name_length: file_name.len() as u16,
extra_field_length: extra_field.len() as u16,
},
file_name: file_name.clone(),
extra_field: extra_field.clone(),
};
assert!(lf.is_valid_sizes());
let _ = lf.get_partial();
}
#[test]
fn partial_archive_extra_data_record() {
let extra_field_data = vec![48, 49, 32, 50];
let ad = ArchiveExtraDataRecord {
fixed: ArchiveExtraDataRecordFixed {
archive_extra_data_signature: 1,
extra_field_length: extra_field_data.len() as u64,
},
extra_field_data: extra_field_data.clone(),
};
assert!(ad.is_valid_sizes());
let _ = ad.get_partial();
}
#[test]
fn partial_central_directory_header() {
let file_name = vec![48, 49, 32, 50];
let extra_field = vec![61, 62, 32, 63, 64];
let file_comment = vec![51, 52, 53, 32, 54, 55];
let cd = CentralDirectoryHeader {
fixed: CentralDirectoryHeaderFixed {
central_file_header_signature: 1,
version_made_by: 2,
version_needed_to_extract: 3,
general_purpose_bit_flag: 4,
compression_method: 5,
last_mod_file_time: 6,
last_mod_file_date: 7,
crc_32: 8,
compressed_size: 9,
uncompressed_size: 10,
file_name_length: file_name.len() as u16,
extra_field_length: extra_field.len() as u16,
file_comment_length: file_comment.len() as u16,
disk_number_start: 11,
internal_file_attributes: 12,
external_file_attributes: 13,
relative_offset_of_local_header: 14,
},
file_name: file_name.clone(),
extra_field: extra_field.clone(),
file_comment: file_comment.clone(),
};
assert!(cd.is_valid_sizes());
let _ = cd.get_partial();
}
#[test]
fn partial_digital_signature() {
let signature_data = vec![48, 49, 32, 50];
let ds = DigitalSignature {
fixed: DigitalSignatureFixed {
header_signature: DigitalSignatureFixed::HEADER_SIGNATURE,
size_of_data: signature_data.len() as u16,
},
signature_data: signature_data.clone(),
};
assert!(ds.is_valid_sizes());
let _ = ds.get_partial();
}
#[test]
fn partial_zip64_end_of_central_directory() {
let mut directory = Zip64EndOfCentralDirectory {
fixed: Zip64EndOfCentralDirectoryFixed {
zip64_end_of_central_dir_signature: 1,
size_of_zip64_end_of_central_directory_record: Zip64EndOfCentralDirectoryFixed::SIZE_IN_BYTES as u64
- 8,
version_made_by: 3,
version_needed_to_extract: 4,
number_of_this_disk: 5,
number_of_the_disk_with_the_start_of_the_central_directory: 6,
total_number_of_entries_in_the_central_directory_on_this_disk: 7,
total_number_of_entries_in_the_central_directory: 8,
size_of_the_central_directory: 9,
offset_of_start_of_central_directory_with_respect_to_the_starting_disk_number: 10,
},
zip64_extensible_data_sector: vec![48, 49, 50, 51],
};
assert!(directory.is_valid_sizes());
let _ = directory.get_partial();
directory.fixed.size_of_zip64_end_of_central_directory_record =
Zip64EndOfCentralDirectoryFixed::SIZE_IN_BYTES as u64 - 13;
assert!(!directory.is_valid_sizes());
}
#[test]
fn partial_end_of_central_directory() {
let zip_file_comment = vec![48, 49, 32, 50];
let cd = EndOfCentralDirectory {
fixed: EndOfCentralDirectoryFixed {
end_of_central_dir_signature: 1,
number_of_this_disk: 2,
number_of_the_disk_with_the_start_of_the_central_directory: 3,
total_number_of_entries_in_the_central_directory_on_this_disk: 4,
total_number_of_entries_in_the_central_directory: 5,
size_of_the_central_directory: 6,
offset_of_start_of_central_directory_with_respect_to_the_starting_disk_number: 7,
zip_file_comment_length: zip_file_comment.len() as u16,
},
zip_file_comment: zip_file_comment.clone(),
};
assert!(cd.is_valid_sizes());
let _ = cd.get_partial();
}
#[test]
fn partial_extensible_data() {
let data = vec![48, 49, 32];
let ed = ExtensibleData {
fixed: ExtensibleDataFixed {
header_id: 0x0001,
data_size: data.len() as u16,
},
data: data.clone(),
};
assert!(ed.is_valid_sizes());
let _ = ed.get_partial();
}
}