diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/zip/src/spec.rs | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/zip/src/spec.rs')
-rw-r--r-- | third_party/rust/zip/src/spec.rs | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/third_party/rust/zip/src/spec.rs b/third_party/rust/zip/src/spec.rs new file mode 100644 index 0000000000..2f5466f744 --- /dev/null +++ b/third_party/rust/zip/src/spec.rs @@ -0,0 +1,190 @@ +use std::io; +use std::io::prelude::*; +use result::{ZipResult, ZipError}; +use podio::{ReadPodExt, WritePodExt, LittleEndian}; + +pub const LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; +pub const CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; +const CENTRAL_DIRECTORY_END_SIGNATURE : u32 = 0x06054b50; +pub const ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE : u32 = 0x06064b50; +const ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE : u32 = 0x07064b50; + +pub struct CentralDirectoryEnd +{ + pub disk_number: u16, + pub disk_with_central_directory: u16, + pub number_of_files_on_this_disk: u16, + pub number_of_files: u16, + pub central_directory_size: u32, + pub central_directory_offset: u32, + pub zip_file_comment: Vec<u8>, +} + +impl CentralDirectoryEnd +{ + pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> + { + let magic = try!(reader.read_u32::<LittleEndian>()); + if magic != CENTRAL_DIRECTORY_END_SIGNATURE + { + return Err(ZipError::InvalidArchive("Invalid digital signature header")) + } + let disk_number = try!(reader.read_u16::<LittleEndian>()); + let disk_with_central_directory = try!(reader.read_u16::<LittleEndian>()); + let number_of_files_on_this_disk = try!(reader.read_u16::<LittleEndian>()); + let number_of_files = try!(reader.read_u16::<LittleEndian>()); + let central_directory_size = try!(reader.read_u32::<LittleEndian>()); + let central_directory_offset = try!(reader.read_u32::<LittleEndian>()); + let zip_file_comment_length = try!(reader.read_u16::<LittleEndian>()) as usize; + let zip_file_comment = try!(ReadPodExt::read_exact(reader, zip_file_comment_length)); + + Ok(CentralDirectoryEnd + { + disk_number: disk_number, + disk_with_central_directory: disk_with_central_directory, + number_of_files_on_this_disk: number_of_files_on_this_disk, + number_of_files: number_of_files, + central_directory_size: central_directory_size, + central_directory_offset: central_directory_offset, + zip_file_comment: zip_file_comment, + }) + } + + pub fn find_and_parse<T: Read+io::Seek>(reader: &mut T) -> ZipResult<(CentralDirectoryEnd, u64)> + { + const HEADER_SIZE: u64 = 22; + const BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE: u64 = HEADER_SIZE - 6; + let file_length = try!(reader.seek(io::SeekFrom::End(0))); + + let search_upper_bound = file_length.checked_sub(HEADER_SIZE + ::std::u16::MAX as u64).unwrap_or(0); + + if file_length < HEADER_SIZE { + return Err(ZipError::InvalidArchive("Invalid zip header")); + } + + let mut pos = file_length - HEADER_SIZE; + while pos >= search_upper_bound + { + try!(reader.seek(io::SeekFrom::Start(pos as u64))); + if try!(reader.read_u32::<LittleEndian>()) == CENTRAL_DIRECTORY_END_SIGNATURE + { + try!(reader.seek(io::SeekFrom::Current(BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64))); + let comment_length = try!(reader.read_u16::<LittleEndian>()) as u64; + if file_length - pos - HEADER_SIZE == comment_length + { + let cde_start_pos = try!(reader.seek(io::SeekFrom::Start(pos as u64))); + return CentralDirectoryEnd::parse(reader).map(|cde| (cde, cde_start_pos)); + } + } + pos = match pos.checked_sub(1) { + Some(p) => p, + None => break, + }; + } + Err(ZipError::InvalidArchive("Could not find central directory end")) + } + + pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> + { + try!(writer.write_u32::<LittleEndian>(CENTRAL_DIRECTORY_END_SIGNATURE)); + try!(writer.write_u16::<LittleEndian>(self.disk_number)); + try!(writer.write_u16::<LittleEndian>(self.disk_with_central_directory)); + try!(writer.write_u16::<LittleEndian>(self.number_of_files_on_this_disk)); + try!(writer.write_u16::<LittleEndian>(self.number_of_files)); + try!(writer.write_u32::<LittleEndian>(self.central_directory_size)); + try!(writer.write_u32::<LittleEndian>(self.central_directory_offset)); + try!(writer.write_u16::<LittleEndian>(self.zip_file_comment.len() as u16)); + try!(writer.write_all(&self.zip_file_comment)); + Ok(()) + } +} + +pub struct Zip64CentralDirectoryEndLocator +{ + pub disk_with_central_directory: u32, + pub end_of_central_directory_offset: u64, + pub number_of_disks: u32, +} + +impl Zip64CentralDirectoryEndLocator +{ + pub fn parse<T: Read>(reader: &mut T) -> ZipResult<Zip64CentralDirectoryEndLocator> + { + let magic = try!(reader.read_u32::<LittleEndian>()); + if magic != ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE + { + return Err(ZipError::InvalidArchive("Invalid zip64 locator digital signature header")) + } + let disk_with_central_directory = try!(reader.read_u32::<LittleEndian>()); + let end_of_central_directory_offset = try!(reader.read_u64::<LittleEndian>()); + let number_of_disks = try!(reader.read_u32::<LittleEndian>()); + + Ok(Zip64CentralDirectoryEndLocator + { + disk_with_central_directory: disk_with_central_directory, + end_of_central_directory_offset: end_of_central_directory_offset, + number_of_disks: number_of_disks, + }) + } +} + +pub struct Zip64CentralDirectoryEnd +{ + pub version_made_by: u16, + pub version_needed_to_extract: u16, + pub disk_number: u32, + pub disk_with_central_directory: u32, + pub number_of_files_on_this_disk: u64, + pub number_of_files: u64, + pub central_directory_size: u64, + pub central_directory_offset: u64, + //pub extensible_data_sector: Vec<u8>, <-- We don't do anything with this at the moment. +} + +impl Zip64CentralDirectoryEnd +{ + pub fn find_and_parse<T: Read+io::Seek>(reader: &mut T, + nominal_offset: u64, + search_upper_bound: u64) -> ZipResult<(Zip64CentralDirectoryEnd, u64)> + { + let mut pos = nominal_offset; + + while pos <= search_upper_bound + { + reader.seek(io::SeekFrom::Start(pos))?; + + if reader.read_u32::<LittleEndian>()? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE + { + let archive_offset = pos - nominal_offset; + + let _record_size = try!(reader.read_u64::<LittleEndian>()); + // We would use this value if we did anything with the "zip64 extensible data sector". + + let version_made_by = try!(reader.read_u16::<LittleEndian>()); + let version_needed_to_extract = try!(reader.read_u16::<LittleEndian>()); + let disk_number = try!(reader.read_u32::<LittleEndian>()); + let disk_with_central_directory = try!(reader.read_u32::<LittleEndian>()); + let number_of_files_on_this_disk = try!(reader.read_u64::<LittleEndian>()); + let number_of_files = try!(reader.read_u64::<LittleEndian>()); + let central_directory_size = try!(reader.read_u64::<LittleEndian>()); + let central_directory_offset = try!(reader.read_u64::<LittleEndian>()); + + return Ok((Zip64CentralDirectoryEnd + { + version_made_by: version_made_by, + version_needed_to_extract: version_needed_to_extract, + disk_number: disk_number, + disk_with_central_directory: disk_with_central_directory, + number_of_files_on_this_disk: number_of_files_on_this_disk, + number_of_files: number_of_files, + central_directory_size: central_directory_size, + central_directory_offset: central_directory_offset, + }, archive_offset)); + } + + pos += 1; + } + + Err(ZipError::InvalidArchive("Could not find ZIP64 central directory end")) + } +} |