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
use crate::raw::{
    ArchiveExtraDataRecord, ArchiveExtraDataRecordFixed, CentralDirectoryHeader, CentralDirectoryHeaderFixed,
    DigitalSignature, DigitalSignatureFixed, EndOfCentralDirectory, EndOfCentralDirectoryFixed, ExtensibleData,
    ExtensibleDataFixed, LocalFileHeader, LocalFileHeaderFixed, Zip64EndOfCentralDirectory,
    Zip64EndOfCentralDirectoryFixed,
};

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

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

impl PartialRecord for ExtensibleData {
    type Partial = ExtensibleDataFixed;

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

    fn is_valid_sizes(&self) -> bool { self.data.len() == self.fixed.data_size as usize }
}