Skip to main content

git_zero_core/zlib/
stored.rs

1//! Push-driven stored-block zlib for representations whose delta base cannot
2//! be reused. Sinks may change between calls and input fragmentation is inert.
3use super::adler::Adler32;
4use crate::{Error, Result, io::Write};
5
6pub struct StoredEncoder {
7    remaining: u64,
8    block: u16,
9    adler: Adler32,
10    finished: bool,
11    failure: Option<Error>,
12}
13impl StoredEncoder {
14    pub fn encoded_size(size: u64) -> Result<u64> {
15        let blocks = size / 65535 + u64::from(size % 65535 != 0);
16        size.checked_add(blocks.checked_mul(5).ok_or(Error::LimitExceeded)?)
17            .and_then(|size| size.checked_add(11))
18            .ok_or(Error::LimitExceeded)
19    }
20    pub fn new(size: u64, output: &mut impl Write) -> Result<Self> {
21        Self::encoded_size(size)?;
22        output.write_all(&[0x78, 0x01])?;
23        Ok(Self {
24            remaining: size,
25            block: 0,
26            adler: Adler32::new(),
27            finished: false,
28            failure: None,
29        })
30    }
31    pub fn write(&mut self, bytes: &[u8], output: &mut impl Write) -> Result<()> {
32        let result = self.copy(bytes, output);
33        if let Err(error) = result {
34            self.failure = Some(error);
35        }
36        result
37    }
38    fn ready(&self) -> Result<()> {
39        if let Some(error) = self.failure {
40            return Err(error);
41        }
42        if self.finished {
43            return Err(Error::InvalidRequest);
44        }
45        Ok(())
46    }
47    fn copy(&mut self, mut bytes: &[u8], output: &mut impl Write) -> Result<()> {
48        self.ready()?;
49        if bytes.len() as u64 > self.remaining {
50            return Err(Error::InvalidObject);
51        }
52        while !bytes.is_empty() {
53            if self.block == 0 {
54                self.block = self.remaining.min(65535) as u16;
55                output.write_all(&[0])?;
56                output.write_all(&self.block.to_le_bytes())?;
57                output.write_all(&(!self.block).to_le_bytes())?;
58            }
59            let count = bytes.len().min(usize::from(self.block));
60            output.write_all(&bytes[..count])?;
61            self.adler.update(&bytes[..count]);
62            self.block -= count as u16;
63            self.remaining -= count as u64;
64            bytes = &bytes[count..];
65        }
66        Ok(())
67    }
68    pub fn finish(&mut self, output: &mut impl Write) -> Result<()> {
69        let result = (|| {
70            self.ready()?;
71            if self.remaining != 0 {
72                return Err(Error::InvalidObject);
73            }
74            output.write_all(&[1, 0, 0, 0xff, 0xff])?;
75            output.write_all(&self.adler.value().to_be_bytes())?;
76            self.finished = true;
77            Ok(())
78        })();
79        if let Err(error) = result {
80            self.failure = Some(error);
81        }
82        result
83    }
84}