@@ -1900,6 +1900,71 @@ impl<'a> Drop for ZipFile<'a> {
19001900 }
19011901}
19021902
1903+ /// Read ZipFile structures from a non-seekable reader.
1904+ ///
1905+ /// This is an alternative method to read a zip file. If possible, use the ZipArchive functions
1906+ /// as some information will be missing when reading this manner.
1907+ ///
1908+ /// Reads a file header from the start of the stream. Will return `Ok(Some(..))` if a file is
1909+ /// present at the start of the stream. Returns `Ok(None)` if the start of the central directory
1910+ /// is encountered. No more files should be read after this.
1911+ ///
1912+ /// The Drop implementation of ZipFile ensures that the reader will be correctly positioned after
1913+ /// the structure is done.
1914+ ///
1915+ /// Missing fields are:
1916+ /// * `comment`: set to an empty string
1917+ /// * `data_start`: set to 0
1918+ /// * `external_attributes`: `unix_mode()`: will return None
1919+ pub fn read_zipfile_from_stream < ' a , R : Read > ( reader : & ' a mut R ) -> ZipResult < Option < ZipFile < ' _ > > > {
1920+ // We can't use the typical ::parse() method, as we follow separate code paths depending on the
1921+ // "magic" value (since the magic value will be from the central directory header if we've
1922+ // finished iterating over all the actual files).
1923+ /* TODO: smallvec? */
1924+ let mut block = [ 0u8 ; mem:: size_of :: < ZipLocalEntryBlock > ( ) ] ;
1925+ reader. read_exact ( & mut block) ?;
1926+ let block: Box < [ u8 ] > = block. into ( ) ;
1927+
1928+ let signature = spec:: Magic :: from_first_le_bytes ( & block) ;
1929+
1930+ match signature {
1931+ spec:: Magic :: LOCAL_FILE_HEADER_SIGNATURE => ( ) ,
1932+ spec:: Magic :: CENTRAL_DIRECTORY_HEADER_SIGNATURE => return Ok ( None ) ,
1933+ _ => return Err ( ZipLocalEntryBlock :: WRONG_MAGIC_ERROR ) ,
1934+ }
1935+
1936+ let block = ZipLocalEntryBlock :: interpret ( & block) ?;
1937+
1938+ let mut result = ZipFileData :: from_local_block ( block, reader) ?;
1939+
1940+ match parse_extra_field ( & mut result) {
1941+ Ok ( ..) | Err ( ZipError :: Io ( ..) ) => { }
1942+ Err ( e) => return Err ( e) ,
1943+ }
1944+
1945+ let limit_reader = ( reader as & ' a mut dyn Read ) . take ( result. compressed_size ) ;
1946+
1947+ let result_crc32 = result. crc32 ;
1948+ let result_compression_method = result. compression_method ;
1949+ let crypto_reader = make_crypto_reader (
1950+ result_compression_method,
1951+ result_crc32,
1952+ result. last_modified_time ,
1953+ result. using_data_descriptor ,
1954+ limit_reader,
1955+ None ,
1956+ None ,
1957+ #[ cfg( feature = "aes-crypto" ) ]
1958+ result. compressed_size ,
1959+ ) ?;
1960+
1961+ Ok ( Some ( ZipFile {
1962+ data : Cow :: Owned ( result) ,
1963+ crypto_reader : None ,
1964+ reader : make_reader ( result_compression_method, result_crc32, crypto_reader) ?,
1965+ } ) )
1966+ }
1967+
19031968#[ cfg( test) ]
19041969mod test {
19051970 use crate :: result:: ZipResult ;
@@ -1952,13 +2017,16 @@ mod test {
19522017
19532018 #[ test]
19542019 fn zip_read_streaming ( ) {
1955- use crate :: unstable :: read :: streaming :: StreamingArchive ;
2020+ use super :: read_zipfile_from_stream ;
19562021
19572022 let mut v = Vec :: new ( ) ;
19582023 v. extend_from_slice ( include_bytes ! ( "../tests/data/mimetype.zip" ) ) ;
1959- let reader = Cursor :: new ( v) ;
1960- let mut archive = StreamingArchive :: new ( reader) ;
1961- while archive. next_entry ( ) . unwrap ( ) . is_some ( ) { }
2024+ let mut reader = Cursor :: new ( v) ;
2025+ loop {
2026+ if read_zipfile_from_stream ( & mut reader) . unwrap ( ) . is_none ( ) {
2027+ break ;
2028+ }
2029+ }
19622030 }
19632031
19642032 #[ test]
0 commit comments