#zip-file #zip #parser #file-format #data-file

no-std zip_parser

A zip file format parser, supporting no_std environment, stream parsing and seeking

9 unstable releases (3 breaking)

0.4.3 Feb 20, 2023
0.4.2 Jan 6, 2023
0.4.1 Nov 10, 2022
0.3.0 Nov 5, 2022
0.1.1 Jan 25, 2022

#1549 in Parser implementations

39 downloads per month

MIT license

89KB
952 lines

Contains (Zip file, 43KB) test.zip

zip_parser

Zip file format parser implemented by rust, supports stream parsing, no_std environment.

The Parser will search central directory at the end of zip file if Seek is available. Also, It supports sequence read parsing when Seek is not available. All types in std env implemented std::io::Read automatically implement Read, and so is the trait Seek. PassiveParser can be used for some situations in which data is recvieved by other task.

stream parsing

#[derive(Debug)]
struct DataBuffer {
    index: usize,
    pub buffer: Vec<u8>,
}

fn file_stream_parsing(mut file: File) {
    println!("*** get stream from file ***");
    let mut buffer = DataBuffer {
        index: 0,
        buffer: Vec::new(),
    };
    let file_size = file.read_to_end(&mut buffer.buffer).unwrap_or(0);
    println!("zip size: {} bytes", file_size);

    println!("SequentialParser:");
    parse(SequentialParser::<DataBuffer>::new(&mut buffer));

    println!("\n\nPassiveParser:");
    let mut parser = PassiveParser::<128>::new();
    parser.feed_data(
        &buffer.buffer,
        |evt| {
            match evt {
                ParserEvent::LocalFileHeader(file_index, file) => {
                    println!("#{}: {}({}/{} bytes)",
                    file_index, file.file_name().unwrap_or("Utf8EncodeErr"),
                        file.compressed_size, file.uncompressed_size);
                    true
                },
                ParserEvent::ParsingError(_file_index, e) => {
                    println!("error: {e}");
                    false
                },
                _ => {
                    // println!("unprocessed event: {evt:?}");
                    true
                },
            }
        }
    );
    println!(r#"zip file comment: "{}""#, parser.file_comment().unwrap())
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() >= 2 {
        let file = File::open(args[1].as_str()).unwrap();
        file_stream_parsing(file);
    }
}

You just need to pass a stream which implements Read into the Parser::new(), then you can iterate over it. For more detail, see example stream_parsing.

Example

Stream_parsing

  1. From stdin
    cat test.zip | cargo run --features="std" --example stream_parsing
    
    or even you can cat multiple zip files:
    cat test.zip test.zip | cargo run --features="std" --example stream_parsing
    
  2. Stream parsing (Read and PassiveParser) from file
    cargo run --features="std" --example stream_parsing -- test.zip
    

Passive parsing

In example stream_parsing, there is a case for passive parsing: read data from a file and PassiveParser::feed_data to the parser.

Dependencies

~635KB
~12K SLoC