smdiff_decoder/
reader.rs

1//! This module contains the `SectionReader` struct, which is used to read sections from a smdiff delta file.
2//! This is just like the `SectionIterator` struct from the `smdiff-reader` crate, but this can read sections that have secondary compression.
3use std::io::{BufReader, Cursor, Read, Seek};
4
5use smdiff_common::SectionHeader;
6use smdiff_reader::{read_ops_no_comp, read_section_header, Op};
7
8use crate::apply_no_sec_comp;
9
10/// A reader that will keep reading sections until it reaches the terminal section.
11pub struct SectionIterator<R>{
12    source: BufReader<R>,
13    done:bool,
14    win_data: Vec<u8>,
15    ops: Vec<Op>,
16}
17impl<R: Read+Seek> SectionIterator<R>{
18    pub fn new(patch: R) -> Self {
19        Self {
20            source:BufReader::new(patch),
21            done:false,
22            win_data: Vec::new(),
23            ops: Vec::new(),
24        }
25    }
26    /// Reads and returns the next section (if it exists).
27    ///
28    /// This is useful if you don't need the Ops, just need to read them.
29    pub fn next_borrowed(&mut self) -> Option<std::io::Result<(&[Op],SectionHeader)>>{
30        let mut header = match self.read_header()?{
31            Ok(h) => h,
32            Err(e) => {
33                return Some(Err(e));
34            }
35        };
36        self.ops.clear();
37        if let Err(e) = self.read_ops(&mut header){
38            return Some(Err(e));
39        }
40        Some(Ok((&self.ops,header)))
41    }
42    ///In the event the caller needs to do something to the ops (more than just read them), this avoids the need to clone the slice.
43    fn next_owned(&mut self) -> Option<std::io::Result<(Vec<Op>,SectionHeader)>>{
44        let mut header = match self.read_header()?{
45            Ok(h) => h,
46            Err(e) => {
47                return Some(Err(e));
48            }
49        };
50        self.ops.clear();
51        if let Err(e) = self.read_ops(&mut header){
52            return Some(Err(e));
53        }
54        Some(Ok((std::mem::take(&mut self.ops),header)))
55    }
56    fn read_header(&mut self) -> Option<std::io::Result<SectionHeader>>{
57        if self.done{
58            return None;
59        }
60        match read_section_header(&mut self.source){
61            Ok(h) => Some(Ok(h)),
62            Err(e) => {
63                return Some(Err(e));
64            }
65        }
66    }
67    fn read_ops(&mut self,header:&mut SectionHeader) -> std::io::Result<()>{
68        self.win_data.clear();
69        self.ops.clear();
70        if header.compression_algo == 1 {
71            let mut crsr = Cursor::new(&mut self.win_data);
72            apply_no_sec_comp::<_,R,_>(&mut self.source, None, &mut crsr)?;
73            crsr.rewind()?;
74            read_ops_no_comp(&mut crsr, header,&mut self.ops)?;
75        }else if header.compression_algo == 2 {
76            let mut zstd = ruzstd::StreamingDecoder::new(&mut self.source).unwrap();
77            read_ops_no_comp(&mut zstd, header,&mut self.ops)?;
78        }else if header.compression_algo == 3 {
79            let mut brot = brotlic::DecompressorReader::new(&mut self.source);
80            read_ops_no_comp(&mut brot, header,&mut self.ops)?;
81            let _ = brot.into_inner()?;
82        }else{
83            read_ops_no_comp(&mut self.source, header,&mut self.ops)?;
84        }
85        if !header.more_sections{
86            self.done = true;
87        }
88        Ok(())
89    }
90    pub fn into_inner(self) -> R {
91        self.source.into_inner()
92    }
93}
94
95impl<R: Read+Seek> Iterator for SectionIterator<R> {
96    type Item = std::io::Result<(Vec<Op>, SectionHeader)>;
97
98    fn next(&mut self) -> Option<Self::Item> {
99        self.next_owned()
100    }
101}