From 2afb5a1fa301e13ff0d4fdfc05a9ae694954cd03 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sat, 11 May 2024 23:54:49 -0300 Subject: [PATCH 01/17] Add sync feature to Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf36d0041..477ae167a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,11 +67,11 @@ deflate = ["flate2/rust_backend", "_deflate-any"] # DEPRECATED: previously enabled `flate2/miniz_oxide` which is equivalent to `flate2/rust_backend` deflate-miniz = ["deflate", "_deflate-any"] - deflate-zlib = ["flate2/zlib", "_deflate-any"] deflate-zlib-ng = ["flate2/zlib-ng", "_deflate-any"] deflate-zopfli = ["zopfli", "_deflate-any"] lzma = ["lzma-rs/stream"] +sync = [] unreserved = [] default = [ "aes-crypto", From e0b6be7eee0170c7983a2225354fc5943aba630a Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sat, 11 May 2024 23:56:18 -0300 Subject: [PATCH 02/17] Add initial error message for when io logic is missing do to feature missing --- src/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/build.rs b/src/build.rs index 8ec1aeab2..cfddbe244 100644 --- a/src/build.rs +++ b/src/build.rs @@ -4,4 +4,6 @@ fn main() { if var("CARGO_FEATURE_DEFLATE_MINIZ").is_ok() { println!("cargo:warning=Feature `deflate-miniz` is deprecated; replace it with `deflate`"); } + #[cfg(not(any(feature = "sync")))] + compile_error!("Missing Required feature"); } From 975fbecb817ec7b1e472dfab1867d05eb824aaee Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sun, 12 May 2024 23:00:21 -0300 Subject: [PATCH 03/17] Add sync and tokio features and sync is on default --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 477ae167a..922139733 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ zstd = { version = "0.13.1", optional = true, default-features = false } zopfli = { version = "0.8.0", optional = true } deflate64 = { version = "0.1.8", optional = true } lzma-rs = { version = "0.3.0", default-features = false, optional = true } +true = { version = "0.1.0", optional = true } +tokio = { version = "1.37.0", optional = true } [target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies] crossbeam-utils = "0.8.19" @@ -72,6 +74,7 @@ deflate-zlib-ng = ["flate2/zlib-ng", "_deflate-any"] deflate-zopfli = ["zopfli", "_deflate-any"] lzma = ["lzma-rs/stream"] sync = [] +tokio = ["tokio/io-util"] unreserved = [] default = [ "aes-crypto", @@ -81,6 +84,7 @@ default = [ "deflate-zlib-ng", "deflate-zopfli", "lzma", + "sync", "time", "zstd", ] From c056382b5c17b1d1f49081067579f9c998d79602 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sun, 12 May 2024 23:01:14 -0300 Subject: [PATCH 04/17] Add compile error for missing/conflicting features --- src/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/build.rs b/src/build.rs index cfddbe244..a511a1487 100644 --- a/src/build.rs +++ b/src/build.rs @@ -4,6 +4,9 @@ fn main() { if var("CARGO_FEATURE_DEFLATE_MINIZ").is_ok() { println!("cargo:warning=Feature `deflate-miniz` is deprecated; replace it with `deflate`"); } - #[cfg(not(any(feature = "sync")))] + #[cfg(not(any(feature = "sync", feature = "tokio")))] compile_error!("Missing Required feature"); + + #[cfg(all(feature = "sync", feature = "tokio"))] + compile_error!("The features sync and tokio cannot be used together") } From 8afd5679fa63bf2f3da659cb175b19b6786fc82c Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sun, 12 May 2024 23:02:03 -0300 Subject: [PATCH 05/17] Begin async support on spec module --- src/spec.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/spec.rs b/src/spec.rs index 89481faf9..0a2c0eaa5 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "tokio")] +use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt}; + use crate::result::{ZipError, ZipResult}; use crate::unstable::{LittleEndianReadExt, LittleEndianWriteExt}; use core::mem::size_of_val; @@ -112,6 +115,7 @@ pub struct Zip64CentralDirectoryEndLocator { pub number_of_disks: u32, } +#[cfg(feature = "sync")] impl Zip64CentralDirectoryEndLocator { pub fn parse(reader: &mut T) -> ZipResult { let magic = reader.read_u32_le()?; @@ -140,6 +144,30 @@ impl Zip64CentralDirectoryEndLocator { } } +#[cfg(feature = "tokio")] +impl Zip64CentralDirectoryEndLocator { + pub async fn parse(reader: &mut T) -> ZipResult + where + T: AsyncRead + Unpin, + { + let magic = reader.read_u32_le().await?; + if magic != ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE { + return Err(ZipError::InvalidArchive( + "Invalid zip64 locator digital signature header", + )); + } + let disk_with_central_directory = reader.read_u32_le().await?; + let end_of_central_directory_offset = reader.read_u64_le().await?; + let number_of_disks = reader.read_u32_le().await?; + + Ok(Self { + disk_with_central_directory, + end_of_central_directory_offset, + number_of_disks, + }) + } +} + pub struct Zip64CentralDirectoryEnd { pub version_made_by: u16, pub version_needed_to_extract: u16, @@ -152,6 +180,7 @@ pub struct Zip64CentralDirectoryEnd { //pub extensible_data_sector: Vec, <-- We don't do anything with this at the moment. } +#[cfg(feature = "sync")] impl Zip64CentralDirectoryEnd { pub fn find_and_parse( reader: &mut T, @@ -227,6 +256,69 @@ impl Zip64CentralDirectoryEnd { } } +#[cfg(feature = "tokio")] +impl Zip64CentralDirectoryEnd { + pub async fn find_and_parse( + reader: &mut T, + nominal_offset: u64, + search_upper_bound: u64, + ) -> ZipResult> + where + T: AsyncRead + AsyncSeek + Unpin, + { + let mut results = Vec::new(); + let mut pos = search_upper_bound; + + while pos >= nominal_offset { + let mut have_signature = false; + reader.seek(tokio::io::SeekFrom::Start(pos)).await?; + if reader.read_u32_le().await? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE { + have_signature = true; + let archive_offset = pos - nominal_offset; + + let _record_size = reader.read_u64_le().await?; + let version_made_by = reader.read_u16_le().await?; + let version_needed_to_extract = reader.read_u16_le().await?; + let disk_number = reader.read_u32_le().await?; + let disk_with_central_directory = reader.read_u32_le().await?; + let number_of_files_on_this_disk = reader.read_u64_le().await?; + let number_of_files = reader.read_u64_le().await?; + let central_directory_size = reader.read_u64_le().await?; + let central_directory_offset = reader.read_u64_le().await?; + + results.push(( + Self { + version_made_by, + version_needed_to_extract, + disk_number, + disk_with_central_directory, + number_of_files_on_this_disk, + number_of_files, + central_directory_size, + central_directory_offset, + }, + archive_offset, + )); + } + pos = match pos.checked_sub(if have_signature { + size_of_val(&ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE) as u64 + } else { + 1 + }) { + None => break, + Some(p) => p, + } + } + if results.is_empty() { + Err(ZipError::InvalidArchive( + "Could not find ZIP64 central directory end", + )) + } else { + Ok(results) + } + } +} + /// Converts a path to the ZIP format (forward-slash-delimited and normalized). pub(crate) fn path_to_string>(path: T) -> Box { let mut maybe_original = None; From 45f918c5a72e62367b637cd0c6c06ac8f64d230b Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Mon, 13 May 2024 22:38:33 -0300 Subject: [PATCH 06/17] Move synchronous code into sync submodule --- examples/stdin_info.rs | 2 +- src/read.rs | 1245 +-------------------------------------- src/read/stream.rs | 4 +- src/read/sync.rs | 1261 ++++++++++++++++++++++++++++++++++++++++ src/write.rs | 2 +- 5 files changed, 1276 insertions(+), 1238 deletions(-) create mode 100644 src/read/sync.rs diff --git a/examples/stdin_info.rs b/examples/stdin_info.rs index a609916a0..8c0309ca0 100644 --- a/examples/stdin_info.rs +++ b/examples/stdin_info.rs @@ -10,7 +10,7 @@ fn real_main() -> i32 { let mut buf = [0u8; 16]; loop { - match zip::read::read_zipfile_from_stream(&mut stdin_handle) { + match zip::read::sync::read_zipfile_from_stream(&mut stdin_handle) { Ok(Some(mut file)) => { println!( "{}: {} bytes ({} bytes packed)", diff --git a/src/read.rs b/src/read.rs index d717ee18a..1af561898 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,24 +1,23 @@ //! Types for reading ZIP archives +#[cfg(feature = "tokio")] +///Module for logic using tokio::io +pub mod tokio; +#[cfg(feature = "sync")] +/// Module for logic using std::io +pub mod sync; + #[cfg(feature = "aes-crypto")] -use crate::aes::{AesReader, AesReaderValid}; -use crate::compression::CompressionMethod; -use crate::cp437::FromCp437; +use crate::aes::AesReaderValid; use crate::crc32::Crc32Reader; -use crate::extra_fields::{ExtendedTimestamp, ExtraField}; -use crate::read::zip_archive::Shared; use crate::result::{ZipError, ZipResult}; use crate::spec; -use crate::types::{AesMode, AesVendorVersion, DateTime, System, ZipFileData}; -use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator}; +use crate::types::{AesVendorVersion, ZipFileData}; +use crate::zipcrypto::ZipCryptoReaderValid; use indexmap::IndexMap; use std::borrow::Cow; -use std::fs::create_dir_all; use std::io::{self, copy, prelude::*, sink}; -use std::ops::Deref; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, OnceLock}; - +use self::sync::*; #[cfg(any( feature = "deflate", feature = "deflate-zlib", @@ -83,9 +82,6 @@ pub(crate) mod zip_archive { #[cfg(feature = "lzma")] use crate::read::lzma::LzmaDecoder; -use crate::result::ZipError::{InvalidPassword, UnsupportedArchive}; -use crate::spec::path_to_string; -use crate::unstable::LittleEndianReadExt; pub use zip_archive::ZipArchive; #[allow(clippy::large_enum_variant)] @@ -99,17 +95,6 @@ pub(crate) enum CryptoReader<'a> { }, } -impl<'a> Read for CryptoReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self { - CryptoReader::Plaintext(r) => r.read(buf), - CryptoReader::ZipCrypto(r) => r.read(buf), - #[cfg(feature = "aes-crypto")] - CryptoReader::Aes { reader: r, .. } => r.read(buf), - } - } -} - impl<'a> CryptoReader<'a> { /// Consumes this decoder, returning the underlying reader. pub fn into_inner(self) -> io::Take<&'a mut dyn Read> { @@ -152,26 +137,6 @@ pub(crate) enum ZipFileReader<'a> { Lzma(Crc32Reader>>>), } -impl<'a> Read for ZipFileReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self { - ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"), - ZipFileReader::Raw(r) => r.read(buf), - ZipFileReader::Stored(r) => r.read(buf), - #[cfg(feature = "_deflate-any")] - ZipFileReader::Deflated(r) => r.read(buf), - #[cfg(feature = "deflate64")] - ZipFileReader::Deflate64(r) => r.read(buf), - #[cfg(feature = "bzip2")] - ZipFileReader::Bzip2(r) => r.read(buf), - #[cfg(feature = "zstd")] - ZipFileReader::Zstd(r) => r.read(buf), - #[cfg(feature = "lzma")] - ZipFileReader::Lzma(r) => r.read(buf), - } - } -} - impl<'a> ZipFileReader<'a> { /// Consumes this decoder, returning the underlying reader. pub fn drain(self) { @@ -208,1194 +173,6 @@ pub struct ZipFile<'a> { pub(crate) reader: ZipFileReader<'a>, } -pub(crate) fn find_content<'a>( - data: &ZipFileData, - reader: &'a mut (impl Read + Seek), -) -> ZipResult> { - // Parse local header - reader.seek(io::SeekFrom::Start(data.header_start))?; - let signature = reader.read_u32_le()?; - if signature != spec::LOCAL_FILE_HEADER_SIGNATURE { - return Err(ZipError::InvalidArchive("Invalid local file header")); - } - let data_start = match data.data_start.get() { - None => { - reader.seek(io::SeekFrom::Current(22))?; - let file_name_length = reader.read_u16_le()? as u64; - let extra_field_length = reader.read_u16_le()? as u64; - let magic_and_header = 4 + 22 + 2 + 2; - let data_start = - data.header_start + magic_and_header + file_name_length + extra_field_length; - data.data_start.get_or_init(|| data_start); - data_start - } - Some(start) => *start, - }; - - reader.seek(io::SeekFrom::Start(data_start))?; - Ok((reader as &mut dyn Read).take(data.compressed_size)) -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn make_crypto_reader<'a>( - compression_method: CompressionMethod, - crc32: u32, - last_modified_time: DateTime, - using_data_descriptor: bool, - reader: io::Take<&'a mut dyn Read>, - password: Option<&[u8]>, - aes_info: Option<(AesMode, AesVendorVersion, CompressionMethod)>, - #[cfg(feature = "aes-crypto")] compressed_size: u64, -) -> ZipResult> { - #[allow(deprecated)] - { - if let CompressionMethod::Unsupported(_) = compression_method { - return unsupported_zip_error("Compression method not supported"); - } - } - - let reader = match (password, aes_info) { - #[cfg(not(feature = "aes-crypto"))] - (Some(_), Some(_)) => { - return Err(ZipError::UnsupportedArchive( - "AES encrypted files cannot be decrypted without the aes-crypto feature.", - )) - } - #[cfg(feature = "aes-crypto")] - (Some(password), Some((aes_mode, vendor_version, _))) => CryptoReader::Aes { - reader: AesReader::new(reader, aes_mode, compressed_size).validate(password)?, - vendor_version, - }, - (Some(password), None) => { - let validator = if using_data_descriptor { - ZipCryptoValidator::InfoZipMsdosTime(last_modified_time.timepart()) - } else { - ZipCryptoValidator::PkzipCrc32(crc32) - }; - CryptoReader::ZipCrypto(ZipCryptoReader::new(reader, password).validate(validator)?) - } - (None, Some(_)) => return Err(InvalidPassword), - (None, None) => CryptoReader::Plaintext(reader), - }; - Ok(reader) -} - -pub(crate) fn make_reader( - compression_method: CompressionMethod, - crc32: u32, - reader: CryptoReader, -) -> ZipResult { - let ae2_encrypted = reader.is_ae2_encrypted(); - - match compression_method { - CompressionMethod::Stored => Ok(ZipFileReader::Stored(Crc32Reader::new( - reader, - crc32, - ae2_encrypted, - ))), - #[cfg(feature = "_deflate-any")] - CompressionMethod::Deflated => { - let deflate_reader = DeflateDecoder::new(reader); - Ok(ZipFileReader::Deflated(Crc32Reader::new( - deflate_reader, - crc32, - ae2_encrypted, - ))) - } - #[cfg(feature = "deflate64")] - CompressionMethod::Deflate64 => { - let deflate64_reader = Deflate64Decoder::new(reader); - Ok(ZipFileReader::Deflate64(Crc32Reader::new( - deflate64_reader, - crc32, - ae2_encrypted, - ))) - } - #[cfg(feature = "bzip2")] - CompressionMethod::Bzip2 => { - let bzip2_reader = BzDecoder::new(reader); - Ok(ZipFileReader::Bzip2(Crc32Reader::new( - bzip2_reader, - crc32, - ae2_encrypted, - ))) - } - #[cfg(feature = "zstd")] - CompressionMethod::Zstd => { - let zstd_reader = ZstdDecoder::new(reader).unwrap(); - Ok(ZipFileReader::Zstd(Crc32Reader::new( - zstd_reader, - crc32, - ae2_encrypted, - ))) - } - #[cfg(feature = "lzma")] - CompressionMethod::Lzma => { - let reader = LzmaDecoder::new(reader); - Ok(ZipFileReader::Lzma(Crc32Reader::new( - Box::new(reader), - crc32, - ae2_encrypted, - ))) - } - _ => Err(UnsupportedArchive("Compression method not supported")), - } -} - -pub(crate) struct CentralDirectoryInfo { - pub(crate) archive_offset: u64, - pub(crate) directory_start: u64, - pub(crate) number_of_files: usize, - pub(crate) disk_number: u32, - pub(crate) disk_with_central_directory: u32, -} - -impl ZipArchive { - pub(crate) fn from_finalized_writer( - files: IndexMap, ZipFileData>, - comment: Box<[u8]>, - reader: R, - central_start: u64, - ) -> ZipResult { - let initial_offset = match files.first() { - Some((_, file)) => file.header_start, - None => 0, - }; - let shared = Arc::new(zip_archive::Shared { - files, - offset: initial_offset, - dir_start: central_start, - }); - Ok(Self { - reader, - shared, - comment: comment.into(), - }) - } - - /// Total size of the files in the archive, if it can be known. Doesn't include directories or - /// metadata. - pub fn decompressed_size(&self) -> Option { - let mut total = 0u128; - for file in self.shared.files.values() { - if file.using_data_descriptor { - return None; - } - total = total.checked_add(file.uncompressed_size as u128)?; - } - Some(total) - } -} - -impl ZipArchive { - pub(crate) fn merge_contents( - &mut self, - mut w: W, - ) -> ZipResult, ZipFileData>> { - if self.shared.files.is_empty() { - return Ok(IndexMap::new()); - } - let mut new_files = self.shared.files.clone(); - /* The first file header will probably start at the beginning of the file, but zip doesn't - * enforce that, and executable zips like PEX files will have a shebang line so will - * definitely be greater than 0. - * - * assert_eq!(0, new_files[0].header_start); // Avoid this. - */ - - let new_initial_header_start = w.stream_position()?; - /* Push back file header starts for all entries in the covered files. */ - new_files.values_mut().try_for_each(|f| { - /* This is probably the only really important thing to change. */ - f.header_start = f.header_start.checked_add(new_initial_header_start).ok_or( - ZipError::InvalidArchive("new header start from merge would have been too large"), - )?; - /* This is only ever used internally to cache metadata lookups (it's not part of the - * zip spec), and 0 is the sentinel value. */ - f.central_header_start = 0; - /* This is an atomic variable so it can be updated from another thread in the - * implementation (which is good!). */ - if let Some(old_data_start) = f.data_start.take() { - let new_data_start = old_data_start.checked_add(new_initial_header_start).ok_or( - ZipError::InvalidArchive("new data start from merge would have been too large"), - )?; - f.data_start.get_or_init(|| new_data_start); - } - Ok::<_, ZipError>(()) - })?; - - /* Rewind to the beginning of the file. - * - * NB: we *could* decide to start copying from new_files[0].header_start instead, which - * would avoid copying over e.g. any pex shebangs or other file contents that start before - * the first zip file entry. However, zip files actually shouldn't care about garbage data - * in *between* real entries, since the central directory header records the correct start - * location of each, and keeping track of that math is more complicated logic that will only - * rarely be used, since most zips that get merged together are likely to be produced - * specifically for that purpose (and therefore are unlikely to have a shebang or other - * preface). Finally, this preserves any data that might actually be useful. - */ - self.reader.rewind()?; - /* Find the end of the file data. */ - let length_to_read = self.shared.dir_start; - /* Produce a Read that reads bytes up until the start of the central directory header. - * This "as &mut dyn Read" trick is used elsewhere to avoid having to clone the underlying - * handle, which it really shouldn't need to anyway. */ - let mut limited_raw = (&mut self.reader as &mut dyn Read).take(length_to_read); - /* Copy over file data from source archive directly. */ - io::copy(&mut limited_raw, &mut w)?; - - /* Return the files we've just written to the data stream. */ - Ok(new_files) - } - - fn get_directory_info_zip32( - footer: &spec::CentralDirectoryEnd, - cde_start_pos: u64, - ) -> ZipResult { - // Some zip files have data prepended to them, resulting in the - // offsets all being too small. Get the amount of error by comparing - // the actual file position we found the CDE at with the offset - // recorded in the CDE. - let archive_offset = cde_start_pos - .checked_sub(footer.central_directory_size as u64) - .and_then(|x| x.checked_sub(footer.central_directory_offset as u64)) - .ok_or(ZipError::InvalidArchive( - "Invalid central directory size or offset", - ))?; - - let directory_start = footer.central_directory_offset as u64 + archive_offset; - let number_of_files = footer.number_of_files_on_this_disk as usize; - Ok(CentralDirectoryInfo { - archive_offset, - directory_start, - number_of_files, - disk_number: footer.disk_number as u32, - disk_with_central_directory: footer.disk_with_central_directory as u32, - }) - } - - fn get_directory_info_zip64( - reader: &mut R, - footer: &spec::CentralDirectoryEnd, - cde_start_pos: u64, - ) -> ZipResult>> { - // See if there's a ZIP64 footer. The ZIP64 locator if present will - // have its signature 20 bytes in front of the standard footer. The - // standard footer, in turn, is 22+N bytes large, where N is the - // comment length. Therefore: - reader.seek(io::SeekFrom::End( - -(20 + 22 + footer.zip_file_comment.len() as i64), - ))?; - let locator64 = spec::Zip64CentralDirectoryEndLocator::parse(reader)?; - - // We need to reassess `archive_offset`. We know where the ZIP64 - // central-directory-end structure *should* be, but unfortunately we - // don't know how to precisely relate that location to our current - // actual offset in the file, since there may be junk at its - // beginning. Therefore we need to perform another search, as in - // read::CentralDirectoryEnd::find_and_parse, except now we search - // forward. There may be multiple results because of Zip64 central-directory signatures in - // ZIP comment data. - - let mut results = Vec::new(); - - let search_upper_bound = cde_start_pos - .checked_sub(60) // minimum size of Zip64CentralDirectoryEnd + Zip64CentralDirectoryEndLocator - .ok_or(ZipError::InvalidArchive( - "File cannot contain ZIP64 central directory end", - ))?; - let search_results = spec::Zip64CentralDirectoryEnd::find_and_parse( - reader, - locator64.end_of_central_directory_offset, - search_upper_bound, - )?; - search_results.into_iter().for_each(|(footer64, archive_offset)| { - results.push({ - let directory_start_result = footer64 - .central_directory_offset - .checked_add(archive_offset) - .ok_or(ZipError::InvalidArchive( - "Invalid central directory size or offset", - )); - directory_start_result.and_then(|directory_start| { - if directory_start > search_upper_bound { - Err(ZipError::InvalidArchive( - "Invalid central directory size or offset", - )) - } else if footer64.number_of_files_on_this_disk > footer64.number_of_files { - Err(ZipError::InvalidArchive( - "ZIP64 footer indicates more files on this disk than in the whole archive", - )) - } else if footer64.version_needed_to_extract > footer64.version_made_by { - Err(ZipError::InvalidArchive( - "ZIP64 footer indicates a new version is needed to extract this archive than the \ - version that wrote it", - )) - } else { - Ok(CentralDirectoryInfo { - archive_offset, - directory_start, - number_of_files: footer64.number_of_files as usize, - disk_number: footer64.disk_number, - disk_with_central_directory: footer64.disk_with_central_directory, - }) - } - }) - }); - }); - Ok(results) - } - - /// Get the directory start offset and number of files. This is done in a - /// separate function to ease the control flow design. - pub(crate) fn get_metadata( - reader: &mut R, - footer: &spec::CentralDirectoryEnd, - cde_start_pos: u64, - ) -> ZipResult { - // Check if file has a zip64 footer - let mut results = Self::get_directory_info_zip64(reader, footer, cde_start_pos) - .unwrap_or_else(|e| vec![Err(e)]); - let zip32_result = Self::get_directory_info_zip32(footer, cde_start_pos); - let mut invalid_errors = Vec::new(); - let mut unsupported_errors = Vec::new(); - let mut ok_results = Vec::new(); - results.iter_mut().for_each(|result| { - if let Ok(central_dir) = result { - if let Ok(zip32_central_dir) = &zip32_result { - // Both zip32 and zip64 footers exist, so check if the zip64 footer is valid; if not, try zip32 - if central_dir.number_of_files != zip32_central_dir.number_of_files - && zip32_central_dir.number_of_files != u16::MAX as usize - { - *result = Err(ZipError::InvalidArchive( - "ZIP32 and ZIP64 file counts don't match", - )); - return; - } - if central_dir.disk_number != zip32_central_dir.disk_number - && zip32_central_dir.disk_number != u16::MAX as u32 - { - *result = Err(ZipError::InvalidArchive( - "ZIP32 and ZIP64 disk numbers don't match", - )); - return; - } - if central_dir.disk_with_central_directory - != zip32_central_dir.disk_with_central_directory - && zip32_central_dir.disk_with_central_directory != u16::MAX as u32 - { - *result = Err(ZipError::InvalidArchive( - "ZIP32 and ZIP64 last-disk numbers don't match", - )); - } - } - } - }); - results.push(zip32_result); - results - .into_iter() - .map(|result| { - result.and_then(|dir_info| { - // If the parsed number of files is greater than the offset then - // something fishy is going on and we shouldn't trust number_of_files. - let file_capacity = - if dir_info.number_of_files > dir_info.directory_start as usize { - 0 - } else { - dir_info.number_of_files - }; - let mut files = IndexMap::with_capacity(file_capacity); - reader.seek(io::SeekFrom::Start(dir_info.directory_start))?; - for _ in 0..dir_info.number_of_files { - let file = central_header_to_zip_file(reader, dir_info.archive_offset)?; - files.insert(file.file_name.clone(), file); - } - if dir_info.disk_number != dir_info.disk_with_central_directory { - unsupported_zip_error("Support for multi-disk files is not implemented") - } else { - Ok(Shared { - files, - offset: dir_info.archive_offset, - dir_start: dir_info.directory_start, - }) - } - }) - }) - .for_each(|result| match result { - Err(ZipError::UnsupportedArchive(e)) => { - unsupported_errors.push(ZipError::UnsupportedArchive(e)) - } - Err(e) => invalid_errors.push(e), - Ok(o) => ok_results.push(o), - }); - if ok_results.is_empty() { - return Err(unsupported_errors - .into_iter() - .next() - .unwrap_or_else(|| invalid_errors.into_iter().next().unwrap())); - } - let shared = ok_results - .into_iter() - .max_by_key(|shared| shared.dir_start) - .unwrap(); - reader.seek(io::SeekFrom::Start(shared.dir_start))?; - Ok(shared) - } - - /// Read a ZIP archive, collecting the files it contains - /// - /// This uses the central directory record of the ZIP file, and ignores local file headers - pub fn new(mut reader: R) -> ZipResult> { - let (footer, cde_start_pos) = spec::CentralDirectoryEnd::find_and_parse(&mut reader)?; - let shared = Self::get_metadata(&mut reader, &footer, cde_start_pos)?; - Ok(ZipArchive { - reader, - shared: shared.into(), - comment: footer.zip_file_comment.into(), - }) - } - /// Extract a Zip archive into a directory, overwriting files if they - /// already exist. Paths are sanitized with [`ZipFile::enclosed_name`]. - /// - /// Extraction is not atomic. If an error is encountered, some of the files - /// may be left on disk. However, on Unix targets, no newly-created directories with part but - /// not all of their contents extracted will be readable, writable or usable as process working - /// directories by any non-root user except you. - pub fn extract>(&mut self, directory: P) -> ZipResult<()> { - use std::fs; - #[cfg(unix)] - let mut files_by_unix_mode = Vec::new(); - for i in 0..self.len() { - let mut file = self.by_index(i)?; - let filepath = file - .enclosed_name() - .ok_or(ZipError::InvalidArchive("Invalid file path"))?; - - let outpath = directory.as_ref().join(filepath); - - if file.is_dir() { - Self::make_writable_dir_all(&outpath)?; - } else { - if let Some(p) = outpath.parent() { - Self::make_writable_dir_all(p)?; - } - let mut outfile = fs::File::create(&outpath)?; - io::copy(&mut file, &mut outfile)?; - } - #[cfg(unix)] - { - // Check for real permissions, which we'll set in a second pass - if let Some(mode) = file.unix_mode() { - files_by_unix_mode.push((outpath.clone(), mode)); - } - } - } - #[cfg(unix)] - { - use std::cmp::Reverse; - use std::os::unix::fs::PermissionsExt; - - if files_by_unix_mode.len() > 1 { - // Ensure we update children's permissions before making a parent unwritable - files_by_unix_mode.sort_by_key(|(path, _)| Reverse(path.clone())); - } - for (path, mode) in files_by_unix_mode.into_iter() { - fs::set_permissions(&path, fs::Permissions::from_mode(mode))?; - } - } - Ok(()) - } - - fn make_writable_dir_all>(outpath: T) -> Result<(), ZipError> { - create_dir_all(outpath.as_ref())?; - #[cfg(unix)] - { - // Dirs must be writable until all normal files are extracted - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(outpath.as_ref(), std::fs::Permissions::from_mode(0o700))?; - } - Ok(()) - } - - /// Number of files contained in this zip. - pub fn len(&self) -> usize { - self.shared.files.len() - } - - /// Whether this zip archive contains no files - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Get the offset from the beginning of the underlying reader that this zip begins at, in bytes. - /// - /// Normally this value is zero, but if the zip has arbitrary data prepended to it, then this value will be the size - /// of that prepended data. - pub fn offset(&self) -> u64 { - self.shared.offset - } - - /// Get the comment of the zip archive. - pub fn comment(&self) -> &[u8] { - &self.comment - } - - /// Returns an iterator over all the file and directory names in this archive. - pub fn file_names(&self) -> impl Iterator { - self.shared.files.keys().map(|s| s.as_ref()) - } - - /// Search for a file entry by name, decrypt with given password - /// - /// # Warning - /// - /// The implementation of the cryptographic algorithms has not - /// gone through a correctness review, and you should assume it is insecure: - /// passwords used with this API may be compromised. - /// - /// This function sometimes accepts wrong password. This is because the ZIP spec only allows us - /// to check for a 1/256 chance that the password is correct. - /// There are many passwords out there that will also pass the validity checks - /// we are able to perform. This is a weakness of the ZipCrypto algorithm, - /// due to its fairly primitive approach to cryptography. - pub fn by_name_decrypt(&mut self, name: &str, password: &[u8]) -> ZipResult { - self.by_name_with_optional_password(name, Some(password)) - } - - /// Search for a file entry by name - pub fn by_name(&mut self, name: &str) -> ZipResult { - self.by_name_with_optional_password(name, None) - } - - /// Get the index of a file entry by name, if it's present. - #[inline(always)] - pub fn index_for_name(&self, name: &str) -> Option { - self.shared.files.get_index_of(name) - } - - /// Get the index of a file entry by path, if it's present. - #[inline(always)] - pub fn index_for_path>(&self, path: T) -> Option { - self.index_for_name(&path_to_string(path)) - } - - /// Get the name of a file entry, if it's present. - #[inline(always)] - pub fn name_for_index(&self, index: usize) -> Option<&str> { - self.shared - .files - .get_index(index) - .map(|(name, _)| name.as_ref()) - } - - fn by_name_with_optional_password<'a>( - &'a mut self, - name: &str, - password: Option<&[u8]>, - ) -> ZipResult> { - let Some(index) = self.shared.files.get_index_of(name) else { - return Err(ZipError::FileNotFound); - }; - self.by_index_with_optional_password(index, password) - } - - /// Get a contained file by index, decrypt with given password - /// - /// # Warning - /// - /// The implementation of the cryptographic algorithms has not - /// gone through a correctness review, and you should assume it is insecure: - /// passwords used with this API may be compromised. - /// - /// This function sometimes accepts wrong password. This is because the ZIP spec only allows us - /// to check for a 1/256 chance that the password is correct. - /// There are many passwords out there that will also pass the validity checks - /// we are able to perform. This is a weakness of the ZipCrypto algorithm, - /// due to its fairly primitive approach to cryptography. - pub fn by_index_decrypt( - &mut self, - file_number: usize, - password: &[u8], - ) -> ZipResult> { - self.by_index_with_optional_password(file_number, Some(password)) - } - - /// Get a contained file by index - pub fn by_index(&mut self, file_number: usize) -> ZipResult> { - self.by_index_with_optional_password(file_number, None) - } - - /// Get a contained file by index without decompressing it - pub fn by_index_raw(&mut self, file_number: usize) -> ZipResult> { - let reader = &mut self.reader; - let (_, data) = self - .shared - .files - .get_index(file_number) - .ok_or(ZipError::FileNotFound)?; - Ok(ZipFile { - crypto_reader: None, - reader: ZipFileReader::Raw(find_content(data, reader)?), - data: Cow::Borrowed(data), - }) - } - - fn by_index_with_optional_password( - &mut self, - file_number: usize, - mut password: Option<&[u8]>, - ) -> ZipResult> { - let (_, data) = self - .shared - .files - .get_index(file_number) - .ok_or(ZipError::FileNotFound)?; - - match (password, data.encrypted) { - (None, true) => return Err(ZipError::UnsupportedArchive(ZipError::PASSWORD_REQUIRED)), - (Some(_), false) => password = None, //Password supplied, but none needed! Discard. - _ => {} - } - let limit_reader = find_content(data, &mut self.reader)?; - - let crypto_reader = make_crypto_reader( - data.compression_method, - data.crc32, - data.last_modified_time, - data.using_data_descriptor, - limit_reader, - password, - data.aes_mode, - #[cfg(feature = "aes-crypto")] - data.compressed_size, - )?; - Ok(ZipFile { - crypto_reader: Some(crypto_reader), - reader: ZipFileReader::NoReader, - data: Cow::Borrowed(data), - }) - } - - /// Unwrap and return the inner reader object - /// - /// The position of the reader is undefined. - pub fn into_inner(self) -> R { - self.reader - } -} - -const fn unsupported_zip_error(detail: &'static str) -> ZipResult { - Err(ZipError::UnsupportedArchive(detail)) -} - -/// Parse a central directory entry to collect the information for the file. -pub(crate) fn central_header_to_zip_file( - reader: &mut R, - archive_offset: u64, -) -> ZipResult { - let central_header_start = reader.stream_position()?; - - // Parse central header - let signature = reader.read_u32_le()?; - if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { - Err(ZipError::InvalidArchive("Invalid Central Directory header")) - } else { - central_header_to_zip_file_inner(reader, archive_offset, central_header_start) - } -} - -/// Parse a central directory entry to collect the information for the file. -fn central_header_to_zip_file_inner( - reader: &mut R, - archive_offset: u64, - central_header_start: u64, -) -> ZipResult { - let version_made_by = reader.read_u16_le()?; - let _version_to_extract = reader.read_u16_le()?; - let flags = reader.read_u16_le()?; - let encrypted = flags & 1 == 1; - let is_utf8 = flags & (1 << 11) != 0; - let using_data_descriptor = flags & (1 << 3) != 0; - let compression_method = reader.read_u16_le()?; - let last_mod_time = reader.read_u16_le()?; - let last_mod_date = reader.read_u16_le()?; - let crc32 = reader.read_u32_le()?; - let compressed_size = reader.read_u32_le()?; - let uncompressed_size = reader.read_u32_le()?; - let file_name_length = reader.read_u16_le()? as usize; - let extra_field_length = reader.read_u16_le()? as usize; - let file_comment_length = reader.read_u16_le()? as usize; - let _disk_number = reader.read_u16_le()?; - let _internal_file_attributes = reader.read_u16_le()?; - let external_file_attributes = reader.read_u32_le()?; - let offset = reader.read_u32_le()? as u64; - let mut file_name_raw = vec![0; file_name_length]; - reader.read_exact(&mut file_name_raw)?; - let mut extra_field = vec![0; extra_field_length]; - reader.read_exact(&mut extra_field)?; - let mut file_comment_raw = vec![0; file_comment_length]; - reader.read_exact(&mut file_comment_raw)?; - - let file_name: Box = match is_utf8 { - true => String::from_utf8_lossy(&file_name_raw).into(), - false => file_name_raw.from_cp437().into(), - }; - let file_comment: Box = match is_utf8 { - true => String::from_utf8_lossy(&file_comment_raw).into(), - false => file_comment_raw.from_cp437().into(), - }; - - // Construct the result - let mut result = ZipFileData { - system: System::from((version_made_by >> 8) as u8), - version_made_by: version_made_by as u8, - encrypted, - using_data_descriptor, - compression_method: { - #[allow(deprecated)] - CompressionMethod::from_u16(compression_method) - }, - compression_level: None, - last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), - crc32, - compressed_size: compressed_size as u64, - uncompressed_size: uncompressed_size as u64, - file_name, - file_name_raw: file_name_raw.into(), - extra_field: Some(Arc::new(extra_field)), - central_extra_field: None, - file_comment, - header_start: offset, - extra_data_start: None, - central_header_start, - data_start: OnceLock::new(), - external_attributes: external_file_attributes, - large_file: false, - aes_mode: None, - aes_extra_data_start: 0, - extra_fields: Vec::new(), - }; - - match parse_extra_field(&mut result) { - Ok(..) | Err(ZipError::Io(..)) => {} - Err(e) => return Err(e), - } - - let aes_enabled = result.compression_method == CompressionMethod::AES; - if aes_enabled && result.aes_mode.is_none() { - return Err(ZipError::InvalidArchive( - "AES encryption without AES extra data field", - )); - } - - // Account for shifted zip offsets. - result.header_start = result - .header_start - .checked_add(archive_offset) - .ok_or(ZipError::InvalidArchive("Archive header is too large"))?; - - Ok(result) -} - -fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> { - let Some(extra_field) = &file.extra_field else { - return Ok(()); - }; - let mut reader = io::Cursor::new(extra_field.as_ref()); - - while (reader.position() as usize) < extra_field.len() { - let kind = reader.read_u16_le()?; - let len = reader.read_u16_le()?; - let mut len_left = len as i64; - match kind { - // Zip64 extended information extra field - 0x0001 => { - if file.uncompressed_size == spec::ZIP64_BYTES_THR { - file.large_file = true; - file.uncompressed_size = reader.read_u64_le()?; - len_left -= 8; - } - if file.compressed_size == spec::ZIP64_BYTES_THR { - file.large_file = true; - file.compressed_size = reader.read_u64_le()?; - len_left -= 8; - } - if file.header_start == spec::ZIP64_BYTES_THR { - file.header_start = reader.read_u64_le()?; - len_left -= 8; - } - } - 0x9901 => { - // AES - if len != 7 { - return Err(ZipError::UnsupportedArchive( - "AES extra data field has an unsupported length", - )); - } - let vendor_version = reader.read_u16_le()?; - let vendor_id = reader.read_u16_le()?; - let mut out = [0u8]; - reader.read_exact(&mut out)?; - let aes_mode = out[0]; - #[allow(deprecated)] - let compression_method = CompressionMethod::from_u16(reader.read_u16_le()?); - - if vendor_id != 0x4541 { - return Err(ZipError::InvalidArchive("Invalid AES vendor")); - } - let vendor_version = match vendor_version { - 0x0001 => AesVendorVersion::Ae1, - 0x0002 => AesVendorVersion::Ae2, - _ => return Err(ZipError::InvalidArchive("Invalid AES vendor version")), - }; - match aes_mode { - 0x01 => { - file.aes_mode = Some((AesMode::Aes128, vendor_version, compression_method)) - } - 0x02 => { - file.aes_mode = Some((AesMode::Aes192, vendor_version, compression_method)) - } - 0x03 => { - file.aes_mode = Some((AesMode::Aes256, vendor_version, compression_method)) - } - _ => return Err(ZipError::InvalidArchive("Invalid AES encryption strength")), - }; - file.compression_method = compression_method; - } - 0x5455 => { - // extended timestamp - // https://libzip.org/specifications/extrafld.txt - - file.extra_fields.push(ExtraField::ExtendedTimestamp( - ExtendedTimestamp::try_from_reader(&mut reader, len)?, - )); - - // the reader for ExtendedTimestamp consumes `len` bytes - len_left = 0; - } - _ => { - // Other fields are ignored - } - } - - // We could also check for < 0 to check for errors - if len_left > 0 { - reader.seek(io::SeekFrom::Current(len_left))?; - } - } - Ok(()) -} - -/// Methods for retrieving information on zip files -impl<'a> ZipFile<'a> { - fn get_reader(&mut self) -> ZipResult<&mut ZipFileReader<'a>> { - if let ZipFileReader::NoReader = self.reader { - let data = &self.data; - let crypto_reader = self.crypto_reader.take().expect("Invalid reader state"); - self.reader = make_reader(data.compression_method, data.crc32, crypto_reader)?; - } - Ok(&mut self.reader) - } - - pub(crate) fn get_raw_reader(&mut self) -> &mut dyn Read { - if let ZipFileReader::NoReader = self.reader { - let crypto_reader = self.crypto_reader.take().expect("Invalid reader state"); - self.reader = ZipFileReader::Raw(crypto_reader.into_inner()) - } - &mut self.reader - } - - /// Get the version of the file - pub fn version_made_by(&self) -> (u8, u8) { - ( - self.data.version_made_by / 10, - self.data.version_made_by % 10, - ) - } - - /// Get the name of the file - /// - /// # Warnings - /// - /// It is dangerous to use this name directly when extracting an archive. - /// It may contain an absolute path (`/etc/shadow`), or break out of the - /// current directory (`../runtime`). Carelessly writing to these paths - /// allows an attacker to craft a ZIP archive that will overwrite critical - /// files. - /// - /// You can use the [`ZipFile::enclosed_name`] method to validate the name - /// as a safe path. - pub fn name(&self) -> &str { - &self.data.file_name - } - - /// Get the name of the file, in the raw (internal) byte representation. - /// - /// The encoding of this data is currently undefined. - pub fn name_raw(&self) -> &[u8] { - &self.data.file_name_raw - } - - /// Get the name of the file in a sanitized form. It truncates the name to the first NULL byte, - /// removes a leading '/' and removes '..' parts. - #[deprecated( - since = "0.5.7", - note = "by stripping `..`s from the path, the meaning of paths can change. - `mangled_name` can be used if this behaviour is desirable" - )] - pub fn sanitized_name(&self) -> PathBuf { - self.mangled_name() - } - - /// Rewrite the path, ignoring any path components with special meaning. - /// - /// - Absolute paths are made relative - /// - [`ParentDir`]s are ignored - /// - Truncates the filename at a NULL byte - /// - /// This is appropriate if you need to be able to extract *something* from - /// any archive, but will easily misrepresent trivial paths like - /// `foo/../bar` as `foo/bar` (instead of `bar`). Because of this, - /// [`ZipFile::enclosed_name`] is the better option in most scenarios. - /// - /// [`ParentDir`]: `Component::ParentDir` - pub fn mangled_name(&self) -> PathBuf { - self.data.file_name_sanitized() - } - - /// Ensure the file path is safe to use as a [`Path`]. - /// - /// - It can't contain NULL bytes - /// - It can't resolve to a path outside the current directory - /// > `foo/../bar` is fine, `foo/../../bar` is not. - /// - It can't be an absolute path - /// - /// This will read well-formed ZIP files correctly, and is resistant - /// to path-based exploits. It is recommended over - /// [`ZipFile::mangled_name`]. - pub fn enclosed_name(&self) -> Option { - self.data.enclosed_name() - } - - /// Get the comment of the file - pub fn comment(&self) -> &str { - &self.data.file_comment - } - - /// Get the compression method used to store the file - pub fn compression(&self) -> CompressionMethod { - self.data.compression_method - } - - /// Get the size of the file, in bytes, in the archive - pub fn compressed_size(&self) -> u64 { - self.data.compressed_size - } - - /// Get the size of the file, in bytes, when uncompressed - pub fn size(&self) -> u64 { - self.data.uncompressed_size - } - - /// Get the time the file was last modified - pub fn last_modified(&self) -> DateTime { - self.data.last_modified_time - } - /// Returns whether the file is actually a directory - pub fn is_dir(&self) -> bool { - self.name() - .chars() - .next_back() - .map_or(false, |c| c == '/' || c == '\\') - } - - /// Returns whether the file is a regular file - pub fn is_file(&self) -> bool { - !self.is_dir() - } - - /// Get unix mode for the file - pub fn unix_mode(&self) -> Option { - self.data.unix_mode() - } - - /// Get the CRC32 hash of the original file - pub fn crc32(&self) -> u32 { - self.data.crc32 - } - - /// Get the extra data of the zip header for this file - pub fn extra_data(&self) -> Option<&[u8]> { - self.data.extra_field.as_ref().map(|v| v.deref().deref()) - } - - /// Get the starting offset of the data of the compressed file - pub fn data_start(&self) -> u64 { - *self.data.data_start.get().unwrap_or(&0) - } - - /// Get the starting offset of the zip header for this file - pub fn header_start(&self) -> u64 { - self.data.header_start - } - /// Get the starting offset of the zip header in the central directory for this file - pub fn central_header_start(&self) -> u64 { - self.data.central_header_start - } - - /// iterate through all extra fields - pub fn extra_data_fields(&self) -> impl Iterator { - self.data.extra_fields.iter() - } -} - -impl<'a> Read for ZipFile<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.get_reader()?.read(buf) - } -} - -impl<'a> Drop for ZipFile<'a> { - fn drop(&mut self) { - // self.data is Owned, this reader is constructed by a streaming reader. - // In this case, we want to exhaust the reader so that the next file is accessible. - if let Cow::Owned(_) = self.data { - // Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped. - match &mut self.reader { - ZipFileReader::NoReader => { - let innerreader = self.crypto_reader.take(); - let _ = copy( - &mut innerreader.expect("Invalid reader state").into_inner(), - &mut sink(), - ); - } - reader => { - let innerreader = std::mem::replace(reader, ZipFileReader::NoReader); - innerreader.drain(); - } - }; - } - } -} - -/// Read ZipFile structures from a non-seekable reader. -/// -/// This is an alternative method to read a zip file. If possible, use the ZipArchive functions -/// as some information will be missing when reading this manner. -/// -/// Reads a file header from the start of the stream. Will return `Ok(Some(..))` if a file is -/// present at the start of the stream. Returns `Ok(None)` if the start of the central directory -/// is encountered. No more files should be read after this. -/// -/// The Drop implementation of ZipFile ensures that the reader will be correctly positioned after -/// the structure is done. -/// -/// Missing fields are: -/// * `comment`: set to an empty string -/// * `data_start`: set to 0 -/// * `external_attributes`: `unix_mode()`: will return None -pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult>> { - let signature = reader.read_u32_le()?; - - match signature { - spec::LOCAL_FILE_HEADER_SIGNATURE => (), - spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE => return Ok(None), - _ => return Err(ZipError::InvalidArchive("Invalid local file header")), - } - - let version_made_by = reader.read_u16_le()?; - let flags = reader.read_u16_le()?; - let encrypted = flags & 1 == 1; - let is_utf8 = flags & (1 << 11) != 0; - let using_data_descriptor = flags & (1 << 3) != 0; - #[allow(deprecated)] - let compression_method = CompressionMethod::from_u16(reader.read_u16_le()?); - let last_mod_time = reader.read_u16_le()?; - let last_mod_date = reader.read_u16_le()?; - let crc32 = reader.read_u32_le()?; - let compressed_size = reader.read_u32_le()?; - let uncompressed_size = reader.read_u32_le()?; - let file_name_length = reader.read_u16_le()? as usize; - let extra_field_length = reader.read_u16_le()? as usize; - - let mut file_name_raw = vec![0; file_name_length]; - reader.read_exact(&mut file_name_raw)?; - let mut extra_field = vec![0; extra_field_length]; - reader.read_exact(&mut extra_field)?; - - let file_name: Box = match is_utf8 { - true => String::from_utf8_lossy(&file_name_raw).into(), - false => file_name_raw.clone().from_cp437().into(), - }; - - let mut result = ZipFileData { - system: System::from((version_made_by >> 8) as u8), - version_made_by: version_made_by as u8, - encrypted, - using_data_descriptor, - compression_method, - compression_level: None, - last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), - crc32, - compressed_size: compressed_size as u64, - uncompressed_size: uncompressed_size as u64, - file_name, - file_name_raw: file_name_raw.into(), - extra_field: Some(Arc::new(extra_field)), - central_extra_field: None, - file_comment: String::with_capacity(0).into_boxed_str(), // file comment is only available in the central directory - // header_start and data start are not available, but also don't matter, since seeking is - // not available. - header_start: 0, - extra_data_start: None, - data_start: OnceLock::new(), - central_header_start: 0, - // The external_attributes field is only available in the central directory. - // We set this to zero, which should be valid as the docs state 'If input came - // from standard input, this field is set to zero.' - external_attributes: 0, - large_file: false, - aes_mode: None, - aes_extra_data_start: 0, - extra_fields: Vec::new(), - }; - - match parse_extra_field(&mut result) { - Ok(..) | Err(ZipError::Io(..)) => {} - Err(e) => return Err(e), - } - - if encrypted { - return unsupported_zip_error("Encrypted files are not supported"); - } - if using_data_descriptor { - return unsupported_zip_error("The file length is not available in the local header"); - } - - let limit_reader = (reader as &'a mut dyn Read).take(result.compressed_size); - - let result_crc32 = result.crc32; - let result_compression_method = result.compression_method; - let crypto_reader = make_crypto_reader( - result_compression_method, - result_crc32, - result.last_modified_time, - result.using_data_descriptor, - limit_reader, - None, - None, - #[cfg(feature = "aes-crypto")] - result.compressed_size, - )?; - - Ok(Some(ZipFile { - data: Cow::Owned(result), - crypto_reader: None, - reader: make_reader(result_compression_method, result_crc32, crypto_reader)?, - })) -} - #[cfg(test)] mod test { use crate::ZipArchive; diff --git a/src/read/stream.rs b/src/read/stream.rs index 40cb9efc8..3432dc132 100644 --- a/src/read/stream.rs +++ b/src/read/stream.rs @@ -4,8 +4,8 @@ use std::io::{self, Read}; use std::path::{Path, PathBuf}; use super::{ - central_header_to_zip_file_inner, read_zipfile_from_stream, spec, ZipError, ZipFile, - ZipFileData, ZipResult, + read_zipfile_from_stream, spec, ZipError, ZipFile, +ZipFileData, ZipResult, sync::central_header_to_zip_file_inner }; /// Stream decoder for zip. diff --git a/src/read/sync.rs b/src/read/sync.rs new file mode 100644 index 000000000..b781fe589 --- /dev/null +++ b/src/read/sync.rs @@ -0,0 +1,1261 @@ +use std::{ + borrow::Cow, + fs::create_dir_all, + io::{self, copy, sink, Read, Seek, Write}, + ops::Deref, + path::{Path, PathBuf}, + sync::{Arc, OnceLock}, +}; + +#[cfg(feature = "aes-crypto")] +use crate::aes::AesReader; +#[cfg(feature = "bzip2")] +use bzip2::read::BzDecoder; +#[cfg(feature = "deflate64")] +use deflate64::Deflate64Decoder; +#[cfg(any( + feature = "deflate", + feature = "deflate-zlib", + feature = "deflate-zlib-ng" +))] +use flate2::read::DeflateDecoder; +use indexmap::IndexMap; + +use crate::{ + cp437::FromCp437, + crc32::Crc32Reader, + extra_fields::ExtendedTimestamp, + result::{ZipError, ZipResult}, + spec::{self, path_to_string}, + types::{AesVendorVersion, System, ZipFileData}, + unstable::LittleEndianReadExt, + zipcrypto::{ZipCryptoReader, ZipCryptoValidator}, + AesMode, CompressionMethod, DateTime, ExtraField, ZipArchive, +}; +#[cfg(feature = "zstd")] +use zstd::stream::read::Decoder as ZstdDecoder; +#[cfg(feature = "lzma")] +use super::lzma::LzmaDecoder; +use super::{ + zip_archive::{self, Shared}, + CryptoReader, ZipFile, ZipFileReader +}; + +impl<'a> Read for CryptoReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + CryptoReader::Plaintext(r) => r.read(buf), + CryptoReader::ZipCrypto(r) => r.read(buf), + #[cfg(feature = "aes-crypto")] + CryptoReader::Aes { reader: r, .. } => r.read(buf), + } + } +} + +impl<'a> Read for ZipFileReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"), + ZipFileReader::Raw(r) => r.read(buf), + ZipFileReader::Stored(r) => r.read(buf), + #[cfg(feature = "_deflate-any")] + ZipFileReader::Deflated(r) => r.read(buf), + #[cfg(feature = "deflate64")] + ZipFileReader::Deflate64(r) => r.read(buf), + #[cfg(feature = "bzip2")] + ZipFileReader::Bzip2(r) => r.read(buf), + #[cfg(feature = "zstd")] + ZipFileReader::Zstd(r) => r.read(buf), + #[cfg(feature = "lzma")] + ZipFileReader::Lzma(r) => r.read(buf), + } + } +} + +pub(crate) fn find_content<'a>( + data: &ZipFileData, + reader: &'a mut (impl Read + Seek), +) -> ZipResult> { + // Parse local header + reader.seek(io::SeekFrom::Start(data.header_start))?; + let signature = reader.read_u32_le()?; + if signature != spec::LOCAL_FILE_HEADER_SIGNATURE { + return Err(ZipError::InvalidArchive("Invalid local file header")); + } + let data_start = match data.data_start.get() { + None => { + reader.seek(io::SeekFrom::Current(22))?; + let file_name_length = reader.read_u16_le()? as u64; + let extra_field_length = reader.read_u16_le()? as u64; + let magic_and_header = 4 + 22 + 2 + 2; + let data_start = + data.header_start + magic_and_header + file_name_length + extra_field_length; + data.data_start.get_or_init(|| data_start); + data_start + } + Some(start) => *start, + }; + + reader.seek(io::SeekFrom::Start(data_start))?; + Ok((reader as &mut dyn Read).take(data.compressed_size)) +} + +impl ZipArchive { + pub(crate) fn merge_contents( + &mut self, + mut w: W, + ) -> ZipResult, ZipFileData>> { + if self.shared.files.is_empty() { + return Ok(IndexMap::new()); + } + let mut new_files = self.shared.files.clone(); + /* The first file header will probably start at the beginning of the file, but zip doesn't + * enforce that, and executable zips like PEX files will have a shebang line so will + * definitely be greater than 0. + * + * assert_eq!(0, new_files[0].header_start); // Avoid this. + */ + + let new_initial_header_start = w.stream_position()?; + /* Push back file header starts for all entries in the covered files. */ + new_files.values_mut().try_for_each(|f| { + /* This is probably the only really important thing to change. */ + f.header_start = f.header_start.checked_add(new_initial_header_start).ok_or( + ZipError::InvalidArchive("new header start from merge would have been too large"), + )?; + /* This is only ever used internally to cache metadata lookups (it's not part of the + * zip spec), and 0 is the sentinel value. */ + f.central_header_start = 0; + /* This is an atomic variable so it can be updated from another thread in the + * implementation (which is good!). */ + if let Some(old_data_start) = f.data_start.take() { + let new_data_start = old_data_start.checked_add(new_initial_header_start).ok_or( + ZipError::InvalidArchive("new data start from merge would have been too large"), + )?; + f.data_start.get_or_init(|| new_data_start); + } + Ok::<_, ZipError>(()) + })?; + + /* Rewind to the beginning of the file. + * + * NB: we *could* decide to start copying from new_files[0].header_start instead, which + * would avoid copying over e.g. any pex shebangs or other file contents that start before + * the first zip file entry. However, zip files actually shouldn't care about garbage data + * in *between* real entries, since the central directory header records the correct start + * location of each, and keeping track of that math is more complicated logic that will only + * rarely be used, since most zips that get merged together are likely to be produced + * specifically for that purpose (and therefore are unlikely to have a shebang or other + * preface). Finally, this preserves any data that might actually be useful. + */ + self.reader.rewind()?; + /* Find the end of the file data. */ + let length_to_read = self.shared.dir_start; + /* Produce a Read that reads bytes up until the start of the central directory header. + * This "as &mut dyn Read" trick is used elsewhere to avoid having to clone the underlying + * handle, which it really shouldn't need to anyway. */ + let mut limited_raw = (&mut self.reader as &mut dyn Read).take(length_to_read); + /* Copy over file data from source archive directly. */ + io::copy(&mut limited_raw, &mut w)?; + + /* Return the files we've just written to the data stream. */ + Ok(new_files) + } + + fn get_directory_info_zip32( + footer: &spec::CentralDirectoryEnd, + cde_start_pos: u64, + ) -> ZipResult { + // Some zip files have data prepended to them, resulting in the + // offsets all being too small. Get the amount of error by comparing + // the actual file position we found the CDE at with the offset + // recorded in the CDE. + let archive_offset = cde_start_pos + .checked_sub(footer.central_directory_size as u64) + .and_then(|x| x.checked_sub(footer.central_directory_offset as u64)) + .ok_or(ZipError::InvalidArchive( + "Invalid central directory size or offset", + ))?; + + let directory_start = footer.central_directory_offset as u64 + archive_offset; + let number_of_files = footer.number_of_files_on_this_disk as usize; + Ok(CentralDirectoryInfo { + archive_offset, + directory_start, + number_of_files, + disk_number: footer.disk_number as u32, + disk_with_central_directory: footer.disk_with_central_directory as u32, + }) + } + + fn get_directory_info_zip64( + reader: &mut R, + footer: &spec::CentralDirectoryEnd, + cde_start_pos: u64, + ) -> ZipResult>> { + // See if there's a ZIP64 footer. The ZIP64 locator if present will + // have its signature 20 bytes in front of the standard footer. The + // standard footer, in turn, is 22+N bytes large, where N is the + // comment length. Therefore: + reader.seek(io::SeekFrom::End( + -(20 + 22 + footer.zip_file_comment.len() as i64), + ))?; + let locator64 = spec::Zip64CentralDirectoryEndLocator::parse(reader)?; + + // We need to reassess `archive_offset`. We know where the ZIP64 + // central-directory-end structure *should* be, but unfortunately we + // don't know how to precisely relate that location to our current + // actual offset in the file, since there may be junk at its + // beginning. Therefore we need to perform another search, as in + // read::CentralDirectoryEnd::find_and_parse, except now we search + // forward. There may be multiple results because of Zip64 central-directory signatures in + // ZIP comment data. + + let mut results = Vec::new(); + + let search_upper_bound = cde_start_pos + .checked_sub(60) // minimum size of Zip64CentralDirectoryEnd + Zip64CentralDirectoryEndLocator + .ok_or(ZipError::InvalidArchive( + "File cannot contain ZIP64 central directory end", + ))?; + let search_results = spec::Zip64CentralDirectoryEnd::find_and_parse( + reader, + locator64.end_of_central_directory_offset, + search_upper_bound, + )?; + search_results.into_iter().for_each(|(footer64, archive_offset)| { + results.push({ + let directory_start_result = footer64 + .central_directory_offset + .checked_add(archive_offset) + .ok_or(ZipError::InvalidArchive( + "Invalid central directory size or offset", + )); + directory_start_result.and_then(|directory_start| { + if directory_start > search_upper_bound { + Err(ZipError::InvalidArchive( + "Invalid central directory size or offset", + )) + } else if footer64.number_of_files_on_this_disk > footer64.number_of_files { + Err(ZipError::InvalidArchive( + "ZIP64 footer indicates more files on this disk than in the whole archive", + )) + } else if footer64.version_needed_to_extract > footer64.version_made_by { + Err(ZipError::InvalidArchive( + "ZIP64 footer indicates a new version is needed to extract this archive than the \ + version that wrote it", + )) + } else { + Ok(CentralDirectoryInfo { + archive_offset, + directory_start, + number_of_files: footer64.number_of_files as usize, + disk_number: footer64.disk_number, + disk_with_central_directory: footer64.disk_with_central_directory, + }) + } + }) + }); + }); + Ok(results) + } + + /// Get the directory start offset and number of files. This is done in a + /// separate function to ease the control flow design. + pub(crate) fn get_metadata( + reader: &mut R, + footer: &spec::CentralDirectoryEnd, + cde_start_pos: u64, + ) -> ZipResult { + // Check if file has a zip64 footer + let mut results = Self::get_directory_info_zip64(reader, footer, cde_start_pos) + .unwrap_or_else(|e| vec![Err(e)]); + let zip32_result = Self::get_directory_info_zip32(footer, cde_start_pos); + let mut invalid_errors = Vec::new(); + let mut unsupported_errors = Vec::new(); + let mut ok_results = Vec::new(); + results.iter_mut().for_each(|result| { + if let Ok(central_dir) = result { + if let Ok(zip32_central_dir) = &zip32_result { + // Both zip32 and zip64 footers exist, so check if the zip64 footer is valid; if not, try zip32 + if central_dir.number_of_files != zip32_central_dir.number_of_files + && zip32_central_dir.number_of_files != u16::MAX as usize + { + *result = Err(ZipError::InvalidArchive( + "ZIP32 and ZIP64 file counts don't match", + )); + return; + } + if central_dir.disk_number != zip32_central_dir.disk_number + && zip32_central_dir.disk_number != u16::MAX as u32 + { + *result = Err(ZipError::InvalidArchive( + "ZIP32 and ZIP64 disk numbers don't match", + )); + return; + } + if central_dir.disk_with_central_directory + != zip32_central_dir.disk_with_central_directory + && zip32_central_dir.disk_with_central_directory != u16::MAX as u32 + { + *result = Err(ZipError::InvalidArchive( + "ZIP32 and ZIP64 last-disk numbers don't match", + )); + } + } + } + }); + results.push(zip32_result); + results + .into_iter() + .map(|result| { + result.and_then(|dir_info| { + // If the parsed number of files is greater than the offset then + // something fishy is going on and we shouldn't trust number_of_files. + let file_capacity = + if dir_info.number_of_files > dir_info.directory_start as usize { + 0 + } else { + dir_info.number_of_files + }; + let mut files = IndexMap::with_capacity(file_capacity); + reader.seek(io::SeekFrom::Start(dir_info.directory_start))?; + for _ in 0..dir_info.number_of_files { + let file = central_header_to_zip_file(reader, dir_info.archive_offset)?; + files.insert(file.file_name.clone(), file); + } + if dir_info.disk_number != dir_info.disk_with_central_directory { + unsupported_zip_error("Support for multi-disk files is not implemented") + } else { + Ok(Shared { + files, + offset: dir_info.archive_offset, + dir_start: dir_info.directory_start, + }) + } + }) + }) + .for_each(|result| match result { + Err(ZipError::UnsupportedArchive(e)) => { + unsupported_errors.push(ZipError::UnsupportedArchive(e)) + } + Err(e) => invalid_errors.push(e), + Ok(o) => ok_results.push(o), + }); + if ok_results.is_empty() { + return Err(unsupported_errors + .into_iter() + .next() + .unwrap_or_else(|| invalid_errors.into_iter().next().unwrap())); + } + let shared = ok_results + .into_iter() + .max_by_key(|shared| shared.dir_start) + .unwrap(); + reader.seek(io::SeekFrom::Start(shared.dir_start))?; + Ok(shared) + } + + /// Read a ZIP archive, collecting the files it contains + /// + /// This uses the central directory record of the ZIP file, and ignores local file headers + pub fn new(mut reader: R) -> ZipResult> { + let (footer, cde_start_pos) = spec::CentralDirectoryEnd::find_and_parse(&mut reader)?; + let shared = Self::get_metadata(&mut reader, &footer, cde_start_pos)?; + Ok(ZipArchive { + reader, + shared: shared.into(), + comment: footer.zip_file_comment.into(), + }) + } + /// Extract a Zip archive into a directory, overwriting files if they + /// already exist. Paths are sanitized with [`ZipFile::enclosed_name`]. + /// + /// Extraction is not atomic. If an error is encountered, some of the files + /// may be left on disk. However, on Unix targets, no newly-created directories with part but + /// not all of their contents extracted will be readable, writable or usable as process working + /// directories by any non-root user except you. + pub fn extract>(&mut self, directory: P) -> ZipResult<()> { + use std::fs; + #[cfg(unix)] + let mut files_by_unix_mode = Vec::new(); + for i in 0..self.len() { + let mut file = self.by_index(i)?; + let filepath = file + .enclosed_name() + .ok_or(ZipError::InvalidArchive("Invalid file path"))?; + + let outpath = directory.as_ref().join(filepath); + + if file.is_dir() { + Self::make_writable_dir_all(&outpath)?; + } else { + if let Some(p) = outpath.parent() { + Self::make_writable_dir_all(p)?; + } + let mut outfile = fs::File::create(&outpath)?; + io::copy(&mut file, &mut outfile)?; + } + #[cfg(unix)] + { + // Check for real permissions, which we'll set in a second pass + if let Some(mode) = file.unix_mode() { + files_by_unix_mode.push((outpath.clone(), mode)); + } + } + } + #[cfg(unix)] + { + use std::cmp::Reverse; + use std::os::unix::fs::PermissionsExt; + + if files_by_unix_mode.len() > 1 { + // Ensure we update children's permissions before making a parent unwritable + files_by_unix_mode.sort_by_key(|(path, _)| Reverse(path.clone())); + } + for (path, mode) in files_by_unix_mode.into_iter() { + fs::set_permissions(&path, fs::Permissions::from_mode(mode))?; + } + } + Ok(()) + } + + fn make_writable_dir_all>(outpath: T) -> Result<(), ZipError> { + create_dir_all(outpath.as_ref())?; + #[cfg(unix)] + { + // Dirs must be writable until all normal files are extracted + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(outpath.as_ref(), std::fs::Permissions::from_mode(0o700))?; + } + Ok(()) + } + + /// Number of files contained in this zip. + pub fn len(&self) -> usize { + self.shared.files.len() + } + + /// Whether this zip archive contains no files + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the offset from the beginning of the underlying reader that this zip begins at, in bytes. + /// + /// Normally this value is zero, but if the zip has arbitrary data prepended to it, then this value will be the size + /// of that prepended data. + pub fn offset(&self) -> u64 { + self.shared.offset + } + + /// Get the comment of the zip archive. + pub fn comment(&self) -> &[u8] { + &self.comment + } + + /// Returns an iterator over all the file and directory names in this archive. + pub fn file_names(&self) -> impl Iterator { + self.shared.files.keys().map(|s| s.as_ref()) + } + + /// Search for a file entry by name, decrypt with given password + /// + /// # Warning + /// + /// The implementation of the cryptographic algorithms has not + /// gone through a correctness review, and you should assume it is insecure: + /// passwords used with this API may be compromised. + /// + /// This function sometimes accepts wrong password. This is because the ZIP spec only allows us + /// to check for a 1/256 chance that the password is correct. + /// There are many passwords out there that will also pass the validity checks + /// we are able to perform. This is a weakness of the ZipCrypto algorithm, + /// due to its fairly primitive approach to cryptography. + pub fn by_name_decrypt(&mut self, name: &str, password: &[u8]) -> ZipResult { + self.by_name_with_optional_password(name, Some(password)) + } + + /// Search for a file entry by name + pub fn by_name(&mut self, name: &str) -> ZipResult { + self.by_name_with_optional_password(name, None) + } + + /// Get the index of a file entry by name, if it's present. + #[inline(always)] + pub fn index_for_name(&self, name: &str) -> Option { + self.shared.files.get_index_of(name) + } + + /// Get the index of a file entry by path, if it's present. + #[inline(always)] + pub fn index_for_path>(&self, path: T) -> Option { + self.index_for_name(&path_to_string(path)) + } + + /// Get the name of a file entry, if it's present. + #[inline(always)] + pub fn name_for_index(&self, index: usize) -> Option<&str> { + self.shared + .files + .get_index(index) + .map(|(name, _)| name.as_ref()) + } + + fn by_name_with_optional_password<'a>( + &'a mut self, + name: &str, + password: Option<&[u8]>, + ) -> ZipResult> { + let Some(index) = self.shared.files.get_index_of(name) else { + return Err(ZipError::FileNotFound); + }; + self.by_index_with_optional_password(index, password) + } + + /// Get a contained file by index, decrypt with given password + /// + /// # Warning + /// + /// The implementation of the cryptographic algorithms has not + /// gone through a correctness review, and you should assume it is insecure: + /// passwords used with this API may be compromised. + /// + /// This function sometimes accepts wrong password. This is because the ZIP spec only allows us + /// to check for a 1/256 chance that the password is correct. + /// There are many passwords out there that will also pass the validity checks + /// we are able to perform. This is a weakness of the ZipCrypto algorithm, + /// due to its fairly primitive approach to cryptography. + pub fn by_index_decrypt( + &mut self, + file_number: usize, + password: &[u8], + ) -> ZipResult> { + self.by_index_with_optional_password(file_number, Some(password)) + } + + /// Get a contained file by index + pub fn by_index(&mut self, file_number: usize) -> ZipResult> { + self.by_index_with_optional_password(file_number, None) + } + + /// Get a contained file by index without decompressing it + pub fn by_index_raw(&mut self, file_number: usize) -> ZipResult> { + let reader = &mut self.reader; + let (_, data) = self + .shared + .files + .get_index(file_number) + .ok_or(ZipError::FileNotFound)?; + Ok(ZipFile { + crypto_reader: None, + reader: ZipFileReader::Raw(find_content(data, reader)?), + data: Cow::Borrowed(data), + }) + } + + fn by_index_with_optional_password( + &mut self, + file_number: usize, + mut password: Option<&[u8]>, + ) -> ZipResult> { + let (_, data) = self + .shared + .files + .get_index(file_number) + .ok_or(ZipError::FileNotFound)?; + + match (password, data.encrypted) { + (None, true) => return Err(ZipError::UnsupportedArchive(ZipError::PASSWORD_REQUIRED)), + (Some(_), false) => password = None, //Password supplied, but none needed! Discard. + _ => {} + } + let limit_reader = find_content(data, &mut self.reader)?; + + let crypto_reader = make_crypto_reader( + data.compression_method, + data.crc32, + data.last_modified_time, + data.using_data_descriptor, + limit_reader, + password, + data.aes_mode, + #[cfg(feature = "aes-crypto")] + data.compressed_size, + )?; + Ok(ZipFile { + crypto_reader: Some(crypto_reader), + reader: ZipFileReader::NoReader, + data: Cow::Borrowed(data), + }) + } + + /// Unwrap and return the inner reader object + /// + /// The position of the reader is undefined. + pub fn into_inner(self) -> R { + self.reader + } +} + +/// Parse a central directory entry to collect the information for the file. +pub(crate) fn central_header_to_zip_file( + reader: &mut R, + archive_offset: u64, +) -> ZipResult { + let central_header_start = reader.stream_position()?; + + // Parse central header + let signature = reader.read_u32_le()?; + if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { + Err(ZipError::InvalidArchive("Invalid Central Directory header")) + } else { + central_header_to_zip_file_inner(reader, archive_offset, central_header_start) + } +} + +/// Parse a central directory entry to collect the information for the file. +pub(crate) fn central_header_to_zip_file_inner( + reader: &mut R, + archive_offset: u64, + central_header_start: u64, +) -> ZipResult { + let version_made_by = reader.read_u16_le()?; + let _version_to_extract = reader.read_u16_le()?; + let flags = reader.read_u16_le()?; + let encrypted = flags & 1 == 1; + let is_utf8 = flags & (1 << 11) != 0; + let using_data_descriptor = flags & (1 << 3) != 0; + let compression_method = reader.read_u16_le()?; + let last_mod_time = reader.read_u16_le()?; + let last_mod_date = reader.read_u16_le()?; + let crc32 = reader.read_u32_le()?; + let compressed_size = reader.read_u32_le()?; + let uncompressed_size = reader.read_u32_le()?; + let file_name_length = reader.read_u16_le()? as usize; + let extra_field_length = reader.read_u16_le()? as usize; + let file_comment_length = reader.read_u16_le()? as usize; + let _disk_number = reader.read_u16_le()?; + let _internal_file_attributes = reader.read_u16_le()?; + let external_file_attributes = reader.read_u32_le()?; + let offset = reader.read_u32_le()? as u64; + let mut file_name_raw = vec![0; file_name_length]; + reader.read_exact(&mut file_name_raw)?; + let mut extra_field = vec![0; extra_field_length]; + reader.read_exact(&mut extra_field)?; + let mut file_comment_raw = vec![0; file_comment_length]; + reader.read_exact(&mut file_comment_raw)?; + + let file_name: Box = match is_utf8 { + true => String::from_utf8_lossy(&file_name_raw).into(), + false => file_name_raw.from_cp437().into(), + }; + let file_comment: Box = match is_utf8 { + true => String::from_utf8_lossy(&file_comment_raw).into(), + false => file_comment_raw.from_cp437().into(), + }; + + // Construct the result + let mut result = ZipFileData { + system: System::from((version_made_by >> 8) as u8), + version_made_by: version_made_by as u8, + encrypted, + using_data_descriptor, + compression_method: { + #[allow(deprecated)] + CompressionMethod::from_u16(compression_method) + }, + compression_level: None, + last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), + crc32, + compressed_size: compressed_size as u64, + uncompressed_size: uncompressed_size as u64, + file_name, + file_name_raw: file_name_raw.into(), + extra_field: Some(Arc::new(extra_field)), + central_extra_field: None, + file_comment, + header_start: offset, + extra_data_start: None, + central_header_start, + data_start: OnceLock::new(), + external_attributes: external_file_attributes, + large_file: false, + aes_mode: None, + aes_extra_data_start: 0, + extra_fields: Vec::new(), + }; + + match parse_extra_field(&mut result) { + Ok(..) | Err(ZipError::Io(..)) => {} + Err(e) => return Err(e), + } + + let aes_enabled = result.compression_method == CompressionMethod::AES; + if aes_enabled && result.aes_mode.is_none() { + return Err(ZipError::InvalidArchive( + "AES encryption without AES extra data field", + )); + } + + // Account for shifted zip offsets. + result.header_start = result + .header_start + .checked_add(archive_offset) + .ok_or(ZipError::InvalidArchive("Archive header is too large"))?; + + Ok(result) +} + +pub(crate) fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> { + let Some(extra_field) = &file.extra_field else { + return Ok(()); + }; + let mut reader = io::Cursor::new(extra_field.as_ref()); + + while (reader.position() as usize) < extra_field.len() { + let kind = reader.read_u16_le()?; + let len = reader.read_u16_le()?; + let mut len_left = len as i64; + match kind { + // Zip64 extended information extra field + 0x0001 => { + if file.uncompressed_size == spec::ZIP64_BYTES_THR { + file.large_file = true; + file.uncompressed_size = reader.read_u64_le()?; + len_left -= 8; + } + if file.compressed_size == spec::ZIP64_BYTES_THR { + file.large_file = true; + file.compressed_size = reader.read_u64_le()?; + len_left -= 8; + } + if file.header_start == spec::ZIP64_BYTES_THR { + file.header_start = reader.read_u64_le()?; + len_left -= 8; + } + } + 0x9901 => { + // AES + if len != 7 { + return Err(ZipError::UnsupportedArchive( + "AES extra data field has an unsupported length", + )); + } + let vendor_version = reader.read_u16_le()?; + let vendor_id = reader.read_u16_le()?; + let mut out = [0u8]; + reader.read_exact(&mut out)?; + let aes_mode = out[0]; + #[allow(deprecated)] + let compression_method = CompressionMethod::from_u16(reader.read_u16_le()?); + + if vendor_id != 0x4541 { + return Err(ZipError::InvalidArchive("Invalid AES vendor")); + } + let vendor_version = match vendor_version { + 0x0001 => AesVendorVersion::Ae1, + 0x0002 => AesVendorVersion::Ae2, + _ => return Err(ZipError::InvalidArchive("Invalid AES vendor version")), + }; + match aes_mode { + 0x01 => { + file.aes_mode = Some((AesMode::Aes128, vendor_version, compression_method)) + } + 0x02 => { + file.aes_mode = Some((AesMode::Aes192, vendor_version, compression_method)) + } + 0x03 => { + file.aes_mode = Some((AesMode::Aes256, vendor_version, compression_method)) + } + _ => return Err(ZipError::InvalidArchive("Invalid AES encryption strength")), + }; + file.compression_method = compression_method; + } + 0x5455 => { + // extended timestamp + // https://libzip.org/specifications/extrafld.txt + + file.extra_fields.push(ExtraField::ExtendedTimestamp( + ExtendedTimestamp::try_from_reader(&mut reader, len)?, + )); + + // the reader for ExtendedTimestamp consumes `len` bytes + len_left = 0; + } + _ => { + // Other fields are ignored + } + } + + // We could also check for < 0 to check for errors + if len_left > 0 { + reader.seek(io::SeekFrom::Current(len_left))?; + } + } + Ok(()) +} + +/// Read ZipFile structures from a non-seekable reader. +/// +/// This is an alternative method to read a zip file. If possible, use the ZipArchive functions +/// as some information will be missing when reading this manner. +/// +/// Reads a file header from the start of the stream. Will return `Ok(Some(..))` if a file is +/// present at the start of the stream. Returns `Ok(None)` if the start of the central directory +/// is encountered. No more files should be read after this. +/// +/// The Drop implementation of ZipFile ensures that the reader will be correctly positioned after +/// the structure is done. +/// +/// Missing fields are: +/// * `comment`: set to an empty string +/// * `data_start`: set to 0 +/// * `external_attributes`: `unix_mode()`: will return None +pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult>> { + let signature = reader.read_u32_le()?; + + match signature { + spec::LOCAL_FILE_HEADER_SIGNATURE => (), + spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE => return Ok(None), + _ => return Err(ZipError::InvalidArchive("Invalid local file header")), + } + + let version_made_by = reader.read_u16_le()?; + let flags = reader.read_u16_le()?; + let encrypted = flags & 1 == 1; + let is_utf8 = flags & (1 << 11) != 0; + let using_data_descriptor = flags & (1 << 3) != 0; + #[allow(deprecated)] + let compression_method = CompressionMethod::from_u16(reader.read_u16_le()?); + let last_mod_time = reader.read_u16_le()?; + let last_mod_date = reader.read_u16_le()?; + let crc32 = reader.read_u32_le()?; + let compressed_size = reader.read_u32_le()?; + let uncompressed_size = reader.read_u32_le()?; + let file_name_length = reader.read_u16_le()? as usize; + let extra_field_length = reader.read_u16_le()? as usize; + + let mut file_name_raw = vec![0; file_name_length]; + reader.read_exact(&mut file_name_raw)?; + let mut extra_field = vec![0; extra_field_length]; + reader.read_exact(&mut extra_field)?; + + let file_name: Box = match is_utf8 { + true => String::from_utf8_lossy(&file_name_raw).into(), + false => file_name_raw.clone().from_cp437().into(), + }; + + let mut result = ZipFileData { + system: System::from((version_made_by >> 8) as u8), + version_made_by: version_made_by as u8, + encrypted, + using_data_descriptor, + compression_method, + compression_level: None, + last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), + crc32, + compressed_size: compressed_size as u64, + uncompressed_size: uncompressed_size as u64, + file_name, + file_name_raw: file_name_raw.into(), + extra_field: Some(Arc::new(extra_field)), + central_extra_field: None, + file_comment: String::with_capacity(0).into_boxed_str(), // file comment is only available in the central directory + // header_start and data start are not available, but also don't matter, since seeking is + // not available. + header_start: 0, + extra_data_start: None, + data_start: OnceLock::new(), + central_header_start: 0, + // The external_attributes field is only available in the central directory. + // We set this to zero, which should be valid as the docs state 'If input came + // from standard input, this field is set to zero.' + external_attributes: 0, + large_file: false, + aes_mode: None, + aes_extra_data_start: 0, + extra_fields: Vec::new(), + }; + + match parse_extra_field(&mut result) { + Ok(..) | Err(ZipError::Io(..)) => {} + Err(e) => return Err(e), + } + + if encrypted { + return unsupported_zip_error("Encrypted files are not supported"); + } + if using_data_descriptor { + return unsupported_zip_error("The file length is not available in the local header"); + } + + let limit_reader = (reader as &'a mut dyn Read).take(result.compressed_size); + + let result_crc32 = result.crc32; + let result_compression_method = result.compression_method; + let crypto_reader = make_crypto_reader( + result_compression_method, + result_crc32, + result.last_modified_time, + result.using_data_descriptor, + limit_reader, + None, + None, + #[cfg(feature = "aes-crypto")] + result.compressed_size, + )?; + + Ok(Some(ZipFile { + data: Cow::Owned(result), + crypto_reader: None, + reader: make_reader(result_compression_method, result_crc32, crypto_reader)?, + })) +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn make_crypto_reader<'a>( + compression_method: CompressionMethod, + crc32: u32, + last_modified_time: DateTime, + using_data_descriptor: bool, + reader: io::Take<&'a mut dyn Read>, + password: Option<&[u8]>, + aes_info: Option<(AesMode, AesVendorVersion, CompressionMethod)>, + #[cfg(feature = "aes-crypto")] compressed_size: u64, +) -> ZipResult> { + #[allow(deprecated)] + { + if let CompressionMethod::Unsupported(_) = compression_method { + return unsupported_zip_error("Compression method not supported"); + } + } + + let reader = match (password, aes_info) { + #[cfg(not(feature = "aes-crypto"))] + (Some(_), Some(_)) => { + return Err(ZipError::UnsupportedArchive( + "AES encrypted files cannot be decrypted without the aes-crypto feature.", + )) + } + #[cfg(feature = "aes-crypto")] + (Some(password), Some((aes_mode, vendor_version, _))) => CryptoReader::Aes { + reader: AesReader::new(reader, aes_mode, compressed_size).validate(password)?, + vendor_version, + }, + (Some(password), None) => { + let validator = if using_data_descriptor { + ZipCryptoValidator::InfoZipMsdosTime(last_modified_time.timepart()) + } else { + ZipCryptoValidator::PkzipCrc32(crc32) + }; + CryptoReader::ZipCrypto(ZipCryptoReader::new(reader, password).validate(validator)?) + } + (None, Some(_)) => return Err(ZipError::InvalidPassword), + (None, None) => CryptoReader::Plaintext(reader), + }; + Ok(reader) +} + +pub(crate) fn make_reader( + compression_method: CompressionMethod, + crc32: u32, + reader: CryptoReader, +) -> ZipResult { + let ae2_encrypted = reader.is_ae2_encrypted(); + + match compression_method { + CompressionMethod::Stored => Ok(ZipFileReader::Stored(Crc32Reader::new( + reader, + crc32, + ae2_encrypted, + ))), + #[cfg(feature = "_deflate-any")] + CompressionMethod::Deflated => { + let deflate_reader = DeflateDecoder::new(reader); + Ok(ZipFileReader::Deflated(Crc32Reader::new( + deflate_reader, + crc32, + ae2_encrypted, + ))) + } + #[cfg(feature = "deflate64")] + CompressionMethod::Deflate64 => { + let deflate64_reader = Deflate64Decoder::new(reader); + Ok(ZipFileReader::Deflate64(Crc32Reader::new( + deflate64_reader, + crc32, + ae2_encrypted, + ))) + } + #[cfg(feature = "bzip2")] + CompressionMethod::Bzip2 => { + let bzip2_reader = BzDecoder::new(reader); + Ok(ZipFileReader::Bzip2(Crc32Reader::new( + bzip2_reader, + crc32, + ae2_encrypted, + ))) + } + #[cfg(feature = "zstd")] + CompressionMethod::Zstd => { + let zstd_reader = ZstdDecoder::new(reader).unwrap(); + Ok(ZipFileReader::Zstd(Crc32Reader::new( + zstd_reader, + crc32, + ae2_encrypted, + ))) + } + #[cfg(feature = "lzma")] + CompressionMethod::Lzma => { + let reader = LzmaDecoder::new(reader); + Ok(ZipFileReader::Lzma(Crc32Reader::new( + Box::new(reader), + crc32, + ae2_encrypted, + ))) + } + _ => Err(ZipError::UnsupportedArchive("Compression method not supported")), + } +} + +pub(crate) struct CentralDirectoryInfo { + pub(crate) archive_offset: u64, + pub(crate) directory_start: u64, + pub(crate) number_of_files: usize, + pub(crate) disk_number: u32, + pub(crate) disk_with_central_directory: u32, +} + +impl ZipArchive { + pub(crate) fn from_finalized_writer( + files: IndexMap, ZipFileData>, + comment: Box<[u8]>, + reader: R, + central_start: u64, + ) -> ZipResult { + let initial_offset = match files.first() { + Some((_, file)) => file.header_start, + None => 0, + }; + let shared = Arc::new(zip_archive::Shared { + files, + offset: initial_offset, + dir_start: central_start, + }); + Ok(Self { + reader, + shared, + comment: comment.into(), + }) + } + + /// Total size of the files in the archive, if it can be known. Doesn't include directories or + /// metadata. + pub fn decompressed_size(&self) -> Option { + let mut total = 0u128; + for file in self.shared.files.values() { + if file.using_data_descriptor { + return None; + } + total = total.checked_add(file.uncompressed_size as u128)?; + } + Some(total) + } +} + +const fn unsupported_zip_error(detail: &'static str) -> ZipResult { + Err(ZipError::UnsupportedArchive(detail)) +} + +/// Methods for retrieving information on zip files +impl<'a> ZipFile<'a> { + fn get_reader(&mut self) -> ZipResult<&mut ZipFileReader<'a>> { + if let ZipFileReader::NoReader = self.reader { + let data = &self.data; + let crypto_reader = self.crypto_reader.take().expect("Invalid reader state"); + self.reader = make_reader(data.compression_method, data.crc32, crypto_reader)?; + } + Ok(&mut self.reader) + } + + pub(crate) fn get_raw_reader(&mut self) -> &mut dyn Read { + if let ZipFileReader::NoReader = self.reader { + let crypto_reader = self.crypto_reader.take().expect("Invalid reader state"); + self.reader = ZipFileReader::Raw(crypto_reader.into_inner()) + } + &mut self.reader + } + + /// Get the version of the file + pub fn version_made_by(&self) -> (u8, u8) { + ( + self.data.version_made_by / 10, + self.data.version_made_by % 10, + ) + } + + /// Get the name of the file + /// + /// # Warnings + /// + /// It is dangerous to use this name directly when extracting an archive. + /// It may contain an absolute path (`/etc/shadow`), or break out of the + /// current directory (`../runtime`). Carelessly writing to these paths + /// allows an attacker to craft a ZIP archive that will overwrite critical + /// files. + /// + /// You can use the [`ZipFile::enclosed_name`] method to validate the name + /// as a safe path. + pub fn name(&self) -> &str { + &self.data.file_name + } + + /// Get the name of the file, in the raw (internal) byte representation. + /// + /// The encoding of this data is currently undefined. + pub fn name_raw(&self) -> &[u8] { + &self.data.file_name_raw + } + + /// Get the name of the file in a sanitized form. It truncates the name to the first NULL byte, + /// removes a leading '/' and removes '..' parts. + #[deprecated( + since = "0.5.7", + note = "by stripping `..`s from the path, the meaning of paths can change. + `mangled_name` can be used if this behaviour is desirable" + )] + pub fn sanitized_name(&self) -> PathBuf { + self.mangled_name() + } + + /// Rewrite the path, ignoring any path components with special meaning. + /// + /// - Absolute paths are made relative + /// - [`ParentDir`]s are ignored + /// - Truncates the filename at a NULL byte + /// + /// This is appropriate if you need to be able to extract *something* from + /// any archive, but will easily misrepresent trivial paths like + /// `foo/../bar` as `foo/bar` (instead of `bar`). Because of this, + /// [`ZipFile::enclosed_name`] is the better option in most scenarios. + /// + /// [`ParentDir`]: `Component::ParentDir` + pub fn mangled_name(&self) -> PathBuf { + self.data.file_name_sanitized() + } + + /// Ensure the file path is safe to use as a [`Path`]. + /// + /// - It can't contain NULL bytes + /// - It can't resolve to a path outside the current directory + /// > `foo/../bar` is fine, `foo/../../bar` is not. + /// - It can't be an absolute path + /// + /// This will read well-formed ZIP files correctly, and is resistant + /// to path-based exploits. It is recommended over + /// [`ZipFile::mangled_name`]. + pub fn enclosed_name(&self) -> Option { + self.data.enclosed_name() + } + + /// Get the comment of the file + pub fn comment(&self) -> &str { + &self.data.file_comment + } + + /// Get the compression method used to store the file + pub fn compression(&self) -> CompressionMethod { + self.data.compression_method + } + + /// Get the size of the file, in bytes, in the archive + pub fn compressed_size(&self) -> u64 { + self.data.compressed_size + } + + /// Get the size of the file, in bytes, when uncompressed + pub fn size(&self) -> u64 { + self.data.uncompressed_size + } + + /// Get the time the file was last modified + pub fn last_modified(&self) -> DateTime { + self.data.last_modified_time + } + /// Returns whether the file is actually a directory + pub fn is_dir(&self) -> bool { + self.name() + .chars() + .next_back() + .map_or(false, |c| c == '/' || c == '\\') + } + + /// Returns whether the file is a regular file + pub fn is_file(&self) -> bool { + !self.is_dir() + } + + /// Get unix mode for the file + pub fn unix_mode(&self) -> Option { + self.data.unix_mode() + } + + /// Get the CRC32 hash of the original file + pub fn crc32(&self) -> u32 { + self.data.crc32 + } + + /// Get the extra data of the zip header for this file + pub fn extra_data(&self) -> Option<&[u8]> { + self.data.extra_field.as_ref().map(|v| v.deref().deref()) + } + + /// Get the starting offset of the data of the compressed file + pub fn data_start(&self) -> u64 { + *self.data.data_start.get().unwrap_or(&0) + } + + /// Get the starting offset of the zip header for this file + pub fn header_start(&self) -> u64 { + self.data.header_start + } + /// Get the starting offset of the zip header in the central directory for this file + pub fn central_header_start(&self) -> u64 { + self.data.central_header_start + } + + /// iterate through all extra fields + pub fn extra_data_fields(&self) -> impl Iterator { + self.data.extra_fields.iter() + } +} + +impl<'a> Read for ZipFile<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_reader()?.read(buf) + } +} + +impl<'a> Drop for ZipFile<'a> { + fn drop(&mut self) { + // self.data is Owned, this reader is constructed by a streaming reader. + // In this case, we want to exhaust the reader so that the next file is accessible. + if let Cow::Owned(_) = self.data { + // Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped. + match &mut self.reader { + ZipFileReader::NoReader => { + let innerreader = self.crypto_reader.take(); + let _ = copy( + &mut innerreader.expect("Invalid reader state").into_inner(), + &mut sink(), + ); + } + reader => { + let innerreader = std::mem::replace(reader, ZipFileReader::NoReader); + innerreader.drain(); + } + }; + } + } +} diff --git a/src/write.rs b/src/write.rs index e56aff025..e79c62cfd 100644 --- a/src/write.rs +++ b/src/write.rs @@ -3,7 +3,7 @@ #[cfg(feature = "aes-crypto")] use crate::aes::AesWriter; use crate::compression::CompressionMethod; -use crate::read::{find_content, ZipArchive, ZipFile, ZipFileReader}; +use crate::read::{sync::find_content, ZipArchive, ZipFile, ZipFileReader}; use crate::result::{ZipError, ZipResult}; use crate::spec; #[cfg(feature = "aes-crypto")] From 62788e213bf3f0f863408d6011cfb24b6d3338be Mon Sep 17 00:00:00 2001 From: Shun Sakai Date: Sat, 18 May 2024 09:42:23 +0900 Subject: [PATCH 07/17] docs: Add `package.metadata.docs.rs` This is to enable `doc_auto_cfg` feature with Docs.rs. --- Cargo.toml | 17 +++++++++++++++++ src/lib.rs | 1 + 2 files changed, 18 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 0e85fef24..b656d8230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,23 @@ edition = "2021" exclude = ["tests/**", "examples/**", ".github/**", "fuzz/**"] build = "src/build.rs" +[package.metadata.docs.rs] +features = [ + "aes-crypto", + "bzip2", + "chrono", + "deflate", + "deflate64", + "deflate-zlib-ng", + "lzma", + "time", + "zstd", +] +# Can be enabled when is fixed +# all-features = true +no-default-features = true +rustdoc-args = ["--cfg", "docsrs"] + [workspace.dependencies] time = { version = "0.3.36", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 35ffcaa68..f6fbb89f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ //! | ZipCrypto deprecated encryption | ✅ | ✅ | //! //! +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs)] #![allow(unexpected_cfgs)] // Needed for cfg(fuzzing) on nightly as of 2024-05-06 pub use crate::compression::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS}; From 933ccc4f92b79ecc8c8a26fa1a62769c9134f189 Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Fri, 17 May 2024 18:55:22 -0700 Subject: [PATCH 08/17] Enable deflate-zlib as well, and keep deflate64 separate deflate-zlib was an omission; deflate64 is a different, backward-incompatible algorithm. Signed-off-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index b656d8230..311b10634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,8 @@ features = [ "chrono", "deflate", "deflate64", + "deflate", + "deflate-zlib", "deflate-zlib-ng", "lzma", "time", From 57eaa50e354619c31a24bc50cc61e67f44eae127 Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Fri, 17 May 2024 22:39:01 -0700 Subject: [PATCH 09/17] ci(fuzz): Update seed corpora --- .../019c8bfcf6e2a0f39504d02bc7c8bb34812e4887 | Bin 0 -> 232 bytes ... 06f31fb623538066764dd8e746764877796eea48} | Bin 1261 -> 1261 bytes .../0a58f7ee2ab822e077de7f018cdb03e16c28d960 | Bin 0 -> 403 bytes .../0e3e457faab9969ec629c52f9cd4982c5140a027 | Bin 0 -> 461 bytes .../110f5cbf787fbba053e81394af110604b2b4dcff | Bin 967 -> 0 bytes .../1131a07f6681078e9ecfd3fbf8f23401951b57ea | Bin 0 -> 1291 bytes .../116a56cfaba358c33ba5752206654a0e78fe1dce | Bin 0 -> 460 bytes .../159aaa6f8f7bcad7dccd2400a36cbe31c786c4e1 | Bin 0 -> 1210 bytes .../34a0aa51dd90905f218fb626ddd5521d6e9641a6 | Bin 0 -> 1275 bytes .../3f26e1e17a91ba019a42711f950ac148497ab19c | Bin 3862 -> 0 bytes .../41f2b36a77af07c2ce1eaa9da39561200f1ae850 | Bin 0 -> 1300 bytes .../42924eb4ba0ace9ef2b2bfd94c90a656f91bb3a8 | Bin 0 -> 107 bytes .../430b7455adafc907f672910c4bcd1028232a1e53 | Bin 0 -> 614 bytes .../47783f3a01ca82718d8a6c66221399cdeaf1c30f | Bin 1449 -> 0 bytes ... 49ebb9bdd61e500c6eff877486d34607819d1f85} | Bin 562 -> 562 bytes .../55be0351b7bef24421f2fa6768521dfd8e15719c | Bin 0 -> 562 bytes .../5ba9fa14f3f0f86f4b22ac255f0ae813e948f28c | Bin 604 -> 0 bytes .../6a6c4f710b70b26c94a88efa28a4e33db6bad937 | Bin 0 -> 305 bytes .../6b9e2302f5b83fad82a7695a7ed83882ec060476 | Bin 0 -> 107 bytes .../6e15b9f9c7b0dd5df30a211abf5cba8545c95cee | Bin 0 -> 562 bytes .../7f19933f263fa3944b254f8caea77f22294145e4 | Bin 1213 -> 0 bytes .../8021bf5230ec2fd27f145b7e460216dd362329d4 | Bin 0 -> 367 bytes .../8051fabc50844c730df40c46d0f0b6363a408034 | Bin 162 -> 0 bytes .../8192c940f4dfc3fbda7467808afe2944b308d488 | Bin 0 -> 1183 bytes .../8afe4d1bad2d3cbf8c1b41508849eb44f4873cd6 | Bin 0 -> 139 bytes .../8b8354a90039c69337f79234c25484b1440153dd | Bin 0 -> 1290 bytes .../98152f7f7623d746f780399c64fe55a0b803923a | Bin 0 -> 1278 bytes .../9c478f8a10294eef29fac8ff86d9fdf539f3d824 | Bin 0 -> 706 bytes .../a6ee2d3f4e9966428ccb0c674acee81ad691c80e | Bin 107 -> 0 bytes .../a810ee160e91b465c236afdea2f79b5bcb829be0 | Bin 0 -> 156 bytes .../b400e1bcd82491191d6e4d677437fa1e4632d21f | Bin 0 -> 242 bytes .../b7fd7ee9eb40b280e2fa8f78a39b4989aee9e073 | Bin 0 -> 640 bytes .../ba02b67868bcf9583f797d42fe25744db526dc87 | Bin 562 -> 0 bytes .../c0cafdba839eedc796e119ff82ad100d3e1abc4a | Bin 0 -> 806 bytes .../c1409732af8289277a5a21075f6d4a26188ab8db | Bin 1886 -> 0 bytes .../c30fa0680cd367c0a6d999a8829a3e76be42fca2 | Bin 0 -> 1250 bytes .../cc1d23b6e796a3ab7346cbf19a3e9e5050e88a9b | Bin 0 -> 562 bytes .../d3ce2736a9f125c8ba2340992a38a4f4d92a2564 | Bin 0 -> 1287 bytes .../d438bd6a0c51f77c005c5b888ef2e07430a4b701 | Bin 0 -> 1261 bytes .../da37ea434d5ed679551951af7f16c05f64828864 | Bin 0 -> 149 bytes .../dac4aa320536c9d1e783925f91171c389ddcde94 | Bin 3710 -> 0 bytes .../fb3c0f45a986ca65f2f56e9284f77866bc4e93eb | Bin 0 -> 250 bytes .../040b549640f6aef57b0c3ff7f3f5ecab3b313cb5 | Bin 0 -> 445 bytes .../04c4997b51cae7239a72715281bd99feb349c647 | Bin 0 -> 379 bytes .../065b3abb5108d0195dea24d37eeedf67dfb6a381 | Bin 0 -> 355 bytes .../067d07028d75abc58527d9d0afb360e6291bde37 | Bin 0 -> 440 bytes .../0789d72c17a5b84d298170d693367a0be7a2f0fc | Bin 0 -> 332 bytes .../08220b2a54482ffc228446b9ee448c8943f6783e | Bin 448 -> 0 bytes .../0eabde1680227e799be7bb7df9b7c59037714be3 | Bin 390 -> 0 bytes .../0f499182bc99844fef7c8437a1c32b9fd0915a02 | Bin 0 -> 316 bytes .../1830711dbd2791fef483f6edc47a291549b26fcd | Bin 0 -> 336 bytes .../1954077934afbf7d6b9a061c1515b24c7109551e | Bin 0 -> 388 bytes .../1d389e4c93af1687abbb0d3f206b58db6104fc02 | Bin 0 -> 438 bytes .../1d48838eb5245c2f87594c679bad8d18f030c07f | Bin 0 -> 438 bytes .../1dae961448e74c73567e686dfacec88c1df4cb90 | Bin 375 -> 0 bytes .../1fba93f6fc7311d6b7eb7a9963380c8eda88475b | Bin 0 -> 113 bytes .../200a4b89561b39dc48ff2e0a61cfc809332cb1d0 | Bin 0 -> 442 bytes .../209fa8fe4b42baf5e34887aeb0edf94688cc63dd | Bin 0 -> 415 bytes .../233bfc53a9120ead9996acb36e8942bff74e1492 | Bin 0 -> 442 bytes .../258030bcd10032e492e6e4d8b0bce78a19fd464b | Bin 0 -> 445 bytes .../29018a952fcbfd963ae4af36033ff0409296ac6c | Bin 428 -> 0 bytes .../2a5a999e20c2504bef2ed192cd4ae1458a3ce1a8 | Bin 0 -> 437 bytes .../2deaf0291a879a99e066566f0d77e709ce02b480 | Bin 0 -> 170 bytes .../2e0e8bc4c8adc01e935495d85c74864382ce7e19 | Bin 0 -> 444 bytes .../2e522bba59dc10b8c333861e03b4a4a679f41c9f | Bin 0 -> 431 bytes .../336e95e761bf4eb53e37ace38ac2ba4a699fd5e9 | Bin 0 -> 442 bytes .../33ca792e4b3380c5e63fa77ca72001899c0dde44 | Bin 0 -> 432 bytes .../3494830f936515d2dfa5fd22da65fbfeaed02a82 | Bin 0 -> 405 bytes .../3572a9845b65d2a06ef4e8497c0f7a334226b5f2 | Bin 0 -> 398 bytes .../3583774a805e9874c77d712a3383c9826b47c960 | Bin 189 -> 0 bytes .../382817cbec4bd6d7b7a3bb59d289f718c89f0392 | Bin 0 -> 328 bytes .../396789d05dc588d88d7317766a263c5ed76b34d7 | Bin 0 -> 276 bytes .../39f7a2608f4927b9db04dee0bdbe0b539d1d758d | Bin 0 -> 408 bytes .../3cf84b84d303b12325b4cac0bbfc709064562a62 | Bin 0 -> 333 bytes ... 3d73c62d2a2d6b00c475864ddf2393dfaa27f10b} | Bin 444 -> 444 bytes .../3e6c5e8891fb286b53372b586143b99fbe109a9e | Bin 0 -> 187 bytes .../40304037be01aa178c1d117b74b9ef8acd18fcd9 | Bin 0 -> 211 bytes .../4350b0a6acb951a53ea443960795b79fa2e78642 | Bin 0 -> 440 bytes .../457f626c9723d1654d4eb4d1ad74da5cca22ca41 | Bin 0 -> 439 bytes .../475029a9a19107fccd990135f242fb5d6f61a5e8 | Bin 0 -> 420 bytes .../4773386289158d62fc0d85b54244812e91881c8e | Bin 422 -> 0 bytes .../480dcfec5d4e3cefea3e939f6759e06a1b019928 | Bin 0 -> 389 bytes .../488c33d51947a56294be41a4bdf94d17002c454c | Bin 0 -> 319 bytes .../4921220f9a2ce55611e2824cd3c39aa511dfb8e5 | Bin 0 -> 410 bytes .../49a5fac1ae49328b289712912fea13156435ffb2 | Bin 426 -> 0 bytes .../4ab9580bd35308f744503b46b94ee286eb61f6f2 | Bin 0 -> 413 bytes .../4b68f36fe04ecea312a4f0f9c02f13996c0ff010 | Bin 0 -> 411 bytes .../4d0b6106b569cfed448f1ab7605aed415ac9efee | Bin 0 -> 132 bytes .../4eee2a214afba54fadbe9a082d1989dcfa7d5aa4 | Bin 0 -> 372 bytes .../507390266b77f0dde2fbd6e9844132933554a73c | Bin 0 -> 333 bytes .../508d587b573d080de181e71891a6698c17e1e311 | Bin 0 -> 421 bytes .../512334645b1554d07770e79f1ef8c898e81d1e7b | Bin 439 -> 0 bytes .../519d6ce2de488d89ff4792448f5920f58f0d6c60 | Bin 0 -> 440 bytes .../566bc9dc31b53c07da8d87097b035946f0feea76 | Bin 0 -> 442 bytes .../5704d0aa9ab65f2ee1bdb962f1ef5163352c125f | Bin 0 -> 438 bytes .../57ac44c923f4ef9c3e80063d9646d99e44b9038c | Bin 438 -> 0 bytes .../5bdf13800c37ed54085bef8134d1d7c50351a5b8 | Bin 402 -> 0 bytes .../61427d5b5cabf0278b7ff6d978968524ad518a0a | Bin 0 -> 438 bytes .../625bf9ab1cb07c9f5a67134e8c56cf7ff1e9e305 | Bin 0 -> 430 bytes .../64924d68b5a4aec348d9ed51b3cd6319c60a7c13 | Bin 0 -> 364 bytes .../64f2f96cee1fd79e154c0bf63f64028d1b3df034 | Bin 335 -> 0 bytes .../65717e0373facba79a96d34aa40c00ca21ca5602 | Bin 404 -> 0 bytes .../664b03092b93cd24eaa371db0baf086865e53568 | Bin 0 -> 409 bytes .../67d75719928b600d7cb621fa2dd34fd03a74ebae | Bin 0 -> 427 bytes .../687de92fd3dc455ed84a9cc07b8edde555b4bf54 | Bin 0 -> 442 bytes .../689959e4b3e4abbc13eb79fcdc786e58ad3bfa9e | Bin 0 -> 430 bytes .../696ed4fc3c919221ccc3211c9b522a7bcce976f1 | Bin 437 -> 0 bytes .../6af85b878b99229a6de4e1a2efe66ded214f5f6c | Bin 0 -> 264 bytes .../6b17b0a4af43b0f9f3d1a7185b558d93e168751c | Bin 0 -> 265 bytes .../6c08c1bf7b525451bf5ca7cbd01f5f4d0c94c6e1 | Bin 414 -> 0 bytes .../6d68e0560db48c549775bb2f698aa8b69a0f29ca | Bin 0 -> 412 bytes .../6d8b5ca436ed188f6f9afbc2205ed2d12ab7d2bd | Bin 0 -> 397 bytes .../6da4e6f8a01957eab1a1e2c9d94e4f5b3bf90277 | Bin 0 -> 146 bytes .../72489e3c88ecf6ea12a547034129df1dc71f4697 | Bin 351 -> 0 bytes .../72c49dbc3ceefe03a073f95fdd90075efef449ec | Bin 440 -> 0 bytes .../72ecd095908cbd7a6cdfa5bacd8d3a234aeb7e63 | Bin 346 -> 0 bytes .../75ec38ff4ae8129531a0438043414e63a13c3af7 | Bin 0 -> 440 bytes .../774faccd7bcf5a5802265c6be4275e74500fb4ac | Bin 0 -> 403 bytes .../78814c51503fb35809cc9191f4a5974bab541cbf | Bin 0 -> 434 bytes .../79b1a1b8e88f91771d4709f6e4865892b450de57 | Bin 385 -> 0 bytes .../7a8dc6a199b3d007a0fb72942895f0de926f82fe | Bin 0 -> 426 bytes .../7bd45db8423c9a4596bc6e01a7e408685b1648dc | Bin 427 -> 0 bytes .../7d4ddcfa4373f45d478efc874701703ddb39e9b0 | Bin 0 -> 434 bytes .../7dcff5bcb3d43356e94c4749911277b2917697fa | Bin 434 -> 0 bytes .../7e380a13d82a8ecc2677f426a96e51534d151604 | Bin 242 -> 0 bytes .../801f748efb447c4b9309bdf948f9f1e144ab7699 | Bin 433 -> 0 bytes .../81ccbd9be9ec79eec24dfa5338054c540c074cac | Bin 228 -> 0 bytes .../84b8d3d91b987e994fc85511d4a1920289e7984c | Bin 0 -> 233 bytes .../852aa22fd53f7075a7104b632a550b3681ff169a | Bin 0 -> 297 bytes .../8593052cc5f8976bf7cb53c4a0c24a7d1ada8a82 | Bin 436 -> 0 bytes .../864dd3cc7af635312484dfa337ecde1b8dbdf140 | Bin 0 -> 368 bytes .../8788c779c1947e0c78dbac2f0ad99e29681f94f7 | Bin 0 -> 391 bytes .../89a2a78b04bc79d938bfc392c45dea3a46e154bc | Bin 0 -> 371 bytes .../8aba822423e4ecb85ec9504fb44054ff118c93b9 | Bin 326 -> 0 bytes .../8d95303e29184c21dba2ee4e69884af3fe719b5e | Bin 0 -> 159 bytes .../8de15ff4d95b571161d18ad963620c65fbcb7757 | Bin 0 -> 440 bytes .../8ded3b724e4e17a8af5377de0754827c0d8a0a3e | Bin 0 -> 432 bytes .../90f4914db71c3352c878a7fb1c44a03113f55435 | Bin 354 -> 0 bytes .../920260d144dc94ad444398b567e964d73ca44f9e | Bin 0 -> 173 bytes .../944a346ae52a03c1a7337fc7c87a2f8e4742850b | Bin 0 -> 352 bytes .../95cf7289af99052df43f3b65737cb75884c5e10a | Bin 0 -> 441 bytes .../9aeb063c60a9860fc30780f871e6fd340dd7403a | Bin 0 -> 433 bytes .../9c59e64c8b489629da8aa131095c26696bdd3b71 | Bin 0 -> 435 bytes .../9c8ac134fdad1e73bf0646a81267389b7f963bde | Bin 0 -> 410 bytes .../9ca0c8e90ecee4ce923643c7a233ea9991d68a62 | Bin 0 -> 356 bytes .../9debde139dae690926fe0d8f5bcf013b51632cbe | Bin 0 -> 442 bytes .../a023124e84e2c31591ee38699829921ce8e09efa | Bin 0 -> 435 bytes .../a052dd5a3c1ada13f3f719607d134514e07963cd | Bin 0 -> 335 bytes .../a2f6302a9961c10e49ae3aaffd7335944c0217de | Bin 433 -> 0 bytes .../a316dd19918f60e9ae843585291f340a19f511fe | Bin 0 -> 349 bytes .../a833a7d49c837dc03e3c18de09079c9a2a08b36f | Bin 27 -> 0 bytes .../a8dbb85833b64d3aaf42667e3a8c66c544b095da | Bin 0 -> 402 bytes .../aa0f203c1e6d73f6d2c1931428f3a50d3d3159e0 | Bin 0 -> 441 bytes .../ab6594c50a0e471097af9bf9e9d643a8de283c5f | Bin 0 -> 442 bytes .../abc9e1c96fb12ac4dbae5fa4e08aeb96165a2d02 | Bin 0 -> 358 bytes .../abf9761554b820aef4e462e637b638b69f2274c0 | Bin 0 -> 253 bytes .../ad0eb1bb73c7ff273db0b419b0327da14bea51fb | Bin 424 -> 0 bytes .../ad1e139f66b779fd5611bdb59a4ad156fbef1376 | Bin 445 -> 0 bytes .../adf3b89038d3b77ddaf522658fbdae1f05d7e9fb | Bin 421 -> 0 bytes .../af85b5d04bd588f74b042bcf1839f375899b8114 | Bin 0 -> 336 bytes .../b177214021fdefd17b383027374ac65000d24e48 | Bin 0 -> 310 bytes .../b1bcbe30df5281ae9cccc6cce5167b60383c879f | Bin 0 -> 442 bytes .../b1d9618a19742259c2ed6c965b7ab2279e3806ca | Bin 381 -> 0 bytes .../b1f781c0001bbd9778cd6e400ff573374ce533ea | Bin 432 -> 0 bytes ... b234aaff4d312a8999de3187bdff55634ba50c8c} | Bin 441 -> 442 bytes .../b2699886f15b1ca72455b54ff9b37a237da8a252 | Bin 0 -> 278 bytes .../bc9f059f0b393f6f23d6cd6328040227672fbe7e | Bin 384 -> 0 bytes .../bd3684f924c0b9542976f6777df2a15635af33b4 | Bin 0 -> 222 bytes .../bece4e44d6614eb0c55f0cf0f54297acf0c65d57 | Bin 440 -> 0 bytes .../bf41768e88fd266b1da7f161c89fa0f20aee50e9 | Bin 0 -> 444 bytes .../bff13adbdbe7c9f1ea19b46189f248dc316fed24 | Bin 0 -> 346 bytes .../c3768fca74ca772409996955fdbfd46cff0f1a8d | Bin 0 -> 446 bytes .../c5c4cde83788cbf0faf4c51a97d5630d020c5c8c | Bin 0 -> 370 bytes .../c913368cf938e068235361e53b27a6000091fb92 | Bin 0 -> 436 bytes .../c9d5d7dca894e05c162a051102ff94ea13c50a68 | Bin 0 -> 343 bytes .../c9f8004bea284b80bcb6cdd0606143c9a1b94249 | Bin 0 -> 356 bytes .../cae18387976cbfc33bab8044aec293bb1c9b3af8 | Bin 0 -> 323 bytes .../cb4835d663b53e2de71e763582a3357db5153f5b | Bin 0 -> 229 bytes .../cbdd4dfb0f101f3e64c3663118dac8cbafc93a9a | Bin 0 -> 403 bytes .../d2a173fbde746a342fd1a07736139db9d0146ceb | Bin 370 -> 0 bytes .../d3604f81acaf02502ee56b8103821957ec174ce3 | Bin 393 -> 0 bytes .../d5447d8592e341356c89798dd92f8dfbd626fa01 | Bin 253 -> 0 bytes .../d731e1be1d3defd0890f3c2a73e3d1d07eebd09e | Bin 0 -> 443 bytes .../d7653af0f02828fc6cbb0076e6e6d30db04b77a6 | Bin 0 -> 445 bytes .../d82f622f75f6eaa7b6ed72d085b1a4d9f6d61352 | Bin 0 -> 49 bytes .../d8cde1a5581abb06cfa6ea8fb6d2f7dd2dd898a7 | Bin 0 -> 429 bytes .../d94cdff1089a532beb5e59d88e6807c900428145 | Bin 417 -> 0 bytes .../d9e285568d2107f497d162ed577d5d4965d4416b | Bin 0 -> 425 bytes .../db315b3070a2af366e603d699085ac4846164b19 | Bin 441 -> 0 bytes .../de4e1a1e9f38bb876a32a2c53a00334a11148767 | Bin 0 -> 400 bytes .../dec24e99a6f38848838a513c0fec97ea592720a3 | Bin 0 -> 438 bytes .../dedd117472b5d4ec3eecde02de58b200cdf1f10f | Bin 0 -> 284 bytes .../e1e4cbe538b48c6f143e71bd990dfa730426d778 | Bin 0 -> 444 bytes .../e429f9c46f499f3c5905ffec51d4a132b2b6a25a | Bin 0 -> 441 bytes .../e441ebc04d6e74502b9fabeb2da0f3062b070248 | Bin 349 -> 0 bytes ... eb4de99d8d69a81fa28d98c8ae90e1552735a9ac} | Bin 338 -> 338 bytes .../f0244605b8de13c7ad906efb6ba66003e781b064 | Bin 0 -> 340 bytes .../f1d8650747a9904b6f613e8bbc1b8abf4f0de273 | Bin 0 -> 413 bytes .../f2c2351d9b5c7fc9b43e721975d1116be978d28a | Bin 0 -> 335 bytes ... f371ba5b4bdd6f2ed41a3ba149df83cfc0ed03ea} | Bin 438 -> 438 bytes .../f6f1ba104c1def2c2bbea7aca98e57860f8dfa15 | Bin 0 -> 314 bytes .../f78deb113d772b7884b167fd2a4ee6076116db92 | Bin 0 -> 341 bytes .../fb06e9ed4a8e9580db46f444e44e63e6018eefc4 | Bin 0 -> 445 bytes .../fb4e17df269f29003cc66731a7d9d71c704ba599 | Bin 0 -> 438 bytes .../fcda8512ce8f678cdbb10d685bd4c0c529dd2f06 | Bin 0 -> 444 bytes 205 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 fuzz/corpus/fuzz_read/019c8bfcf6e2a0f39504d02bc7c8bb34812e4887 rename fuzz/corpus/fuzz_read/{370651fc79b3e4782de1002358f618238b875d08 => 06f31fb623538066764dd8e746764877796eea48} (89%) create mode 100644 fuzz/corpus/fuzz_read/0a58f7ee2ab822e077de7f018cdb03e16c28d960 create mode 100644 fuzz/corpus/fuzz_read/0e3e457faab9969ec629c52f9cd4982c5140a027 delete mode 100644 fuzz/corpus/fuzz_read/110f5cbf787fbba053e81394af110604b2b4dcff create mode 100644 fuzz/corpus/fuzz_read/1131a07f6681078e9ecfd3fbf8f23401951b57ea create mode 100644 fuzz/corpus/fuzz_read/116a56cfaba358c33ba5752206654a0e78fe1dce create mode 100644 fuzz/corpus/fuzz_read/159aaa6f8f7bcad7dccd2400a36cbe31c786c4e1 create mode 100644 fuzz/corpus/fuzz_read/34a0aa51dd90905f218fb626ddd5521d6e9641a6 delete mode 100644 fuzz/corpus/fuzz_read/3f26e1e17a91ba019a42711f950ac148497ab19c create mode 100644 fuzz/corpus/fuzz_read/41f2b36a77af07c2ce1eaa9da39561200f1ae850 create mode 100644 fuzz/corpus/fuzz_read/42924eb4ba0ace9ef2b2bfd94c90a656f91bb3a8 create mode 100644 fuzz/corpus/fuzz_read/430b7455adafc907f672910c4bcd1028232a1e53 delete mode 100644 fuzz/corpus/fuzz_read/47783f3a01ca82718d8a6c66221399cdeaf1c30f rename fuzz/corpus/fuzz_read/{cf9ffcefefec9fbb2c0e50629a1a36c882a4784a => 49ebb9bdd61e500c6eff877486d34607819d1f85} (79%) create mode 100644 fuzz/corpus/fuzz_read/55be0351b7bef24421f2fa6768521dfd8e15719c delete mode 100644 fuzz/corpus/fuzz_read/5ba9fa14f3f0f86f4b22ac255f0ae813e948f28c create mode 100644 fuzz/corpus/fuzz_read/6a6c4f710b70b26c94a88efa28a4e33db6bad937 create mode 100644 fuzz/corpus/fuzz_read/6b9e2302f5b83fad82a7695a7ed83882ec060476 create mode 100644 fuzz/corpus/fuzz_read/6e15b9f9c7b0dd5df30a211abf5cba8545c95cee delete mode 100644 fuzz/corpus/fuzz_read/7f19933f263fa3944b254f8caea77f22294145e4 create mode 100644 fuzz/corpus/fuzz_read/8021bf5230ec2fd27f145b7e460216dd362329d4 delete mode 100644 fuzz/corpus/fuzz_read/8051fabc50844c730df40c46d0f0b6363a408034 create mode 100644 fuzz/corpus/fuzz_read/8192c940f4dfc3fbda7467808afe2944b308d488 create mode 100644 fuzz/corpus/fuzz_read/8afe4d1bad2d3cbf8c1b41508849eb44f4873cd6 create mode 100644 fuzz/corpus/fuzz_read/8b8354a90039c69337f79234c25484b1440153dd create mode 100644 fuzz/corpus/fuzz_read/98152f7f7623d746f780399c64fe55a0b803923a create mode 100644 fuzz/corpus/fuzz_read/9c478f8a10294eef29fac8ff86d9fdf539f3d824 delete mode 100644 fuzz/corpus/fuzz_read/a6ee2d3f4e9966428ccb0c674acee81ad691c80e create mode 100644 fuzz/corpus/fuzz_read/a810ee160e91b465c236afdea2f79b5bcb829be0 create mode 100644 fuzz/corpus/fuzz_read/b400e1bcd82491191d6e4d677437fa1e4632d21f create mode 100644 fuzz/corpus/fuzz_read/b7fd7ee9eb40b280e2fa8f78a39b4989aee9e073 delete mode 100644 fuzz/corpus/fuzz_read/ba02b67868bcf9583f797d42fe25744db526dc87 create mode 100644 fuzz/corpus/fuzz_read/c0cafdba839eedc796e119ff82ad100d3e1abc4a delete mode 100644 fuzz/corpus/fuzz_read/c1409732af8289277a5a21075f6d4a26188ab8db create mode 100644 fuzz/corpus/fuzz_read/c30fa0680cd367c0a6d999a8829a3e76be42fca2 create mode 100644 fuzz/corpus/fuzz_read/cc1d23b6e796a3ab7346cbf19a3e9e5050e88a9b create mode 100644 fuzz/corpus/fuzz_read/d3ce2736a9f125c8ba2340992a38a4f4d92a2564 create mode 100644 fuzz/corpus/fuzz_read/d438bd6a0c51f77c005c5b888ef2e07430a4b701 create mode 100644 fuzz/corpus/fuzz_read/da37ea434d5ed679551951af7f16c05f64828864 delete mode 100644 fuzz/corpus/fuzz_read/dac4aa320536c9d1e783925f91171c389ddcde94 create mode 100644 fuzz/corpus/fuzz_read/fb3c0f45a986ca65f2f56e9284f77866bc4e93eb create mode 100644 fuzz/corpus/fuzz_write/040b549640f6aef57b0c3ff7f3f5ecab3b313cb5 create mode 100644 fuzz/corpus/fuzz_write/04c4997b51cae7239a72715281bd99feb349c647 create mode 100644 fuzz/corpus/fuzz_write/065b3abb5108d0195dea24d37eeedf67dfb6a381 create mode 100644 fuzz/corpus/fuzz_write/067d07028d75abc58527d9d0afb360e6291bde37 create mode 100644 fuzz/corpus/fuzz_write/0789d72c17a5b84d298170d693367a0be7a2f0fc delete mode 100644 fuzz/corpus/fuzz_write/08220b2a54482ffc228446b9ee448c8943f6783e delete mode 100644 fuzz/corpus/fuzz_write/0eabde1680227e799be7bb7df9b7c59037714be3 create mode 100644 fuzz/corpus/fuzz_write/0f499182bc99844fef7c8437a1c32b9fd0915a02 create mode 100644 fuzz/corpus/fuzz_write/1830711dbd2791fef483f6edc47a291549b26fcd create mode 100644 fuzz/corpus/fuzz_write/1954077934afbf7d6b9a061c1515b24c7109551e create mode 100644 fuzz/corpus/fuzz_write/1d389e4c93af1687abbb0d3f206b58db6104fc02 create mode 100644 fuzz/corpus/fuzz_write/1d48838eb5245c2f87594c679bad8d18f030c07f delete mode 100644 fuzz/corpus/fuzz_write/1dae961448e74c73567e686dfacec88c1df4cb90 create mode 100644 fuzz/corpus/fuzz_write/1fba93f6fc7311d6b7eb7a9963380c8eda88475b create mode 100644 fuzz/corpus/fuzz_write/200a4b89561b39dc48ff2e0a61cfc809332cb1d0 create mode 100644 fuzz/corpus/fuzz_write/209fa8fe4b42baf5e34887aeb0edf94688cc63dd create mode 100644 fuzz/corpus/fuzz_write/233bfc53a9120ead9996acb36e8942bff74e1492 create mode 100644 fuzz/corpus/fuzz_write/258030bcd10032e492e6e4d8b0bce78a19fd464b delete mode 100644 fuzz/corpus/fuzz_write/29018a952fcbfd963ae4af36033ff0409296ac6c create mode 100644 fuzz/corpus/fuzz_write/2a5a999e20c2504bef2ed192cd4ae1458a3ce1a8 create mode 100644 fuzz/corpus/fuzz_write/2deaf0291a879a99e066566f0d77e709ce02b480 create mode 100644 fuzz/corpus/fuzz_write/2e0e8bc4c8adc01e935495d85c74864382ce7e19 create mode 100644 fuzz/corpus/fuzz_write/2e522bba59dc10b8c333861e03b4a4a679f41c9f create mode 100644 fuzz/corpus/fuzz_write/336e95e761bf4eb53e37ace38ac2ba4a699fd5e9 create mode 100644 fuzz/corpus/fuzz_write/33ca792e4b3380c5e63fa77ca72001899c0dde44 create mode 100644 fuzz/corpus/fuzz_write/3494830f936515d2dfa5fd22da65fbfeaed02a82 create mode 100644 fuzz/corpus/fuzz_write/3572a9845b65d2a06ef4e8497c0f7a334226b5f2 delete mode 100644 fuzz/corpus/fuzz_write/3583774a805e9874c77d712a3383c9826b47c960 create mode 100644 fuzz/corpus/fuzz_write/382817cbec4bd6d7b7a3bb59d289f718c89f0392 create mode 100644 fuzz/corpus/fuzz_write/396789d05dc588d88d7317766a263c5ed76b34d7 create mode 100644 fuzz/corpus/fuzz_write/39f7a2608f4927b9db04dee0bdbe0b539d1d758d create mode 100644 fuzz/corpus/fuzz_write/3cf84b84d303b12325b4cac0bbfc709064562a62 rename fuzz/corpus/fuzz_write/{8c02cfa0069ae9a4ecad41ca3e159c09ff00328c => 3d73c62d2a2d6b00c475864ddf2393dfaa27f10b} (85%) create mode 100644 fuzz/corpus/fuzz_write/3e6c5e8891fb286b53372b586143b99fbe109a9e create mode 100644 fuzz/corpus/fuzz_write/40304037be01aa178c1d117b74b9ef8acd18fcd9 create mode 100644 fuzz/corpus/fuzz_write/4350b0a6acb951a53ea443960795b79fa2e78642 create mode 100644 fuzz/corpus/fuzz_write/457f626c9723d1654d4eb4d1ad74da5cca22ca41 create mode 100644 fuzz/corpus/fuzz_write/475029a9a19107fccd990135f242fb5d6f61a5e8 delete mode 100644 fuzz/corpus/fuzz_write/4773386289158d62fc0d85b54244812e91881c8e create mode 100644 fuzz/corpus/fuzz_write/480dcfec5d4e3cefea3e939f6759e06a1b019928 create mode 100644 fuzz/corpus/fuzz_write/488c33d51947a56294be41a4bdf94d17002c454c create mode 100644 fuzz/corpus/fuzz_write/4921220f9a2ce55611e2824cd3c39aa511dfb8e5 delete mode 100644 fuzz/corpus/fuzz_write/49a5fac1ae49328b289712912fea13156435ffb2 create mode 100644 fuzz/corpus/fuzz_write/4ab9580bd35308f744503b46b94ee286eb61f6f2 create mode 100644 fuzz/corpus/fuzz_write/4b68f36fe04ecea312a4f0f9c02f13996c0ff010 create mode 100644 fuzz/corpus/fuzz_write/4d0b6106b569cfed448f1ab7605aed415ac9efee create mode 100644 fuzz/corpus/fuzz_write/4eee2a214afba54fadbe9a082d1989dcfa7d5aa4 create mode 100644 fuzz/corpus/fuzz_write/507390266b77f0dde2fbd6e9844132933554a73c create mode 100644 fuzz/corpus/fuzz_write/508d587b573d080de181e71891a6698c17e1e311 delete mode 100644 fuzz/corpus/fuzz_write/512334645b1554d07770e79f1ef8c898e81d1e7b create mode 100644 fuzz/corpus/fuzz_write/519d6ce2de488d89ff4792448f5920f58f0d6c60 create mode 100644 fuzz/corpus/fuzz_write/566bc9dc31b53c07da8d87097b035946f0feea76 create mode 100644 fuzz/corpus/fuzz_write/5704d0aa9ab65f2ee1bdb962f1ef5163352c125f delete mode 100644 fuzz/corpus/fuzz_write/57ac44c923f4ef9c3e80063d9646d99e44b9038c delete mode 100644 fuzz/corpus/fuzz_write/5bdf13800c37ed54085bef8134d1d7c50351a5b8 create mode 100644 fuzz/corpus/fuzz_write/61427d5b5cabf0278b7ff6d978968524ad518a0a create mode 100644 fuzz/corpus/fuzz_write/625bf9ab1cb07c9f5a67134e8c56cf7ff1e9e305 create mode 100644 fuzz/corpus/fuzz_write/64924d68b5a4aec348d9ed51b3cd6319c60a7c13 delete mode 100644 fuzz/corpus/fuzz_write/64f2f96cee1fd79e154c0bf63f64028d1b3df034 delete mode 100644 fuzz/corpus/fuzz_write/65717e0373facba79a96d34aa40c00ca21ca5602 create mode 100644 fuzz/corpus/fuzz_write/664b03092b93cd24eaa371db0baf086865e53568 create mode 100644 fuzz/corpus/fuzz_write/67d75719928b600d7cb621fa2dd34fd03a74ebae create mode 100644 fuzz/corpus/fuzz_write/687de92fd3dc455ed84a9cc07b8edde555b4bf54 create mode 100644 fuzz/corpus/fuzz_write/689959e4b3e4abbc13eb79fcdc786e58ad3bfa9e delete mode 100644 fuzz/corpus/fuzz_write/696ed4fc3c919221ccc3211c9b522a7bcce976f1 create mode 100644 fuzz/corpus/fuzz_write/6af85b878b99229a6de4e1a2efe66ded214f5f6c create mode 100644 fuzz/corpus/fuzz_write/6b17b0a4af43b0f9f3d1a7185b558d93e168751c delete mode 100644 fuzz/corpus/fuzz_write/6c08c1bf7b525451bf5ca7cbd01f5f4d0c94c6e1 create mode 100644 fuzz/corpus/fuzz_write/6d68e0560db48c549775bb2f698aa8b69a0f29ca create mode 100644 fuzz/corpus/fuzz_write/6d8b5ca436ed188f6f9afbc2205ed2d12ab7d2bd create mode 100644 fuzz/corpus/fuzz_write/6da4e6f8a01957eab1a1e2c9d94e4f5b3bf90277 delete mode 100644 fuzz/corpus/fuzz_write/72489e3c88ecf6ea12a547034129df1dc71f4697 delete mode 100644 fuzz/corpus/fuzz_write/72c49dbc3ceefe03a073f95fdd90075efef449ec delete mode 100644 fuzz/corpus/fuzz_write/72ecd095908cbd7a6cdfa5bacd8d3a234aeb7e63 create mode 100644 fuzz/corpus/fuzz_write/75ec38ff4ae8129531a0438043414e63a13c3af7 create mode 100644 fuzz/corpus/fuzz_write/774faccd7bcf5a5802265c6be4275e74500fb4ac create mode 100644 fuzz/corpus/fuzz_write/78814c51503fb35809cc9191f4a5974bab541cbf delete mode 100644 fuzz/corpus/fuzz_write/79b1a1b8e88f91771d4709f6e4865892b450de57 create mode 100644 fuzz/corpus/fuzz_write/7a8dc6a199b3d007a0fb72942895f0de926f82fe delete mode 100644 fuzz/corpus/fuzz_write/7bd45db8423c9a4596bc6e01a7e408685b1648dc create mode 100644 fuzz/corpus/fuzz_write/7d4ddcfa4373f45d478efc874701703ddb39e9b0 delete mode 100644 fuzz/corpus/fuzz_write/7dcff5bcb3d43356e94c4749911277b2917697fa delete mode 100644 fuzz/corpus/fuzz_write/7e380a13d82a8ecc2677f426a96e51534d151604 delete mode 100644 fuzz/corpus/fuzz_write/801f748efb447c4b9309bdf948f9f1e144ab7699 delete mode 100644 fuzz/corpus/fuzz_write/81ccbd9be9ec79eec24dfa5338054c540c074cac create mode 100644 fuzz/corpus/fuzz_write/84b8d3d91b987e994fc85511d4a1920289e7984c create mode 100644 fuzz/corpus/fuzz_write/852aa22fd53f7075a7104b632a550b3681ff169a delete mode 100644 fuzz/corpus/fuzz_write/8593052cc5f8976bf7cb53c4a0c24a7d1ada8a82 create mode 100644 fuzz/corpus/fuzz_write/864dd3cc7af635312484dfa337ecde1b8dbdf140 create mode 100644 fuzz/corpus/fuzz_write/8788c779c1947e0c78dbac2f0ad99e29681f94f7 create mode 100644 fuzz/corpus/fuzz_write/89a2a78b04bc79d938bfc392c45dea3a46e154bc delete mode 100644 fuzz/corpus/fuzz_write/8aba822423e4ecb85ec9504fb44054ff118c93b9 create mode 100644 fuzz/corpus/fuzz_write/8d95303e29184c21dba2ee4e69884af3fe719b5e create mode 100644 fuzz/corpus/fuzz_write/8de15ff4d95b571161d18ad963620c65fbcb7757 create mode 100644 fuzz/corpus/fuzz_write/8ded3b724e4e17a8af5377de0754827c0d8a0a3e delete mode 100644 fuzz/corpus/fuzz_write/90f4914db71c3352c878a7fb1c44a03113f55435 create mode 100644 fuzz/corpus/fuzz_write/920260d144dc94ad444398b567e964d73ca44f9e create mode 100644 fuzz/corpus/fuzz_write/944a346ae52a03c1a7337fc7c87a2f8e4742850b create mode 100644 fuzz/corpus/fuzz_write/95cf7289af99052df43f3b65737cb75884c5e10a create mode 100644 fuzz/corpus/fuzz_write/9aeb063c60a9860fc30780f871e6fd340dd7403a create mode 100644 fuzz/corpus/fuzz_write/9c59e64c8b489629da8aa131095c26696bdd3b71 create mode 100644 fuzz/corpus/fuzz_write/9c8ac134fdad1e73bf0646a81267389b7f963bde create mode 100644 fuzz/corpus/fuzz_write/9ca0c8e90ecee4ce923643c7a233ea9991d68a62 create mode 100644 fuzz/corpus/fuzz_write/9debde139dae690926fe0d8f5bcf013b51632cbe create mode 100644 fuzz/corpus/fuzz_write/a023124e84e2c31591ee38699829921ce8e09efa create mode 100644 fuzz/corpus/fuzz_write/a052dd5a3c1ada13f3f719607d134514e07963cd delete mode 100644 fuzz/corpus/fuzz_write/a2f6302a9961c10e49ae3aaffd7335944c0217de create mode 100644 fuzz/corpus/fuzz_write/a316dd19918f60e9ae843585291f340a19f511fe delete mode 100644 fuzz/corpus/fuzz_write/a833a7d49c837dc03e3c18de09079c9a2a08b36f create mode 100644 fuzz/corpus/fuzz_write/a8dbb85833b64d3aaf42667e3a8c66c544b095da create mode 100644 fuzz/corpus/fuzz_write/aa0f203c1e6d73f6d2c1931428f3a50d3d3159e0 create mode 100644 fuzz/corpus/fuzz_write/ab6594c50a0e471097af9bf9e9d643a8de283c5f create mode 100644 fuzz/corpus/fuzz_write/abc9e1c96fb12ac4dbae5fa4e08aeb96165a2d02 create mode 100644 fuzz/corpus/fuzz_write/abf9761554b820aef4e462e637b638b69f2274c0 delete mode 100644 fuzz/corpus/fuzz_write/ad0eb1bb73c7ff273db0b419b0327da14bea51fb delete mode 100644 fuzz/corpus/fuzz_write/ad1e139f66b779fd5611bdb59a4ad156fbef1376 delete mode 100644 fuzz/corpus/fuzz_write/adf3b89038d3b77ddaf522658fbdae1f05d7e9fb create mode 100644 fuzz/corpus/fuzz_write/af85b5d04bd588f74b042bcf1839f375899b8114 create mode 100644 fuzz/corpus/fuzz_write/b177214021fdefd17b383027374ac65000d24e48 create mode 100644 fuzz/corpus/fuzz_write/b1bcbe30df5281ae9cccc6cce5167b60383c879f delete mode 100644 fuzz/corpus/fuzz_write/b1d9618a19742259c2ed6c965b7ab2279e3806ca delete mode 100644 fuzz/corpus/fuzz_write/b1f781c0001bbd9778cd6e400ff573374ce533ea rename fuzz/corpus/fuzz_write/{3683ea1cf2ae880d806a5a85fd7ddf9ed571fcab => b234aaff4d312a8999de3187bdff55634ba50c8c} (72%) create mode 100644 fuzz/corpus/fuzz_write/b2699886f15b1ca72455b54ff9b37a237da8a252 delete mode 100644 fuzz/corpus/fuzz_write/bc9f059f0b393f6f23d6cd6328040227672fbe7e create mode 100644 fuzz/corpus/fuzz_write/bd3684f924c0b9542976f6777df2a15635af33b4 delete mode 100644 fuzz/corpus/fuzz_write/bece4e44d6614eb0c55f0cf0f54297acf0c65d57 create mode 100644 fuzz/corpus/fuzz_write/bf41768e88fd266b1da7f161c89fa0f20aee50e9 create mode 100644 fuzz/corpus/fuzz_write/bff13adbdbe7c9f1ea19b46189f248dc316fed24 create mode 100644 fuzz/corpus/fuzz_write/c3768fca74ca772409996955fdbfd46cff0f1a8d create mode 100644 fuzz/corpus/fuzz_write/c5c4cde83788cbf0faf4c51a97d5630d020c5c8c create mode 100644 fuzz/corpus/fuzz_write/c913368cf938e068235361e53b27a6000091fb92 create mode 100644 fuzz/corpus/fuzz_write/c9d5d7dca894e05c162a051102ff94ea13c50a68 create mode 100644 fuzz/corpus/fuzz_write/c9f8004bea284b80bcb6cdd0606143c9a1b94249 create mode 100644 fuzz/corpus/fuzz_write/cae18387976cbfc33bab8044aec293bb1c9b3af8 create mode 100644 fuzz/corpus/fuzz_write/cb4835d663b53e2de71e763582a3357db5153f5b create mode 100644 fuzz/corpus/fuzz_write/cbdd4dfb0f101f3e64c3663118dac8cbafc93a9a delete mode 100644 fuzz/corpus/fuzz_write/d2a173fbde746a342fd1a07736139db9d0146ceb delete mode 100644 fuzz/corpus/fuzz_write/d3604f81acaf02502ee56b8103821957ec174ce3 delete mode 100644 fuzz/corpus/fuzz_write/d5447d8592e341356c89798dd92f8dfbd626fa01 create mode 100644 fuzz/corpus/fuzz_write/d731e1be1d3defd0890f3c2a73e3d1d07eebd09e create mode 100644 fuzz/corpus/fuzz_write/d7653af0f02828fc6cbb0076e6e6d30db04b77a6 create mode 100644 fuzz/corpus/fuzz_write/d82f622f75f6eaa7b6ed72d085b1a4d9f6d61352 create mode 100644 fuzz/corpus/fuzz_write/d8cde1a5581abb06cfa6ea8fb6d2f7dd2dd898a7 delete mode 100644 fuzz/corpus/fuzz_write/d94cdff1089a532beb5e59d88e6807c900428145 create mode 100644 fuzz/corpus/fuzz_write/d9e285568d2107f497d162ed577d5d4965d4416b delete mode 100644 fuzz/corpus/fuzz_write/db315b3070a2af366e603d699085ac4846164b19 create mode 100644 fuzz/corpus/fuzz_write/de4e1a1e9f38bb876a32a2c53a00334a11148767 create mode 100644 fuzz/corpus/fuzz_write/dec24e99a6f38848838a513c0fec97ea592720a3 create mode 100644 fuzz/corpus/fuzz_write/dedd117472b5d4ec3eecde02de58b200cdf1f10f create mode 100644 fuzz/corpus/fuzz_write/e1e4cbe538b48c6f143e71bd990dfa730426d778 create mode 100644 fuzz/corpus/fuzz_write/e429f9c46f499f3c5905ffec51d4a132b2b6a25a delete mode 100644 fuzz/corpus/fuzz_write/e441ebc04d6e74502b9fabeb2da0f3062b070248 rename fuzz/corpus/fuzz_write/{f5395136fb16aa5bd4fa32383cf52f85f2b47276 => eb4de99d8d69a81fa28d98c8ae90e1552735a9ac} (81%) create mode 100644 fuzz/corpus/fuzz_write/f0244605b8de13c7ad906efb6ba66003e781b064 create mode 100644 fuzz/corpus/fuzz_write/f1d8650747a9904b6f613e8bbc1b8abf4f0de273 create mode 100644 fuzz/corpus/fuzz_write/f2c2351d9b5c7fc9b43e721975d1116be978d28a rename fuzz/corpus/fuzz_write/{f6570bdf27436889c39dd87c44b87d97e0fbe63f => f371ba5b4bdd6f2ed41a3ba149df83cfc0ed03ea} (85%) create mode 100644 fuzz/corpus/fuzz_write/f6f1ba104c1def2c2bbea7aca98e57860f8dfa15 create mode 100644 fuzz/corpus/fuzz_write/f78deb113d772b7884b167fd2a4ee6076116db92 create mode 100644 fuzz/corpus/fuzz_write/fb06e9ed4a8e9580db46f444e44e63e6018eefc4 create mode 100644 fuzz/corpus/fuzz_write/fb4e17df269f29003cc66731a7d9d71c704ba599 create mode 100644 fuzz/corpus/fuzz_write/fcda8512ce8f678cdbb10d685bd4c0c529dd2f06 diff --git a/fuzz/corpus/fuzz_read/019c8bfcf6e2a0f39504d02bc7c8bb34812e4887 b/fuzz/corpus/fuzz_read/019c8bfcf6e2a0f39504d02bc7c8bb34812e4887 new file mode 100644 index 0000000000000000000000000000000000000000..8d7a7b09dc71319434035d200dc6118baad0b45f GIT binary patch literal 232 zcmWIWW@cds3Si)4zy<;!vfc~~tPBhd=qjMHJPZu~{{KgpWPr-j%H;n6-mGj8OC6By H#vu*>@bMGT literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/370651fc79b3e4782de1002358f618238b875d08 b/fuzz/corpus/fuzz_read/06f31fb623538066764dd8e746764877796eea48 similarity index 89% rename from fuzz/corpus/fuzz_read/370651fc79b3e4782de1002358f618238b875d08 rename to fuzz/corpus/fuzz_read/06f31fb623538066764dd8e746764877796eea48 index df00162f59cf5afaf4fccc0938aa41f59136f12f..a2f331b73f06fad2dc68c4c1fb2b895aec29440e 100644 GIT binary patch delta 27 ecmaFM`Id9SeGUc)VBYw=f{BTjVRIsL47c@P{&UW=Kl%||3P}dCO`=mFb#A814C6Dx}k{AZ*6I&8ssj{${ z{f6Wi2E`hX(W2k=d-_=#T=Oz~mWzP(!{_FUc)+Fzx{~=7;rrclfr?|N5fWkuZ}ELU AegFUf literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/110f5cbf787fbba053e81394af110604b2b4dcff b/fuzz/corpus/fuzz_read/110f5cbf787fbba053e81394af110604b2b4dcff deleted file mode 100644 index 3f3548a8c1adb5a9e7410417890b6ffcb439b1a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 967 zcmWIWW@cds3Si)5VDO&6#-OjK@4x^TU|?Vf^bXPiQXmlEeQggI{AYmBa1tcP#tv3= zivbAX;0BxpW^BC-=bMoVAUa9ag-v}GHbFvSod3}PJHvkl29Q`QGMI|Yfw6I!4e`;QkR2)fr;_IcR)}a0Gj%Hn*aa+ diff --git a/fuzz/corpus/fuzz_read/1131a07f6681078e9ecfd3fbf8f23401951b57ea b/fuzz/corpus/fuzz_read/1131a07f6681078e9ecfd3fbf8f23401951b57ea new file mode 100644 index 0000000000000000000000000000000000000000..61e984bcc59f3cf07249766405325805addbd479 GIT binary patch literal 1291 zcmWIWW?*Ir@MdIy00{=c0KJ_22?5@0Y!yIpHZ}%^1O`S1kT{TI4^>72g<;lz2w*1G zEQsaQbrb^w2Ll6!%P82y13=B|r2#=&>fk?HOER2YvO78gc tAI&CK2tUA^6$fh~kjJrY=Kv7?#h&B_n}wvCB_iJ^gkfhz^9008JLTPFYj literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/116a56cfaba358c33ba5752206654a0e78fe1dce b/fuzz/corpus/fuzz_read/116a56cfaba358c33ba5752206654a0e78fe1dce new file mode 100644 index 0000000000000000000000000000000000000000..6dd08695702efa737d2d24e0630da3fc45140b7e GIT binary patch literal 460 zcmdszF$#b%3`Ku!txlbK1y7T~xOf*gZzCdjJlFW^;v!B?2J-VDfzOYM4;ethHtiz; zRgoD894aw->VI#HDH9uQ$%~B2i4H4qDWB*Go=rT^5r9Ueju*X%<1VQ|4EFrc4~&b6 G-GvhuvN-Ah literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/159aaa6f8f7bcad7dccd2400a36cbe31c786c4e1 b/fuzz/corpus/fuzz_read/159aaa6f8f7bcad7dccd2400a36cbe31c786c4e1 new file mode 100644 index 0000000000000000000000000000000000000000..72dd8a69fce1dea608df46e75bdba78bda9d7ae2 GIT binary patch literal 1210 zcmds0El&eM5Pf^ceN+)h1wl0g2e}3Up{ObhYgRNhh(dxP;HaReJ4yHjq=<@h4K@6a z28rbdplb-n%--(ZH7NABAm86{rb+H zvj=(H;fxloOExN$%2F%ViXrs+Ro9=NZN^Ec*&;U>nx zAv0h8T*Hr5OJ+VJv8_p`$qNsweVXP~>7Q81B2#)$I_fNXAv_&-)P~3X96Xn6?6l{5 c{OaWe(M_JP>;YJC8-kjTF5f2R>+7R`07d45(f|Me literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/34a0aa51dd90905f218fb626ddd5521d6e9641a6 b/fuzz/corpus/fuzz_read/34a0aa51dd90905f218fb626ddd5521d6e9641a6 new file mode 100644 index 0000000000000000000000000000000000000000..79c17400edff054ec8e5bc66bf2e93c52ea3a7ff GIT binary patch literal 1275 zcmds0OA5k341KNr=s8^aJAojGs{t8%08eB073@*Ojkgd)T=o*;DrTm?sdW%>rH|4~ zl1C=IWTfbLh$MP|NCHg8lNqW2fR%`bY!sw89~lSrGodm;m~(J#rb~ z6(MxWVCTowj0{SLm|mT&H9t(eYN2s`d85@98r8jNrnQF0e3$3K6DlNAvTLP@R4s=% z{;TqCp5^~uUoGb!suus$;&8KS1{ztq&2~xk1->T*;G+*LOOCdo>j+7AT4+qC^EZoc ZEDy#cg&#D^70#&raJu}a91=2GKL97M40!+m literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/3f26e1e17a91ba019a42711f950ac148497ab19c b/fuzz/corpus/fuzz_read/3f26e1e17a91ba019a42711f950ac148497ab19c deleted file mode 100644 index 617245a94e5ce3e21bad39aebc0e719fc2f55bf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3862 zcmWIWW?*Ir@MdHH0!9W228NHHSoMW&FgDoneAi>49ROMZvx;#h8{3jbp#2H~-fV0P z43fNH2Rva!mtb&Z0;&S3WMEjr0CY7-H7W@3WPz}leBnl-04wIn_z zF?(A4sbhv*3<_XL5TORd7-0<#5C^ke-Zz98XR^ao{D%d`$}f6Sz#xPBPXS~I2p~z2 z;DPUY^tBI1fa!z1K$8H&k$Qj@g3}uHQ%?ZCoHUx;(TWyq$&VkL8bAbP$^K>btvXvh z1_q+@?Qlwl6c=JN3=E{Q3SQBm7xJ(I4@dqTE&W0HgS^t81z6}|R9__2iukfHw3eJl zL@h~`1jYyo2JDq6qyaOUu0Sm~Y{e|4#VaV}Nop1mAK}z!C+$SElb~(cp_~+8?ODtm z&&SFDY3jnIfbCEQ237{BFt9xW0l+pRs9_JUQ*o56K*cm_84Z~#2^a+Mz(lF5kR@=3 yGBtW0_{v!FdIjJ_0QVNE>*2y9!neQfTN9xfr+7kfq^RpEDHcT22_>+ diff --git a/fuzz/corpus/fuzz_read/41f2b36a77af07c2ce1eaa9da39561200f1ae850 b/fuzz/corpus/fuzz_read/41f2b36a77af07c2ce1eaa9da39561200f1ae850 new file mode 100644 index 0000000000000000000000000000000000000000..a08ea58948bd85d931a6d2fe53f14d4afe9a81cd GIT binary patch literal 1300 zcmds1FHgfj6#rdIyG{|v1VJqX2k8QVFcb>I2~I3CgbWf40mlSGwUY1&$Pg2C3p0EV zg2eIx&@+Vc-u15QmXaW*c*)(ncklo2{wN6-3Pei!KJy|e53;x^fXM2*b}_~M^-Mgb zXiB;ZS~|^5D3=UH4X$$thjR+&zDCXH1Zi)gS&RPQA5TMFFtf!5xj zKj@x!wziuusB5*r3ZjqCpt1ZeqO~eQ=0>K1HTj<8Tt*^(sh3K6y1gnD6Vc8EjoF@Q zi+f69n#w^kL0E4nYny~wkhp*0gl1`PTQfCIlQb5elpbz2#fkMNQ#tZ)$7>Z}l>7CWRVD^HN#CSs^i_HuQU};7M35JG; zZ#ndZZZI||aWd$EXegf%tb&sP6h1(^z&s=Z=08qg2sHr3Q^0Z{cY{I$=vahW(gVp5 ws2MqsfIff%q60}6Gmwn12NJFTnFX^GLc=@^j&62TIZ!HrMF==JxFEp+0Jire?;7c($$1prOC0XJO<403YvS68kJ z16jbtz`y~bfl3(yyxG{88UBL+NQi->kjGnMd1y5s1A_?=Gn4_b5fJ|e>S_=KGJs%7 zBZvg)<0u}@Sb*V`1 diff --git a/fuzz/corpus/fuzz_read/cf9ffcefefec9fbb2c0e50629a1a36c882a4784a b/fuzz/corpus/fuzz_read/49ebb9bdd61e500c6eff877486d34607819d1f85 similarity index 79% rename from fuzz/corpus/fuzz_read/cf9ffcefefec9fbb2c0e50629a1a36c882a4784a rename to fuzz/corpus/fuzz_read/49ebb9bdd61e500c6eff877486d34607819d1f85 index 8c4989c40d5de76dd2ef0eaf6d7f160dd2db3b85..7804c9aa13ec7796f1404d1170d2e98d46dc96c8 100644 GIT binary patch delta 17 XcmdnQvWaEGUq;q21|XQs#AE;fF z!1N8m&kPJp8dbnLA^JeJ2mzUxdf>hU$}Va2LMX@XD3Cl1ENRRJGVwVG7GWSAOB%bu q8WHL-y(|t^0U?$&u7xmwzGg=f2Qve_S;3xVV_;*j0D9pGSQG$@S~VsB literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/5ba9fa14f3f0f86f4b22ac255f0ae813e948f28c b/fuzz/corpus/fuzz_read/5ba9fa14f3f0f86f4b22ac255f0ae813e948f28c deleted file mode 100644 index 98ce78bd05fedd40f2f07a80901a4a47aa29427b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 604 zcmZWm%}T>S5S~rainRm_IrJngB6?^lcyGn8gQ4o zmW^J9hp=qX{UUh1-UG1cvHgAjAxkh}#-3_7T;vvcJM@`QuW*8dV*tTxb#js~CuH$V zryKHGp6;B&bO*lREez*eDF!r0RU;g-G-vGCTs(h#KIM6~W>zq>Qfb5<{MULsi6sE4 z6(_w;oOTzDBqFsAGqo@SZ_a34SkHOI{;(9tu(F$bd7aAnC<^D{=xi{soov%o`)J)R fFS@*kFBPm@9FIWikWN~>JN?YmDYW}G+L3gB1LTew diff --git a/fuzz/corpus/fuzz_read/6a6c4f710b70b26c94a88efa28a4e33db6bad937 b/fuzz/corpus/fuzz_read/6a6c4f710b70b26c94a88efa28a4e33db6bad937 new file mode 100644 index 0000000000000000000000000000000000000000..f3565f1a3e03e95fa51c6f727dd65a1b2e33ccb3 GIT binary patch literal 305 zcmWIWW@Zs#U|`^6SY5d;49H+$1Q84@B`iQPK;N5R Y3Ruzz;s$uLvVmwuAk+iW>L3mS0CL6&$N&HU literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/6e15b9f9c7b0dd5df30a211abf5cba8545c95cee b/fuzz/corpus/fuzz_read/6e15b9f9c7b0dd5df30a211abf5cba8545c95cee new file mode 100644 index 0000000000000000000000000000000000000000..847547d77041f77dd600989d8494a71744f45fe0 GIT binary patch literal 562 zcmZ`$s}jO65ZpE;1%Y9h!5|Pw2F*7RK~;YOfkr`ee#`Faj;r{dD=auM; zPavYi+KGbqEwwUaTbAz~ryM3IOo$Y@;mqdfFRN0^403Eczj_wb4?SH1ycyBIw=qn$Sf#R({ z7KlmlSlH3x`H)EM_y6Bk;L~VZtGzE9tvW76sP+ES_~i7;E7fWMqZ=ZiM-!6(3+Hn7 E1tc$!WdHyG diff --git a/fuzz/corpus/fuzz_read/8021bf5230ec2fd27f145b7e460216dd362329d4 b/fuzz/corpus/fuzz_read/8021bf5230ec2fd27f145b7e460216dd362329d4 new file mode 100644 index 0000000000000000000000000000000000000000..c1e0ded0c1a51e011b8d6fe8462992a0150ec83e GIT binary patch literal 367 zcmWIWW@cds3Si)5V9?WN^JbW!e}Dld;LX6m5a=DG!|(wK0L6eH!28-BG%x|ohe!j- zK=1!LP!3S>jy-zknQ2+n{ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/8051fabc50844c730df40c46d0f0b6363a408034 b/fuzz/corpus/fuzz_read/8051fabc50844c730df40c46d0f0b6363a408034 deleted file mode 100644 index 7f25fb62efbed9e651aa34afba0ab7880fc579e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmWIWW@cds3Si)40D=H0hk=0=#H|Ahv9f{KAm9yT>g(x))qxdUy7Zqoz+ej0{*&?l de+GvC0U%?r0$mOU1}2yc0p=1W;2~RY&k{-P(E?&NCZOaI2NI6$$*u57^ke1K=v6;VdXa2VDS_&&~km zBiYv4I<<8dj3272g<;lz2w*1G zEQsaQbrjhB7%rp0mxutN*i>5hcknn0!zF_yIY8YZ%z)v-;hQWFsTPw(n_&3!AI&CK l2tUA^6=TH*iz literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/98152f7f7623d746f780399c64fe55a0b803923a b/fuzz/corpus/fuzz_read/98152f7f7623d746f780399c64fe55a0b803923a new file mode 100644 index 0000000000000000000000000000000000000000..b93a0d1614dccedf593a5158a9a2895876f4a5d5 GIT binary patch literal 1278 zcmea#*VEHa{r^8RFI^$4G!KNc^|%7OnOSrhKwwoNkGI6~(CYsnu>ZdZBg20NT}B20 z20pMfm;f_9Qgd?hbrj0;i*iyFfd()#$uWbB-~$^W05pQH0mNfqU<5<3PKE|S5N#Xa z&Bms~z`z9Jh=R3&SRkbk0HgJxd`Bn^)W;5D7J&I0Kn>~)41?W`DTu%!(}!Ran04iN zAi)5PqiNts0);LlULau)lJ0=0fyoTNXkvzXkm95SG-vpw_Cc5*QPL(XXTxY%4hKdC pObA9JNr9srn)%sSy#t_007{{j3J`+=yjj^m(x74tWRN3REdW-Xg69AL literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/9c478f8a10294eef29fac8ff86d9fdf539f3d824 b/fuzz/corpus/fuzz_read/9c478f8a10294eef29fac8ff86d9fdf539f3d824 new file mode 100644 index 0000000000000000000000000000000000000000..5b107578db03df348f65be66a6fda49e2b7a98d5 GIT binary patch literal 706 zcmWIWW@Zs#U|`^5SY5d;49H+$0uc=i3@kt@z?+SY8Ay(*ArwCUfuY3*#0(suaAOc* zU}E$R2wVwdE(e9EKaj!9z;F{CfaJb0sDiXGum^avvVmE62u7eBU%-C`@Ba+{VKD_( kE&+=v;#`8uVnY7JomTKT8jBR(V8Z1%usNU*_>TY#08o2cSpWb4 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/a6ee2d3f4e9966428ccb0c674acee81ad691c80e b/fuzz/corpus/fuzz_read/a6ee2d3f4e9966428ccb0c674acee81ad691c80e deleted file mode 100644 index 0a2d56588d557c6d9ab519faa2f6eab31297d32d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 zcmWIWW@Zs#U|@)4cp#b^0c0?6f(R(k*sA|mfq{{MA;6oFNsk$!FdL`x;otxNDDoflB{Y;4Rx5|Ppek5I!Dx`KC5_!63Y&U(#6rUgtZvC#u%EGqT!1$#*t2X5 NYz!7aFFXNj0RVQ`Ga3K@ diff --git a/fuzz/corpus/fuzz_read/c0cafdba839eedc796e119ff82ad100d3e1abc4a b/fuzz/corpus/fuzz_read/c0cafdba839eedc796e119ff82ad100d3e1abc4a new file mode 100644 index 0000000000000000000000000000000000000000..7e8e88b61d7eae58e673de6086cb23639cc92f38 GIT binary patch literal 806 zcmWIWW@cds3Si)4zy<=KvJ4EYDAF8Y9!!>x;otxNDDofcSa@g1y7!nv586+44K^%LyYT7YC_6&s8 z`4cF#84^l*ITRU0k!Db&P{kG4VwYlfyYU~&WjU`(+?SP+t8x1od@I~9{3 z#V$kkCYfv$&q4AQBLfS=ghx}Lh>exS8>7S7#5@DmM5hdbLIRly+y;&IozzLd(fr+7kfq^Rp>^K0t Cj&Mr= diff --git a/fuzz/corpus/fuzz_read/c30fa0680cd367c0a6d999a8829a3e76be42fca2 b/fuzz/corpus/fuzz_read/c30fa0680cd367c0a6d999a8829a3e76be42fca2 new file mode 100644 index 0000000000000000000000000000000000000000..52946136991ba2ed8d2caa3d15cdd042cdaaa27a GIT binary patch literal 1250 zcmZQzU|?WjUlxx7;GvKmcKU}Uw}6=M0G4omH}wLw;rPi12YqYD-+0WMkagabASGQoAbZZ z+c*TI&J1Xl6p-d;Fo0a64!O-yV zEr2mqH*Obkp6 L4GauiDPUOuMh2xi literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/cc1d23b6e796a3ab7346cbf19a3e9e5050e88a9b b/fuzz/corpus/fuzz_read/cc1d23b6e796a3ab7346cbf19a3e9e5050e88a9b new file mode 100644 index 0000000000000000000000000000000000000000..37ed7abb655f27346473abeff0fd56d365e23901 GIT binary patch literal 562 zcmWIWW@Zs#U|`^2SY5d;49H+$0ueyK0>lB{Y;4Lv5~7BkVM${*ST4Yukx7qPgyHqH z-kM%Lun=6IID`u(mo%>Z@gD@%Z((Cc5(hH_yjj^`VvG#TaBDD~VhdL09RPC(rV6N~ zK=)!;12P!mS_TGAtiFUfVo4)}MXC-^D8cOD02+ZFl5k%F<(4$6z^p@Z7p8|8;i^D- vyg)pd71$yRNi|S;HnM6YlVDK`r9q+9xE7)nTgbs8h>d}b!2)Q^6R=VM6<;@* literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/d3ce2736a9f125c8ba2340992a38a4f4d92a2564 b/fuzz/corpus/fuzz_read/d3ce2736a9f125c8ba2340992a38a4f4d92a2564 new file mode 100644 index 0000000000000000000000000000000000000000..0de9a5026b73ad316d51906e8115216d90f6984d GIT binary patch literal 1287 zcmcIjJxc>Y5Ph4=$Hhhw3$c(OX+%g&8e?T;;|g98(uf2hjaZr{R(ECa7f1wCTo*{= z{}4-Cu@vhx;yJS)cb6D7jYIbKYu?P8w-Zmofd?{A=JPzK&C5Zi4+Y@c`>tI~&H1w4 zo=`MTI$5U@MKVEB09`g6%!S<2$tR^ezf(eJVxDu3^4XZoJmsn6*mTLqzcyPmr`dFjbjec< vO7XvEnQG}G5@A=!{jZj$+DX{gAB~&cbS6oux-c$MFYI5QN&CQ3M;(6wSiH3y literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/d438bd6a0c51f77c005c5b888ef2e07430a4b701 b/fuzz/corpus/fuzz_read/d438bd6a0c51f77c005c5b888ef2e07430a4b701 new file mode 100644 index 0000000000000000000000000000000000000000..ab9a460973faa3bcf2471504f286821253084402 GIT binary patch literal 1261 zcma)6ze^lJ6#nM+e%dI(BBYXVjR<>clUPNNG?{=ah>eH{He#ubVzFBW{{m5n#dZfa z{vRP_+SDPnO>pzQw==W5dLBM*cIM5zAK&}t%_SBQ5>OJ`?aEx2qyt;uG(hUlPyM1X zcZa3A$!Lj<+N$jZ6Xvq9nMc(6jF#jytxwU9e~-mY@y)JnFVpZN$2*Q$jGWuTexCg- zfRk%r`@`+^?die($_DPSpauqSk^cVMAHDfy()Rht|ifufIH@8iHY!zD4yvoA7*6g`-$vpehrNOD?9o*h#O z)-^!pp|o=d#C%|iNy?JH zPHncL-fXVqGDf}RMuRf)^DK>)9-tz2j^@pl<_p+bNBctmKk8Z7((aj(FzvO9DP8%8 MElw#gbEv!j0oezY9RL6T literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/da37ea434d5ed679551951af7f16c05f64828864 b/fuzz/corpus/fuzz_read/da37ea434d5ed679551951af7f16c05f64828864 new file mode 100644 index 0000000000000000000000000000000000000000..74eb54b4cb158459087c9bc78138f21afe275c6b GIT binary patch literal 149 zcmWIWW@Zs#U|`^5SY5d;49H+$17em2AOQpc-fV2lKoVUIJ4mtts1B+INO6GJ4E7=n lOpM+j77(xpc(Z~`!wM2WqI?XxP+OTm#xcB+SQ7y>2mn=W4o3h0 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_read/dac4aa320536c9d1e783925f91171c389ddcde94 b/fuzz/corpus/fuzz_read/dac4aa320536c9d1e783925f91171c389ddcde94 deleted file mode 100644 index ffc4a38c13fbe11ede10e6d5b7e91365c4aa0843..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3710 zcmWIWW?*Ir_zwZ%zd0Bf7#V;fY60GiOnS^B3=BY-9ysF$Bg4l}tolMX7#U}>GcYkY zx-u~^1bDNtF(84e03gSk6(nYcB+LS1m%tb(G@A;9>kl+7z?&JOIu@=3=tyrpMiB;P zCI*O|j7;{r=l=ZrKj(j^w`B-Oof#JcgA|bFXHWxiK@Oiar#H1EJ|(dvG5*vsBQ6F7 zkOa_&5)3eZG}!Tc*L!Dx;V%XTHa717p#M0476a{KHehCCNLDY~U^fsNH0=ue1! z`V0(DR({cw()jnEOOk=(*czZEVL%KF90;%gxeBW4KTrk3F@`lD1xPBEG=li(Vab3! zEI~>!K>h@f?h2?G31Dvuf`sfbl+s8b021p!(}C8qBU?g|+bl-I201J-*r4<*7@(I! zW*`%p$qbDZqu_SpukZO7$f@xykP0J3B5Qo8k3rNRPY0tV=4gqDlv)WgY1Hl-0y$;0 z#AG0{`9@BO3GM4)uatn@B4$_z43tt}iSQRj;~yyL&B_n}?j$k+yF3jH3|uK7Eerqz C2DqdE diff --git a/fuzz/corpus/fuzz_read/fb3c0f45a986ca65f2f56e9284f77866bc4e93eb b/fuzz/corpus/fuzz_read/fb3c0f45a986ca65f2f56e9284f77866bc4e93eb new file mode 100644 index 0000000000000000000000000000000000000000..157fd45ed45ccb6022f4f3f67df27437cd705362 GIT binary patch literal 250 zcmWIWW@cds3Si)5VDO&6#-OjK@4x^QU;qm+Ffasq2k8JQ1_mo2xJE7jX{Hdg-a-R= sfPfw3vj6`Me=yEVHFfso34hV_^0EdZPKL7v# literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/040b549640f6aef57b0c3ff7f3f5ecab3b313cb5 b/fuzz/corpus/fuzz_write/040b549640f6aef57b0c3ff7f3f5ecab3b313cb5 new file mode 100644 index 0000000000000000000000000000000000000000..d0f45b4e44516e723f4f007281953fba2bec3204 GIT binary patch literal 445 zcmb7AOA5k342?+ZAw;1*5m!#3-~|LX-SkB6J%}q0;o38a#C)dBbm@bcWM0C{%N+T% z6x@KXW9X||GI_)CG;BTStu$|}Sds)>2)LNPPVPo65G? literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/04c4997b51cae7239a72715281bd99feb349c647 b/fuzz/corpus/fuzz_write/04c4997b51cae7239a72715281bd99feb349c647 new file mode 100644 index 0000000000000000000000000000000000000000..ee8cc1210efd893bcd17c39878710e0998e4e924 GIT binary patch literal 379 zcmeC${vQY)k`6xL(E>8^|9^cDp#d>lua1GuT~W4I@#9fWW$b{B)f=ZnfR=#_!w%Tk zy#t^!tllQr%(yNBaxBb{zu1g{8p6f~Hw&l=j~5Z{`3*CUj{(L4(I5jeAqFrYz(WQG IVW_GA02(+VzyJUM literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/065b3abb5108d0195dea24d37eeedf67dfb6a381 b/fuzz/corpus/fuzz_write/065b3abb5108d0195dea24d37eeedf67dfb6a381 new file mode 100644 index 0000000000000000000000000000000000000000..007d95a8d685a64da2aec62a2af1ec5dd84db181 GIT binary patch literal 355 zcmZ>WK5@d}#ECP^EL{2;|Mlt^*xVIm#d;M#9#sZ{k4HH{l(MoKgaVT?Ad-=bL4W}Q z9zt0_QD+9Q3Lv4O{2xd%F#JaV9b^td_`eB|4b{d7G!bS(fH#Z_bM}X!qg0z4EL@gs!ixrrLkRT=i DlPRpj literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/0789d72c17a5b84d298170d693367a0be7a2f0fc b/fuzz/corpus/fuzz_write/0789d72c17a5b84d298170d693367a0be7a2f0fc new file mode 100644 index 0000000000000000000000000000000000000000..345ab469bb16ba3583b71792d2b3c1d982880a27 GIT binary patch literal 332 zcma)$F$%&!5JkTz3C1Qj(12Rlq~B@_yDi+_QwTP8IfsRfwFs8eDhSpILGT_n;yBq| zgf!wS=FgkI#cHE9bHXj2E&Cyhl-|A`l5lbyd^86SFoS38qX;VT0%{GD*}e!h#l)H@ zk_;5Ern%^WEIxcA2=ioC}Ch|D4ZuCQToeS34_0XP+>iO^FCd}8pbymp zQhxpaf3OiuK;=-CSdD~g!A*fJL=dQE86)evzPKLUc^Y7OuzMDRotuxW0T&x#8;0X? uT8N|v)rkm8kd*xY{~K?pVEQB<9LCUq2AK)*)c*i)U`#B}cg+7E{~rLWo}`=r diff --git a/fuzz/corpus/fuzz_write/0eabde1680227e799be7bb7df9b7c59037714be3 b/fuzz/corpus/fuzz_write/0eabde1680227e799be7bb7df9b7c59037714be3 deleted file mode 100644 index 7d0643bfe378a852262f47af88836df1682d8560..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 390 zcmah@I|{-;5PkkuJ%gkOi-pbZ6$G(LlMAHs07}XTv9k0a78V|2!N$V~qLqv@vk9rh zR}AxZ-e=(t39gKzV5F1BUY}LT1)h%23gKrA&(Oxv=_Ts zp}ooWESSw&ZB(&XP0XT?qsewYRu}f!xCZ=-Xfr0(l70`^m1PMj`zJxT1ivQloR@8( xo0|2)oDZ77Kr+^?O-q}YnR%tUD-f-FB~v2dItc-`GJ^~fq{XEfq{bsNHZ`^gt35}1q`YU3@jjV zrvC(hwY8Nx1H<}&_v_b#j6nteA>8%*5kLj%8Y(*j=*nlivT-;A>V{GZ0aUtrfih!yg?fM63c00}?<1A`U=1gJo$1}GOu{b69Z?!e%!7{CeS>;g%s z26(fv0cj{`UUofk90lEME!K1LT2$6$3~GP#P8N+O;@(*DiL2 v!>GaxyZ*D_aTh$`SP|BbeA&{sO!HLB!>Ep#TO3Ed~fsflv)lE`+-7z~HSIz{$YC z^q-H9uP>n5a4(l;l?PDL|Gz!ZK+*qa{-0U*|Npv#bwI$#z_1P|B>=>15dC0sR|Akz z4e(}z2(mz=0=z*Y4%`f2N{^j^0jOO~A1qnPu&V*c0|P4tkP4tQ7?7n2s+WOb*CpbC p;iXF;m*LV-0`jmx2`ErwD+9b4nHU&K3c=w2u6b9iKw-fA9{{!ex}E?4 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/1dae961448e74c73567e686dfacec88c1df4cb90 b/fuzz/corpus/fuzz_write/1dae961448e74c73567e686dfacec88c1df4cb90 deleted file mode 100644 index 6438c2c7ef2602febea70f3f3fad3a141e8f731d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 375 zcmcb6lZ|z~{`&O+@7J$izyIsEuORTB-eCX!{Wz=y%0MK`|1&@URADxh3!;ERCo=#4 v*Z==N69SOrkeK_8A*O*zpm(8)ffSM=1am)OB@7G@6V31&%m_8q3T`+6=?2|) diff --git a/fuzz/corpus/fuzz_write/1fba93f6fc7311d6b7eb7a9963380c8eda88475b b/fuzz/corpus/fuzz_write/1fba93f6fc7311d6b7eb7a9963380c8eda88475b new file mode 100644 index 0000000000000000000000000000000000000000..3c429af32b5cf21e6a52ae4ee08d296f9bbd3de3 GIT binary patch literal 113 ucmZSh|Np-g5TgP`DA$ew0{;JpGC-6nf~^|!|36f%9ZU&swXO`Z9Yz2c%_}(o literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/200a4b89561b39dc48ff2e0a61cfc809332cb1d0 b/fuzz/corpus/fuzz_write/200a4b89561b39dc48ff2e0a61cfc809332cb1d0 new file mode 100644 index 0000000000000000000000000000000000000000..456fd048495a135e1db501872ee98241366dc832 GIT binary patch literal 442 zcmah_Jqp5L42_FFxCoBYp$61JS`eh}f=d?%H}xvsz+?0%3QnCI96f>{bP#;zr4}bO zL;J}4`I3y1Xeae;nCCgHf_->9v{cijssdy7fVSa+z*_z%c8RH|E6@alU6$%xoUjkk zeQTgscF3kH!$3{sTzRkm&1-thym2!IKp0rK=a#Rk4u{lG<|1zL5wYjIlV66iBzJTv zVtpL2I7|K(NV-~$^F+KG>Sc<}{+m|K^zzWt6PV2UG*4( p2f&qigDuDF9-tD0dzcu#fldNBn1CMS&_Qzx9;YxcMB_G@4*DY;qq_=y`Gv!K1izIg2tTX`xtY{g5p3 zXXd}mmdzdV%W8RBz4clLdGB}Obke$xA`mCQd}bXbIZ0L!9SIGy!SH6%-I!LkUd@V% z%Gpwaz*GTZ4nLK3@)S)c*}_3-0WtzevjCY@7(v!qAw#F4NMcmX9Aq8KZ#Y8ti^w&k q|MIE0I@`;RbnOz5+!^6E?OZ9;+)If70#2hb><8T^|Q!~_i z*Z)gGJ@@~=7Z9*809`|U3;!@MKrOVzY9q)iUS7bUh4=|U{)2{=Gs8ljt$Y9fm%OEA Ot$#~TkB!YcKpz0|6K;6` literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/29018a952fcbfd963ae4af36033ff0409296ac6c b/fuzz/corpus/fuzz_write/29018a952fcbfd963ae4af36033ff0409296ac6c deleted file mode 100644 index 312b738a1befbd6bf52725707d611bc6140ac513..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 428 zcmcb6lZ|z~{(m}v_3H!PuV24j*n7?{gG2j~!219H_wQf7fdZgvwO)7qdIns;I{-=M zAp?Uj3J?@Vl0{`Q1G)2on1zACk%1wGfk9tSPamcvz?+SYg8>+DFad`DTC$NKjtWC$ yWTYyJCBkZOZaAC;WH18F6jl}%6y^Zx1M(fbX=N*R5ZAih+S47KkB$5la0JJQ@fFYzz$SP&pnb%>a=Bk&Gp5 z+-&#u?)@M5AIK{N2?a7hO#jc!&;ZlGU3;g$_c`ByFLC z#SHC{%Uxb>5d}wbQZLVQNVzBPc^)#y2{Qvr?Exdfg#u~WU$KqIl+G0x0Hj?l<}Dc^ zA4Ts}z_jWp8}9`JJ)&EqeYC_ct4@m~b{vt3&B1Ko1D-2u%4!4i+-M{979;ERZL;H8 za)2o&zwKmkmmw^<>Nw3I(B$AWK7VNDjPD=5mcVK=Q_;9iF=Jo0GS*Q@nle$JIK1q> D$ceUM literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/2e522bba59dc10b8c333861e03b4a4a679f41c9f b/fuzz/corpus/fuzz_write/2e522bba59dc10b8c333861e03b4a4a679f41c9f new file mode 100644 index 0000000000000000000000000000000000000000..cc1ab39aea06c0853a3f631f40d236b7f9c5a459 GIT binary patch literal 431 zcmZQ)VE9inFa;~1s&!axprRlH0~HMe83i{GIT+Tg|F@pO>YJl}gCipwt9Jkc!)(`C XY&vY-Y78K7dHuEv@Bjb(x#$i60>3!% literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/336e95e761bf4eb53e37ace38ac2ba4a699fd5e9 b/fuzz/corpus/fuzz_write/336e95e761bf4eb53e37ace38ac2ba4a699fd5e9 new file mode 100644 index 0000000000000000000000000000000000000000..4e39a9492f1ae21040ed761c02dd12147d4bfce2 GIT binary patch literal 442 zcmWIWW@GsOzxn_E{}6B=E2x5s-i6Wu-pnlb?}0fCRSXQS3^;%+Q2fefAd#ZQ&cG1h z%?2bPfRT|A!uZede+3$_h42Hs8JUn|*cn!=L~yY=6WLWj!*RL_C^rQPzy?Ch+6@P& zW)p2HGz5vDV75=0VlXAZd&(59cw1wW*dPBPA)=t8%);y)01Y0fAdm+WTCsx5_<#I= E0B<7Hc>n+a literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/33ca792e4b3380c5e63fa77ca72001899c0dde44 b/fuzz/corpus/fuzz_write/33ca792e4b3380c5e63fa77ca72001899c0dde44 new file mode 100644 index 0000000000000000000000000000000000000000..f7173fe63f8851eecacc45dd531305e1c362d5db GIT binary patch literal 432 zcmZ?pc5wLrpX)yg_>RIu;xI!&0+3#f01XTb45|U%Y-~Up3K|#!yg?!k+&~79(qm^} zU}RuW(+A5}GVE%AskCAMsQ^kN0cSYd>dKWPSFc{RnsthS;Yvv%82sNgZ|`2Ke4v_u z|Nj{nbgx{w;>`+lCB$sFRv?3rIbgM1Aad8P#nHQVF$nG5%d{5=h%%iB3#jGLc~`6i K827V5RhhPK;o>x=0s#C0jC^ PTd3|ogJNs>h3^aig1m~B diff --git a/fuzz/corpus/fuzz_write/382817cbec4bd6d7b7a3bb59d289f718c89f0392 b/fuzz/corpus/fuzz_write/382817cbec4bd6d7b7a3bb59d289f718c89f0392 new file mode 100644 index 0000000000000000000000000000000000000000..dca28fe792995172a18352b43ec20dbe0b63fbdd GIT binary patch literal 328 zcmdP+uUE&w=B_B)tN8IKr!o-S2NBAvSFZ+9|Nm<%$1;FfU=k>d3Y3-qA^=Do5JZD? zqXLld|NkHoNe;|)2AcbyYydO@ZvD@{U;~wvgMqXnhz%xyv^vByAR)NVenVUX5rcUb l!qWm$_D~5Rh2l7{u-gBV|Nk4C>ofdkU|?WpP}V=@1^_Gas6GGy literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/396789d05dc588d88d7317766a263c5ed76b34d7 b/fuzz/corpus/fuzz_write/396789d05dc588d88d7317766a263c5ed76b34d7 new file mode 100644 index 0000000000000000000000000000000000000000..16efc361e00d9b603c5f769b09daf0261305f11f GIT binary patch literal 276 zcmZS3|BnuSBMIz40!YHtVls3<043%bLNp6`2l(&b9~Q^P{+}UkKLf+z#>0)7IY7i< ez<>r|QVa}CVBa$vb#?i4G45|<02=i-sQ0YoyE!4(~N2cU}p`2pUn zY*>WhLJa5tCW9_cO+L&HVrkj+EKuwD7#NrkF5zHch*YimpYXp*_W%F?E({DFAh|l( xg#Z7ms$_xSy{v2%P^L?J0sur|Ys&xt literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/3cf84b84d303b12325b4cac0bbfc709064562a62 b/fuzz/corpus/fuzz_write/3cf84b84d303b12325b4cac0bbfc709064562a62 new file mode 100644 index 0000000000000000000000000000000000000000..47d1db229950bd67c3b750512a1f3548bc4c6736 GIT binary patch literal 333 zcmZQzXSlB4pu3(yF@S-K0SZFzFfbT!LO9p|Oa6xeFHbM8xHvCHm^v8k1yZngum0Y> zoD3RuDllOX9Sg({_i`=O2il+!z{c*4u;xE?jbi}08Ui5h0Xhe}dx&!^%rJC%AoR z=>LC^wz-u7XT90jLBe`D-U}g$kw~C;QBe_)Ji7L%K0AY+u7N&C?Me{Az@QB#(T$s< Q&t1q1F#{+Mb|lAt0IzyM{Qv*} literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/40304037be01aa178c1d117b74b9ef8acd18fcd9 b/fuzz/corpus/fuzz_write/40304037be01aa178c1d117b74b9ef8acd18fcd9 new file mode 100644 index 0000000000000000000000000000000000000000..f06e8a6589e7ba98e0e3e4d860fbd52cd07ac21f GIT binary patch literal 211 zcmZ?R9B<5Q80+D|00jCT4IqjcL_h!&jKRR59)bp7QuUc04F3c47^{@^J#--kL8Ls` bkd0zs0O==M6C0a1Of3VZ4I0>N_zwX9U&>-O&aP}jW&BRheL(pV0#Ih&06$fQLyxt!J{5sfwZ@Yajs z-QAitM@FuK9Z$RmnpoL~oZ>~AtVojq5(YvE9Bbro-HN>mt^B-Mo&U~GQfuaR{g-3d lbgbW^HOmS8Bfs9kuZNETQ+~zo@NpwAkwZfe03~XAp1)Nf&P-sN0=E6IlO`j`Q-*LE1cOpDVZj765$Kmdguxt8CaNd{2SY4M eh;ShDsvMy_2Plo?{%nYO`Uo4KEN}k+eQyBtg@VZd literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/475029a9a19107fccd990135f242fb5d6f61a5e8 b/fuzz/corpus/fuzz_write/475029a9a19107fccd990135f242fb5d6f61a5e8 new file mode 100644 index 0000000000000000000000000000000000000000..fe12bc568bbef6ac02a7eee4267e0eb2d17c6b59 GIT binary patch literal 420 zcmb7AK?=e!5S-fD-U2?rLkWl=Wq}YnR%tUD-f-FB~v2dItc-`GJ^~fq{XEfq{bsNHZ`^gt35}1q`YnF)W~g r0jL_R0Vqj88PL%GVDJw@K}Z_83CXg!{|x^x|3?x)vYuYHL#zY<_uqi) literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/488c33d51947a56294be41a4bdf94d17002c454c b/fuzz/corpus/fuzz_write/488c33d51947a56294be41a4bdf94d17002c454c new file mode 100644 index 0000000000000000000000000000000000000000..18bd56edda757d554a9fd242a9ff56e9d40a36a5 GIT binary patch literal 319 zcmdP+uUE&w=B_B)tN8IKr!o-S2NBAvSFZ+9|Nm<%$1;Fe5C9ZL1QYPB(Zq0vN}W`SQ*SgzyCwHPF)%Q2FsL>FDg7&(fnncNg>k%>N8}Az}WUMhB6|=^cnsG!+?Q-ok3aum>U3M C&4*?H diff --git a/fuzz/corpus/fuzz_write/4ab9580bd35308f744503b46b94ee286eb61f6f2 b/fuzz/corpus/fuzz_write/4ab9580bd35308f744503b46b94ee286eb61f6f2 new file mode 100644 index 0000000000000000000000000000000000000000..433672001d44d2566b3bacba151d05f90110a92c GIT binary patch literal 413 zcmcb6lZ|z~{`&O+@7J$izyIsEuOP60zsrB@U_TfD<;wpva5BIEP!Pt1(?B&RGXMYA z|IY^!$^-+rBno4{F~n3b33LTSEr+MVYMd3^SOAdA Bhy?%u literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/4b68f36fe04ecea312a4f0f9c02f13996c0ff010 b/fuzz/corpus/fuzz_write/4b68f36fe04ecea312a4f0f9c02f13996c0ff010 new file mode 100644 index 0000000000000000000000000000000000000000..1d6c8ee19a0b7057dcb8df19892ec62947b91f50 GIT binary patch literal 411 zcmcb6lZ|z~{`&O+@7J$izyIsEuOP60|Nj5j0Z;}ixqmm5bt3csfBpZQ4F54i7(n1Z om?TJGSO>NU?2P@pHBqdBnuuaB3J14k6xu?j!Ps1n(Hq)$ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/4d0b6106b569cfed448f1ab7605aed415ac9efee b/fuzz/corpus/fuzz_write/4d0b6106b569cfed448f1ab7605aed415ac9efee new file mode 100644 index 0000000000000000000000000000000000000000..f0cd6375139154bf1e7f879345490ed6be0de35f GIT binary patch literal 132 zcmeDBjt_9|0)c8E{==Z5Qg^s9GY5#i|7U=LsW8TpKaTs?Z~5=IKT-Yf(yqUZiVQm# j7#w$VGMan0wzdYeGBhwS1pNOG*9g&P=gr{2z@P&F73)3K literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/4eee2a214afba54fadbe9a082d1989dcfa7d5aa4 b/fuzz/corpus/fuzz_write/4eee2a214afba54fadbe9a082d1989dcfa7d5aa4 new file mode 100644 index 0000000000000000000000000000000000000000..71b3922c24f22a6b0735ebac656f49dd624af081 GIT binary patch literal 372 zcmZ?LW=z&D1Og)v0Ro8-3PzTL8D%goHkx5a*i9_r`lw$jZ3FLKBz* zG%G`)cCxX02Y{5|a>7TL{=z~WPCzICvCv!q6fpz|g8-TfAcEL*z};L}7~svu4pRuD Wf$m`V|NehHjE_d|^7anU_XYschn5fk literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/507390266b77f0dde2fbd6e9844132933554a73c b/fuzz/corpus/fuzz_write/507390266b77f0dde2fbd6e9844132933554a73c new file mode 100644 index 0000000000000000000000000000000000000000..6af889c97f455d4a7e250057782b993c3f2644c9 GIT binary patch literal 333 zcmZS3uV>q}YnR%tUD-f-F9;Ze2qs4F0H8QO5VJBcFfcJNaIgSr2BwKH7Lc=mLA8Ma zBK#i>urPZEpb0(OmAyXT{rdgu_alG`%uin1^R)$xEtv59GF8UbZYI0JyX@#~Gn oFb|;@WY>QN+(2JXA1n!R1S6Wmz*6FxKQxDtk2E!ZtiO8`0L3ypCIA2c literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/512334645b1554d07770e79f1ef8c898e81d1e7b b/fuzz/corpus/fuzz_write/512334645b1554d07770e79f1ef8c898e81d1e7b deleted file mode 100644 index 740fc211fd049267f19beebb3c53fbb372bbbcc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 439 zcmcb6lZ|z~{`&O+@7J$izyIsEuOP60|Nj5j0Z;}aS^l2^27m%ECY%Q9K9TwVzy5zd zkWeNVz$H-_`;EayLI|K6AZkG*iZU2yKVc;d3=qT25C+3^qtgHDL5>XYW@h;hwG~w! g#v|2<`yq}5yHpA0ADCfiG=@{Ld5{sR$qKF+09TZjYybcN diff --git a/fuzz/corpus/fuzz_write/519d6ce2de488d89ff4792448f5920f58f0d6c60 b/fuzz/corpus/fuzz_write/519d6ce2de488d89ff4792448f5920f58f0d6c60 new file mode 100644 index 0000000000000000000000000000000000000000..7f6010da1f48f9ef3a581ab013c5047b9099d537 GIT binary patch literal 440 zcmcJLK?=e!5Ji7YZFd0=;G$%qASOq!P!viwxsZbA$vwP}%UOh&nN}#`#)WSY!u-ih z{@-VNLo;;SYxguljPV#_J^|&%7?T)+8sM7N2NFU}UJ>==Y|hq|nw4`BeOH1-_VV>M5GfvZY7ufQ*2o1hpp;(vAqC&le+WLu;~dJmNd-~x;K_mAz%sKl zNtPPVm>jG5sk(=ZuItuTFNDx15H1Qm-5wIXko?Lk9l4{#UOiWrwy8@viKez4!)a6sbKtUigAo|?#;hp6r8*}=Fn^LK!B(yyL_Rm+e_RR72V#8;ozR;WM Mb|X*#Qv|sl9^x(4T>t<8 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/57ac44c923f4ef9c3e80063d9646d99e44b9038c b/fuzz/corpus/fuzz_write/57ac44c923f4ef9c3e80063d9646d99e44b9038c deleted file mode 100644 index 16e551817522bc69ffa912c85b4fa6444950e936..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 438 zcmcgpOA5j;5Ph|=-32^=ixLn)%z$_RK~PFIxsZbA={*FG<8l^ZY(AnJ(UlKo0(p-& zkC~;|Gn!*JKXrGLFbuX~$^a6vS$F5dMD zH6_LKEjC#h5~q1Osb(I%11biR1SG{{^w%6ySRLnm%=w4eFI5&J@J OBHIl?0JJc4Jv;!^XVw=0 diff --git a/fuzz/corpus/fuzz_write/5bdf13800c37ed54085bef8134d1d7c50351a5b8 b/fuzz/corpus/fuzz_write/5bdf13800c37ed54085bef8134d1d7c50351a5b8 deleted file mode 100644 index dfc8ca32bb6b25b20dc1d164e4b275e3e95b2061..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmd<`SJG$D`ws-NDfR#V2LSfgVBla725W>7FdZ;OAR5Uo29RA)0Jh5jq7ddV!X~PNHJ}>Fh+-tj f`B(r*3%W3pF(ifpUQgk00ShxQlp$dbbchB3Ve!#> diff --git a/fuzz/corpus/fuzz_write/61427d5b5cabf0278b7ff6d978968524ad518a0a b/fuzz/corpus/fuzz_write/61427d5b5cabf0278b7ff6d978968524ad518a0a new file mode 100644 index 0000000000000000000000000000000000000000..4ba5bc4ac4977b6801d4c287ec8a620b60610b75 GIT binary patch literal 438 zcmWIWW@Y2@7x?!d3>X=N*R5ZAih+S47KkB$5la0JJQ@fFYzz$SP&pnb%>a@J@MdER z3}h@}<7T_Jcklne|3I-qkVGH@#Pt8n3=J?140b?c*wlbrh5s;Mb z1Ulh=phRF`Fi$

#9Q7K*w5E!Ywckdx<0DCub;Q#;t literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/625bf9ab1cb07c9f5a67134e8c56cf7ff1e9e305 b/fuzz/corpus/fuzz_write/625bf9ab1cb07c9f5a67134e8c56cf7ff1e9e305 new file mode 100644 index 0000000000000000000000000000000000000000..500b8a61fb513eec35bc2a9ea80587702db58c85 GIT binary patch literal 430 zcmcb6lZ|yf|N8a+M*-DCVE_L0K)?V*x(qA~jtmS;3~;~!WJN|s!t7L4{q^que+CA| d5}1nr{N4d~T+~(nXR7{J?JBWWTpkvn4*>o!a`6BF literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/64924d68b5a4aec348d9ed51b3cd6319c60a7c13 b/fuzz/corpus/fuzz_write/64924d68b5a4aec348d9ed51b3cd6319c60a7c13 new file mode 100644 index 0000000000000000000000000000000000000000..0eda5c333da5f28d8af5812ab182ee09e4e31299 GIT binary patch literal 364 zcmZS3ua{-m2n4MlzzQaTMD@mv|NsAI21&rcxBpcPAW(IJK^4qk0g-I6in6_mA8T-f z|NjHL+1P=msm$kL;PhkAV_;*raFK<tz|XGNfn$UCzOv+5n{VuWSaA zDO&6d3<2J3KoS-FXZXJY3J9x!sl-aNGXRCx!=$F*0s4A+`dFn`tl%>FAO9Z!;Dw}5 diff --git a/fuzz/corpus/fuzz_write/664b03092b93cd24eaa371db0baf086865e53568 b/fuzz/corpus/fuzz_write/664b03092b93cd24eaa371db0baf086865e53568 new file mode 100644 index 0000000000000000000000000000000000000000..d37fb0c2e0c8ed05226a1fb8a5b2a55b3c8152c7 GIT binary patch literal 409 zcmWIWW@GsOzxn_E|Ns9h|Nnpb|9vRvVPs$cF%yB90SVkUgepLnKvF}98Q{&v4pRfP m1_;(@!}x?~sO{LOb6^MGzdr<>K5q&X1b8#EaGCs%{|^9)B6X?& literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/67d75719928b600d7cb621fa2dd34fd03a74ebae b/fuzz/corpus/fuzz_write/67d75719928b600d7cb621fa2dd34fd03a74ebae new file mode 100644 index 0000000000000000000000000000000000000000..7e445adda12da3003c0b469072ad2174c82e3da6 GIT binary patch literal 427 zcmWIWX8R8W`9ScK;W`5zzygv3sf7T25Os4sSR+`9fx#GA_w~i~0brG}|F7#afE8+h zVBiSg~5**s1jrs5CGkRtQ=zCZ>X!y sAZj2ava6}>1XysKM*^^*$^ZH5xgRr_Kn|t<0p7r{Tb}Qj|3Cge02orX5&!@I literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/687de92fd3dc455ed84a9cc07b8edde555b4bf54 b/fuzz/corpus/fuzz_write/687de92fd3dc455ed84a9cc07b8edde555b4bf54 new file mode 100644 index 0000000000000000000000000000000000000000..93ef819cc0987f19a32954d76f347da9a7bfe6c9 GIT binary patch literal 442 zcmaKoO$x#=5QSe&ZE+Lu04_>E1Tlf0pdu(Gn_Nht=jlBJkK=L{VNBB>QHui!VSe8G zCOg(QWS3%dEuJby+qQ>r-l3HD-dTb;!DP906vL%t1yMytGiwuaI^KQJrbErMq)ATH%T46mL2EZ ve%^=u{xSFLQJjtg^PE3M|4+{@`}1QX^E5LsfAcD}A`ieGMt)aeG#b1 z5TXZ<>8vnir~fnjU-h4X0csuGEELB7U;qE>K;1#e?r2i&7KB>`^D@vjB!J68kPnRh o1D(zYHUO>zC=7Bh0^l%K!iX literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/696ed4fc3c919221ccc3211c9b522a7bcce976f1 b/fuzz/corpus/fuzz_write/696ed4fc3c919221ccc3211c9b522a7bcce976f1 deleted file mode 100644 index 01bb59676cb6d84b72888e06e00ee5edcf2188b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 437 zcmZ?pc5wLrpX)yg_>RKE!|@l`^$#K~zY7I0FlaGAfC_|afN~+!bq5A-#Q;tQ2B!af ze0+TY)rNbyG^;#-lK%hgfd-2HKlA_0y8r*zC9DGiMh1p;Kq&zrW`pPlle-##lxl!C z8?qonfHz3Qfg8vGQhMwR42%p5)%3wSDj9Y)Fv7fp?Dp-*jwjXa!ayJhBG??f;|-W? qjAP>&f%XXt2@8X5C5r&MGPW|nn~{lup`;KD{_mQ1#R?P#%>MzTq?r2v diff --git a/fuzz/corpus/fuzz_write/6af85b878b99229a6de4e1a2efe66ded214f5f6c b/fuzz/corpus/fuzz_write/6af85b878b99229a6de4e1a2efe66ded214f5f6c new file mode 100644 index 0000000000000000000000000000000000000000..d5e7105894ca89d626b977ed7860a44d743f1d1b GIT binary patch literal 264 zcmZS3uV>q}YnR$gWbhx%VPo|U05f*&Vn78fATArbcYtaGLj!}V!%RXN;M%;g08H6hR{#J2 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/6b17b0a4af43b0f9f3d1a7185b558d93e168751c b/fuzz/corpus/fuzz_write/6b17b0a4af43b0f9f3d1a7185b558d93e168751c new file mode 100644 index 0000000000000000000000000000000000000000..f3d4761cab43ef605eef468332998bc1d79995df GIT binary patch literal 265 zcmd;Dcpe6nA&im|X9hH&g2rd~{~ukX8zS%rOa*wev7swqU|?bP4p3)c07|kmFfcN3 zKvX0^00V=U7lT0W**SM_PS4WSWnj2)fsJ*&{`xCWc^p&<9)O}n83NS)pZx#d$XK5N Tgi7>T3y|K$JwCMNm}{}~t<*ctvOKn$F&tbfc6 E04JVp5C8xG diff --git a/fuzz/corpus/fuzz_write/6d68e0560db48c549775bb2f698aa8b69a0f29ca b/fuzz/corpus/fuzz_write/6d68e0560db48c549775bb2f698aa8b69a0f29ca new file mode 100644 index 0000000000000000000000000000000000000000..751f03a16eefbf264d3332a2854e8f1d2b2c9d22 GIT binary patch literal 412 zcmZS3uV>q}>lhg5fl0SxH^~IANdo`>6IA{ZO@%O&kHvi;r!y>Fx)%g??V9BX_R6ti zd<-DQaVQT#fz|EZ%fKLeVE@s$xTQ;%aw6-N*tN@-fq{V$h=Jh$|Nrd&85uZOI3g!9 zM7Bo)S*8sjiC6}P1t1;+7&9<1=`-A1&%j{+pDo}yyZ5i3KzW8giVXijY8e>b0j**4 g4gjL1OXL2t{dmu?C4lXJ00Tx00G;X0%J=_206hr{A^-pY literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/6d8b5ca436ed188f6f9afbc2205ed2d12ab7d2bd b/fuzz/corpus/fuzz_write/6d8b5ca436ed188f6f9afbc2205ed2d12ab7d2bd new file mode 100644 index 0000000000000000000000000000000000000000..d2b0bd40fb23aa69fac576c63eca12606c33c84d GIT binary patch literal 397 zcmZ{gJqiLb5Jo4(M#OS!i!dOfV8lkzB8Z?xnmLg-@D_GChl1c`Y!w-ku$!O4DUvTQ znHQ2NFU}xOYJ5?z+mLJ{F_m*JWafE7h#oq3jexs~C=L-HARqtc%24IlC*K|7hkFp_ z!b=u~g4Pm?aH*N`$jHW$99VkpQEX#h7Ek!G<4Wd94bn~C(-P{m#vsMgwX8e;tFpr< agXO>Z=Y-u&cO*L2D-8^m0Nw)i{rCg@y?0dr literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/6da4e6f8a01957eab1a1e2c9d94e4f5b3bf90277 b/fuzz/corpus/fuzz_write/6da4e6f8a01957eab1a1e2c9d94e4f5b3bf90277 new file mode 100644 index 0000000000000000000000000000000000000000..05b5169e949a813cb54e30e2a650a9bc68fc2b23 GIT binary patch literal 146 zcmZR0uUE$q-Fl(<<1uTs{~!=yq}YnR%tUD-f-FB~v2dItc-`GJ^~fq{XEfq{bsNHZ`^gt35}1q`YU3=rY} zgaObB6u1oLwx{pECgn{!v6C+em_Q3wQxVZle J|1U!w0sziDt^EK1 diff --git a/fuzz/corpus/fuzz_write/72c49dbc3ceefe03a073f95fdd90075efef449ec b/fuzz/corpus/fuzz_write/72c49dbc3ceefe03a073f95fdd90075efef449ec deleted file mode 100644 index 4883fb31a83664f8403f0666fb0ecfbd08b7b20b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 440 zcmZ>WK5@d}#ECP^EL{2;|Mlt^*xVImdlf$(RR)5OM>#Gg2Dn>N{nFrJk)n^Z)XCVw>U_h{eES<%RaTw@~Y#x{mcN4^FI2Xl05C>{vD2fyL Wkj#T?MKfvQM7@a@HL#LZS}A1hOC|njuU_k%e>q p*MpoI;LXhPKQj~Pc~p->l@aG=xS0?Jh68{O$M7B_RFf54GXP#Dn*IO) literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/78814c51503fb35809cc9191f4a5974bab541cbf b/fuzz/corpus/fuzz_write/78814c51503fb35809cc9191f4a5974bab541cbf new file mode 100644 index 0000000000000000000000000000000000000000..beec918b07086cf41a3eb88e8229d0f7ccb0106e GIT binary patch literal 434 zcma)2u?oUa42(-vTm(nyP!Fnuv>-^`1(z-kj`mml13#mmqTtlY!O>3;gbspd^4cy! z(G2e$N$!%%EQt={WkFFC)bNkN8+I+)Wql=kq*&GhSc@y@ zW9XSF7*`pqraQ%CN95XY@Bfqcj?9n@d=;;CfvIY_8KgOAE4D17YdglMTJu{@mD>c} swAzxnkL+Ib8l4|yAjj>6%bQ%RCPo_8x62WlA1;$v?6x9ZL44kP0FP6zCIA2c literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/79b1a1b8e88f91771d4709f6e4865892b450de57 b/fuzz/corpus/fuzz_write/79b1a1b8e88f91771d4709f6e4865892b450de57 deleted file mode 100644 index 059479dcb63bdd32209b2aacc2a1b6a67a9b1786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385 zcmdP+uUE&w=B_B)tN8IKr!o-S2NBAvSFZ+9|Nm<%$1;Fe5C9ZL1q}YnR$gWbhx%VPo|U05f*&Vn78fATArbcYtaGLj!}V!%RXN;M%c9;zU-F_cu&zt>U_dggg!gWI#M5>hCzn>v4 nfq@;Q>p#%radH2FMzKH){SCKUc>pZuVF1NK?0=xcK>h{*={}S| literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/7dcff5bcb3d43356e94c4749911277b2917697fa b/fuzz/corpus/fuzz_write/7dcff5bcb3d43356e94c4749911277b2917697fa deleted file mode 100644 index 7dd1f8a2b6845f92a13196887682d2132df07b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 434 zcmeYcP?^ue!0E@J=gPpwaN!~ggAP9f5@2HV4q##S4uA+TGu)s4arV5~|8@U^z$-TI zfZ4MhX3w4tG=Poa7Dzi=00TR}H$*u*gi_4Fr3Ypa$+j>Ac(buX9g4>mHikPOH!+}k n3G8-q2^_vB;1hzjF?uuo-?9#9iUPX=N*R5ZAih+S47Kl;6|NntU1Hpiefq@+=#RF3UkpYp6C2ZVm z_xA4nANU{0D+CDzGC)lK&kR+LX;uTwAO<_2@oZ{9E>sVQ0vi%Y*xqH>?PX>_H~t~e zePI6t1C0h*=v~IZaJzva;F>p(&A=eYz$VPV#-;{THw6g(|7VO23}gbi5fMU3ATBb1 in20RGzyLEIXe_D(l*fw!0wcBe?mfhSASgjLB?FqjAe5GIw#UAuOv0WlD;GB7YOF)%VPZ~z%#pxOYW9Ik9; eU;sG@A_gKk85qD)S2k-g)OU4p)*=CrNe2LDLZL?h literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/852aa22fd53f7075a7104b632a550b3681ff169a b/fuzz/corpus/fuzz_write/852aa22fd53f7075a7104b632a550b3681ff169a new file mode 100644 index 0000000000000000000000000000000000000000..112897b0814dff0d7ff2fd63b03766abf9a82eed GIT binary patch literal 297 zcmZS3um6t#4hSX=7Tc~}$G|`jLg6D5fs)3S$MzoE3kD1fvIq7bjf-2lbSWpp(xqUr zUAt!O0s>YBMg}GZ1`ZYm28M|Y$2ou$16Y^=BGS&m@QZK&l^mBDzE?&W7;7{PA0jg#!TIp$x{+Y@3Q0&kCQ_+E zmq7zwR7nUYGe#5Z^EuZU+|27~JZ%Vw<2ce~kp#)Kxh~ztVIys$&^nKVeT!YR_be-i z*mAOx@lN~R)3~ZO$K?*27eXmWM?X!BPUzuJ$q@&Et; diff --git a/fuzz/corpus/fuzz_write/864dd3cc7af635312484dfa337ecde1b8dbdf140 b/fuzz/corpus/fuzz_write/864dd3cc7af635312484dfa337ecde1b8dbdf140 new file mode 100644 index 0000000000000000000000000000000000000000..166278581bcdeb1ac76254859115fd4f6c08e14b GIT binary patch literal 368 zcmZR0`t(2PpdO^yA`ieGMt)aeG#b1 z5TXZ<>8vnir~fnjU-h4X0cPDVxOH@~1Y{d7i$G2^f;;E`e^6*3oJT+-Gzg&DzyJR~ Q;s5_{ARfXteIQQ*0E~XaV*mgE literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/89a2a78b04bc79d938bfc392c45dea3a46e154bc b/fuzz/corpus/fuzz_write/89a2a78b04bc79d938bfc392c45dea3a46e154bc new file mode 100644 index 0000000000000000000000000000000000000000..213fcbbbe4db5887eebd652f5e526877b17fb3e0 GIT binary patch literal 371 zcmZ?LW=z&D1Og)v0Ro8-3PzTL8D%goHkx5a*iCHWC}Ih0Qy4(tu#+a#MiZDknvJ1Q zE7@4R13*e}x!@yAe_7qBKM2 YtRLtyV*0VKNngD0zY7LX!-d=N0ZFsk$^ZZW literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/8ded3b724e4e17a8af5377de0754827c0d8a0a3e b/fuzz/corpus/fuzz_write/8ded3b724e4e17a8af5377de0754827c0d8a0a3e new file mode 100644 index 0000000000000000000000000000000000000000..71aacb9a892ff437ef9d33647bd679fe7323861d GIT binary patch literal 432 zcmZ?pc5wLrpX)yg_>RIu;xI!&0+3#f01XTb45|U%Y-~Up3K|#!yg?!k+&~79(qm^} zU}RuW(+A5}GVE%AskCAMsQ^kNfPgccZFS|!k*im)TFpAez;LCc5DfnBnzwhaRX$Kn z!2kaY47yjYT=8ZFx)NeGTq}@)%^ZHHg2KZ8yTD8?5V>pD;^V{I-ETEP{QOvnwCBX3iKl6V8f`OI1 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/90f4914db71c3352c878a7fb1c44a03113f55435 b/fuzz/corpus/fuzz_write/90f4914db71c3352c878a7fb1c44a03113f55435 deleted file mode 100644 index 2c05a248af6a10d3cd3390e301967f38ba6f5bad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 354 zcmcb6lZ|z~{(m}v_3H!PuV24j*n7?{gG2j~!219H_wQe?YPDW>{dxvmz&ij*<{<-v zFbWV9Mv_G^nITLT1_nn4h8PA0eLX#Wm@Eea(9bXq!++UG5L<;IGBQ#X#b{wQI5!;5 i0x}qZ#tAD63xdQPyyFd-ZH!~%J%DBi3n42Leg*)-_>f2d diff --git a/fuzz/corpus/fuzz_write/920260d144dc94ad444398b567e964d73ca44f9e b/fuzz/corpus/fuzz_write/920260d144dc94ad444398b567e964d73ca44f9e new file mode 100644 index 0000000000000000000000000000000000000000..cec2f6ce7a3a0cdc3f0726f99215920acfb3b280 GIT binary patch literal 173 zcmd<`7x@1_-PrTF$~i7D(+tF9U??eJ*s;T52g9FLh4l07j1Wz%5DJZ)9sm+xWB0bVhs)5xat)Qb!;P6aK*Vr(@#4k*|1vdM1PJT_N&8&J literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/95cf7289af99052df43f3b65737cb75884c5e10a b/fuzz/corpus/fuzz_write/95cf7289af99052df43f3b65737cb75884c5e10a new file mode 100644 index 0000000000000000000000000000000000000000..9c8d7adc1b6c8c57fb677528ce9e9cc9f65870a6 GIT binary patch literal 441 zcma)0I|>3Z5FN~_EW+NvVjU1+At?lFVL_2J+lyBbJb(w0oI}CmSWdBw`KJeQ|vNNC_L8cYr5Z^Ml+egj~S>EH2LM|tf%5wzBg7|Jus23}7x$1O`9~{{IJ&K#Iyh zpUURJjRUz>5kvriI?#8@|5<=6W)K(XFA(*6KZt~Z)!qTCfmm5t2PUHYU!_|d%z+#F n|2{Mv)WG6kbAc>o5RV$B{y+KuzpG3|ny m2{#D8i-7KM26+zza$vqfaU4j7XvcxVivbAO8I<*pxd8w!2h!pI literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/9ca0c8e90ecee4ce923643c7a233ea9991d68a62 b/fuzz/corpus/fuzz_write/9ca0c8e90ecee4ce923643c7a233ea9991d68a62 new file mode 100644 index 0000000000000000000000000000000000000000..fc49e51072f87cb5edb3634497a2cf1a6120940d GIT binary patch literal 356 zcmaJ+OA5j;6r9@H;wIn$TxdW9FicUO|y>6e0L{un6 W7ka$kHd@c+CbC&u2!IOOUiT02^Qx!- literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/9debde139dae690926fe0d8f5bcf013b51632cbe b/fuzz/corpus/fuzz_write/9debde139dae690926fe0d8f5bcf013b51632cbe new file mode 100644 index 0000000000000000000000000000000000000000..27c8017dbbca03e840994de1df00d12f6d1aa360 GIT binary patch literal 442 zcmZXQy-EX75QS&Wx^anUYJ){Mf&oJiL@X>)SXeB`7Pk8;f~}Azut*WC_Bm2msa5bX z0s#@hucZG|5JQ4f_%cG*B91D9jol4Yn6ZL(B#_5@NOWtdq!0us)ERz5rQJ z?NF~lc@Rpumviw^#g8!GLj-}Ihk6xk0;WSCt^yeh4!IDR9S-o&1lkOB`!uj5s=EJr n|NnC<|7U}lqpZAC`Q~rslmGtzH?jZ=3IGlGZ)&cOY>pcM2AkfM literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/a052dd5a3c1ada13f3f719607d134514e07963cd b/fuzz/corpus/fuzz_write/a052dd5a3c1ada13f3f719607d134514e07963cd new file mode 100644 index 0000000000000000000000000000000000000000..5a1993b71b19aa25c9809c650230610604cd3095 GIT binary patch literal 335 zcmZR0uUE$q-Fl(<<1uTs{~!=yC^ STd3|ogJNs>;B)7N?+gGBgZ23U literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/a2f6302a9961c10e49ae3aaffd7335944c0217de b/fuzz/corpus/fuzz_write/a2f6302a9961c10e49ae3aaffd7335944c0217de deleted file mode 100644 index fd96cc1f499529b7c5cfd536eda2257d17ef4898..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 433 zcmdNe*Q;Y-i&d2ERs49AQ#rt!kx5zkKM?4F2yO`b|9_y6va+%?5JSQL|3KBs-T^=^ zNFfMtEB|L>_YMFuAbbe<{XYko!2nW$CNU8N*jPb&{)6PfKv~(D0ce>u#3E+~W#umr zrajbZWsr{F%HLU-!5YDuzzzY*%K=@3Y$M!6m|nPfgUT-_|NZ}OWC3=g0MNrAuvA&? Yzw*id|4q&H89;%&~ev~T_Twd-{&Dl#gN zK>dFRU?2b#;qn4-78*kqjSsU0D9pkT85s$(=r<56tNwcT|33r6ix)r@Rxe&KmY`{b ca+lq4`K1a}&j7>*K>R;*|2ugCYY%mmXXf>qVdj z!~g%GI)5SS1ZoLlPy}iL0(31#ND4t#60H$v7ZeOW7l9o1{r~?7|NnmjF~R=FCI$`@ IeV~j60P?Qa5C8xG literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/aa0f203c1e6d73f6d2c1931428f3a50d3d3159e0 b/fuzz/corpus/fuzz_write/aa0f203c1e6d73f6d2c1931428f3a50d3d3159e0 new file mode 100644 index 0000000000000000000000000000000000000000..d3cad4c6dc0575a662461b5479e63ff3c1cf6889 GIT binary patch literal 441 zcmZ>WK5@d}#ECP^EL{2;|Mlt^*xVImdlf$(RR)5OM>#7!(;8 z7#=bR07(W0paN%9Mat+#B%{dVFau-|6lf?bGyDgG0B;D5Apaql20$iM2P4EGU|xVX z%p4$%a0=M53=9f7$}G&@0TAB*{~#Kn9AYus`zi@Xef>N=eS}^A|I@%?up=E1Tk6Y0Te+g+2leBJx}i;cpR6rC}WaVMWy|a5Hd6W zzhuSciu_zIF6BcfHBGY#>m#k(D1tb`=7sZ=okM+80x`tKpjLX!)h?Y(Jz|+K~^EG)`Zx3RA2MIHImGKeTJ0` ajCBm!v0(W+kdyTO>*?!XyjZQzwh;hS{;%c$ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/abf9761554b820aef4e462e637b638b69f2274c0 b/fuzz/corpus/fuzz_write/abf9761554b820aef4e462e637b638b69f2274c0 new file mode 100644 index 0000000000000000000000000000000000000000..fa9dd3d259b3060a3954f4ad03e8c19fcceaa838 GIT binary patch literal 253 zcmdP+pR8BM!0N8}|G(^iC}7y}|Nn0o2M_&DKY`JJ;Vn>I(EyO0-R5KtcMMh=9z0PxCw0ssI2 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/ad0eb1bb73c7ff273db0b419b0327da14bea51fb b/fuzz/corpus/fuzz_write/ad0eb1bb73c7ff273db0b419b0327da14bea51fb deleted file mode 100644 index eb2064a51996269e8cad24baad61db1362efac9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 424 zcmZ>WK5@d}#ECP^EL{2;|Mlt^*xVImdlf$(RR)5OM>#7!(;8 z7#`jb0Fn$0Kn2bq0tz&gl^GbB85jZ>Sb!u<6iokz0TfXb%7 diff --git a/fuzz/corpus/fuzz_write/ad1e139f66b779fd5611bdb59a4ad156fbef1376 b/fuzz/corpus/fuzz_write/ad1e139f66b779fd5611bdb59a4ad156fbef1376 deleted file mode 100644 index 0acb2b882e7ca0426085ca96a0c3ec646b40d5eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmZ?pc5wLrpX)yg_>RKE!|@l`^$#K~zY7I0FlaG=0Z>+qK?TBYfKUv03`CM5$80t> zs1;x;z&pU3jm?3Z0Zi$!GcYhRFsSK+mb1D5+wlSEL{3a)~(yPPM`!79kRt#0V6d3bU4Ud&$>Hw2L9$`LC=D^kNi{qvmmvodKd7 T>Uj`lrqA-96BI7W`p#|uqIfmL literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/b177214021fdefd17b383027374ac65000d24e48 b/fuzz/corpus/fuzz_write/b177214021fdefd17b383027374ac65000d24e48 new file mode 100644 index 0000000000000000000000000000000000000000..712ad39bed08b0698e72bde706631803491e30cf GIT binary patch literal 310 zcmeDAD8QMZ`TxHj!+x9p|23rx)>|9_wci~onAG9VpbA)pEW+07tkAn62~h+7Wq}>lhg5fl0SxH^~IAae((&#sB}uDvT`n5}5;J3q$!>+y`hQ-QK+n46+CIAB~G!x^yWgvTli8yL=fK7#M*V1eh59|7T?2 zVBv_I$Pn2c31pczfW%`N7#4td3}6gYr_XS6Jp+UNf3|?({b&2}o?%M>+y4Lt^!V{+1^I&S|9=3wbO|E> literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/b1d9618a19742259c2ed6c965b7ab2279e3806ca b/fuzz/corpus/fuzz_write/b1d9618a19742259c2ed6c965b7ab2279e3806ca deleted file mode 100644 index cf474b34bad34edbafd86788f9baba5886e56ae6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 381 zcmcb6lZ|z~{`&R*hYbjLzkdDtBe=o-{rd^{6{rFW0Ghg<0f=-NSQs1`7?>Dh8K8gz yNJmCS0!u?eeOcu|6l-=50HhMhlL@IBnD&yU9f)r+V#2> z6&V#spdMlx&Ixp}KBFxAjyl(x{Q$VR$22|sqJeW2#8suaUP=ruGQUJ`l z(Ee8mE`(snK7a$5&tZ}vrvlyb8;F%vf4u`4{Ne>j@I}cBMxdfwAcY(tVkJ8Rw=F|t jB#6zheAykBU#kEAbAbF|0Cmp)|C#&m?f(x9iT{BBooJ2Q diff --git a/fuzz/corpus/fuzz_write/3683ea1cf2ae880d806a5a85fd7ddf9ed571fcab b/fuzz/corpus/fuzz_write/b234aaff4d312a8999de3187bdff55634ba50c8c similarity index 72% rename from fuzz/corpus/fuzz_write/3683ea1cf2ae880d806a5a85fd7ddf9ed571fcab rename to fuzz/corpus/fuzz_write/b234aaff4d312a8999de3187bdff55634ba50c8c index a17c8ddb12b153a4624806c13eb59023dcf66267..a6e5000bb3a92893f8d82cf78f56ea1a56a7dc69 100644 GIT binary patch delta 29 ncmV+&0OJ3-1G)pSQUL+-lTraU3-ABtx@)gc@2{_^lP>`!!E_C7 delta 17 YcmdnRypwrD5aZ-vM)Qf8dQ7`m0X9noga7~l diff --git a/fuzz/corpus/fuzz_write/b2699886f15b1ca72455b54ff9b37a237da8a252 b/fuzz/corpus/fuzz_write/b2699886f15b1ca72455b54ff9b37a237da8a252 new file mode 100644 index 0000000000000000000000000000000000000000..2aaaa60c6451570237c740d519e085a0fefc469d GIT binary patch literal 278 zcmZS3um6t=u6V4|=Rfjnc&V|$P71p@{K*#rBJ#>FjNx|EY)=~A%R zu3fWs0RbxmBLfoy0|yHO1H(jy;~YSW0W8b_5ozaO_{G4m03-}lwtzvkfq_Af8N_8{ z^$t+|%3!=n_wv3HkihNZ44gm;Bpb`Hk72sFstH5?|NjsnPB7ymSS!Ra>w#c36Qg$k Sh=B$UuU`-Gk2fn{{eJ+VtA=3! literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/bc9f059f0b393f6f23d6cd6328040227672fbe7e b/fuzz/corpus/fuzz_write/bc9f059f0b393f6f23d6cd6328040227672fbe7e deleted file mode 100644 index beabe698a6e51a53d61b84292e30e72d47afdf59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 zcmdP+uUE&w=B|tdNMR9Ec4ojPO1#*A5MW>i0w4|6CZnv(Krt}DW&*ma7_hsYQZK=* i!R7?87+8VY|C9g!n;Ypf{0EA$Gbrn`v3my`a039cP%zQ} diff --git a/fuzz/corpus/fuzz_write/bd3684f924c0b9542976f6777df2a15635af33b4 b/fuzz/corpus/fuzz_write/bd3684f924c0b9542976f6777df2a15635af33b4 new file mode 100644 index 0000000000000000000000000000000000000000..7470ee6cc9890b196a8890c801cc6037283f28c2 GIT binary patch literal 222 zcmdP+uUE&w=B_B)tN8IKr?RrLl(Mptva&vq1q2$(%2PoSvq1nP3j|6G3{Y7hXDV0( zNCYr2Ft9Ty>a($X16dG2zD{GX0Sycw(+Pn8%E~~+Q9xB{9w*rujLq~}{&RxdqO9-i F1^}(>C_?}M literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/bece4e44d6614eb0c55f0cf0f54297acf0c65d57 b/fuzz/corpus/fuzz_write/bece4e44d6614eb0c55f0cf0f54297acf0c65d57 deleted file mode 100644 index 664a0575254f77a871ac97b6aa94c9c23854a194..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 440 zcmdP+uUE&w=B_B)tN8IKr?RrLl(Mptva&vq1p!k*60<=7Bnt#e3=BxJU=bh@z`(%3 z&Y-Bz#_kPdL4YxsYG44VfdNGrLs>Zx&cvk^MJHS}Dnsr6$^ZW?P{sZuxN2;y-T@#b z=0^Gq|A7v|?#TZ?5L%R#u{si20gz1~kWhjUq!p;1#6SZ20_ff-pguK^lk5yY53u~_ L1bIMN-`NcS1F}oZ diff --git a/fuzz/corpus/fuzz_write/bf41768e88fd266b1da7f161c89fa0f20aee50e9 b/fuzz/corpus/fuzz_write/bf41768e88fd266b1da7f161c89fa0f20aee50e9 new file mode 100644 index 0000000000000000000000000000000000000000..9563e3ce7bdb383b4647a12e6bf7dc2fbeb803a1 GIT binary patch literal 444 zcmd6jK?=e^3`KvP+Tv!w1Gp%IAczwX4id4D@2wDqQ4H6Dsybyh<&u+QJ~Bm-NctD8PG%}!-XNa0x172X zj;sT2fsf9?JkRr4vCQZaP%vOwAQ7(-oOH^wYu6P0xbG|HuiX=a1#?!)k^kQr^~%$I M4to-)Y6QBUo<5<|zW@LL literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/bff13adbdbe7c9f1ea19b46189f248dc316fed24 b/fuzz/corpus/fuzz_write/bff13adbdbe7c9f1ea19b46189f248dc316fed24 new file mode 100644 index 0000000000000000000000000000000000000000..fdc2e3ed939be3bf3c215cb0771ba500e9108cf3 GIT binary patch literal 346 zcmZRW2nRD5K)^)R`1QK>+jEqzj Xh698laNj{ZfyC9DIPoYn7%l<;F!+AC literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/c3768fca74ca772409996955fdbfd46cff0f1a8d b/fuzz/corpus/fuzz_write/c3768fca74ca772409996955fdbfd46cff0f1a8d new file mode 100644 index 0000000000000000000000000000000000000000..6df0156433546fe724fe7636dabe70315830e7b9 GIT binary patch literal 446 zcmah_u?_)I5M0e68i`UAXA=}cA`yCt<{E{PU-1V%!>5p_u2Lv{f{;iEV|L#OiHI%k zCObQ`^R_kUEF_x8X_|snTgJzAQ8k&UD$uqbP$IqLV>sqOf#0h>3 zo#zDA&@ncd5(7Dr-Aj8g@jZx7UOz1+Nfc2=o0;370mL<~d4vtBO{bl-w>X)t|0F+S zUEi@7!WEToJBFkoM}sAk;d$2W*zFL#oc_?NE8X98`v7{wx{1o!9aq}m RRz-i%6}z)YUbMRzKLK!Ezz+Zb literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/c5c4cde83788cbf0faf4c51a97d5630d020c5c8c b/fuzz/corpus/fuzz_write/c5c4cde83788cbf0faf4c51a97d5630d020c5c8c new file mode 100644 index 0000000000000000000000000000000000000000..92be2d9fe63d6e328c7945861be3415a129c587a GIT binary patch literal 370 zcmdNe*Q;Y-i&d2ERs49AQ(4(NKv`M&KNN5aFaUW#uvA&?zw*id|4q&H8UAPgS7u`a zs{^T2R{qWbR?Yy^b^netRGYFgi1h_zf;5PLfdBuIECQJX(a5d*pN$>F;f5ImqQCz~ zn2su;&oL1Kz{(k3iX#Dp35?3h)(~sqPJy{YS(%O1JK#4$+e@;|(Eb1aq_UX_*kl}G O_Md@)ok3aum>U3#rJ%(C literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/c913368cf938e068235361e53b27a6000091fb92 b/fuzz/corpus/fuzz_write/c913368cf938e068235361e53b27a6000091fb92 new file mode 100644 index 0000000000000000000000000000000000000000..47c3d4c9da21f586aba4798c5c4ec9293637e820 GIT binary patch literal 436 zcmdP+uUE&w=B_B)d+Xy-PGumt4yNz5^;nDEJFz zqc}x*F)$ETgKY#^xUw5=?f?Jo6atXNU*Sf>+=K84kfp4A1sDTrC;$JqG|*@G&%nUI K&Y-M+%nbm&|C)#Z literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/c9d5d7dca894e05c162a051102ff94ea13c50a68 b/fuzz/corpus/fuzz_write/c9d5d7dca894e05c162a051102ff94ea13c50a68 new file mode 100644 index 0000000000000000000000000000000000000000..8cfdca8882f7c9cf137882d468c885ae770a66cb GIT binary patch literal 343 zcmZR0uUE$q-Fl(<<1uTs{~!=yDY;qR&3ZAF;5Il~{S(I-Qi;AKH$s#lP z@6TM!3FW??9P68&>Y%o5m*Kpmbr(hCTiCL4o=Lu-%gGI`5ivHrnRG|fdRO#bCyI-+ zcTIuZrUdd4o=Nt}E_sT>K{obi9FP%6AjH`}clyV9@Y0aK94f|cMnw`2%vJe0jw7u-^9OtRt literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/cae18387976cbfc33bab8044aec293bb1c9b3af8 b/fuzz/corpus/fuzz_write/cae18387976cbfc33bab8044aec293bb1c9b3af8 new file mode 100644 index 0000000000000000000000000000000000000000..3cfd7a626fba459dab1ba492ea409a00ee1e2291 GIT binary patch literal 323 zcmZ?LWK7mB1Og)v0Ro8-3PzTL8D%goHkx5a*iCHWC}Ih0Qy4(tuoG?@!3ux`NF&%r lJeF5MO()ZGh;B5$LXAXFAjALv|6h*~L1FFk_72eZ1^^l!gYEzT literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/cb4835d663b53e2de71e763582a3357db5153f5b b/fuzz/corpus/fuzz_write/cb4835d663b53e2de71e763582a3357db5153f5b new file mode 100644 index 0000000000000000000000000000000000000000..cf330e5914a7707a74e31ff5d9c9df56e3a80c6a GIT binary patch literal 229 zcmcb6lZ|z~{`&O+@7J$izaJL>%4OmK7ASH+#p@XuSQtRSfC)^22@W6`85#K>3RG2( zzx)4RogXZ!4>SR0ikf4DCtLKQlP6CyoMcG7%>XeR$<*7+*csT=L1x}w6mZgj6|NX! Y+p;?@>dOB!RsXC0Z|^EmTpktx0I0rSn*aa+ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/cbdd4dfb0f101f3e64c3663118dac8cbafc93a9a b/fuzz/corpus/fuzz_write/cbdd4dfb0f101f3e64c3663118dac8cbafc93a9a new file mode 100644 index 0000000000000000000000000000000000000000..f93d6341a02d24ca5042cfcad52f9448199c1c24 GIT binary patch literal 403 zcmaJ-u?@m75Htixm02QDP|z?ynyldoC>iNT_?8i%Ug@w~r KZXG+1xqkw;!K0J_ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/d2a173fbde746a342fd1a07736139db9d0146ceb b/fuzz/corpus/fuzz_write/d2a173fbde746a342fd1a07736139db9d0146ceb deleted file mode 100644 index 494adc5164f17b8f73bfe8060c18b9c604e5d225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370 zcmdNe*Q;Y-i&d2ERs49AQ(4(NKv`M&|9_qTV89Jxg8-2F4q^TO4^{$H1(N&zpX2|3 z2AGVpvNHo%0!V;ZUt)m_X^03+4Uh(F0@6^sATmI!pa$dA$;Jjz0dx)s7(!`?`N*Wk z|LcwH3~zqA!@UJ`4AdPUb^rf^y&3{$0<9;k>^u-a+^P5fKezIKHiUIcm2du5KKbwe he!U=7EBlA+lsE0K?OnvH$=8 diff --git a/fuzz/corpus/fuzz_write/d5447d8592e341356c89798dd92f8dfbd626fa01 b/fuzz/corpus/fuzz_write/d5447d8592e341356c89798dd92f8dfbd626fa01 deleted file mode 100644 index 6088578b54740dd550a2e213643dde5178fa17df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253 zcmZS3uV>q}>lhg5K`3OBj{%v7VDE(h1_s#!`;W%OF%SzDFfeeifD|)Lgt2}xFf3qD zZD3%~V+M*NF&Wrcy#rJkz8de+y}qvmq)F#611FFIDU4;<$DnG$!1@0_Q~>G{Mvyun Zi2Kj*o{h~rfbD+(12!*uv-17_4*sQ0YoyE!4(a-cn3g4T#zLK zyjj_h`RHs0bO2KT5{I!tG=}ksU|DqS)Z!ysO$=LhJqy%oJ_ZIRgey207$Q}x{wMse zlKubxzY7C{2S~0?HsSyOsw!C^crPnk1(d1MsR9B<#=Cn#f^UI>P*B_I<>lzr+S&@@ JgB5|;ssJlbbz=Yk literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/d7653af0f02828fc6cbb0076e6e6d30db04b77a6 b/fuzz/corpus/fuzz_write/d7653af0f02828fc6cbb0076e6e6d30db04b77a6 new file mode 100644 index 0000000000000000000000000000000000000000..80875cf57aec792d73da2e7689a944ca9de4ad76 GIT binary patch literal 445 zcmZ?pc5wLrpX)yg_>RKE04Dwo~LZyiud zfPuj~z?+TDft!I1ZW05-t_B7Mkdyv_i2q<$fmsAx#RM{<;s1XmlQ3LmK+shpSY0Ix zHWcJA2Gsy7pp%g-VPFXW`r=YRHXGX|2vCR8aH?e8x~g?0K=1$mA6pr)_1`}>hLS=s Q_`hqO_Z6l9Mh52p0Lv}NEdT%j literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/d82f622f75f6eaa7b6ed72d085b1a4d9f6d61352 b/fuzz/corpus/fuzz_write/d82f622f75f6eaa7b6ed72d085b1a4d9f6d61352 new file mode 100644 index 0000000000000000000000000000000000000000..56c655d1728fff284c6b1369d18b2fd2bf53b042 GIT binary patch literal 49 scmd;Ds>{H@@P9iH{QvhK1h#JlVjvHQ*#EOL04b0lkjuaj;2oeV3X|9@@e zSOyRa0)WD(Kw0@O7$_^NLv+B^ff&C*=7IqWvv&YcCy=cH6#-KA2qwr4a7SrE9JOaX wNM7y#$^ZWiEeKfvQcAQ1NWRv<5-<#u08&F0>_1~OeTM%)TiF?u^^ds$0BB&7VE_OC literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/d94cdff1089a532beb5e59d88e6807c900428145 b/fuzz/corpus/fuzz_write/d94cdff1089a532beb5e59d88e6807c900428145 deleted file mode 100644 index fc7753c5c0d67860ed7666c54c20fa6b28b9afea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmWIWW@Y2@7x?!d3>X=N*R5ZAih+S47Kl;6|NntU1Hpiefq@+=#RF3UkpYp6C2ZVm z_xA4nANU{0D+CDzGC)lK&kR+LX;uTwAO<_2@oZ`!E=UzrBX$aGb|Bf#VP-(L^&!yN zU~dKkjRv{HyNrS1b^}AeHE$rBfkBXgO_+g=O%14S3K0DN&lnvT$OLjLF#!iQ5NHrc RJqF;#0D+O(d-oo)1^_I7eB=NC diff --git a/fuzz/corpus/fuzz_write/d9e285568d2107f497d162ed577d5d4965d4416b b/fuzz/corpus/fuzz_write/d9e285568d2107f497d162ed577d5d4965d4416b new file mode 100644 index 0000000000000000000000000000000000000000..6b342836002ed2089f7b8cccfbec7a39bce2efa8 GIT binary patch literal 425 zcmcb6lZ|z~{(m}v_3H!PuV24j*n7?{gG2j~!219H_wQf70ViO<0=xr|1RpXm2%`W& zVI)~pCNq#bABb5P7#tZGVi*|o_4M>%N&>vu*f=bJVF43h_^%}!3F4?QL`Fuc3bP|y zqz1GTr%Dv}fK)<2IE(?J8G*J7D+>z>a{z4s@*TY6kNr7(X3>J}Kx2i4kd+EQ0|14) Bs~rFU literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/db315b3070a2af366e603d699085ac4846164b19 b/fuzz/corpus/fuzz_write/db315b3070a2af366e603d699085ac4846164b19 deleted file mode 100644 index d3fc382d0933515c2df9a7be89c6f972cc391d8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 441 zcmbVG%L>9U5L`@c5utzJp)80{NDhK$p`b`Exr@Id_&xm(!B3h)S(DVX#mB`tWXSI9 z%xpwoDL+=LE&&~n5UIxxx9?z1SDus5x=$IiNZhyWIc<}^=U~*(I2(*CAV<6hV*IX* rg}T)WN)w?X3&|-Uvn# literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/dec24e99a6f38848838a513c0fec97ea592720a3 b/fuzz/corpus/fuzz_write/dec24e99a6f38848838a513c0fec97ea592720a3 new file mode 100644 index 0000000000000000000000000000000000000000..d4858c4a3b2d6d678fe9e90c4d5f6a012fb7898f GIT binary patch literal 438 zcma)3TMEK35S-fD`W5g1ew2U+Vit-A5Co;{ z$>bpBiSl0W9`#2@^nHKw>j$le07iZVm6dfI;R?1n^M%QX81gk^ND>-ni}7v{#mCOs zwm?pv!CohwqfBBBv8H&v%C-)z1u_OA1zt62_-@6)g;8PNtk31M=U%#8Au|8nZzkMN aq?Hn2o=PiyM%efA7CAQr0Z>8H>-Gh)WYzHi literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/dedd117472b5d4ec3eecde02de58b200cdf1f10f b/fuzz/corpus/fuzz_write/dedd117472b5d4ec3eecde02de58b200cdf1f10f new file mode 100644 index 0000000000000000000000000000000000000000..3236bea48646e00408d109366c10e47d13cb80e6 GIT binary patch literal 284 zcmZS3umAu5zakKW0Rv3{%ycl#%cRV}5Ua+(kiy8&0I^OVNL|^i3F4qA1#yT}4${b= j4%dyUixp%t#1aN)WGl4c8o-Rs|7>hv1_OhNinTugYE@~r literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/e1e4cbe538b48c6f143e71bd990dfa730426d778 b/fuzz/corpus/fuzz_write/e1e4cbe538b48c6f143e71bd990dfa730426d778 new file mode 100644 index 0000000000000000000000000000000000000000..fa229d8edb281cbe931cbd2ac9cd2f78193e0e8a GIT binary patch literal 444 zcmZ8dK}rKb5bVXUaf!&DBOb;A2`GsKLIQ#wgm_qF_uzHkkRJqmK;Ga%Jnh*hM99gb z@eLDLsop=S1=9FMB1 zERz=~1$mxh4BSa*;>M~?=|xY%U87(r)u*0{G)v+g84qxs}cA3Z&?3e^-B&XemK=9-5KzTbMwp5WFWdOinIlT G_vs%h?YXG{ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/e429f9c46f499f3c5905ffec51d4a132b2b6a25a b/fuzz/corpus/fuzz_write/e429f9c46f499f3c5905ffec51d4a132b2b6a25a new file mode 100644 index 0000000000000000000000000000000000000000..166eda0ce04119d1da1e16e2285ee741147f5e80 GIT binary patch literal 441 zcma)0I|{-;5FNA85QN;oA`XZU$QCx1LO_viwimA=cmNL~dkzJUV>v|__n+2R%;(MH zz1ebqgT<*`J=*W9#*C*iZf5Q>g=hj;3Kd7&5XT8gtn?%ZQ*iTlV=n2M^r1VS0VXc{ z!iczzeCv86iTs{7asVK@f*?AO?3sJ3qTW~1s?2;t%ez+R5`^;@$6}_mck?Bul1)v> uIiAQ{OvV3FyO=8dPar~f9u-Xg*?*fFXkMgj#0`I#cY6su091hTef$C3CA}R0 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/e441ebc04d6e74502b9fabeb2da0f3062b070248 b/fuzz/corpus/fuzz_write/e441ebc04d6e74502b9fabeb2da0f3062b070248 deleted file mode 100644 index fc779e91a5846f6345e1ad3d7c384c0b46fe9907..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 349 zcmcb6lZ|z~{`&RP#RJ~2U%!4oDwq%9%F_;rBN+{31MOSCe(ieQii(U1BvAh!2-q3^ zGY|lZaCreZ3ymR*%>VoUe>v0|pfC$VWMm}Brr$uUtorNSf1rggUVs$5c)?f#RB;QW knFBy{4v#CJ;|nWR#k0$0z~-s7(l> delta 28 Zcmcb_bctyL6XV1OqPz^qV6qCM9spok1l0fl diff --git a/fuzz/corpus/fuzz_write/f0244605b8de13c7ad906efb6ba66003e781b064 b/fuzz/corpus/fuzz_write/f0244605b8de13c7ad906efb6ba66003e781b064 new file mode 100644 index 0000000000000000000000000000000000000000..0ee2f4b5b98a4466e926c1c428a3992331a0aa26 GIT binary patch literal 340 zcmYLDI|>3Z5FO0wvQ2Jau?~o^kl5G@3yP%KUOb46-~l{{(dwM8Z z?u8L?HR-KqSweBwL_x|Mc>o|?KoEUND`w?Vq}+QY8cgN%eb6O!_raVh5Zb$x*jLn0 alFpM2(0o>|uld8g-D%(+pmu-P@53J&DT_t` literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/f1d8650747a9904b6f613e8bbc1b8abf4f0de273 b/fuzz/corpus/fuzz_write/f1d8650747a9904b6f613e8bbc1b8abf4f0de273 new file mode 100644 index 0000000000000000000000000000000000000000..bae8da17de69f3aedc14f48b9bf0423c1bfa69d7 GIT binary patch literal 413 zcmZQzXSlB4aC<$2VgLgd0~CbbVPG)egmA9^m;4U{UY=fF4smf_j4*`|`o9+g15nA{ zz509iax!StsUSBS=1tS?b@ZbYnM8RWMyDrU;<(UP;CIR9ja($X16dG2zD_f+0Sycw)4`y6VB7(-9+UpBeE0wV|4Z-Oxu)iElAXcW POrPaHCnyM%^_|@S$~Hur literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/fb06e9ed4a8e9580db46f444e44e63e6018eefc4 b/fuzz/corpus/fuzz_write/fb06e9ed4a8e9580db46f444e44e63e6018eefc4 new file mode 100644 index 0000000000000000000000000000000000000000..b3b4a635d037e87c6d4d6d5e5c23480a2c725422 GIT binary patch literal 445 zcmdP+uUE&w=B_B)tN8IKr?RrLl(Mptva&vq1p!k*60<=7Bnt$nvQQD_00ssIb_PX# zHg<0y3j&P6R09K88h*n;(*8eAGStGP7Fres$>p*7wSNpH5eDc2qvY4_m tPz)7J1#y9nr^KlZ4Grlw4YMvn0m)8PR#y9e^8bG`B$xgFPj-O10RZ5`P#*vQ literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/fb4e17df269f29003cc66731a7d9d71c704ba599 b/fuzz/corpus/fuzz_write/fb4e17df269f29003cc66731a7d9d71c704ba599 new file mode 100644 index 0000000000000000000000000000000000000000..483a295540e27bc47432cabbadd21577ae9f3a6c GIT binary patch literal 438 zcma)&O$x#=5QSfDZE+Lu04_>Egkl2X0Sba5+2lT=;CXrv!Q;4`MH!Q6q5j~{gJhAJ zy!Xv4*qo5>%Gt5JX;ITO%Wwv1-9{184QyUGPa>a@ONnZ-hS}KgX5{XQF6(P8E2_@k z?K7lSI*?BA*4au;(Rh?hJ@yVr2oNt=W)&>Rgm5jzNscca*=fsXF-A k>}b$$;E7Xajhyws`OrIT>)#o*p7WJ?y|Q2c1+=|v?{z)Xm;e9( literal 0 HcmV?d00001 diff --git a/fuzz/corpus/fuzz_write/fcda8512ce8f678cdbb10d685bd4c0c529dd2f06 b/fuzz/corpus/fuzz_write/fcda8512ce8f678cdbb10d685bd4c0c529dd2f06 new file mode 100644 index 0000000000000000000000000000000000000000..badd6026646a2f0258322385e1afb92409a12c86 GIT binary patch literal 444 zcmZ?pc5wLrpX)yg_>RKE!|@l`^$#K~zY7I0FlaG=0Z>+qK?TBYfKX8Kx&wo^VgM%t z1Ji##KEA$yYQw!;npGY^S^xj`Ky9M`&-_2L?*IRF3G0A>k%3_yP)dM-!8^d4jm?3Z zfep#DT@4HjAa_6hLS=s_`hqO_Z6l9Mh52p0F0Q+3;+NC literal 0 HcmV?d00001 From af5752b65f726862860549acb727682f1f489ae4 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sat, 11 May 2024 23:54:49 -0300 Subject: [PATCH 10/17] Add sync feature to Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0e85fef24..51fdebd12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,11 +68,11 @@ deflate = ["flate2/rust_backend", "_deflate-any"] # DEPRECATED: previously enabled `flate2/miniz_oxide` which is equivalent to `flate2/rust_backend` deflate-miniz = ["deflate", "_deflate-any"] - deflate-zlib = ["flate2/zlib", "_deflate-any"] deflate-zlib-ng = ["flate2/zlib-ng", "_deflate-any"] deflate-zopfli = ["zopfli", "_deflate-any"] lzma = ["lzma-rs/stream"] +sync = [] unreserved = [] default = [ "aes-crypto", From f871fff58f1e9bc7c2cd518e9829b6f6d2b6365e Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sat, 11 May 2024 23:56:18 -0300 Subject: [PATCH 11/17] Add initial error message for when io logic is missing do to feature missing --- src/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/build.rs b/src/build.rs index 26d9689e7..2e760975a 100644 --- a/src/build.rs +++ b/src/build.rs @@ -4,4 +4,6 @@ fn main() { if var("CARGO_FEATURE_DEFLATE_MINIZ").is_ok() && var("CARGO_FEATURE__ALL_FEATURES").is_err() { println!("cargo:warning=Feature `deflate-miniz` is deprecated; replace it with `deflate`"); } + #[cfg(not(any(feature = "sync")))] + compile_error!("Missing Required feature"); } From 951184a78e21598991795bfa5c685d6b6b37432a Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sun, 12 May 2024 23:00:21 -0300 Subject: [PATCH 12/17] Add sync and tokio features and sync is on default --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 51fdebd12..93404635b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ zstd = { version = "0.13.1", optional = true, default-features = false } zopfli = { version = "0.8.0", optional = true } deflate64 = { version = "0.1.8", optional = true } lzma-rs = { version = "0.3.0", default-features = false, optional = true } +true = { version = "0.1.0", optional = true } +tokio = { version = "1.37.0", optional = true } [target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies] crossbeam-utils = "0.8.19" @@ -73,6 +75,7 @@ deflate-zlib-ng = ["flate2/zlib-ng", "_deflate-any"] deflate-zopfli = ["zopfli", "_deflate-any"] lzma = ["lzma-rs/stream"] sync = [] +tokio = ["tokio/io-util"] unreserved = [] default = [ "aes-crypto", @@ -82,6 +85,7 @@ default = [ "deflate-zlib-ng", "deflate-zopfli", "lzma", + "sync", "time", "zstd", ] From ff97edd287941954284f57e4714844b49e9a8a4a Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sun, 12 May 2024 23:01:14 -0300 Subject: [PATCH 13/17] Add compile error for missing/conflicting features --- src/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/build.rs b/src/build.rs index 2e760975a..0d777101d 100644 --- a/src/build.rs +++ b/src/build.rs @@ -4,6 +4,9 @@ fn main() { if var("CARGO_FEATURE_DEFLATE_MINIZ").is_ok() && var("CARGO_FEATURE__ALL_FEATURES").is_err() { println!("cargo:warning=Feature `deflate-miniz` is deprecated; replace it with `deflate`"); } - #[cfg(not(any(feature = "sync")))] + #[cfg(not(any(feature = "sync", feature = "tokio")))] compile_error!("Missing Required feature"); + + #[cfg(all(feature = "sync", feature = "tokio"))] + compile_error!("The features sync and tokio cannot be used together") } From 8129f2e17ffbba7ff8f14228505d9d6293fb3fb3 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Sat, 18 May 2024 12:36:37 -0300 Subject: [PATCH 14/17] Finished rebasing to upstream/sync-async branch --- src/spec.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/spec.rs b/src/spec.rs index 893228e4e..03b15d74c 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "tokio")] +use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt}; + use crate::result::{ZipError, ZipResult}; use crate::unstable::{LittleEndianReadExt, LittleEndianWriteExt}; use core::mem::size_of_val; @@ -112,6 +115,7 @@ pub struct Zip64CentralDirectoryEndLocator { pub number_of_disks: u32, } +#[cfg(feature = "sync")] impl Zip64CentralDirectoryEndLocator { pub fn parse(reader: &mut T) -> ZipResult { let magic = reader.read_u32_le()?; @@ -140,6 +144,30 @@ impl Zip64CentralDirectoryEndLocator { } } +#[cfg(feature = "tokio")] +impl Zip64CentralDirectoryEndLocator { + pub async fn parse(reader: &mut T) -> ZipResult + where + T: AsyncRead + Unpin, + { + let magic = reader.read_u32_le().await?; + if magic != ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE { + return Err(ZipError::InvalidArchive( + "Invalid zip64 locator digital signature header", + )); + } + let disk_with_central_directory = reader.read_u32_le().await?; + let end_of_central_directory_offset = reader.read_u64_le().await?; + let number_of_disks = reader.read_u32_le().await?; + + Ok(Self { + disk_with_central_directory, + end_of_central_directory_offset, + number_of_disks, + }) + } +} + pub struct Zip64CentralDirectoryEnd { pub version_made_by: u16, pub version_needed_to_extract: u16, @@ -152,6 +180,7 @@ pub struct Zip64CentralDirectoryEnd { //pub extensible_data_sector: Vec, <-- We don't do anything with this at the moment. } +#[cfg(feature = "sync")] impl Zip64CentralDirectoryEnd { pub fn find_and_parse( reader: &mut T, @@ -227,6 +256,69 @@ impl Zip64CentralDirectoryEnd { } } +#[cfg(feature = "tokio")] +impl Zip64CentralDirectoryEnd { + pub async fn find_and_parse( + reader: &mut T, + nominal_offset: u64, + search_upper_bound: u64, + ) -> ZipResult> + where + T: AsyncRead + AsyncSeek + Unpin, + { + let mut results = Vec::new(); + let mut pos = search_upper_bound; + + while pos >= nominal_offset { + let mut have_signature = false; + reader.seek(tokio::io::SeekFrom::Start(pos)).await?; + if reader.read_u32_le().await? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE { + have_signature = true; + let archive_offset = pos - nominal_offset; + + let _record_size = reader.read_u64_le().await?; + let version_made_by = reader.read_u16_le().await?; + let version_needed_to_extract = reader.read_u16_le().await?; + let disk_number = reader.read_u32_le().await?; + let disk_with_central_directory = reader.read_u32_le().await?; + let number_of_files_on_this_disk = reader.read_u64_le().await?; + let number_of_files = reader.read_u64_le().await?; + let central_directory_size = reader.read_u64_le().await?; + let central_directory_offset = reader.read_u64_le().await?; + + results.push(( + Self { + version_made_by, + version_needed_to_extract, + disk_number, + disk_with_central_directory, + number_of_files_on_this_disk, + number_of_files, + central_directory_size, + central_directory_offset, + }, + archive_offset, + )); + } + pos = match pos.checked_sub(if have_signature { + size_of_val(&ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE) as u64 + } else { + 1 + }) { + None => break, + Some(p) => p, + } + } + if results.is_empty() { + Err(ZipError::InvalidArchive( + "Could not find ZIP64 central directory end", + )) + } else { + Ok(results) + } + } +} + pub(crate) fn is_dir(filename: &str) -> bool { filename .chars() From c95da50a7893c1bc8e04ce3d876e33c96986aef8 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Mon, 13 May 2024 22:38:33 -0300 Subject: [PATCH 15/17] Move synchronous code into sync submodule --- src/read.rs | 3 + src/read/tokio.rs | 328 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 src/read/tokio.rs diff --git a/src/read.rs b/src/read.rs index 00649f60f..b36a339e4 100644 --- a/src/read.rs +++ b/src/read.rs @@ -3,6 +3,9 @@ /// Module for code with synchronous logic pub mod sync; +/// Module for code with asynchronous logic +pub mod tokio; + #[cfg(feature = "aes-crypto")] use crate::{aes::AesReaderValid, types::AesVendorVersion}; use crate::{crc32::Crc32Reader, types::ZipFileData, zipcrypto::ZipCryptoReaderValid}; diff --git a/src/read/tokio.rs b/src/read/tokio.rs new file mode 100644 index 000000000..f22a2de76 --- /dev/null +++ b/src/read/tokio.rs @@ -0,0 +1,328 @@ +use indexmap::IndexMap; +use std::{ + io::Cursor, + sync::{Arc, OnceLock}, +}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, SeekFrom}; + +use crate::{ + extra_fields::ExtendedTimestamp, + result::{ZipError, ZipResult}, + spec, + cp437::FromCp437, + types::{AesVendorVersion, System, ZipFileData}, + AesMode, CompressionMethod, DateTime, ExtraField, ZipArchive, +}; + +use super::CentralDirectoryInfo; + +impl ZipArchive +where + R: AsyncRead + AsyncSeek + Unpin, +{ + pub(crate) async fn merge_contents( + &mut self, + mut w: W, + ) -> ZipResult, ZipFileData>> + where + W: AsyncWrite + AsyncSeek + Unpin, + { + if self.shared.files.is_empty() { + return Ok(IndexMap::new()); + } + let mut new_files = self.shared.files.clone(); + + let new_initial_header_start = w.stream_position().await?; + new_files.values_mut().try_for_each(|f| { + f.header_start = f.header_start.checked_add(new_initial_header_start).ok_or( + ZipError::InvalidArchive("new header start from merge would have been to large"), + )?; + f.central_header_start = 0; + + if let Some(old_data_start) = f.data_start.take() { + let new_data_start = old_data_start.checked_add(new_initial_header_start).ok_or( + ZipError::InvalidArchive("new data start from merge would have been to large"), + )?; + f.data_start.get_or_init(|| new_data_start); + } + Ok::<_, ZipError>(()) + })?; + + self.reader.rewind().await?; + + let length_to_read = self.shared.dir_start; + + let mut limited_raw = (&mut self.reader as &mut R).take(length_to_read); + tokio::io::copy(&mut limited_raw, &mut w).await?; + + Ok(new_files) + } + + async fn get_directory_info_zip32( + footer: &spec::CentralDirectoryEnd, + cde_start_pos: u64, + ) -> ZipResult { + let archive_offset = cde_start_pos + .checked_sub(footer.central_directory_size as u64) + .and_then(|x| x.checked_sub(footer.central_directory_offset as u64)) + .ok_or(ZipError::InvalidArchive( + "Invalid central directory size or offset", + ))?; + let directory_start = footer.central_directory_offset as u64 + archive_offset; + let number_of_files = footer.number_of_files_on_this_disk as usize; + + Ok(CentralDirectoryInfo { + archive_offset, + directory_start, + number_of_files, + disk_number: footer.disk_number as u32, + disk_with_central_directory: footer.disk_with_central_directory as u32, + }) + } + + pub async fn get_directory_info_zip64( + reader: &mut R, + footer: &spec::CentralDirectoryEnd, + cde_start_pos: u64, + ) -> ZipResult>> { + reader + .seek(tokio::io::SeekFrom::End( + -(20 + 22 + footer.zip_file_comment.len() as i64), + )) + .await?; + + let locator64 = spec::Zip64CentralDirectoryEndLocator::parse(reader).await?; + + let search_upper_bound = cde_start_pos + .checked_sub(60) + .ok_or(ZipError::InvalidArchive( + "File cannot contain ZIP64 central directory end", + ))?; + + let search_results = spec::Zip64CentralDirectoryEnd::find_and_parse( + reader, + locator64.end_of_central_directory_offset, + search_upper_bound, + ) + .await?; + + let results: Vec> = search_results.iter().map(|(footer64, archive_offset)| { + let directory_start_result = footer64.central_directory_offset.checked_add(*archive_offset).ok_or(ZipError::InvalidArchive("Invalid central directory size or effect")); + directory_start_result.and_then(| directory_start| { + if directory_start > search_upper_bound { + Err(ZipError::InvalidArchive("Invalid central directory size or offset")) + } else if footer64.number_of_files_on_this_disk > footer64.number_of_files { + Err(ZipError::InvalidArchive("ZIP64 footer indicates more files on this disk then in the whole archive")) + } else if footer64.version_needed_to_extract > footer64.version_made_by { + Err(ZipError::InvalidArchive("ZIP64 footer indicates a new version is needed to extract this archive than the \ + version that wrote it")) + } else { + Ok(CentralDirectoryInfo { + archive_offset: *archive_offset, + directory_start, + number_of_files: footer64.number_of_files as usize, + disk_number: footer64.disk_number, + disk_with_central_directory: footer64.disk_with_central_directory + }) + } + }) + }).collect(); + Ok(results) + } +} + +pub(crate) async fn central_header_to_zip_file( + reader: &mut R, + archive_offset: u64, +) -> ZipResult +where + R: AsyncRead + AsyncSeek + Unpin, +{ + let central_header_start = reader.stream_position().await?; + + let signature = reader.read_u32_le().await?; + if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { + Err(ZipError::InvalidArchive("INvalid Central Directory header")) + } else { + central_header_to_zip_file_inner(reader, archive_offset, central_header_start).await + } +} + +async fn central_header_to_zip_file_inner( + reader: &mut R, + archive_offset: u64, + central_header_start: u64, +) -> ZipResult +where + R: AsyncRead + Unpin, +{ + let version_made_by = reader.read_u16_le().await?; + let _version_to_extract = reader.read_u16_le().await?; + let flags = reader.read_u16_le().await?; + let encrypted = flags & 1 == 1; + let is_utf8 = flags & (1 << 11) != 0; + let using_data_descriptor = flags & (1 << 3) != 0; + let compression_method = reader.read_u16_le().await?; + let last_mod_time = reader.read_u16_le().await?; + let last_mod_date = reader.read_u16_le().await?; + let crc32 = reader.read_u32_le().await?; + let compressed_size = reader.read_u32_le().await?; + let uncompressed_size = reader.read_u32_le().await?; + let file_name_length = reader.read_u16_le().await? as usize; + let extra_field_length = reader.read_u16_le().await? as usize; + let file_comment_length = reader.read_u16_le().await? as usize; + let _disk_number = reader.read_u16_le().await?; + let _internal_file_attributes = reader.read_u16_le().await?; + let external_file_attributes = reader.read_u32_le().await?; + let offset = reader.read_u32_le().await? as u64; + let mut file_name_raw = Vec::with_capacity(file_name_length); + let mut extra_field = Vec::with_capacity(extra_field_length); + let mut file_comment_raw = Vec::with_capacity(file_comment_length); + reader.read_exact(&mut file_name_raw).await?; + reader.read_exact(&mut extra_field).await?; + reader.read_exact(&mut file_comment_raw).await?; + + let file_name: Box = if is_utf8 { + String::from_utf8_lossy(&file_name_raw).into() + } else { + file_name_raw.from_cp437().into() + }; + let file_comment: Box = if is_utf8 { + String::from_utf8_lossy(&file_comment_raw).into() + } else { + file_comment_raw.from_cp437().into() + }; + + let mut result = ZipFileData { + system: System::from((version_made_by >> 8) as u8), + version_made_by: version_made_by as u8, + encrypted, + using_data_descriptor, + compression_method: { + #[allow(deprecated)] + CompressionMethod::from_u16(compression_method) + }, + compression_level: None, + last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), + crc32, + compressed_size: compressed_size as u64, + uncompressed_size: uncompressed_size as u64, + file_name, + file_name_raw: file_name_raw.into(), + extra_field: Some(Arc::new(extra_field)), + central_extra_field: None, + file_comment, + header_start: offset, + extra_data_start: None, + central_header_start, + data_start: OnceLock::new(), + external_attributes: external_file_attributes, + large_file: false, + aes_mode: None, + aes_extra_data_start: 0, + extra_fields: Vec::new(), + }; + + match parse_extra_field(&mut result).await { + Ok(..) | Err(ZipError::Io(..)) => {} + Err(err) => return Err(err), + } + + let aes_enabled = result.compression_method == CompressionMethod::AES; + if aes_enabled && result.aes_mode.is_none() { + return Err(ZipError::InvalidArchive( + "AES encryption without AES extra data field", + )); + } + + result.header_start = result + .header_start + .checked_add(archive_offset) + .ok_or(ZipError::InvalidArchive("Archive header is too large"))?; + Ok(result) +} + +pub async fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> { + let Some(extra_field) = &file.extra_field else { + return Ok(()); + }; + let mut reader = Cursor::new(extra_field.as_ref()); + + while (reader.position() as usize) < extra_field.len() { + let kind = reader.read_u16_le().await?; + let len = reader.read_u16_le().await?; + let mut len_left = len as i64; + match kind { + 0x001 => { + if file.uncompressed_size == spec::ZIP64_BYTES_THR { + file.large_file = true; + file.uncompressed_size = reader.read_u64_le().await?; + len_left -= 8; + } + if file.compressed_size == spec::ZIP64_BYTES_THR { + file.large_file = true; + file.compressed_size = reader.read_u64_le().await?; + len_left -= 8; + } + if file.header_start == spec::ZIP64_BYTES_THR { + file.header_start = reader.read_u64_le().await?; + len_left -= 8; + } + } + 0x9901 => { + if len != 7 { + return Err(ZipError::UnsupportedArchive( + "AES extra data field has an unsupported length", + )); + let vendor_version = reader.read_u16_le().await?; + let vendor_id = reader.read_u16_le().await?; + let mut out = [0u8]; + reader.read_exact(&mut out).await?; + let aes_mode = out[0]; + #[allow(deprecated)] + let compression_method = + CompressionMethod::from_u16(reader.read_u16_le().await?); + + if vendor_id != 0x4541 { + return Err(ZipError::InvalidArchive("Invalid AES vendor")); + } + let vendor_version = match vendor_version { + 0x0001 => AesVendorVersion::Ae1, + 0x0002 => AesVendorVersion::Ae2, + _ => return Err(ZipError::InvalidArchive("Invalid AES vendor version")), + }; + match aes_mode { + 0x01 => { + file.aes_mode = + Some((AesMode::Aes128, vendor_version, compression_method)) + } + 0x02 => { + file.aes_mode = + Some((AesMode::Aes192, vendor_version, compression_method)) + } + 0x03 => { + file.aes_mode = + Some((AesMode::Aes256, vendor_version, compression_method)) + } + _ => { + return Err(ZipError::InvalidArchive("Invalid AES encryption strength")) + } + }; + file.compression_method = compression_method; + } + } + 0x5455 => { + file.extra_fields.push(ExtraField::ExtendedTimestamp( + ExtendedTimestamp::try_from_reader(&mut reader, len)?, + )); + + len_left = 0; + } + _ => {} + } + if len_left > 0 { + reader.seek(SeekFrom::Current(len_left)).await?; + } + } + Ok(()) +} From 2e6053e91a0966d3f0b1090b18c3125ef7e7b414 Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Wed, 29 May 2024 15:10:17 -0300 Subject: [PATCH 16/17] Updated CI --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9762b3b47..c6f34d49c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,7 +21,7 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] rustalias: [stable, nightly, msrv] - feature_flag: ["--all-features", "--no-default-features", ""] + feature_flag: ["--no-default-features --features sync_all", "--no-default-features --features tokio_all", "--no-default-features --features sync", "--no-default-features --features tokio", ""] include: - rustalias: stable rust: stable From 794a1d099fc0f4240fac29615b969a5976f15eae Mon Sep 17 00:00:00 2001 From: SapryWenInera Date: Wed, 29 May 2024 15:11:46 -0300 Subject: [PATCH 17/17] Sync feature enablement --- Cargo.toml | 2 ++ src/read.rs | 2 ++ src/read/stream.rs | 1 + src/write.rs | 1 + 4 files changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index ebb53c756..29de3e387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,8 @@ deflate-zlib-ng = ["flate2/zlib-ng", "_deflate-any"] deflate-zopfli = ["zopfli", "_deflate-any"] lzma = ["lzma-rs/stream"] sync = [] +sync_all = ["aes-crypto", "chrono", "deflate", "deflate-miniz", "deflate-zlib", "deflate-zlib-ng", "deflate-zopfli", "lzma", "sync","time"] +tokio_all = ["aes-crypto", "chrono", "deflate", "deflate-miniz", "deflate-zlib", "deflate-zlib-ng", "deflate-zopfli", "lzma","time", "tokio"] tokio = ["tokio/io-util"] unreserved = [] default = [ diff --git a/src/read.rs b/src/read.rs index b36a339e4..25b155213 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,9 +1,11 @@ //! Types for reading ZIP archives /// Module for code with synchronous logic +#[cfg(feature = "sync")] pub mod sync; /// Module for code with asynchronous logic +#[cfg(feature = "tokio")] pub mod tokio; #[cfg(feature = "aes-crypto")] diff --git a/src/read/stream.rs b/src/read/stream.rs index 081b3c6f3..8c08d6754 100644 --- a/src/read/stream.rs +++ b/src/read/stream.rs @@ -9,6 +9,7 @@ use std::fs; use std::io::{self, Read}; use std::path::{Path, PathBuf}; +#[cfg(feature = "sync")] use super::sync::{central_header_to_zip_file_inner, read_zipfile_from_stream}; /// Stream decoder for zip. diff --git a/src/write.rs b/src/write.rs index 87f3a49e2..168c4abef 100644 --- a/src/write.rs +++ b/src/write.rs @@ -3,6 +3,7 @@ #[cfg(feature = "aes-crypto")] use crate::aes::AesWriter; use crate::compression::CompressionMethod; +#[cfg(feature = "sync")] use crate::read::{sync::find_content, ZipArchive, ZipFile, ZipFileReader}; use crate::result::{ZipError, ZipResult}; use crate::spec;