zip-core 0.0.4

zip implementation independent structs and helpers
Documentation
//! `zip-core::raw` contains 1:1 memory format of zip headers for use in your
//! projects  e.g. if you want to build your own zip crate.
//!
//! Note: for concenience, all structs with variable size are split into a fixed
//! part and the variable part. The fixed part is prepended with `Fixed`. This
//! should make parsing easier
//!
//!
//! ### Rage List of things about <https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT>
//! - all fields unless noted are unsigned and little endian (there are no
//!   notions), however we should set one to -1 in 4.4.1.4, how?!?!
//! - optional signature that are not standart but are recomended.
//! - noone explains what zip64 does, what it tries to do, etc.
//! - measurements, sometimes its offset, sometimes total size, sometimes
//!   remaining size, and sometimes, size from this byte onwards
//!
//! #### Naming Rage
//! During reading the document I almost had a seizure regarding to naming.
//! Nevertheless I decided against renaming fields, as this is what the author
//! PKWARE decided on, and probably the whole industry has adopted to and i dont
//! want to create xkcd:927 However, if in future revisions some names are
//! adopted I would be more than happy. Here are some of the incompatibilities
//!
//! - of all fields and structures, sometimes sturct, sometimes record, often
//!   nothing
//! - sometimes central dir, sometimes central directory
//! - Zip64 end of central directory locator vs Zip64 end of central directory
//!   locator record
//! - the central directory is sometimes a single central directory header and
//!   sometimes a central directory structure
//! - sometimes its a length sometimes a size
extern crate alloc;
use alloc::vec::Vec;

#[cfg(feature = "parse")] pub mod parse;

/// part of [`LocalFileHeader`] which has a fixed size
///
/// [`LocalFileHeader`]: LocalFileHeader
#[derive(Debug, Clone, PartialEq)]
pub struct LocalFileHeaderFixed {
    pub local_file_header_signature: u32,
    pub version_needed_to_extract: u16,
    pub general_purpose_bit_flag: u16,
    pub compression_method: u16,
    pub last_mod_file_time: u16,
    pub last_mod_file_date: u16,
    pub crc_32: u32,
    pub compressed_size: u32,
    pub uncompressed_size: u32,
    pub file_name_length: u16,
    pub extra_field_length: u16,
}

/// Local File Header
///
/// The local file header is prepended before each file.
/// The bytes after it are usually the file or an Encryption Header.
/// is is linked by an [`CentralDirectoryHeader`]
///
/// see [4.3.7](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
///
/// [`CentralDirectoryHeader`]: CentralDirectoryHeader
#[derive(Debug, Clone, PartialEq)]
pub struct LocalFileHeader {
    pub fixed:       LocalFileHeaderFixed,
    pub file_name:   Vec<u8>,
    pub extra_field: Vec<u8>,
}

/// Data descriptor
///
/// the data descriptior is prepended to the file data.
/// It might be used sometimes, in this case the corresponding fields in
/// [`LocalFileHeader`] are zero.
///
/// Note: There exists a zip64 variant of this descriptor:
/// [`DataDescriptorZip64`] Note: the DataDescriptor should contain a signature,
/// see the struct [`DataDescriptorSignature`]. Its not standart but recomended.
/// When parsing you are on your own if the first 4 bytes a the signature or
/// just a random crc32 according to the documentation
/// see [`DataDescriptorZip64Signature`] for Zip64 with Signature
///
/// see [4.3.9](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
///
/// [`LocalFileHeader`]: LocalFileHeaderFixed
/// [`DataDescriptorZip64`]: DataDescriptorZip64
/// [`DataDescriptorSignature`]: DataDescriptorSignature
/// [`DataDescriptorZip64Signature`]: DataDescriptorZip64Signature
#[derive(Debug, Clone, PartialEq)]
pub struct DataDescriptor {
    pub crc_32: u32,
    pub compressed_size: u32,
    pub uncompressed_size: u32,
}

/// Data descriptor with a signature see [`DataDescriptor`]
///
/// [`DataDescriptor`]: DataDescriptor
#[derive(Debug, Clone, PartialEq)]
pub struct DataDescriptorSignature {
    pub signature: u32,
    pub crc_32: u32,
    pub compressed_size: u32,
    pub uncompressed_size: u32,
}

/// Data descriptor for Zip64, sizes are 8 bytes instead of 4, see
/// [`DataDescriptor`]
///
/// [`DataDescriptor`]: DataDescriptor
#[derive(Debug, Clone, PartialEq)]
pub struct DataDescriptorZip64 {
    pub crc_32: u32,
    pub compressed_size: u64,
    pub uncompressed_size: u64,
}

/// Data descriptor for Zip64, sizes are 8 bytes instead of 4 and with a
/// signature, see [`DataDescriptor`]
///
/// [`DataDescriptor`]: DataDescriptor
#[derive(Debug, Clone, PartialEq)]
pub struct DataDescriptorZip64Signature {
    pub signature: u32,
    pub crc_32: u32,
    pub compressed_size: u64,
    pub uncompressed_size: u64,
}

/// part of [`ArchiveExtraDataRecord`] which has a fixed size
///
/// [`ArchiveExtraDataRecord`]: ArchiveExtraDataRecord
#[derive(Debug, Clone, PartialEq)]
pub struct ArchiveExtraDataRecordFixed {
    pub archive_extra_data_signature: u32,
    pub extra_field_length: u64,
}

/// Archive Extra Data Record
///
/// May be used to support the Central Directory Encryption Feature
///
/// see [4.3.11](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
#[derive(Debug, Clone, PartialEq)]
pub struct ArchiveExtraDataRecord {
    pub fixed: ArchiveExtraDataRecordFixed,
    pub extra_field_data: Vec<u8>,
}

/// part of [`CentralDirectoryHeader`] which has a fixed size
///
/// [`CentralDirectoryHeader`]: CentralDirectoryHeader
#[derive(Debug, Clone, PartialEq)]
pub struct CentralDirectoryHeaderFixed {
    pub central_file_header_signature: u32,
    pub version_made_by: u16,
    pub version_needed_to_extract: u16,
    pub general_purpose_bit_flag: u16,
    pub compression_method: u16,
    pub last_mod_file_time: u16,
    pub last_mod_file_date: u16,
    pub crc_32: u32,
    pub compressed_size: u32,
    pub uncompressed_size: u32,
    pub file_name_length: u16,
    pub extra_field_length: u16,
    pub file_comment_length: u16,
    pub disk_number_start: u16,
    pub internal_file_attributes: u16,
    pub external_file_attributes: u32,
    pub relative_offset_of_local_header: u32,
}

/// Central Directory Header
///
/// The Central Directory Structure contains of multiple Central Directory
/// Headers and a Digital Signature. Note: the documentation is confusing about
/// this, the Digital Signature is left out in `4.3.6` and Archive Decryption
/// Header and [`ArchiveExtraDataRecord`] seem to be not part of it, though they
/// have a strong dependency.
///
/// Each Central Directory Header links to exactly one [`LocalFileHeader`]
///
/// see [4.3.12](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
///
/// [`ArchiveExtraDataRecord`]: ArchiveExtraDataRecord
/// [`LocalFileHeader`]: LocalFileHeader
#[derive(Debug, Clone, PartialEq)]
pub struct CentralDirectoryHeader {
    pub fixed:        CentralDirectoryHeaderFixed,
    pub file_name:    Vec<u8>,
    pub extra_field:  Vec<u8>,
    pub file_comment: Vec<u8>,
}

/// part of [`DigitalSignature`] which has a fixed size
///
/// [`DigitalSignature`]: DigitalSignature
#[derive(Debug, Clone, PartialEq)]
pub struct DigitalSignatureFixed {
    pub header_signature: u32,
    pub size_of_data:     u16,
}

/// part of [`LocalFileHeader`] which has a fixed size
///
/// [`LocalFileHeader`]: LocalFileHeader
#[derive(Debug, Clone, PartialEq)]
pub struct DigitalSignature {
    pub fixed: DigitalSignatureFixed,
    pub signature_data: Vec<u8>,
}

/// Zip64 end of central directory record
///
/// see [4.3.14](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
#[derive(Debug, Clone, PartialEq)]
pub struct Zip64EndOfCentralDirectoryFixed {
    pub zip64_end_of_central_dir_signature: u32,
    pub size_of_zip64_end_of_central_directory_record: u64,
    pub version_made_by: u16,
    pub version_needed_to_extract: u16,
    pub number_of_this_disk: u32,
    pub number_of_the_disk_with_the_start_of_the_central_directory: u32,
    pub total_number_of_entries_in_the_central_directory_on_this_disk: u64,
    pub total_number_of_entries_in_the_central_directory: u64,
    pub size_of_the_central_directory: u64,
    pub offset_of_start_of_central_directory_with_respect_to_the_starting_disk_number: u64,
}

/// part of [`Zip64EndOfCentralDirectory`] which has a fixed size
///
/// [`Zip64EndOfCentralDirectory`]: Zip64EndOfCentralDirectory
#[derive(Debug, Clone, PartialEq)]
pub struct Zip64EndOfCentralDirectory {
    pub fixed: Zip64EndOfCentralDirectoryFixed,
    pub zip64_extensible_data_sector: Vec<u8>,
}

///  Zip64 end of central directory locator
///
/// see [4.3.14](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
#[derive(Debug, Clone, PartialEq)]
pub struct Zip64EndOfCentralDirectoryLocator {
    pub zip64_end_of_central_dir_locator_signature: u32,
    pub number_of_the_disk_with_the_start_of_the_central_directory: u32,
    pub relative_offset_of_the_zip64_end_of_central_directory_record: u64,
    pub number_of_this_disk: u32,
}

/// part of [`EndOfCentralDirectory`] which has a fixed size
///
/// [`EndOfCentralDirectory`]: EndOfCentralDirectory
#[derive(Debug, Clone, PartialEq)]
pub struct EndOfCentralDirectoryFixed {
    pub end_of_central_dir_signature: u32,
    pub number_of_this_disk: u16,
    pub number_of_the_disk_with_the_start_of_the_central_directory: u16,
    pub total_number_of_entries_in_the_central_directory_on_this_disk: u16,
    pub total_number_of_entries_in_the_central_directory: u16,
    pub size_of_the_central_directory: u32,
    pub offset_of_start_of_central_directory_with_respect_to_the_starting_disk_number: u32,
    pub zip_file_comment_length: u16,
}

/// End of central directory record
///
/// see [4.3.16](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
#[derive(Debug, Clone, PartialEq)]
pub struct EndOfCentralDirectory {
    pub fixed: EndOfCentralDirectoryFixed,
    pub zip_file_comment: Vec<u8>,
}

/// part of [`ExtensibleData`] which has a fixed size
///
/// [`ExtensibleData`]: ExtensibleData
#[derive(Debug, Clone, PartialEq)]
pub struct ExtensibleDataFixed {
    pub header_id: u16,
    pub data_size: u16,
}

/// Extensible data fields
///
/// often called `extra field` in above Records, they are used to store
/// additional information, like better file times or zip64 data.
/// You prob want to parse the `extra_data` of a record with those in case your
/// program is interested in Extensible Data. According to APPNOTE.TXT, programs
/// that don't understand certain headers should just ignore them.
///
/// see [4.5.1](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
#[derive(Debug, Clone, PartialEq)]
pub struct ExtensibleData {
    pub fixed: ExtensibleDataFixed,
    pub data:  Vec<u8>,
}

impl LocalFileHeaderFixed {
    pub const LOCAL_FILE_HEADER_SIGNATURE: u32 = 0x04034b50;
    pub const SIZE_IN_BYTES: usize = 30;
}

impl DataDescriptor {
    /// Note: At time of writing this is an optional, de-facto-standart
    /// signature
    pub const SIGNATURE: u32 = 0x08074b50;
    pub const SIZE_IN_BYTES: usize = 12;
}

impl DataDescriptorSignature {
    pub const SIZE_IN_BYTES: usize = 16;
}

impl DataDescriptorZip64 {
    pub const SIZE_IN_BYTES: usize = 20;
}

impl DataDescriptorZip64Signature {
    pub const SIZE_IN_BYTES: usize = 24;
}

impl ArchiveExtraDataRecordFixed {
    pub const SIZE_IN_BYTES: usize = 12;
}

impl ArchiveExtraDataRecordFixed {
    pub const ARCHIVE_EXTRA_DATE_SIGNATURE: u32 = 0x08064b50;
}

impl CentralDirectoryHeaderFixed {
    pub const CENTRAL_FILE_HEADER_SIGNATURE: u32 = 0x02014b50;
    pub const SIZE_IN_BYTES: usize = 46;
}

impl DigitalSignatureFixed {
    pub const HEADER_SIGNATURE: u32 = 0x05054b50;
    pub const SIZE_IN_BYTES: usize = 6;
}

impl Zip64EndOfCentralDirectoryFixed {
    pub const SIZE_IN_BYTES: usize = 56;
    pub const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE: u32 = 0x06064b50;
}

impl Zip64EndOfCentralDirectoryLocator {
    pub const SIZE_IN_BYTES: usize = 20;
    pub const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE: u32 = 0x07064b50;
}

impl EndOfCentralDirectoryFixed {
    pub const END_OF_CENTRAL_DIR_SIGNATURE: u32 = 0x06054b50;
    pub const SIZE_IN_BYTES: usize = 22;
}

impl ExtensibleDataFixed {
    pub const SIZE_IN_BYTES: usize = 4;
}