Upgrade zip to 0.6.4

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update rust/crates/zip
For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I27f08defe9ad73375fea1de1028cdf4ed9da500f
diff --git a/src/compression.rs b/src/compression.rs
index abd8b53..baec939 100644
--- a/src/compression.rs
+++ b/src/compression.rs
@@ -141,7 +141,7 @@
 impl fmt::Display for CompressionMethod {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Just duplicate what the Debug format looks like, i.e, the enum key:
-        write!(f, "{:?}", self)
+        write!(f, "{self:?}")
     }
 }
 
@@ -195,8 +195,8 @@
     #[test]
     fn to_display_fmt() {
         fn check_match(method: CompressionMethod) {
-            let debug_str = format!("{:?}", method);
-            let display_str = format!("{}", method);
+            let debug_str = format!("{method:?}");
+            let display_str = format!("{method}");
             assert_eq!(debug_str, display_str);
         }
 
diff --git a/src/read.rs b/src/read.rs
index 728ddf5..dad20c2 100644
--- a/src/read.rs
+++ b/src/read.rs
@@ -348,7 +348,9 @@
             Some(locator64) => {
                 // If we got here, this is indeed a ZIP64 file.
 
-                if footer.disk_number as u32 != locator64.disk_with_central_directory {
+                if !footer.record_too_small()
+                    && footer.disk_number as u32 != locator64.disk_with_central_directory
+                {
                     return unsupported_zip_error(
                         "Support for multi-disk files is not implemented",
                     );
@@ -401,7 +403,7 @@
     pub fn new(mut reader: R) -> ZipResult<ZipArchive<R>> {
         let (footer, cde_start_pos) = spec::CentralDirectoryEnd::find_and_parse(&mut reader)?;
 
-        if footer.disk_number != footer.disk_with_central_directory {
+        if !footer.record_too_small() && footer.disk_number != footer.disk_with_central_directory {
             return unsupported_zip_error("Support for multi-disk files is not implemented");
         }
 
@@ -461,7 +463,7 @@
             } else {
                 if let Some(p) = outpath.parent() {
                     if !p.exists() {
-                        fs::create_dir_all(&p)?;
+                        fs::create_dir_all(p)?;
                     }
                 }
                 let mut outfile = fs::File::create(&outpath)?;
@@ -681,11 +683,11 @@
     reader.read_exact(&mut file_comment_raw)?;
 
     let file_name = match is_utf8 {
-        true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
+        true => String::from_utf8_lossy(&file_name_raw).into_owned(),
         false => file_name_raw.clone().from_cp437(),
     };
     let file_comment = match is_utf8 {
-        true => String::from_utf8_lossy(&*file_comment_raw).into_owned(),
+        true => String::from_utf8_lossy(&file_comment_raw).into_owned(),
         false => file_comment_raw.from_cp437(),
     };
 
@@ -920,12 +922,12 @@
         self.data.compression_method
     }
 
-    /// Get the size of the file in the archive
+    /// 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 when uncompressed
+    /// Get the size of the file, in bytes, when uncompressed
     pub fn size(&self) -> u64 {
         self.data.uncompressed_size
     }
@@ -1085,7 +1087,7 @@
     reader.read_exact(&mut extra_field)?;
 
     let file_name = match is_utf8 {
-        true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
+        true => String::from_utf8_lossy(&file_name_raw).into_owned(),
         false => file_name_raw.clone().from_cp437(),
     };
 
@@ -1129,7 +1131,7 @@
         return unsupported_zip_error("The file length is not available in the local header");
     }
 
-    let limit_reader = (reader as &'a mut dyn io::Read).take(result.compressed_size as u64);
+    let limit_reader = (reader as &'a mut dyn io::Read).take(result.compressed_size);
 
     let result_crc32 = result.crc32;
     let result_compression_method = result.compression_method;
diff --git a/src/result.rs b/src/result.rs
index 72a30e4..00d558c 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -44,9 +44,9 @@
 impl fmt::Display for ZipError {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            ZipError::Io(err) => write!(fmt, "{}", err),
-            ZipError::InvalidArchive(err) => write!(fmt, "invalid Zip archive: {}", err),
-            ZipError::UnsupportedArchive(err) => write!(fmt, "unsupported Zip archive: {}", err),
+            ZipError::Io(err) => write!(fmt, "{err}"),
+            ZipError::InvalidArchive(err) => write!(fmt, "invalid Zip archive: {err}"),
+            ZipError::UnsupportedArchive(err) => write!(fmt, "unsupported Zip archive: {err}"),
             ZipError::FileNotFound => write!(fmt, "specified file not found in archive"),
         }
     }
@@ -81,3 +81,18 @@
         io::Error::new(io::ErrorKind::Other, err)
     }
 }
+
+/// Error type for time parsing
+#[derive(Debug)]
+pub struct DateTimeRangeError;
+
+impl fmt::Display for DateTimeRangeError {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            fmt,
+            "a date could not be represented within the bounds the MS-DOS date range (1980-2107)"
+        )
+    }
+}
+
+impl Error for DateTimeRangeError {}
diff --git a/src/spec.rs b/src/spec.rs
index 3ffcf73..1d8cb0a 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -23,6 +23,18 @@
 }
 
 impl CentralDirectoryEnd {
+    // Per spec 4.4.1.4 - a CentralDirectoryEnd field might be insufficient to hold the
+    // required data. In this case the file SHOULD contain a ZIP64 format record
+    // and the field of this record will be set to -1
+    pub(crate) fn record_too_small(&self) -> bool {
+        self.disk_number == 0xFFFF
+            || self.disk_with_central_directory == 0xFFFF
+            || self.number_of_files_on_this_disk == 0xFFFF
+            || self.number_of_files == 0xFFFF
+            || self.central_directory_size == 0xFFFFFFFF
+            || self.central_directory_offset == 0xFFFFFFFF
+    }
+
     pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> {
         let magic = reader.read_u32::<LittleEndian>()?;
         if magic != CENTRAL_DIRECTORY_END_SIGNATURE {
@@ -64,12 +76,12 @@
 
         let mut pos = file_length - HEADER_SIZE;
         while pos >= search_upper_bound {
-            reader.seek(io::SeekFrom::Start(pos as u64))?;
+            reader.seek(io::SeekFrom::Start(pos))?;
             if reader.read_u32::<LittleEndian>()? == CENTRAL_DIRECTORY_END_SIGNATURE {
                 reader.seek(io::SeekFrom::Current(
                     BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64,
                 ))?;
-                let cde_start_pos = reader.seek(io::SeekFrom::Start(pos as u64))?;
+                let cde_start_pos = reader.seek(io::SeekFrom::Start(pos))?;
                 return CentralDirectoryEnd::parse(reader).map(|cde| (cde, cde_start_pos));
             }
             pos = match pos.checked_sub(1) {
diff --git a/src/types.rs b/src/types.rs
index b65fad4..ad3a570 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,13 +1,16 @@
 //! Types that specify what is contained in a ZIP.
-#[cfg(doc)]
-use {crate::read::ZipFile, crate::write::FileOptions};
-
+#[cfg(feature = "time")]
+use std::convert::{TryFrom, TryInto};
 #[cfg(not(any(
     all(target_arch = "arm", target_pointer_width = "32"),
     target_arch = "mips",
     target_arch = "powerpc"
 )))]
 use std::sync::atomic;
+#[cfg(not(feature = "time"))]
+use std::time::SystemTime;
+#[cfg(doc)]
+use {crate::read::ZipFile, crate::write::FileOptions};
 
 #[cfg(any(
     all(target_arch = "arm", target_pointer_width = "32"),
@@ -42,9 +45,11 @@
 }
 
 #[cfg(feature = "time")]
+use crate::result::DateTimeRangeError;
+#[cfg(feature = "time")]
 use time::{error::ComponentRange, Date, Month, OffsetDateTime, PrimitiveDateTime, Time};
 
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum System {
     Dos = 0,
     Unix = 3,
@@ -115,7 +120,7 @@
         let years = (datepart & 0b1111111000000000) >> 9;
 
         DateTime {
-            year: (years + 1980) as u16,
+            year: years + 1980,
             month: months as u8,
             day: days as u8,
             hour: hours as u8,
@@ -143,10 +148,8 @@
         second: u8,
     ) -> Result<DateTime, ()> {
         if (1980..=2107).contains(&year)
-            && month >= 1
-            && month <= 12
-            && day >= 1
-            && day <= 31
+            && (1..=12).contains(&month)
+            && (1..=31).contains(&day)
             && hour <= 23
             && minute <= 59
             && second <= 60
@@ -169,19 +172,9 @@
     ///
     /// Returns `Err` when this object is out of bounds
     #[allow(clippy::result_unit_err)]
+    #[deprecated(note = "use `DateTime::try_from()`")]
     pub fn from_time(dt: OffsetDateTime) -> Result<DateTime, ()> {
-        if dt.year() >= 1980 && dt.year() <= 2107 {
-            Ok(DateTime {
-                year: (dt.year()) as u16,
-                month: (dt.month()) as u8,
-                day: dt.day() as u8,
-                hour: dt.hour() as u8,
-                minute: dt.minute() as u8,
-                second: dt.second() as u8,
-            })
-        } else {
-            Err(())
-        }
+        dt.try_into().map_err(|_err| ())
     }
 
     /// Gets the time portion of this datetime in the msdos representation
@@ -197,8 +190,6 @@
     #[cfg(feature = "time")]
     /// Converts the DateTime to a OffsetDateTime structure
     pub fn to_time(&self) -> Result<OffsetDateTime, ComponentRange> {
-        use std::convert::TryFrom;
-
         let date =
             Date::from_calendar_date(self.year as i32, Month::try_from(self.month)?, self.day)?;
         let time = Time::from_hms(self.hour, self.minute, self.second)?;
@@ -256,6 +247,26 @@
     }
 }
 
+#[cfg(feature = "time")]
+impl TryFrom<OffsetDateTime> for DateTime {
+    type Error = DateTimeRangeError;
+
+    fn try_from(dt: OffsetDateTime) -> Result<Self, Self::Error> {
+        if dt.year() >= 1980 && dt.year() <= 2107 {
+            Ok(DateTime {
+                year: (dt.year()) as u16,
+                month: (dt.month()) as u8,
+                day: dt.day(),
+                hour: dt.hour(),
+                minute: dt.minute(),
+                second: dt.second(),
+            })
+        } else {
+            Err(DateTimeRangeError)
+        }
+    }
+}
+
 pub const DEFAULT_VERSION: u8 = 46;
 
 /// A type like `AtomicU64` except it implements `Clone` and has predefined
@@ -500,20 +511,43 @@
     #[cfg(feature = "time")]
     #[test]
     fn datetime_from_time_bounds() {
+        use std::convert::TryFrom;
+
         use super::DateTime;
         use time::macros::datetime;
 
         // 1979-12-31 23:59:59
-        assert!(DateTime::from_time(datetime!(1979-12-31 23:59:59 UTC)).is_err());
+        assert!(DateTime::try_from(datetime!(1979-12-31 23:59:59 UTC)).is_err());
 
         // 1980-01-01 00:00:00
-        assert!(DateTime::from_time(datetime!(1980-01-01 00:00:00 UTC)).is_ok());
+        assert!(DateTime::try_from(datetime!(1980-01-01 00:00:00 UTC)).is_ok());
 
         // 2107-12-31 23:59:59
-        assert!(DateTime::from_time(datetime!(2107-12-31 23:59:59 UTC)).is_ok());
+        assert!(DateTime::try_from(datetime!(2107-12-31 23:59:59 UTC)).is_ok());
 
         // 2108-01-01 00:00:00
-        assert!(DateTime::from_time(datetime!(2108-01-01 00:00:00 UTC)).is_err());
+        assert!(DateTime::try_from(datetime!(2108-01-01 00:00:00 UTC)).is_err());
+    }
+
+    #[cfg(feature = "time")]
+    #[test]
+    fn datetime_try_from_bounds() {
+        use std::convert::TryFrom;
+
+        use super::DateTime;
+        use time::macros::datetime;
+
+        // 1979-12-31 23:59:59
+        assert!(DateTime::try_from(datetime!(1979-12-31 23:59:59 UTC)).is_err());
+
+        // 1980-01-01 00:00:00
+        assert!(DateTime::try_from(datetime!(1980-01-01 00:00:00 UTC)).is_ok());
+
+        // 2107-12-31 23:59:59
+        assert!(DateTime::try_from(datetime!(2107-12-31 23:59:59 UTC)).is_ok());
+
+        // 2108-01-01 00:00:00
+        assert!(DateTime::try_from(datetime!(2108-01-01 00:00:00 UTC)).is_err());
     }
 
     #[test]
@@ -564,10 +598,11 @@
     #[test]
     fn time_at_january() {
         use super::DateTime;
+        use std::convert::TryFrom;
 
         // 2020-01-01 00:00:00
         let clock = OffsetDateTime::from_unix_timestamp(1_577_836_800).unwrap();
 
-        assert!(DateTime::from_time(clock).is_ok());
+        assert!(DateTime::try_from(clock).is_ok());
     }
 }
diff --git a/src/write.rs b/src/write.rs
index 61ce378..14252b4 100644
--- a/src/write.rs
+++ b/src/write.rs
@@ -7,6 +7,7 @@
 use crate::types::{AtomicU64, DateTime, System, ZipFileData, DEFAULT_VERSION};
 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 use crc32fast::Hasher;
+use std::convert::TryInto;
 use std::default::Default;
 use std::io;
 use std::io::prelude::*;
@@ -110,31 +111,6 @@
 }
 
 impl FileOptions {
-    /// Construct a new FileOptions object
-    pub fn default() -> FileOptions {
-        FileOptions {
-            #[cfg(any(
-                feature = "deflate",
-                feature = "deflate-miniz",
-                feature = "deflate-zlib"
-            ))]
-            compression_method: CompressionMethod::Deflated,
-            #[cfg(not(any(
-                feature = "deflate",
-                feature = "deflate-miniz",
-                feature = "deflate-zlib"
-            )))]
-            compression_method: CompressionMethod::Stored,
-            compression_level: None,
-            #[cfg(feature = "time")]
-            last_modified_time: DateTime::from_time(OffsetDateTime::now_utc()).unwrap_or_default(),
-            #[cfg(not(feature = "time"))]
-            last_modified_time: DateTime::default(),
-            permissions: None,
-            large_file: false,
-        }
-    }
-
     /// Set the compression method for the new file
     ///
     /// The default is `CompressionMethod::Deflated`. If the deflate compression feature is
@@ -198,8 +174,29 @@
 }
 
 impl Default for FileOptions {
+    /// Construct a new FileOptions object
     fn default() -> Self {
-        Self::default()
+        Self {
+            #[cfg(any(
+                feature = "deflate",
+                feature = "deflate-miniz",
+                feature = "deflate-zlib"
+            ))]
+            compression_method: CompressionMethod::Deflated,
+            #[cfg(not(any(
+                feature = "deflate",
+                feature = "deflate-miniz",
+                feature = "deflate-zlib"
+            )))]
+            compression_method: CompressionMethod::Stored,
+            compression_level: None,
+            #[cfg(feature = "time")]
+            last_modified_time: OffsetDateTime::now_utc().try_into().unwrap_or_default(),
+            #[cfg(not(feature = "time"))]
+            last_modified_time: DateTime::default(),
+            permissions: None,
+            large_file: false,
+        }
     }
 }
 
@@ -848,7 +845,7 @@
     fn drop(&mut self) {
         if !self.inner.is_closed() {
             if let Err(e) = self.finalize() {
-                let _ = write!(io::stderr(), "ZipWriter drop failed: {:?}", e);
+                let _ = write!(io::stderr(), "ZipWriter drop failed: {e:?}");
             }
         }
     }
@@ -1211,8 +1208,7 @@
                 return Err(ZipError::Io(io::Error::new(
                     io::ErrorKind::Other,
                     format!(
-                        "Extra data header ID {:#06} requires crate feature \"unreserved\"",
-                        kind,
+                        "Extra data header ID {kind:#06} requires crate feature \"unreserved\"",
                     ),
                 )));
             }
@@ -1301,7 +1297,7 @@
             if !path_str.is_empty() {
                 path_str.push('/');
             }
-            path_str.push_str(&*os_str.to_string_lossy());
+            path_str.push_str(&os_str.to_string_lossy());
         }
     }
     path_str