1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::raw::{
    ArchiveExtraDataRecord, ArchiveExtraDataRecordFixed, CentralDirectoryHeader, CentralDirectoryHeaderFixed,
    DataDescriptor, DataDescriptorSignature, DataDescriptorZip64Signature, DigitalSignature, DigitalSignatureFixed,
    EndOfCentralDirectory, EndOfCentralDirectoryFixed, LocalFileHeader, LocalFileHeaderFixed,
    Zip64EndOfCentralDirectory, Zip64EndOfCentralDirectoryFixed, Zip64EndOfCentralDirectoryLocator,
};

/// implemented for all dynamic records that contain a fixed element
pub trait PartialRecord {
    type Partial;

    fn get_partial(&self) -> &Self::Partial;
    /// all dynamic records contain dynamic data and length information in the
    /// fixed part. Verify if those 2 values are matching
    fn is_valid_sizes(&self) -> bool;
}

/// implemented for all types containing a signature
pub trait Signature {
    fn is_valid_signature(&self) -> bool;
}

impl<T> Signature for T
where
    T: PartialRecord,
    T::Partial: Signature,
{
    fn is_valid_signature(&self) -> bool { self.get_partial().is_valid_signature() }
}

impl Signature for LocalFileHeaderFixed {
    fn is_valid_signature(&self) -> bool { self.local_file_header_signature == Self::LOCAL_FILE_HEADER_SIGNATURE }
}

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 Signature for DataDescriptorSignature {
    fn is_valid_signature(&self) -> bool { self.signature == DataDescriptor::SIGNATURE }
}

impl Signature for DataDescriptorZip64Signature {
    fn is_valid_signature(&self) -> bool { self.signature == DataDescriptor::SIGNATURE }
}

impl Signature for ArchiveExtraDataRecordFixed {
    fn is_valid_signature(&self) -> bool { self.archive_extra_data_signature == Self::ARCHIVE_EXTRA_DATE_SIGNATURE }
}

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 Signature for CentralDirectoryHeaderFixed {
    fn is_valid_signature(&self) -> bool { self.central_file_header_signature == Self::CENTRAL_FILE_HEADER_SIGNATURE }
}

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 Signature for DigitalSignatureFixed {
    fn is_valid_signature(&self) -> bool { self.header_signature == Self::HEADER_SIGNATURE }
}

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 Signature for Zip64EndOfCentralDirectoryFixed {
    fn is_valid_signature(&self) -> bool {
        self.zip64_end_of_central_dir_signature == Self::ZIP64_END_OF_CENTRAL_DIR_SIGNATURE
    }
}

impl PartialRecord for Zip64EndOfCentralDirectory {
    type Partial = Zip64EndOfCentralDirectoryFixed;

    fn get_partial(&self) -> &Self::Partial { &self.fixed }

    fn is_valid_sizes(&self) -> bool {
        // as stated elsewhere, this is not just a length, but some part of a
        // calculation overflow protection check:
        if (self.fixed.size_of_zip64_end_of_central_directory_record as usize)
            < Zip64EndOfCentralDirectoryFixed::SIZE_IN_BYTES - 12
        {
            return false;
        }
        let length = self.fixed.size_of_zip64_end_of_central_directory_record as usize + 12
            - Zip64EndOfCentralDirectoryFixed::SIZE_IN_BYTES;
        self.zip64_extensible_data_sector.len() == length
    }
}

impl Signature for Zip64EndOfCentralDirectoryLocator {
    fn is_valid_signature(&self) -> bool {
        self.zip64_end_of_central_dir_locator_signature == Self::ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE
    }
}

impl Signature for EndOfCentralDirectoryFixed {
    fn is_valid_signature(&self) -> bool { self.end_of_central_dir_signature == Self::END_OF_CENTRAL_DIR_SIGNATURE }
}

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 }
}