@@ -161,6 +161,7 @@ pub(crate) mod zip_writer {
161
161
pub ( super ) writing_raw : bool ,
162
162
pub ( super ) comment : Box < [ u8 ] > ,
163
163
pub ( super ) flush_on_finish_file : bool ,
164
+ pub ( super ) seek_possible : bool ,
164
165
}
165
166
166
167
impl < W : Write + Seek > Debug for ZipWriter < W > {
@@ -637,6 +638,7 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
637
638
comment : footer. zip_file_comment ,
638
639
writing_raw : true , // avoid recomputing the last file's header
639
640
flush_on_finish_file : false ,
641
+ seek_possible : true ,
640
642
} )
641
643
} else {
642
644
Err ( InvalidArchive ( "No central-directory end header found" ) )
@@ -795,6 +797,7 @@ impl<W: Write + Seek> ZipWriter<W> {
795
797
writing_raw : false ,
796
798
comment : Box :: new ( [ ] ) ,
797
799
flush_on_finish_file : false ,
800
+ seek_possible : true ,
798
801
}
799
802
}
800
803
@@ -955,6 +958,7 @@ impl<W: Write + Seek> ZipWriter<W> {
955
958
aes_mode,
956
959
& extra_data,
957
960
) ;
961
+ file. using_data_descriptor = !self . seek_possible ;
958
962
file. version_made_by = file. version_made_by . max ( file. version_needed ( ) as u8 ) ;
959
963
file. extra_data_start = Some ( header_end) ;
960
964
let index = self . insert_file_data ( file) ?;
@@ -1063,8 +1067,12 @@ impl<W: Write + Seek> ZipWriter<W> {
1063
1067
0
1064
1068
} ;
1065
1069
update_aes_extra_data ( writer, file) ?;
1066
- update_local_file_header ( writer, file) ?;
1067
- writer. seek ( SeekFrom :: Start ( file_end) ) ?;
1070
+ if file. using_data_descriptor {
1071
+ write_data_descriptor ( writer, file) ?;
1072
+ } else {
1073
+ update_local_file_header ( writer, file) ?;
1074
+ writer. seek ( SeekFrom :: Start ( file_end) ) ?;
1075
+ }
1068
1076
}
1069
1077
if self . flush_on_finish_file {
1070
1078
let result = writer. flush ( ) ;
@@ -1550,6 +1558,21 @@ impl<W: Write + Seek> ZipWriter<W> {
1550
1558
}
1551
1559
}
1552
1560
1561
+ impl < W : Write > ZipWriter < StreamWriter < W > > {
1562
+ pub fn new_stream ( inner : W ) -> ZipWriter < StreamWriter < W > > {
1563
+ ZipWriter {
1564
+ inner : Storer ( MaybeEncrypted :: Unencrypted ( StreamWriter :: new ( inner) ) ) ,
1565
+ files : IndexMap :: new ( ) ,
1566
+ stats : Default :: default ( ) ,
1567
+ writing_to_file : false ,
1568
+ writing_raw : false ,
1569
+ comment : Box :: new ( [ ] ) ,
1570
+ flush_on_finish_file : false ,
1571
+ seek_possible : false ,
1572
+ }
1573
+ }
1574
+ }
1575
+
1553
1576
impl < W : Write + Seek > Drop for ZipWriter < W > {
1554
1577
fn drop ( & mut self ) {
1555
1578
if !self . inner . is_closed ( ) {
@@ -1828,6 +1851,26 @@ fn update_aes_extra_data<W: Write + Seek>(writer: &mut W, file: &mut ZipFileData
1828
1851
Ok ( ( ) )
1829
1852
}
1830
1853
1854
+ fn write_data_descriptor < T : Write > ( writer : & mut T , file : & ZipFileData ) -> ZipResult < ( ) > {
1855
+ writer. write_u32_le ( file. crc32 ) ?;
1856
+ if file. large_file {
1857
+ writer. write_u64_le ( file. compressed_size ) ?;
1858
+ writer. write_u64_le ( file. uncompressed_size ) ?;
1859
+ } else {
1860
+ // check compressed size as well as it can also be slightly larger than uncompressed size
1861
+ if file. compressed_size > spec:: ZIP64_BYTES_THR {
1862
+ return Err ( ZipError :: Io ( io:: Error :: new (
1863
+ io:: ErrorKind :: Other ,
1864
+ "Large file option has not been set" ,
1865
+ ) ) ) ;
1866
+ }
1867
+
1868
+ writer. write_u32_le ( file. compressed_size as u32 ) ?;
1869
+ writer. write_u32_le ( file. uncompressed_size as u32 ) ?;
1870
+ }
1871
+ Ok ( ( ) )
1872
+ }
1873
+
1831
1874
fn update_local_file_header < T : Write + Seek > ( writer : & mut T , file : & ZipFileData ) -> ZipResult < ( ) > {
1832
1875
const CRC32_OFFSET : u64 = 14 ;
1833
1876
writer. seek ( SeekFrom :: Start ( file. header_start + CRC32_OFFSET ) ) ?;
@@ -1885,6 +1928,41 @@ fn update_local_zip64_extra_field<T: Write + Seek>(
1885
1928
Ok ( ( ) )
1886
1929
}
1887
1930
1931
+ pub struct StreamWriter < W : Write > {
1932
+ inner : W ,
1933
+ bytes_written : u64 ,
1934
+ }
1935
+
1936
+ impl < W : Write > StreamWriter < W > {
1937
+ pub fn new ( inner : W ) -> StreamWriter < W > {
1938
+ Self {
1939
+ inner,
1940
+ bytes_written : 0 ,
1941
+ }
1942
+ }
1943
+ }
1944
+
1945
+ impl < W : Write > Write for StreamWriter < W > {
1946
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
1947
+ let bytes_written = self . inner . write ( buf) ?;
1948
+ self . bytes_written += bytes_written as u64 ;
1949
+ Ok ( bytes_written)
1950
+ }
1951
+
1952
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
1953
+ self . inner . flush ( )
1954
+ }
1955
+ }
1956
+
1957
+ impl < W : Write > Seek for StreamWriter < W > {
1958
+ fn seek ( & mut self , pos : SeekFrom ) -> io:: Result < u64 > {
1959
+ match pos {
1960
+ SeekFrom :: Current ( 0 ) | SeekFrom :: End ( 0 ) => Ok ( self . bytes_written ) ,
1961
+ _ => panic ! ( "Seek is not supported, trying to seek to {:?}" , pos) ,
1962
+ }
1963
+ }
1964
+ }
1965
+
1888
1966
#[ cfg( not( feature = "unreserved" ) ) ]
1889
1967
const EXTRA_FIELD_MAPPING : [ u16 ; 43 ] = [
1890
1968
0x0007 , 0x0008 , 0x0009 , 0x000a , 0x000c , 0x000d , 0x000e , 0x000f , 0x0014 , 0x0015 , 0x0016 , 0x0017 ,
0 commit comments