From b8c83ab5c133dc1330aa425a012d45f3c62e7ef1 Mon Sep 17 00:00:00 2001 From: Igor Tolmachov Date: Wed, 30 Aug 2023 23:33:11 +0900 Subject: Add zip archive datatypes --- src/zip/datatypes.rs | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/zip/mod.rs | 1 + 2 files changed, 271 insertions(+) create mode 100644 src/zip/datatypes.rs (limited to 'src/zip') diff --git a/src/zip/datatypes.rs b/src/zip/datatypes.rs new file mode 100644 index 0000000..b280e5d --- /dev/null +++ b/src/zip/datatypes.rs @@ -0,0 +1,270 @@ +use crate::datatypes::{utils, ArchiveDatatype}; +use crate::result::{ArchiveError, ArchiveResult}; +use std::io::{Read, Write}; + +utils::create_archive_datatype! { + pub struct LocalFileHeader { + signature: u32, + version_needed: u16, + general_purpose_bit_flag: u16, + compression_method: u16, + last_mod_file_time: u16, + last_mod_file_date: u16, + crc32: u32, + compressed_size: u32, + uncompressed_size: u32, + file_name_length: u16, + extra_field_length: u16, + } + + let file_name: String { + size: file_name_length, + read: utils::read_string, + write: utils::write_string, + } + + let extra_field: Vec { + size: file_name_length, + read: utils::vec, + write: utils::vec, + } + + const { + SIGNATURE: u32 = 0x04034b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +pub struct DataDescriptor { + pub signature: Option, + pub crc32: u32, + pub compressed_size: u32, + pub uncompressed_size: u32, +} + +impl DataDescriptor { + const SIGNATURE: u32 = 0x04034b50; +} + +impl ArchiveDatatype for DataDescriptor { + const SIZE: usize = 12; + + fn read(mut reader: impl Read) -> ArchiveResult { + let mut buf = [0; Self::SIZE]; + reader.read(&mut buf)?; + + let signature = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]); + if signature == Self::SIGNATURE { + return Ok(Self { + signature: Some(signature), + crc32: u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]), + compressed_size: u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]), + uncompressed_size: { + let mut buf = [0; 4]; + reader.read(&mut buf)?; + u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]) + }, + }); + } else { + return Ok(Self { + signature: None, + crc32: signature, + compressed_size: u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]), + uncompressed_size: u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]), + }); + } + } + + fn write(&self, mut writer: impl Write) -> ArchiveResult<()> { + writer.write( + &[ + Self::SIGNATURE.to_le_bytes(), + self.crc32.to_le_bytes(), + self.compressed_size.to_le_bytes(), + self.uncompressed_size.to_le_bytes(), + ] + .concat(), + )?; + Ok(()) + } +} + +utils::create_archive_datatype! { + pub struct ArchiveExtraDataRecord { + signature: u32, + extra_field_length: u32, + } + + let extra_field: Vec { + size: extra_field_length, + read: utils::vec, + write: utils::vec, + } + + const { + SIGNATURE: u32 = 0x08064b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +utils::create_archive_datatype! { + pub struct CentralDirectoryRecord { + signature: u32, + version_made_by: u16, + version_needed: u16, + general_purpose_bit_flag: u16, + compression_method: u16, + last_mod_file_time: u16, + last_mod_file_date: u16, + crc32: u32, + compressed_size: u32, + uncompressed_size: u32, + file_name_length: u16, + extra_field_length: u16, + file_comment_length: u16, + disk_number: u16, + internal_file_attributes: u16, + external_file_attributes: u32, + relative_header_offset: u32, + } + + let file_name: String { + size: file_name_length, + read: utils::read_string, + write: utils::write_string, + } + + let extra_field: Vec { + size: external_file_attributes, + read: utils::vec, + write: utils::vec, + } + + let file_comment: String { + size: file_comment_length, + read: utils::read_string, + write: utils::write_string, + } + + const { + SIGNATURE: u32 = 0x02014b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +utils::create_archive_datatype! { + pub struct DigitalSignature{ + signature: u32, + data_size: u16, + } + + let data: Vec { + size: data_size, + read: utils::vec, + write: utils::vec, + } + + const { + SIGNATURE: u32 = 0x05054b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +utils::create_archive_datatype! { + pub struct Zip64EndOfCentralDirectoryRecord { + signature: u32, + size_of_struct: u64, + version_made_by: u16, + version_needed: u16, + disk_number: u32, + disk_number_where_starts_central_directory: u32, + entries_in_central_directory_on_disk: u64, + entries_in_central_directory: u64, + size_of_central_directory_records: u64, + offset_of_central_directory_entries: u64, + } + + let extensible_data: Vec { + size: size_of_struct - Self::SIZE as u64 + 12, + read: utils::vec, + write: utils::vec, + } + + const { + SIGNATURE: u32 = 0x08064b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +utils::create_archive_datatype! { + pub struct Zip64EndOfCentralDirectoryLocator { + signature: u32, + disk_number_where_starts_zip64_eocd: u32, + relative_offset_of_zip64_eocd: u64, + total_disks_number: u32, + } + + const { + SIGNATURE: u32 = 0x07064b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} + +utils::create_archive_datatype! { + pub struct EndOfCentralDirectoryRecord { + signature: u32, + disk_number: u16, + disk_number_where_starts_central_directory: u16, + entries_in_central_directory_on_disk: u16, + entries_in_central_directory: u16, + size_of_central_directory_records: u32, + offset_of_central_directory_entries: u32, + comment_length: u16, + } + + let comment: String { + size: comment_length, + read: utils::read_string, + write: utils::write_string, + } + + const { + SIGNATURE: u32 = 0x06054b50; + } + + read { + if signature != Self::SIGNATURE { + return Err(ArchiveError::WrongSignature { expected: Self::SIGNATURE, received: signature }) + } + } +} diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 5241c87..b668b6b 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -1,4 +1,5 @@ mod archive; +mod datatypes; mod file; mod io; -- cgit v1.2.3