ZipUnpacker

Struct ZipUnpacker 

Source
pub struct ZipUnpacker<'a> { /* private fields */ }
Expand description

A stream unpacker for ZIP archives

Implementations§

Source§

impl<'a> ZipUnpacker<'a>

Source

pub fn new( central_directory: SortedCentralDirectory, disk_sizes: Vec<usize>, ) -> Self

Creates a new ZipUnpacker

The easiest way to obtain a central directory object is to use read_cd::from_provider. “disk_sizes” must only contain one element if the archive is a cut one, and not a real split one.

Examples found in repository?
examples/archive.rs (line 21)
5fn main() {
6    let output_dir = "unpack";
7    let archive = fs::read("archive.zip").unwrap();
8    let _ = fs::remove_dir_all(output_dir);
9
10    let central_directory = read_cd::from_provider(
11        vec![archive.len()],
12        false,
13        |pos, length| {
14            println!("Requested {length} bytes at {pos}");
15            Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16        }
17    ).unwrap().sort();
18
19    let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21    let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22    unpacker.set_callback(|data| {
23        match data {
24            ZipDecodedData::FileHeader(cdfh, _) => {
25                println!();
26
27                let mut path = PathBuf::from(output_dir);
28                path.push(&cdfh.filename);
29
30                if !cdfh.is_directory() {
31                    print!("New file: {}", cdfh.filename);
32                    io::stdout().flush()?;
33
34                    fs::create_dir_all(path.parent().unwrap())?;
35
36                    *current_file.borrow_mut() = Some(
37                        OpenOptions::new()
38                        .create(true)
39                        .write(true)
40                        .open(path)?
41                    );
42                } else {
43                    print!("New directory: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path)?;
47                }
48            },
49
50            ZipDecodedData::FileData(data) => {
51                print!(".");
52                io::stdout().flush()?;
53
54                current_file.borrow().as_ref().unwrap().write_all(data)?;
55            }
56        }
57
58        Ok(())
59    });
60
61    unpacker.update(archive).unwrap();
62
63    println!("\nDone!");
64}
More examples
Hide additional examples
examples/multipart.rs (line 33)
5fn main() {
6    let output_dir = "unpack";
7
8    let archives = [
9        "multipart/archive_m.z01",
10        "multipart/archive_m.z02",
11        "multipart/archive_m.z03",
12        "multipart/archive_m.z04",
13        "multipart/archive_m.z05",
14        "multipart/archive_m.z06",
15        "multipart/archive_m.z07",
16        "multipart/archive_m.zip"
17    ].map(fs::read).map(Result::unwrap);
18    let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20    let _ = fs::remove_dir_all(output_dir);
21
22    let central_directory = read_cd::from_provider(
23        &sizes,
24        false,
25        |pos, length| {
26            println!("Requested {length} bytes at {pos}");
27            Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28        }
29    ).unwrap().sort();
30
31    let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33    let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34    unpacker.set_callback(|data| {
35        match data {
36            ZipDecodedData::FileHeader(cdfh, _) => {
37                println!();
38
39                let mut path = PathBuf::from(output_dir);
40                path.push(&cdfh.filename);
41
42                if !cdfh.is_directory() {
43                    print!("New file: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path.parent().unwrap())?;
47
48                    *current_file.borrow_mut() = Some(
49                        OpenOptions::new()
50                        .create(true)
51                        .write(true)
52                        .open(path)?
53                    );
54                } else {
55                    print!("New directory: {}", cdfh.filename);
56                    io::stdout().flush()?;
57
58                    fs::create_dir_all(path)?;
59                }
60            },
61
62            ZipDecodedData::FileData(data) => {
63                print!(".");
64                io::stdout().flush()?;
65
66                current_file.borrow().as_ref().unwrap().write_all(data)?;
67            }
68        }
69
70        Ok(())
71    });
72
73    for archive in archives {
74        unpacker.update(archive).unwrap();
75    }
76
77    println!("\nDone!");
78}
Source

pub fn resume( central_directory: SortedCentralDirectory, disk_sizes: Vec<usize>, position: ZipPosition, ) -> Result<Self, DecoderError>

Creates a new ZipUnpacker, starting from the specified position. If the archive is not actually split, you must set disk number to 0 and use the absolute offset, even if there are multiple files

The easiest way to obtain a central directory object is to use read_cd::from_provider. “disk_sizes” must only contain one element if the archive is a cut one, and not a real split one.

Source

pub fn set_callback( &mut self, on_decode: impl Fn(ZipDecodedData<'_>) -> Result<()> + 'a, )

Sets the decode callback. The passed closure will be invoked when new data is decoded from bytes passed to ZipUnpacker::update

Examples found in repository?
examples/archive.rs (lines 22-59)
5fn main() {
6    let output_dir = "unpack";
7    let archive = fs::read("archive.zip").unwrap();
8    let _ = fs::remove_dir_all(output_dir);
9
10    let central_directory = read_cd::from_provider(
11        vec![archive.len()],
12        false,
13        |pos, length| {
14            println!("Requested {length} bytes at {pos}");
15            Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16        }
17    ).unwrap().sort();
18
19    let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21    let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22    unpacker.set_callback(|data| {
23        match data {
24            ZipDecodedData::FileHeader(cdfh, _) => {
25                println!();
26
27                let mut path = PathBuf::from(output_dir);
28                path.push(&cdfh.filename);
29
30                if !cdfh.is_directory() {
31                    print!("New file: {}", cdfh.filename);
32                    io::stdout().flush()?;
33
34                    fs::create_dir_all(path.parent().unwrap())?;
35
36                    *current_file.borrow_mut() = Some(
37                        OpenOptions::new()
38                        .create(true)
39                        .write(true)
40                        .open(path)?
41                    );
42                } else {
43                    print!("New directory: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path)?;
47                }
48            },
49
50            ZipDecodedData::FileData(data) => {
51                print!(".");
52                io::stdout().flush()?;
53
54                current_file.borrow().as_ref().unwrap().write_all(data)?;
55            }
56        }
57
58        Ok(())
59    });
60
61    unpacker.update(archive).unwrap();
62
63    println!("\nDone!");
64}
More examples
Hide additional examples
examples/multipart.rs (lines 34-71)
5fn main() {
6    let output_dir = "unpack";
7
8    let archives = [
9        "multipart/archive_m.z01",
10        "multipart/archive_m.z02",
11        "multipart/archive_m.z03",
12        "multipart/archive_m.z04",
13        "multipart/archive_m.z05",
14        "multipart/archive_m.z06",
15        "multipart/archive_m.z07",
16        "multipart/archive_m.zip"
17    ].map(fs::read).map(Result::unwrap);
18    let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20    let _ = fs::remove_dir_all(output_dir);
21
22    let central_directory = read_cd::from_provider(
23        &sizes,
24        false,
25        |pos, length| {
26            println!("Requested {length} bytes at {pos}");
27            Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28        }
29    ).unwrap().sort();
30
31    let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33    let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34    unpacker.set_callback(|data| {
35        match data {
36            ZipDecodedData::FileHeader(cdfh, _) => {
37                println!();
38
39                let mut path = PathBuf::from(output_dir);
40                path.push(&cdfh.filename);
41
42                if !cdfh.is_directory() {
43                    print!("New file: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path.parent().unwrap())?;
47
48                    *current_file.borrow_mut() = Some(
49                        OpenOptions::new()
50                        .create(true)
51                        .write(true)
52                        .open(path)?
53                    );
54                } else {
55                    print!("New directory: {}", cdfh.filename);
56                    io::stdout().flush()?;
57
58                    fs::create_dir_all(path)?;
59                }
60            },
61
62            ZipDecodedData::FileData(data) => {
63                print!(".");
64                io::stdout().flush()?;
65
66                current_file.borrow().as_ref().unwrap().write_all(data)?;
67            }
68        }
69
70        Ok(())
71    });
72
73    for archive in archives {
74        unpacker.update(archive).unwrap();
75    }
76
77    println!("\nDone!");
78}
Source

pub fn update( &mut self, data: impl AsRef<[u8]>, ) -> Result<(usize, bool), DecoderError>

Update this ZipUnpacker with new bytes. The callback may or may not be fired, depending on the content. The callback may be fired multiple times.

The first return value is how much the caller should advance the input buffer (0 means that there wasn’t enough data in the buffer and the caller should provide more), and the second value determines whether all files were processed (which means that the caller should stop providing data)

Examples found in repository?
examples/archive.rs (line 61)
5fn main() {
6    let output_dir = "unpack";
7    let archive = fs::read("archive.zip").unwrap();
8    let _ = fs::remove_dir_all(output_dir);
9
10    let central_directory = read_cd::from_provider(
11        vec![archive.len()],
12        false,
13        |pos, length| {
14            println!("Requested {length} bytes at {pos}");
15            Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16        }
17    ).unwrap().sort();
18
19    let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21    let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22    unpacker.set_callback(|data| {
23        match data {
24            ZipDecodedData::FileHeader(cdfh, _) => {
25                println!();
26
27                let mut path = PathBuf::from(output_dir);
28                path.push(&cdfh.filename);
29
30                if !cdfh.is_directory() {
31                    print!("New file: {}", cdfh.filename);
32                    io::stdout().flush()?;
33
34                    fs::create_dir_all(path.parent().unwrap())?;
35
36                    *current_file.borrow_mut() = Some(
37                        OpenOptions::new()
38                        .create(true)
39                        .write(true)
40                        .open(path)?
41                    );
42                } else {
43                    print!("New directory: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path)?;
47                }
48            },
49
50            ZipDecodedData::FileData(data) => {
51                print!(".");
52                io::stdout().flush()?;
53
54                current_file.borrow().as_ref().unwrap().write_all(data)?;
55            }
56        }
57
58        Ok(())
59    });
60
61    unpacker.update(archive).unwrap();
62
63    println!("\nDone!");
64}
More examples
Hide additional examples
examples/multipart.rs (line 74)
5fn main() {
6    let output_dir = "unpack";
7
8    let archives = [
9        "multipart/archive_m.z01",
10        "multipart/archive_m.z02",
11        "multipart/archive_m.z03",
12        "multipart/archive_m.z04",
13        "multipart/archive_m.z05",
14        "multipart/archive_m.z06",
15        "multipart/archive_m.z07",
16        "multipart/archive_m.zip"
17    ].map(fs::read).map(Result::unwrap);
18    let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20    let _ = fs::remove_dir_all(output_dir);
21
22    let central_directory = read_cd::from_provider(
23        &sizes,
24        false,
25        |pos, length| {
26            println!("Requested {length} bytes at {pos}");
27            Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28        }
29    ).unwrap().sort();
30
31    let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33    let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34    unpacker.set_callback(|data| {
35        match data {
36            ZipDecodedData::FileHeader(cdfh, _) => {
37                println!();
38
39                let mut path = PathBuf::from(output_dir);
40                path.push(&cdfh.filename);
41
42                if !cdfh.is_directory() {
43                    print!("New file: {}", cdfh.filename);
44                    io::stdout().flush()?;
45
46                    fs::create_dir_all(path.parent().unwrap())?;
47
48                    *current_file.borrow_mut() = Some(
49                        OpenOptions::new()
50                        .create(true)
51                        .write(true)
52                        .open(path)?
53                    );
54                } else {
55                    print!("New directory: {}", cdfh.filename);
56                    io::stdout().flush()?;
57
58                    fs::create_dir_all(path)?;
59                }
60            },
61
62            ZipDecodedData::FileData(data) => {
63                print!(".");
64                io::stdout().flush()?;
65
66                current_file.borrow().as_ref().unwrap().write_all(data)?;
67            }
68        }
69
70        Ok(())
71    });
72
73    for archive in archives {
74        unpacker.update(archive).unwrap();
75    }
76
77    println!("\nDone!");
78}

Trait Implementations§

Source§

impl Debug for ZipUnpacker<'_>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for ZipUnpacker<'a>

§

impl<'a> !RefUnwindSafe for ZipUnpacker<'a>

§

impl<'a> !Send for ZipUnpacker<'a>

§

impl<'a> !Sync for ZipUnpacker<'a>

§

impl<'a> Unpin for ZipUnpacker<'a>

§

impl<'a> !UnwindSafe for ZipUnpacker<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.