parse basic file header
This commit is contained in:
parent
519d0748be
commit
ea18640a78
1 changed files with 203 additions and 5 deletions
|
|
@ -7,6 +7,122 @@ use androscalpel_serializer::{ReadSeek, Result, Serializable};
|
||||||
//struct Signature(pub [u8; 4]);
|
//struct Signature(pub [u8; 4]);
|
||||||
struct Signature(pub u32);
|
struct Signature(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct FileHeader {
|
||||||
|
// signature: Signature(0x02014b50)
|
||||||
|
version_made_by: u16,
|
||||||
|
version_needed_to_extract: u16,
|
||||||
|
general_purpose_flag: u16,
|
||||||
|
compression_method: u16,
|
||||||
|
last_mod_file_time: u16,
|
||||||
|
last_mod_file_data: u16,
|
||||||
|
crc_32: u32,
|
||||||
|
compressed_size: u32,
|
||||||
|
uncompressed_size: u32,
|
||||||
|
// file_name_length: u16,
|
||||||
|
// extra_field_length: u16,
|
||||||
|
// file_comment_length: u16,
|
||||||
|
disk_number_start: u16,
|
||||||
|
internal_file_attributes: u16,
|
||||||
|
external_file_attributes: u32,
|
||||||
|
offset_local_header: u32,
|
||||||
|
file_name: Vec<u8>,
|
||||||
|
extra_field: Vec<u8>, // TODO: zip64
|
||||||
|
file_comment: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for FileHeader {
|
||||||
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::SIGNATURE.serialize(output)?;
|
||||||
|
self.version_made_by.serialize(output)?;
|
||||||
|
self.version_needed_to_extract.serialize(output)?;
|
||||||
|
self.general_purpose_flag.serialize(output)?;
|
||||||
|
self.compression_method.serialize(output)?;
|
||||||
|
self.last_mod_file_time.serialize(output)?;
|
||||||
|
self.last_mod_file_data.serialize(output)?;
|
||||||
|
self.crc_32.serialize(output)?;
|
||||||
|
self.compressed_size.serialize(output)?;
|
||||||
|
self.uncompressed_size.serialize(output)?;
|
||||||
|
(self.file_name.len() as u16).serialize(output)?;
|
||||||
|
(self.extra_field.len() as u16).serialize(output)?;
|
||||||
|
(self.file_comment.len() as u16).serialize(output)?;
|
||||||
|
self.disk_number_start.serialize(output)?;
|
||||||
|
self.internal_file_attributes.serialize(output)?;
|
||||||
|
self.external_file_attributes.serialize(output)?;
|
||||||
|
self.offset_local_header.serialize(output)?;
|
||||||
|
for c in &self.file_name {
|
||||||
|
c.serialize(output)?;
|
||||||
|
}
|
||||||
|
for c in &self.extra_field {
|
||||||
|
c.serialize(output)?;
|
||||||
|
}
|
||||||
|
for c in &self.file_comment {
|
||||||
|
c.serialize(output)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
||||||
|
let signature = Signature::deserialize(input)?;
|
||||||
|
assert_eq!(signature, Self::SIGNATURE); // TODO
|
||||||
|
let version_made_by = u16::deserialize(input)?;
|
||||||
|
let version_needed_to_extract = u16::deserialize(input)?;
|
||||||
|
let general_purpose_flag = u16::deserialize(input)?;
|
||||||
|
let compression_method = u16::deserialize(input)?;
|
||||||
|
let last_mod_file_time = u16::deserialize(input)?;
|
||||||
|
let last_mod_file_data = u16::deserialize(input)?;
|
||||||
|
let crc_32 = u32::deserialize(input)?;
|
||||||
|
let compressed_size = u32::deserialize(input)?;
|
||||||
|
let uncompressed_size = u32::deserialize(input)?;
|
||||||
|
let file_name_length = u16::deserialize(input)?;
|
||||||
|
let extra_field_length = u16::deserialize(input)?;
|
||||||
|
let file_comment_length = u16::deserialize(input)?;
|
||||||
|
let disk_number_start = u16::deserialize(input)?;
|
||||||
|
let internal_file_attributes = u16::deserialize(input)?;
|
||||||
|
let external_file_attributes = u32::deserialize(input)?;
|
||||||
|
let offset_local_header = u32::deserialize(input)?;
|
||||||
|
let mut file_name = vec![];
|
||||||
|
let mut extra_field = vec![];
|
||||||
|
let mut file_comment = vec![];
|
||||||
|
for _ in 0..file_name_length {
|
||||||
|
file_name.push(u8::deserialize(input)?);
|
||||||
|
}
|
||||||
|
for _ in 0..extra_field_length {
|
||||||
|
extra_field.push(u8::deserialize(input)?);
|
||||||
|
}
|
||||||
|
for _ in 0..file_comment_length {
|
||||||
|
file_comment.push(u8::deserialize(input)?);
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
version_made_by,
|
||||||
|
version_needed_to_extract,
|
||||||
|
general_purpose_flag,
|
||||||
|
compression_method,
|
||||||
|
last_mod_file_time,
|
||||||
|
last_mod_file_data,
|
||||||
|
crc_32,
|
||||||
|
compressed_size,
|
||||||
|
uncompressed_size,
|
||||||
|
disk_number_start,
|
||||||
|
internal_file_attributes,
|
||||||
|
external_file_attributes,
|
||||||
|
offset_local_header,
|
||||||
|
file_name,
|
||||||
|
extra_field,
|
||||||
|
file_comment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
Self::MIN_SIZE + self.file_name.len() + self.extra_field.len() + self.file_comment.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileHeader {
|
||||||
|
const SIGNATURE: Signature = Signature(0x02014b50);
|
||||||
|
const MIN_SIZE: usize = 4 + 6 * 2 + 4 * 3 + 5 * 2 + 4 * 2;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct Zip64EndCentralDirectory {
|
struct Zip64EndCentralDirectory {
|
||||||
// signature: Signature
|
// signature: Signature
|
||||||
|
|
@ -164,7 +280,8 @@ impl Serializable for EndCentralDirectory {
|
||||||
|
|
||||||
struct ZipFile<T: Read + Seek> {
|
struct ZipFile<T: Read + Seek> {
|
||||||
end_of_central_directory: EndCentralDirectory,
|
end_of_central_directory: EndCentralDirectory,
|
||||||
end_of_central_directory_off: u64,
|
zip64_end_of_central_directory: Option<Zip64EndCentralDirectory>,
|
||||||
|
files: Vec<FileHeader>,
|
||||||
data: T,
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +300,7 @@ impl<T: Read + Seek> ZipFile<T> {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let zip64_ecd_locator = Zip64EndCentralDirectoryLocator::deserialize(&mut reader).ok();
|
let zip64_ecd_locator = Zip64EndCentralDirectoryLocator::deserialize(&mut reader).ok();
|
||||||
if let Some(zip64_ecd_locator) = zip64_ecd_locator {
|
let zip64_end_of_central_directory = if let Some(zip64_ecd_locator) = zip64_ecd_locator {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
zip64_ecd_locator.disk_number_of_zip64_end_central_directory_start,
|
zip64_ecd_locator.disk_number_of_zip64_end_central_directory_start,
|
||||||
0
|
0
|
||||||
|
|
@ -195,12 +312,93 @@ impl<T: Read + Seek> ZipFile<T> {
|
||||||
reader.seek(SeekFrom::Start(zip64_edc_record_off)).unwrap();
|
reader.seek(SeekFrom::Start(zip64_edc_record_off)).unwrap();
|
||||||
let zip64_edc_reccord = Zip64EndCentralDirectory::deserialize(&mut reader).ok();
|
let zip64_edc_reccord = Zip64EndCentralDirectory::deserialize(&mut reader).ok();
|
||||||
println!("{zip64_edc_reccord:#?}");
|
println!("{zip64_edc_reccord:#?}");
|
||||||
|
zip64_edc_reccord
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// At this point python's ziplib recompute the location of the central directory from the
|
||||||
|
// location of the end of central directory in case the zip was concanated after a file.
|
||||||
|
// We probably don't need that for now.
|
||||||
|
let mut zip_file = Self {
|
||||||
|
end_of_central_directory,
|
||||||
|
zip64_end_of_central_directory,
|
||||||
|
data: reader,
|
||||||
|
files: vec![],
|
||||||
|
};
|
||||||
|
zip_file
|
||||||
|
.data
|
||||||
|
.seek(SeekFrom::Start(zip_file.get_ed_offset()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut size_read = 0;
|
||||||
|
let cd_size = zip_file.get_ed_size();
|
||||||
|
while size_read < cd_size {
|
||||||
|
let file_header = FileHeader::deserialize(&mut zip_file.data).unwrap();
|
||||||
|
size_read += file_header.size() as u64;
|
||||||
|
zip_file.files.push(file_header);
|
||||||
|
}
|
||||||
|
assert_eq!(size_read, cd_size);
|
||||||
|
for f in &zip_file.files {
|
||||||
|
println!("{f:?}");
|
||||||
|
}
|
||||||
|
zip_file
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
/*
|
||||||
end_of_central_directory,
|
fn is_zip64(&self) -> bool {
|
||||||
end_of_central_directory_off,
|
self.zip64_end_of_central_directory.is_some()
|
||||||
data: reader,
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn get_disk_num(&self) -> u32 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.number_of_this_disk
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory.disk_number as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_disk_ed_start(&self) -> u32 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.disk_number_of_central_directory_start
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory
|
||||||
|
.disk_number_of_central_directory_start as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_number_entries_on_disk(&self) -> u64 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.number_entry_in_central_directory_on_this_disk
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory
|
||||||
|
.number_of_entries_in_central_directory_on_disk as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_number_entries(&self) -> u64 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.number_entry_in_central_directory
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory
|
||||||
|
.number_of_entries_in_central_directory as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ed_size(&self) -> u64 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.size_of_central_directory
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory.size_central_directory as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ed_offset(&self) -> u64 {
|
||||||
|
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||||
|
zip64_end_of_central_directory.offset_central_directory
|
||||||
|
} else {
|
||||||
|
self.end_of_central_directory.offset_central_directory as u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue