Skip to main content

preflate_rs/
preflate_input.rs

1/*---------------------------------------------------------------------------------------------
2 *  Copyright (c) Microsoft Corporation. All rights reserved.
3 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
4 *  This software incorporates material from third parties. See NOTICE.txt for details.
5 *--------------------------------------------------------------------------------------------*/
6
7use crate::{
8    ExitCode,
9    preflate_error::{Result, err_exit_code},
10};
11
12/// represents the uncompressed data, including a prefix that is may be referenced by
13/// the compressed data. The prefix data is only visible via the PreflateInput struct.
14pub struct PlainText {
15    /// the entire data, including the prefix
16    data: Vec<u8>,
17
18    /// how long the prefix is, after this the data starts
19    prefix_length: i32,
20
21    /// the current position with regard to the shrinking dictionary
22    pos_offset: i32,
23}
24
25impl std::fmt::Debug for PlainText {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        write!(
28            f,
29            "PlainText {{ prefix_length: {}, pos_offset:{} data: len={} }}",
30            self.prefix_length,
31            self.pos_offset,
32            self.data.len()
33        )
34    }
35}
36
37impl Clone for PlainText {
38    fn clone(&self) -> Self {
39        Self {
40            data: self.data.clone(),
41            prefix_length: self.prefix_length,
42            pos_offset: self.pos_offset,
43        }
44    }
45}
46
47impl PlainText {
48    pub fn new() -> Self {
49        Self {
50            data: Vec::new(),
51            prefix_length: 0,
52            pos_offset: 0,
53        }
54    }
55
56    /// returns the dictionary to be used as a prefix for the next compression, which
57    /// is a maximum of 32KB in size.
58    pub fn shrink_to_dictionary(&mut self) {
59        //self.prefix_length = self.data.len() as i32;
60        self.pos_offset += self.data.len() as i32 - self.prefix_length;
61
62        let amount_to_keep = self.data.len().min(32768);
63
64        self.data.drain(..self.data.len() - amount_to_keep);
65        self.prefix_length = self.data.len() as i32;
66    }
67
68    pub fn new_with_data(data: Vec<u8>) -> Self {
69        Self {
70            data,
71            prefix_length: 0,
72            pos_offset: 0,
73        }
74    }
75
76    pub fn len(&self) -> usize {
77        self.data.len() - (self.prefix_length as usize)
78    }
79
80    /// the total length of the data from the beginning
81    pub fn total_length(&self) -> u32 {
82        self.pos_offset as u32 + self.len() as u32
83    }
84
85    /// the data excluding the prefix
86    pub fn text(&self) -> &[u8] {
87        &self.data[self.prefix_length as usize..]
88    }
89
90    pub fn prefix(&self) -> &[u8] {
91        &self.data[0..self.prefix_length as usize]
92    }
93
94    pub fn truncate(&mut self, len: usize) {
95        self.data.truncate(self.prefix_length as usize + len);
96    }
97
98    pub fn push(&mut self, c: u8) {
99        self.data.push(c);
100    }
101
102    pub fn append(&mut self, data: &[u8]) {
103        self.data.extend_from_slice(data);
104    }
105
106    pub fn append_iter(&mut self, data: impl Iterator<Item = u8>) {
107        self.data.extend(data);
108    }
109
110    /// writes a reference to the buffer, which copies the text from a previous location
111    /// to the current location. In most cases this is non-overlapping, but there are some
112    /// cases where there is overlap between the source and destination.
113    #[inline(always)]
114    pub fn append_reference(&mut self, dist: u32, len: u32) -> Result<()> {
115        if dist as usize > self.data.len() {
116            return err_exit_code(ExitCode::InvalidDeflate, "Invalid distance in reference");
117        }
118
119        if dist == 1 {
120            // special case for distance 1, just repeat the last byte n times
121            let byte = self.data[self.data.len() - 1];
122            self.data.resize(self.data.len() + len as usize, byte);
123        } else if dist >= len {
124            // no overlap
125            self.data.extend_from_within(
126                self.data.len() - dist as usize..self.data.len() - dist as usize + len as usize,
127            );
128        } else {
129            // general case, rarely called, copy one character at a time
130            let start = self.data.len() - dist as usize;
131
132            self.data.reserve(len as usize);
133
134            for i in 0..len {
135                let byte = self.data[start + i as usize];
136                self.data.push(byte);
137            }
138        }
139        Ok(())
140    }
141}
142
143#[derive(Clone, Debug)]
144pub struct PreflateInput<'a> {
145    data: &'a PlainText,
146    pos: i32,
147}
148
149impl<'a> PreflateInput<'a> {
150    pub fn new(v: &'a PlainText) -> Self {
151        PreflateInput {
152            data: v,
153            pos: v.prefix_length,
154        }
155    }
156
157    #[inline(always)]
158    pub fn pos(&self) -> u32 {
159        (self.pos + self.data.pos_offset - self.data.prefix_length) as u32
160    }
161
162    /// total length of the data all the way back to the beginning
163    #[inline(always)]
164    pub fn total_length(&self) -> u32 {
165        self.data.total_length()
166    }
167
168    #[inline(always)]
169    pub fn cur_chars(&self, offset: i32) -> &[u8] {
170        &self.data.data[(self.pos + offset) as usize..]
171    }
172
173    #[inline(always)]
174    pub fn cur_char(&self, offset: i32) -> u8 {
175        self.data.data[(self.pos + offset) as usize]
176    }
177
178    #[inline(always)]
179    pub fn advance(&mut self, l: u32) {
180        self.pos += l as i32;
181        debug_assert!((self.pos) <= self.data.data.len() as i32);
182    }
183
184    #[inline(always)]
185    pub fn remaining(&self) -> u32 {
186        (self.data.data.len() as i32 - self.pos) as u32
187    }
188}
189
190#[test]
191fn test_length_behavior() {
192    let mut data = PlainText::new_with_data(vec![0; 10000]);
193
194    let mut input = PreflateInput::new(&data);
195    assert_eq!(input.total_length(), 10000);
196    assert_eq!(input.pos(), 0);
197    assert_eq!(input.remaining(), 10000);
198
199    input.advance(1000);
200    assert_eq!(input.total_length(), 10000);
201    assert_eq!(input.pos(), 1000);
202    assert_eq!(input.remaining(), 9000);
203
204    input.advance(9000);
205    assert_eq!(input.total_length(), 10000);
206    assert_eq!(input.pos(), 10000);
207    assert_eq!(input.remaining(), 0);
208
209    data.shrink_to_dictionary();
210    data.append(&[1; 10000]);
211
212    let mut input = PreflateInput::new(&data);
213    assert_eq!(input.total_length(), 20000);
214    assert_eq!(input.pos(), 10000);
215    assert_eq!(input.remaining(), 10000);
216    assert_eq!(input.cur_char(0), 1);
217    assert_eq!(input.cur_char(-1), 0);
218    assert_eq!(input.cur_char(-1000), 0);
219
220    input.advance(1000);
221    assert_eq!(input.total_length(), 20000);
222    assert_eq!(input.pos(), 11000);
223    assert_eq!(input.remaining(), 9000);
224
225    assert_eq!(input.cur_char(-1), 1);
226    assert_eq!(input.cur_char(-1000), 1);
227}