Skip to main content

zip/format/
data_descriptor.rs

1//! Zip data descriptor
2
3use crate::format::magic::Magic;
4use core::mem;
5use std::io::{self, Write};
6
7/// Zip Data descriptor
8#[derive(Debug, Copy, Clone, PartialEq)]
9pub enum ZipDataDescriptor {
10    /// Classic zip data descriptor
11    ZipDataDescriptorBlock(ZipDataDescriptorBlock),
12    /// Zip64 data descriptor
13    Zip64DataDescriptorBlock(Zip64DataDescriptorBlock),
14}
15
16/// Zip data descriptor
17#[derive(Copy, Clone, Debug, PartialEq)]
18pub struct ZipDataDescriptorBlock {
19    /// crc 32
20    pub crc32: u32,
21    /// compressed size
22    pub compressed_size: u32,
23    /// uncompressed size
24    pub uncompressed_size: u32,
25}
26
27impl ZipDataDescriptorBlock {
28    /// Signature + fields
29    pub const SIZE: usize = mem::size_of::<u32>()
30        + mem::size_of::<u32>()
31        + mem::size_of::<u32>()
32        + mem::size_of::<u32>();
33    /// Magic
34    pub const MAGIC: Magic = Magic::DATA_DESCRIPTOR_SIGNATURE;
35
36    /// Parse the zip64 data descriptor
37    pub fn parse(buff: &[u8; Self::SIZE]) -> Result<Self, &'static str> {
38        let magic = Magic::from_le_bytes([buff[0], buff[1], buff[2], buff[3]]);
39        if magic != Self::MAGIC {
40            return Err("Invalid data descriptor header");
41        }
42        let crc32 = u32::from_le_bytes([buff[4], buff[5], buff[6], buff[7]]);
43        let compressed_size = u32::from_le_bytes([buff[8], buff[9], buff[10], buff[11]]);
44        let uncompressed_size = u32::from_le_bytes([buff[12], buff[13], buff[14], buff[15]]);
45
46        Ok(Self {
47            crc32,
48            compressed_size,
49            uncompressed_size,
50        })
51    }
52
53    /// Write the zip64 data descriptor
54    pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
55        w.write_all(&Self::MAGIC.to_le_bytes())?;
56        w.write_all(&self.crc32.to_le_bytes())?;
57        w.write_all(&self.compressed_size.to_le_bytes())?;
58        w.write_all(&self.uncompressed_size.to_le_bytes())?;
59        Ok(())
60    }
61}
62
63/// Zip64 data descriptor
64#[derive(Copy, Clone, Debug, PartialEq)]
65pub struct Zip64DataDescriptorBlock {
66    /// crc 32
67    pub crc32: u32,
68    /// compressed size
69    pub compressed_size: u64,
70    /// uncompressed size
71    pub uncompressed_size: u64,
72}
73impl Zip64DataDescriptorBlock {
74    /// Signature + fields
75    pub const SIZE: usize = mem::size_of::<u32>()
76        + mem::size_of::<u32>()
77        + mem::size_of::<u64>()
78        + mem::size_of::<u64>();
79    /// Magic
80    pub const MAGIC: Magic = Magic::DATA_DESCRIPTOR_SIGNATURE;
81
82    /// Parse the zip64 data descriptor
83    pub fn parse(buff: &[u8; Self::SIZE]) -> Result<Self, &'static str> {
84        let magic = Magic::from_le_bytes([buff[0], buff[1], buff[2], buff[3]]);
85        if magic != Self::MAGIC {
86            return Err("Invalid zip64 data descriptor header");
87        }
88        let crc32 = u32::from_le_bytes([buff[4], buff[5], buff[6], buff[7]]);
89        let compressed_size = u64::from_le_bytes([
90            buff[8], buff[9], buff[10], buff[11], buff[12], buff[13], buff[14], buff[15],
91        ]);
92        let uncompressed_size = u64::from_le_bytes([
93            buff[16], buff[17], buff[18], buff[19], buff[20], buff[21], buff[22], buff[23],
94        ]);
95
96        Ok(Self {
97            crc32,
98            compressed_size,
99            uncompressed_size,
100        })
101    }
102
103    /// Write the zip64 data descriptor
104    pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
105        w.write_all(&Self::MAGIC.to_le_bytes())?;
106        w.write_all(&self.crc32.to_le_bytes())?;
107        w.write_all(&self.compressed_size.to_le_bytes())?;
108        w.write_all(&self.uncompressed_size.to_le_bytes())?;
109        Ok(())
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use crate::format::data_descriptor::Zip64DataDescriptorBlock;
116    use crate::format::data_descriptor::ZipDataDescriptorBlock;
117
118    #[test]
119    fn test_data_descriptor_wrong_sig() {
120        assert_eq!(
121            ZipDataDescriptorBlock::MAGIC.to_le_bytes(),
122            [0x50, 0x4b, 0x07, 0x08]
123        );
124        let data_desc =
125            ZipDataDescriptorBlock::parse(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
126        assert!(data_desc.is_err(),);
127
128        // zip64
129        assert_eq!(
130            Zip64DataDescriptorBlock::MAGIC.to_le_bytes(),
131            [0x50, 0x4b, 0x07, 0x08]
132        );
133        let data_desc = Zip64DataDescriptorBlock::parse(&[
134            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
135        ]);
136        assert!(data_desc.is_err(),);
137    }
138
139    #[test]
140    fn test_data_descriptor_parsing() {
141        let raw = [
142            0x50, 0x4b, 0x07, 0x08, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
143        ];
144        let data_desc = ZipDataDescriptorBlock::parse(&raw).unwrap();
145        assert_eq!(
146            data_desc,
147            ZipDataDescriptorBlock {
148                crc32: u32::from_le_bytes(raw[4..8].try_into().unwrap()),
149                compressed_size: u32::from_le_bytes(raw[8..12].try_into().unwrap()),
150                uncompressed_size: u32::from_le_bytes(raw[12..16].try_into().unwrap()),
151            }
152        );
153        let raw = [
154            0x50, 0x4b, 0x07, 0x08, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
155            21, 22, 23,
156        ];
157        let data_desc = Zip64DataDescriptorBlock::parse(&raw).unwrap();
158        assert_eq!(
159            data_desc,
160            Zip64DataDescriptorBlock {
161                crc32: u32::from_le_bytes(raw[4..8].try_into().unwrap()),
162                compressed_size: u64::from_le_bytes(raw[8..16].try_into().unwrap()),
163                uncompressed_size: u64::from_le_bytes(raw[16..24].try_into().unwrap()),
164            }
165        );
166    }
167}