Merge branch 'master' into any-flate2-backend
This commit is contained in:
commit
e123567862
10 changed files with 78 additions and 31 deletions
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||||
rust: [stable]
|
rust: [stable, 1.34.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
|
|
|
@ -15,7 +15,7 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
flate2 = { version = "1.0", default-features = false, optional = true }
|
flate2 = { version = "1.0", default-features = false, optional = true }
|
||||||
time = { version = "0.1", optional = true }
|
time = { version = "0.1", optional = true }
|
||||||
podio = "0.1"
|
byteorder = "1.3"
|
||||||
bzip2 = { version = "0.3", optional = true }
|
bzip2 = { version = "0.3", optional = true }
|
||||||
crc32fast = "1.0"
|
crc32fast = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
11
README.md
11
README.md
|
@ -49,6 +49,17 @@ The features available are:
|
||||||
|
|
||||||
All of these are enabled by default.
|
All of these are enabled by default.
|
||||||
|
|
||||||
|
MSRV
|
||||||
|
----
|
||||||
|
|
||||||
|
Our current Minimum Supported Rust Version is **1.34.0**. When adding features,
|
||||||
|
we will follow these guidelines:
|
||||||
|
|
||||||
|
- We will always support the latest four minor Rust versions. This gives you a 6
|
||||||
|
month window to upgrade your compiler.
|
||||||
|
- Any change to the MSRV will be accompanied with a **minor** version bump
|
||||||
|
- While the crate is pre-1.0, this will be a change to the PATCH version.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
/// Compression methods for the contents of a ZIP file.
|
/// Compression methods for the contents of a ZIP file.
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum CompressionMethod {
|
pub enum CompressionMethod {
|
||||||
|
@ -18,12 +19,21 @@ pub enum CompressionMethod {
|
||||||
#[cfg(feature = "bzip2")]
|
#[cfg(feature = "bzip2")]
|
||||||
Bzip2,
|
Bzip2,
|
||||||
/// Unsupported compression method
|
/// Unsupported compression method
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.5.7",
|
||||||
|
note = "implementation details are being removed from the public API"
|
||||||
|
)]
|
||||||
Unsupported(u16),
|
Unsupported(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompressionMethod {
|
impl CompressionMethod {
|
||||||
/// Converts an u16 to its corresponding CompressionMethod
|
/// Converts an u16 to its corresponding CompressionMethod
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.5.7",
|
||||||
|
note = "implementation details are being removed from the public API"
|
||||||
|
)]
|
||||||
pub fn from_u16(val: u16) -> CompressionMethod {
|
pub fn from_u16(val: u16) -> CompressionMethod {
|
||||||
|
#[allow(deprecated)]
|
||||||
match val {
|
match val {
|
||||||
0 => CompressionMethod::Stored,
|
0 => CompressionMethod::Stored,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
|
@ -34,12 +44,18 @@ impl CompressionMethod {
|
||||||
8 => CompressionMethod::Deflated,
|
8 => CompressionMethod::Deflated,
|
||||||
#[cfg(feature = "bzip2")]
|
#[cfg(feature = "bzip2")]
|
||||||
12 => CompressionMethod::Bzip2,
|
12 => CompressionMethod::Bzip2,
|
||||||
|
|
||||||
v => CompressionMethod::Unsupported(v),
|
v => CompressionMethod::Unsupported(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a CompressionMethod to a u16
|
/// Converts a CompressionMethod to a u16
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.5.7",
|
||||||
|
note = "implementation details are being removed from the public API"
|
||||||
|
)]
|
||||||
pub fn to_u16(self) -> u16 {
|
pub fn to_u16(self) -> u16 {
|
||||||
|
#[allow(deprecated)]
|
||||||
match self {
|
match self {
|
||||||
CompressionMethod::Stored => 0,
|
CompressionMethod::Stored => 0,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
|
@ -69,7 +85,9 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn from_eq_to() {
|
fn from_eq_to() {
|
||||||
for v in 0..(::std::u16::MAX as u32 + 1) {
|
for v in 0..(::std::u16::MAX as u32 + 1) {
|
||||||
|
#[allow(deprecated)]
|
||||||
let from = CompressionMethod::from_u16(v as u16);
|
let from = CompressionMethod::from_u16(v as u16);
|
||||||
|
#[allow(deprecated)]
|
||||||
let to = from.to_u16() as u32;
|
let to = from.to_u16() as u32;
|
||||||
assert_eq!(v, to);
|
assert_eq!(v, to);
|
||||||
}
|
}
|
||||||
|
@ -92,8 +110,11 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn to_eq_from() {
|
fn to_eq_from() {
|
||||||
fn check_match(method: CompressionMethod) {
|
fn check_match(method: CompressionMethod) {
|
||||||
|
#[allow(deprecated)]
|
||||||
let to = method.to_u16();
|
let to = method.to_u16();
|
||||||
|
#[allow(deprecated)]
|
||||||
let from = CompressionMethod::from_u16(to);
|
let from = CompressionMethod::from_u16(to);
|
||||||
|
#[allow(deprecated)]
|
||||||
let back = from.to_u16();
|
let back = from.to_u16();
|
||||||
assert_eq!(to, back);
|
assert_eq!(to, back);
|
||||||
}
|
}
|
||||||
|
|
25
src/read.rs
25
src/read.rs
|
@ -11,7 +11,7 @@ use std::io::prelude::*;
|
||||||
|
|
||||||
use crate::cp437::FromCp437;
|
use crate::cp437::FromCp437;
|
||||||
use crate::types::{DateTime, System, ZipFileData};
|
use crate::types::{DateTime, System, ZipFileData};
|
||||||
use podio::{LittleEndian, ReadPodExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "deflate",
|
feature = "deflate",
|
||||||
|
@ -353,9 +353,12 @@ fn central_header_to_zip_file<R: Read + io::Seek>(
|
||||||
let _internal_file_attributes = reader.read_u16::<LittleEndian>()?;
|
let _internal_file_attributes = reader.read_u16::<LittleEndian>()?;
|
||||||
let external_file_attributes = reader.read_u32::<LittleEndian>()?;
|
let external_file_attributes = reader.read_u32::<LittleEndian>()?;
|
||||||
let offset = reader.read_u32::<LittleEndian>()? as u64;
|
let offset = reader.read_u32::<LittleEndian>()? as u64;
|
||||||
let file_name_raw = ReadPodExt::read_exact(reader, file_name_length)?;
|
let mut file_name_raw = vec![0; file_name_length];
|
||||||
let extra_field = ReadPodExt::read_exact(reader, extra_field_length)?;
|
reader.read_exact(&mut file_name_raw)?;
|
||||||
let file_comment_raw = ReadPodExt::read_exact(reader, file_comment_length)?;
|
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 = match is_utf8 {
|
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(),
|
||||||
|
@ -371,7 +374,10 @@ fn central_header_to_zip_file<R: Read + io::Seek>(
|
||||||
system: System::from_u8((version_made_by >> 8) as u8),
|
system: System::from_u8((version_made_by >> 8) as u8),
|
||||||
version_made_by: version_made_by as u8,
|
version_made_by: version_made_by as u8,
|
||||||
encrypted,
|
encrypted,
|
||||||
compression_method: CompressionMethod::from_u16(compression_method),
|
compression_method: {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
CompressionMethod::from_u16(compression_method)
|
||||||
|
},
|
||||||
last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time),
|
last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time),
|
||||||
crc32,
|
crc32,
|
||||||
compressed_size: compressed_size as u64,
|
compressed_size: compressed_size as u64,
|
||||||
|
@ -632,6 +638,7 @@ pub fn read_zipfile_from_stream<'a, R: io::Read>(
|
||||||
let encrypted = flags & 1 == 1;
|
let encrypted = flags & 1 == 1;
|
||||||
let is_utf8 = flags & (1 << 11) != 0;
|
let is_utf8 = flags & (1 << 11) != 0;
|
||||||
let using_data_descriptor = flags & (1 << 3) != 0;
|
let using_data_descriptor = flags & (1 << 3) != 0;
|
||||||
|
#[allow(deprecated)]
|
||||||
let compression_method = CompressionMethod::from_u16(reader.read_u16::<LittleEndian>()?);
|
let compression_method = CompressionMethod::from_u16(reader.read_u16::<LittleEndian>()?);
|
||||||
let last_mod_time = reader.read_u16::<LittleEndian>()?;
|
let last_mod_time = reader.read_u16::<LittleEndian>()?;
|
||||||
let last_mod_date = reader.read_u16::<LittleEndian>()?;
|
let last_mod_date = reader.read_u16::<LittleEndian>()?;
|
||||||
|
@ -641,8 +648,10 @@ pub fn read_zipfile_from_stream<'a, R: io::Read>(
|
||||||
let file_name_length = reader.read_u16::<LittleEndian>()? as usize;
|
let file_name_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||||
let extra_field_length = reader.read_u16::<LittleEndian>()? as usize;
|
let extra_field_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||||
|
|
||||||
let file_name_raw = ReadPodExt::read_exact(reader, file_name_length)?;
|
let mut file_name_raw = vec![0; file_name_length];
|
||||||
let extra_field = ReadPodExt::read_exact(reader, extra_field_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 = match is_utf8 {
|
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(),
|
||||||
|
@ -725,7 +734,7 @@ mod test {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
||||||
let reader = ZipArchive::new(io::Cursor::new(v)).unwrap();
|
let reader = ZipArchive::new(io::Cursor::new(v)).unwrap();
|
||||||
assert!(reader.comment() == b"zip-rs");
|
assert!(reader.comment() == b"");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::result::{ZipError, ZipResult};
|
use crate::result::{ZipError, ZipResult};
|
||||||
use podio::{LittleEndian, ReadPodExt, WritePodExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ impl CentralDirectoryEnd {
|
||||||
let central_directory_size = reader.read_u32::<LittleEndian>()?;
|
let central_directory_size = reader.read_u32::<LittleEndian>()?;
|
||||||
let central_directory_offset = reader.read_u32::<LittleEndian>()?;
|
let central_directory_offset = reader.read_u32::<LittleEndian>()?;
|
||||||
let zip_file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
|
let zip_file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||||
let zip_file_comment = ReadPodExt::read_exact(reader, zip_file_comment_length)?;
|
let mut zip_file_comment = vec![0; zip_file_comment_length];
|
||||||
|
reader.read_exact(&mut zip_file_comment)?;
|
||||||
|
|
||||||
Ok(CentralDirectoryEnd {
|
Ok(CentralDirectoryEnd {
|
||||||
disk_number,
|
disk_number,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//! Types that specify what is contained in a ZIP.
|
//! Types that specify what is contained in a ZIP.
|
||||||
|
|
||||||
#[non_exhaustive]
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum System {
|
pub enum System {
|
||||||
Dos = 0,
|
Dos = 0,
|
||||||
|
|
40
src/write.rs
40
src/write.rs
|
@ -4,8 +4,8 @@ use crate::compression::CompressionMethod;
|
||||||
use crate::result::{ZipError, ZipResult};
|
use crate::result::{ZipError, ZipResult};
|
||||||
use crate::spec;
|
use crate::spec;
|
||||||
use crate::types::{DateTime, System, ZipFileData, DEFAULT_VERSION};
|
use crate::types::{DateTime, System, ZipFileData, DEFAULT_VERSION};
|
||||||
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use crc32fast::Hasher;
|
use crc32fast::Hasher;
|
||||||
use podio::{LittleEndian, WritePodExt};
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
@ -192,7 +192,7 @@ impl<W: Write + io::Seek> ZipWriter<W> {
|
||||||
files: Vec::new(),
|
files: Vec::new(),
|
||||||
stats: Default::default(),
|
stats: Default::default(),
|
||||||
writing_to_file: false,
|
writing_to_file: false,
|
||||||
comment: "zip-rs".into(),
|
comment: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,23 +417,26 @@ impl<W: Write + io::Seek> GenericZipWriter<W> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
*self = match compression {
|
*self = {
|
||||||
CompressionMethod::Stored => GenericZipWriter::Storer(bare),
|
#[allow(deprecated)]
|
||||||
|
match compression {
|
||||||
|
CompressionMethod::Stored => GenericZipWriter::Storer(bare),
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "deflate",
|
feature = "deflate",
|
||||||
feature = "deflate-miniz",
|
feature = "deflate-miniz",
|
||||||
feature = "deflate-zlib"
|
feature = "deflate-zlib"
|
||||||
))]
|
))]
|
||||||
CompressionMethod::Deflated => GenericZipWriter::Deflater(DeflateEncoder::new(
|
CompressionMethod::Deflated => GenericZipWriter::Deflater(DeflateEncoder::new(
|
||||||
bare,
|
bare,
|
||||||
flate2::Compression::default(),
|
flate2::Compression::default(),
|
||||||
)),
|
)),
|
||||||
#[cfg(feature = "bzip2")]
|
#[cfg(feature = "bzip2")]
|
||||||
CompressionMethod::Bzip2 => {
|
CompressionMethod::Bzip2 => {
|
||||||
GenericZipWriter::Bzip2(BzEncoder::new(bare, bzip2::Compression::Default))
|
GenericZipWriter::Bzip2(BzEncoder::new(bare, bzip2::Compression::Default))
|
||||||
}
|
}
|
||||||
CompressionMethod::Unsupported(..) => {
|
CompressionMethod::Unsupported(..) => {
|
||||||
return Err(ZipError::UnsupportedArchive("Unsupported compression"))
|
return Err(ZipError::UnsupportedArchive("Unsupported compression"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -505,6 +508,7 @@ fn write_local_file_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipR
|
||||||
};
|
};
|
||||||
writer.write_u16::<LittleEndian>(flag)?;
|
writer.write_u16::<LittleEndian>(flag)?;
|
||||||
// Compression method
|
// Compression method
|
||||||
|
#[allow(deprecated)]
|
||||||
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
||||||
// last mod file time and last mod file date
|
// last mod file time and last mod file date
|
||||||
writer.write_u16::<LittleEndian>(file.last_modified_time.timepart())?;
|
writer.write_u16::<LittleEndian>(file.last_modified_time.timepart())?;
|
||||||
|
@ -556,6 +560,7 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
|
||||||
};
|
};
|
||||||
writer.write_u16::<LittleEndian>(flag)?;
|
writer.write_u16::<LittleEndian>(flag)?;
|
||||||
// compression method
|
// compression method
|
||||||
|
#[allow(deprecated)]
|
||||||
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
||||||
// last mod file time + date
|
// last mod file time + date
|
||||||
writer.write_u16::<LittleEndian>(file.last_modified_time.timepart())?;
|
writer.write_u16::<LittleEndian>(file.last_modified_time.timepart())?;
|
||||||
|
@ -645,7 +650,7 @@ mod test {
|
||||||
.write(b"writing to a directory is not allowed, and will not write any data")
|
.write(b"writing to a directory is not allowed, and will not write any data")
|
||||||
.is_err());
|
.is_err());
|
||||||
let result = writer.finish().unwrap();
|
let result = writer.finish().unwrap();
|
||||||
assert_eq!(result.get_ref().len(), 114);
|
assert_eq!(result.get_ref().len(), 108);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*result.get_ref(),
|
*result.get_ref(),
|
||||||
&[
|
&[
|
||||||
|
@ -653,7 +658,7 @@ mod test {
|
||||||
0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 47, 80, 75, 1, 2, 46, 3, 20, 0, 0, 0, 0, 0,
|
0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 47, 80, 75, 1, 2, 46, 3, 20, 0, 0, 0, 0, 0,
|
||||||
163, 165, 15, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
163, 165, 15, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 237, 65, 0, 0, 0, 0, 116, 101, 115, 116, 47, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0,
|
0, 0, 237, 65, 0, 0, 0, 0, 116, 101, 115, 116, 47, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0,
|
||||||
1, 0, 51, 0, 0, 0, 35, 0, 0, 0, 6, 0, 122, 105, 112, 45, 114, 115
|
1, 0, 51, 0, 0, 0, 35, 0, 0, 0, 0, 0,
|
||||||
] as &[u8]
|
] as &[u8]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -671,7 +676,8 @@ mod test {
|
||||||
.write(b"application/vnd.oasis.opendocument.text")
|
.write(b"application/vnd.oasis.opendocument.text")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let result = writer.finish().unwrap();
|
let result = writer.finish().unwrap();
|
||||||
assert_eq!(result.get_ref().len(), 159);
|
|
||||||
|
assert_eq!(result.get_ref().len(), 153);
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
v.extend_from_slice(include_bytes!("../tests/data/mimetype.zip"));
|
||||||
assert_eq!(result.get_ref(), &v);
|
assert_eq!(result.get_ref(), &v);
|
||||||
|
|
Binary file not shown.
|
@ -39,7 +39,7 @@ fn read_zip_file(zip_file: &mut Cursor<Vec<u8>>) -> zip::result::ZipResult<Strin
|
||||||
let mut archive = zip::ZipArchive::new(zip_file).unwrap();
|
let mut archive = zip::ZipArchive::new(zip_file).unwrap();
|
||||||
|
|
||||||
let expected_file_names = ["test/", "test/☃.txt", "test/lorem_ipsum.txt"];
|
let expected_file_names = ["test/", "test/☃.txt", "test/lorem_ipsum.txt"];
|
||||||
let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
|
let expected_file_names = HashSet::from_iter(expected_file_names.iter().map(|&v| v));
|
||||||
let file_names = archive.file_names().collect::<HashSet<_>>();
|
let file_names = archive.file_names().collect::<HashSet<_>>();
|
||||||
assert_eq!(file_names, expected_file_names);
|
assert_eq!(file_names, expected_file_names);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue