async_mtzip/zip/
data.rs

1use std::io::{Write};
2use tokio::io::{AsyncSeek, AsyncWrite};
3
4use super::file::{ZipFile, ZipFileNoData};
5
6const END_OF_CENTRAL_DIR_SIGNATURE: u32 = 0x06054B50;
7
8#[derive(Debug, Default)]
9pub struct ZipData {
10    // pub files: Vec<ZipFile>,
11}
12
13impl ZipData {
14    pub async fn write_with_tokio<W: AsyncWrite + AsyncSeek + Unpin>(
15        &mut self,
16        buf: &mut W,
17        zip_file_iter: &mut tokio::sync::mpsc::Receiver<ZipFile>,
18    ) -> std::io::Result<()> {
19        let mut zip_files = Vec::new();
20        while let Some(zip_file) = zip_file_iter.recv().await {
21            let zip_file_no_data = zip_file.write_local_file_header_with_data_consuming_with_tokio(buf).await?;
22            zip_files.push(zip_file_no_data);
23        }
24
25        let files_amount = super::files_amount_u16(&zip_files);
26
27        let central_dir_offset = super::stream_position_u32_with_tokio(buf).await?;
28
29        self.write_central_dir_with_tokio(zip_files, buf).await?;
30
31        let central_dir_start = super::stream_position_u32_with_tokio(buf).await?;
32
33        self.write_end_of_central_directory_with_tokio(
34            buf,
35            central_dir_offset,
36            central_dir_start,
37            files_amount,
38        ).await
39    }
40
41    async fn write_central_dir_with_tokio<W: AsyncWrite + Unpin, I: IntoIterator<Item=ZipFileNoData>>(
42        &self,
43        zip_files: I,
44        buf: &mut W,
45    ) -> std::io::Result<()> {
46        for zip_file in zip_files {
47            zip_file.write_central_directory_entry_with_tokio(buf).await?;
48        }
49        Ok(())
50    }
51
52    const FOOTER_LENGTH: usize = 22;
53
54    async fn write_end_of_central_directory_with_tokio<W: AsyncWrite + Unpin>(
55        &self,
56        buf: &mut W,
57        central_dir_offset: u32,
58        central_dir_start: u32,
59        files_amount: u16,
60    ) -> std::io::Result<()> {
61        // Temporary in-memory statically sized array
62        let mut central_dir = [0; Self::FOOTER_LENGTH];
63        {
64            let mut central_dir_buf: &mut [u8] = &mut central_dir;
65
66            // Signature
67            central_dir_buf.write_all(&END_OF_CENTRAL_DIR_SIGNATURE.to_le_bytes())?;
68            // number of this disk
69            central_dir_buf.write_all(&0_u16.to_le_bytes())?;
70            // number of the disk with start
71            central_dir_buf.write_all(&0_u16.to_le_bytes())?;
72            // Number of entries on this disk
73            central_dir_buf.write_all(&files_amount.to_le_bytes())?;
74            // Number of entries
75            central_dir_buf.write_all(&files_amount.to_le_bytes())?;
76            // Central dir size
77            central_dir_buf.write_all(&(central_dir_start - central_dir_offset).to_le_bytes())?;
78            // Central dir offset
79            central_dir_buf.write_all(&central_dir_offset.to_le_bytes())?;
80            // Comment length
81            central_dir_buf.write_all(&0_u16.to_le_bytes())?;
82        }
83
84        {
85            use tokio::io::AsyncWriteExt;
86            buf.write_all(&central_dir).await?;
87        }
88
89        Ok(())
90    }
91}