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>, on_decode: impl Fn(ZipDecodedData<'_>) -> Result<()> + 'a ) -> Self

Creates a new ZipUnpacker

Callback on_decode will fire when the unpacker decodes new data

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 (lines 21-58)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
fn main() {
    let output_dir = "unpack";
    let archive = fs::read("archive.zip").unwrap();
    let _ = fs::remove_dir_all(output_dir);

    let central_directory = read_cd::from_provider(
        vec![archive.len()],
        false,
        |pos, length| {
            println!("Requested {length} bytes at {pos}");
            Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
        }
    ).unwrap().sort();

    let current_file: RefCell<Option<File>> = RefCell::new(None);

    let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()], |data| {
        match data {
            ZipDecodedData::FileHeader(cdfh, _) => {
                println!();

                let mut path = PathBuf::from(output_dir);
                path.push(&cdfh.filename);

                if !cdfh.is_directory() {
                    print!("New file: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path.parent().unwrap())?;

                    *current_file.borrow_mut() = Some(
                        OpenOptions::new()
                        .create(true)
                        .write(true)
                        .open(path)?
                    );
                } else {
                    print!("New directory: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path)?;
                }
            },

            ZipDecodedData::FileData(data) => {
                print!(".");
                io::stdout().flush()?;

                current_file.borrow().as_ref().unwrap().write_all(data)?;
            }
        }

        Ok(())
    });

    unpacker.update(archive).unwrap();

    println!("\nDone!");
}
More examples
Hide additional examples
examples/multipart.rs (lines 33-70)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn main() {
    let output_dir = "unpack";

    let archives = [
        "multipart/archive_m.z01",
        "multipart/archive_m.z02",
        "multipart/archive_m.z03",
        "multipart/archive_m.z04",
        "multipart/archive_m.z05",
        "multipart/archive_m.z06",
        "multipart/archive_m.z07",
        "multipart/archive_m.zip"
    ].map(fs::read).map(Result::unwrap);
    let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();

    let _ = fs::remove_dir_all(output_dir);

    let central_directory = read_cd::from_provider(
        &sizes,
        false,
        |pos, length| {
            println!("Requested {length} bytes at {pos}");
            Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
        }
    ).unwrap().sort();

    let current_file: RefCell<Option<File>> = RefCell::new(None);

    let mut unpacker = ZipUnpacker::new(central_directory, sizes, |data| {
        match data {
            ZipDecodedData::FileHeader(cdfh, _) => {
                println!();

                let mut path = PathBuf::from(output_dir);
                path.push(&cdfh.filename);

                if !cdfh.is_directory() {
                    print!("New file: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path.parent().unwrap())?;

                    *current_file.borrow_mut() = Some(
                        OpenOptions::new()
                        .create(true)
                        .write(true)
                        .open(path)?
                    );
                } else {
                    print!("New directory: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path)?;
                }
            },

            ZipDecodedData::FileData(data) => {
                print!(".");
                io::stdout().flush()?;

                current_file.borrow().as_ref().unwrap().write_all(data)?;
            }
        }

        Ok(())
    });

    for archive in archives {
        unpacker.update(archive).unwrap();
    }

    println!("\nDone!");
}
source

pub fn resume( central_directory: SortedCentralDirectory, disk_sizes: Vec<usize>, position: ZipPosition, on_decode: impl Fn(ZipDecodedData<'_>) -> Result<()> + 'a ) -> 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

Callback on_decode will fire when the unpacker decodes new data

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 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 60)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
fn main() {
    let output_dir = "unpack";
    let archive = fs::read("archive.zip").unwrap();
    let _ = fs::remove_dir_all(output_dir);

    let central_directory = read_cd::from_provider(
        vec![archive.len()],
        false,
        |pos, length| {
            println!("Requested {length} bytes at {pos}");
            Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
        }
    ).unwrap().sort();

    let current_file: RefCell<Option<File>> = RefCell::new(None);

    let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()], |data| {
        match data {
            ZipDecodedData::FileHeader(cdfh, _) => {
                println!();

                let mut path = PathBuf::from(output_dir);
                path.push(&cdfh.filename);

                if !cdfh.is_directory() {
                    print!("New file: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path.parent().unwrap())?;

                    *current_file.borrow_mut() = Some(
                        OpenOptions::new()
                        .create(true)
                        .write(true)
                        .open(path)?
                    );
                } else {
                    print!("New directory: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path)?;
                }
            },

            ZipDecodedData::FileData(data) => {
                print!(".");
                io::stdout().flush()?;

                current_file.borrow().as_ref().unwrap().write_all(data)?;
            }
        }

        Ok(())
    });

    unpacker.update(archive).unwrap();

    println!("\nDone!");
}
More examples
Hide additional examples
examples/multipart.rs (line 73)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn main() {
    let output_dir = "unpack";

    let archives = [
        "multipart/archive_m.z01",
        "multipart/archive_m.z02",
        "multipart/archive_m.z03",
        "multipart/archive_m.z04",
        "multipart/archive_m.z05",
        "multipart/archive_m.z06",
        "multipart/archive_m.z07",
        "multipart/archive_m.zip"
    ].map(fs::read).map(Result::unwrap);
    let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();

    let _ = fs::remove_dir_all(output_dir);

    let central_directory = read_cd::from_provider(
        &sizes,
        false,
        |pos, length| {
            println!("Requested {length} bytes at {pos}");
            Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
        }
    ).unwrap().sort();

    let current_file: RefCell<Option<File>> = RefCell::new(None);

    let mut unpacker = ZipUnpacker::new(central_directory, sizes, |data| {
        match data {
            ZipDecodedData::FileHeader(cdfh, _) => {
                println!();

                let mut path = PathBuf::from(output_dir);
                path.push(&cdfh.filename);

                if !cdfh.is_directory() {
                    print!("New file: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path.parent().unwrap())?;

                    *current_file.borrow_mut() = Some(
                        OpenOptions::new()
                        .create(true)
                        .write(true)
                        .open(path)?
                    );
                } else {
                    print!("New directory: {}", cdfh.filename);
                    io::stdout().flush()?;

                    fs::create_dir_all(path)?;
                }
            },

            ZipDecodedData::FileData(data) => {
                print!(".");
                io::stdout().flush()?;

                current_file.borrow().as_ref().unwrap().write_all(data)?;
            }
        }

        Ok(())
    });

    for archive in archives {
        unpacker.update(archive).unwrap();
    }

    println!("\nDone!");
}

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> !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>,

§

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>,

§

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.