refactor: Remove byteorder dependency (#83)
This commit is contained in:
parent
90dc62ba18
commit
84ae5fc157
8 changed files with 193 additions and 145 deletions
|
@ -23,7 +23,6 @@ time = { version = "0.3.36", default-features = false }
|
|||
|
||||
[dependencies]
|
||||
aes = { version = "0.8.4", optional = true }
|
||||
byteorder = "1.5.0"
|
||||
bzip2 = { version = "0.4.4", optional = true }
|
||||
chrono = { version = "0.4.38", optional = true }
|
||||
constant_time_eq = { version = "0.3.0", optional = true }
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
//! different byte order (little endian) than NIST (big endian).
|
||||
//! See [AesCtrZipKeyStream] for more information.
|
||||
|
||||
use crate::unstable::LittleEndianWriteExt;
|
||||
use aes::cipher::generic_array::GenericArray;
|
||||
use aes::cipher::{BlockEncrypt, KeyInit};
|
||||
use byteorder::WriteBytesExt;
|
||||
use std::{any, fmt};
|
||||
|
||||
/// Internal block size of an AES cipher.
|
||||
|
@ -112,7 +112,7 @@ where
|
|||
// Note: AES block size is always 16 bytes, same as u128.
|
||||
self.buffer
|
||||
.as_mut()
|
||||
.write_u128::<byteorder::LittleEndian>(self.counter)
|
||||
.write_u128_le(self.counter)
|
||||
.expect("did not expect u128 le conversion to fail");
|
||||
self.cipher
|
||||
.encrypt_block(GenericArray::from_mut_slice(&mut self.buffer));
|
||||
|
|
84
src/read.rs
84
src/read.rs
|
@ -11,7 +11,6 @@ use crate::result::{ZipError, ZipResult};
|
|||
use crate::spec;
|
||||
use crate::types::{AesMode, AesVendorVersion, DateTime, System, ZipFileData};
|
||||
use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{self, prelude::*};
|
||||
|
@ -87,6 +86,7 @@ pub(crate) mod zip_archive {
|
|||
use crate::read::lzma::LzmaDecoder;
|
||||
use crate::result::ZipError::InvalidPassword;
|
||||
use crate::spec::path_to_string;
|
||||
use crate::unstable::LittleEndianReadExt;
|
||||
pub use zip_archive::ZipArchive;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
|
@ -210,15 +210,15 @@ pub(crate) fn find_content<'a>(
|
|||
) -> ZipResult<io::Take<&'a mut dyn Read>> {
|
||||
// Parse local header
|
||||
reader.seek(io::SeekFrom::Start(data.header_start))?;
|
||||
let signature = reader.read_u32::<LittleEndian>()?;
|
||||
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::<LittleEndian>()? as u64;
|
||||
let extra_field_length = reader.read_u16::<LittleEndian>()? as u64;
|
||||
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;
|
||||
|
@ -762,7 +762,7 @@ pub(crate) fn central_header_to_zip_file<R: Read + Seek>(
|
|||
let central_header_start = reader.stream_position()?;
|
||||
|
||||
// Parse central header
|
||||
let signature = reader.read_u32::<LittleEndian>()?;
|
||||
let signature = reader.read_u32_le()?;
|
||||
if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE {
|
||||
Err(ZipError::InvalidArchive("Invalid Central Directory header"))
|
||||
} else {
|
||||
|
@ -776,25 +776,25 @@ fn central_header_to_zip_file_inner<R: Read>(
|
|||
archive_offset: u64,
|
||||
central_header_start: u64,
|
||||
) -> ZipResult<ZipFileData> {
|
||||
let version_made_by = reader.read_u16::<LittleEndian>()?;
|
||||
let _version_to_extract = reader.read_u16::<LittleEndian>()?;
|
||||
let flags = reader.read_u16::<LittleEndian>()?;
|
||||
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::<LittleEndian>()?;
|
||||
let last_mod_time = reader.read_u16::<LittleEndian>()?;
|
||||
let last_mod_date = reader.read_u16::<LittleEndian>()?;
|
||||
let crc32 = reader.read_u32::<LittleEndian>()?;
|
||||
let compressed_size = reader.read_u32::<LittleEndian>()?;
|
||||
let uncompressed_size = reader.read_u32::<LittleEndian>()?;
|
||||
let file_name_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
let extra_field_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
let file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
let _disk_number = reader.read_u16::<LittleEndian>()?;
|
||||
let _internal_file_attributes = reader.read_u16::<LittleEndian>()?;
|
||||
let external_file_attributes = reader.read_u32::<LittleEndian>()?;
|
||||
let offset = reader.read_u32::<LittleEndian>()? as u64;
|
||||
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];
|
||||
|
@ -868,24 +868,24 @@ fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> {
|
|||
let mut reader = io::Cursor::new(extra_field.as_ref());
|
||||
|
||||
while (reader.position() as usize) < extra_field.len() {
|
||||
let kind = reader.read_u16::<LittleEndian>()?;
|
||||
let len = reader.read_u16::<LittleEndian>()?;
|
||||
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::<LittleEndian>()?;
|
||||
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::<LittleEndian>()?;
|
||||
file.compressed_size = reader.read_u64_le()?;
|
||||
len_left -= 8;
|
||||
}
|
||||
if file.header_start == spec::ZIP64_BYTES_THR {
|
||||
file.header_start = reader.read_u64::<LittleEndian>()?;
|
||||
file.header_start = reader.read_u64_le()?;
|
||||
len_left -= 8;
|
||||
}
|
||||
}
|
||||
|
@ -896,10 +896,12 @@ fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> {
|
|||
"AES extra data field has an unsupported length",
|
||||
));
|
||||
}
|
||||
let vendor_version = reader.read_u16::<LittleEndian>()?;
|
||||
let vendor_id = reader.read_u16::<LittleEndian>()?;
|
||||
let aes_mode = reader.read_u8()?;
|
||||
let compression_method = reader.read_u16::<LittleEndian>()?;
|
||||
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];
|
||||
let compression_method = reader.read_u16_le()?;
|
||||
|
||||
if vendor_id != 0x4541 {
|
||||
return Err(ZipError::InvalidArchive("Invalid AES vendor"));
|
||||
|
@ -1163,7 +1165,7 @@ impl<'a> Drop for ZipFile<'a> {
|
|||
/// * `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<Option<ZipFile<'_>>> {
|
||||
let signature = reader.read_u32::<LittleEndian>()?;
|
||||
let signature = reader.read_u32_le()?;
|
||||
|
||||
match signature {
|
||||
spec::LOCAL_FILE_HEADER_SIGNATURE => (),
|
||||
|
@ -1171,20 +1173,20 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult<Opt
|
|||
_ => return Err(ZipError::InvalidArchive("Invalid local file header")),
|
||||
}
|
||||
|
||||
let version_made_by = reader.read_u16::<LittleEndian>()?;
|
||||
let flags = reader.read_u16::<LittleEndian>()?;
|
||||
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::<LittleEndian>()?);
|
||||
let last_mod_time = reader.read_u16::<LittleEndian>()?;
|
||||
let last_mod_date = reader.read_u16::<LittleEndian>()?;
|
||||
let crc32 = reader.read_u32::<LittleEndian>()?;
|
||||
let compressed_size = reader.read_u32::<LittleEndian>()?;
|
||||
let uncompressed_size = reader.read_u32::<LittleEndian>()?;
|
||||
let file_name_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
let extra_field_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
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)?;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::unstable::LittleEndianReadExt;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -7,8 +8,6 @@ use super::{
|
|||
ZipFileData, ZipResult,
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
|
||||
/// Stream decoder for zip.
|
||||
#[derive(Debug)]
|
||||
pub struct ZipStreamReader<R>(R);
|
||||
|
@ -28,7 +27,7 @@ impl<R: Read> ZipStreamReader<R> {
|
|||
let central_header_start = 0;
|
||||
|
||||
// Parse central header
|
||||
let signature = self.0.read_u32::<LittleEndian>()?;
|
||||
let signature = self.0.read_u32_le()?;
|
||||
if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE {
|
||||
Ok(None)
|
||||
} else {
|
||||
|
|
92
src/spec.rs
92
src/spec.rs
|
@ -1,5 +1,5 @@
|
|||
use crate::result::{ZipError, ZipResult};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use crate::unstable::{LittleEndianReadExt, LittleEndianWriteExt};
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
@ -26,17 +26,17 @@ pub struct CentralDirectoryEnd {
|
|||
|
||||
impl CentralDirectoryEnd {
|
||||
pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> {
|
||||
let magic = reader.read_u32::<LittleEndian>()?;
|
||||
let magic = reader.read_u32_le()?;
|
||||
if magic != CENTRAL_DIRECTORY_END_SIGNATURE {
|
||||
return Err(ZipError::InvalidArchive("Invalid digital signature header"));
|
||||
}
|
||||
let disk_number = reader.read_u16::<LittleEndian>()?;
|
||||
let disk_with_central_directory = reader.read_u16::<LittleEndian>()?;
|
||||
let number_of_files_on_this_disk = reader.read_u16::<LittleEndian>()?;
|
||||
let number_of_files = reader.read_u16::<LittleEndian>()?;
|
||||
let central_directory_size = reader.read_u32::<LittleEndian>()?;
|
||||
let central_directory_offset = reader.read_u32::<LittleEndian>()?;
|
||||
let zip_file_comment_length = reader.read_u16::<LittleEndian>()? as usize;
|
||||
let disk_number = reader.read_u16_le()?;
|
||||
let disk_with_central_directory = reader.read_u16_le()?;
|
||||
let number_of_files_on_this_disk = reader.read_u16_le()?;
|
||||
let number_of_files = reader.read_u16_le()?;
|
||||
let central_directory_size = reader.read_u32_le()?;
|
||||
let central_directory_offset = reader.read_u32_le()?;
|
||||
let zip_file_comment_length = reader.read_u16_le()? as usize;
|
||||
let mut zip_file_comment = vec![0; zip_file_comment_length];
|
||||
reader.read_exact(&mut zip_file_comment)?;
|
||||
|
||||
|
@ -65,7 +65,7 @@ impl CentralDirectoryEnd {
|
|||
let mut pos = file_length - HEADER_SIZE;
|
||||
while pos >= search_upper_bound {
|
||||
reader.seek(io::SeekFrom::Start(pos))?;
|
||||
if reader.read_u32::<LittleEndian>()? == CENTRAL_DIRECTORY_END_SIGNATURE {
|
||||
if reader.read_u32_le()? == CENTRAL_DIRECTORY_END_SIGNATURE {
|
||||
reader.seek(io::SeekFrom::Current(
|
||||
BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64,
|
||||
))?;
|
||||
|
@ -85,14 +85,14 @@ impl CentralDirectoryEnd {
|
|||
}
|
||||
|
||||
pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {
|
||||
writer.write_u32::<LittleEndian>(CENTRAL_DIRECTORY_END_SIGNATURE)?;
|
||||
writer.write_u16::<LittleEndian>(self.disk_number)?;
|
||||
writer.write_u16::<LittleEndian>(self.disk_with_central_directory)?;
|
||||
writer.write_u16::<LittleEndian>(self.number_of_files_on_this_disk)?;
|
||||
writer.write_u16::<LittleEndian>(self.number_of_files)?;
|
||||
writer.write_u32::<LittleEndian>(self.central_directory_size)?;
|
||||
writer.write_u32::<LittleEndian>(self.central_directory_offset)?;
|
||||
writer.write_u16::<LittleEndian>(self.zip_file_comment.len() as u16)?;
|
||||
writer.write_u32_le(CENTRAL_DIRECTORY_END_SIGNATURE)?;
|
||||
writer.write_u16_le(self.disk_number)?;
|
||||
writer.write_u16_le(self.disk_with_central_directory)?;
|
||||
writer.write_u16_le(self.number_of_files_on_this_disk)?;
|
||||
writer.write_u16_le(self.number_of_files)?;
|
||||
writer.write_u32_le(self.central_directory_size)?;
|
||||
writer.write_u32_le(self.central_directory_offset)?;
|
||||
writer.write_u16_le(self.zip_file_comment.len() as u16)?;
|
||||
writer.write_all(&self.zip_file_comment)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -106,15 +106,15 @@ pub struct Zip64CentralDirectoryEndLocator {
|
|||
|
||||
impl Zip64CentralDirectoryEndLocator {
|
||||
pub fn parse<T: Read>(reader: &mut T) -> ZipResult<Zip64CentralDirectoryEndLocator> {
|
||||
let magic = reader.read_u32::<LittleEndian>()?;
|
||||
let magic = reader.read_u32_le()?;
|
||||
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::<LittleEndian>()?;
|
||||
let end_of_central_directory_offset = reader.read_u64::<LittleEndian>()?;
|
||||
let number_of_disks = reader.read_u32::<LittleEndian>()?;
|
||||
let disk_with_central_directory = reader.read_u32_le()?;
|
||||
let end_of_central_directory_offset = reader.read_u64_le()?;
|
||||
let number_of_disks = reader.read_u32_le()?;
|
||||
|
||||
Ok(Zip64CentralDirectoryEndLocator {
|
||||
disk_with_central_directory,
|
||||
|
@ -124,10 +124,10 @@ impl Zip64CentralDirectoryEndLocator {
|
|||
}
|
||||
|
||||
pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {
|
||||
writer.write_u32::<LittleEndian>(ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE)?;
|
||||
writer.write_u32::<LittleEndian>(self.disk_with_central_directory)?;
|
||||
writer.write_u64::<LittleEndian>(self.end_of_central_directory_offset)?;
|
||||
writer.write_u32::<LittleEndian>(self.number_of_disks)?;
|
||||
writer.write_u32_le(ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE)?;
|
||||
writer.write_u32_le(self.disk_with_central_directory)?;
|
||||
writer.write_u64_le(self.end_of_central_directory_offset)?;
|
||||
writer.write_u32_le(self.number_of_disks)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -156,20 +156,20 @@ impl Zip64CentralDirectoryEnd {
|
|||
while pos >= nominal_offset {
|
||||
reader.seek(io::SeekFrom::Start(pos))?;
|
||||
|
||||
if reader.read_u32::<LittleEndian>()? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE {
|
||||
if reader.read_u32_le()? == ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE {
|
||||
let archive_offset = pos - nominal_offset;
|
||||
|
||||
let _record_size = reader.read_u64::<LittleEndian>()?;
|
||||
let _record_size = reader.read_u64_le()?;
|
||||
// We would use this value if we did anything with the "zip64 extensible data sector".
|
||||
|
||||
let version_made_by = reader.read_u16::<LittleEndian>()?;
|
||||
let version_needed_to_extract = reader.read_u16::<LittleEndian>()?;
|
||||
let disk_number = reader.read_u32::<LittleEndian>()?;
|
||||
let disk_with_central_directory = reader.read_u32::<LittleEndian>()?;
|
||||
let number_of_files_on_this_disk = reader.read_u64::<LittleEndian>()?;
|
||||
let number_of_files = reader.read_u64::<LittleEndian>()?;
|
||||
let central_directory_size = reader.read_u64::<LittleEndian>()?;
|
||||
let central_directory_offset = reader.read_u64::<LittleEndian>()?;
|
||||
let version_made_by = reader.read_u16_le()?;
|
||||
let version_needed_to_extract = reader.read_u16_le()?;
|
||||
let disk_number = reader.read_u32_le()?;
|
||||
let disk_with_central_directory = reader.read_u32_le()?;
|
||||
let number_of_files_on_this_disk = reader.read_u64_le()?;
|
||||
let number_of_files = reader.read_u64_le()?;
|
||||
let central_directory_size = reader.read_u64_le()?;
|
||||
let central_directory_offset = reader.read_u64_le()?;
|
||||
|
||||
results.push((
|
||||
Zip64CentralDirectoryEnd {
|
||||
|
@ -201,16 +201,16 @@ impl Zip64CentralDirectoryEnd {
|
|||
}
|
||||
|
||||
pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {
|
||||
writer.write_u32::<LittleEndian>(ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE)?;
|
||||
writer.write_u64::<LittleEndian>(44)?; // record size
|
||||
writer.write_u16::<LittleEndian>(self.version_made_by)?;
|
||||
writer.write_u16::<LittleEndian>(self.version_needed_to_extract)?;
|
||||
writer.write_u32::<LittleEndian>(self.disk_number)?;
|
||||
writer.write_u32::<LittleEndian>(self.disk_with_central_directory)?;
|
||||
writer.write_u64::<LittleEndian>(self.number_of_files_on_this_disk)?;
|
||||
writer.write_u64::<LittleEndian>(self.number_of_files)?;
|
||||
writer.write_u64::<LittleEndian>(self.central_directory_size)?;
|
||||
writer.write_u64::<LittleEndian>(self.central_directory_offset)?;
|
||||
writer.write_u32_le(ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE)?;
|
||||
writer.write_u64_le(44)?; // record size
|
||||
writer.write_u16_le(self.version_made_by)?;
|
||||
writer.write_u16_le(self.version_needed_to_extract)?;
|
||||
writer.write_u32_le(self.disk_number)?;
|
||||
writer.write_u32_le(self.disk_with_central_directory)?;
|
||||
writer.write_u64_le(self.number_of_files_on_this_disk)?;
|
||||
writer.write_u64_le(self.number_of_files)?;
|
||||
writer.write_u64_le(self.central_directory_size)?;
|
||||
writer.write_u64_le(self.central_directory_offset)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Provides high level API for reading from a stream.
|
||||
pub mod stream {
|
||||
pub use crate::read::stream::*;
|
||||
|
@ -18,3 +23,47 @@ pub mod write {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper methods for writing unsigned integers in little-endian form.
|
||||
pub trait LittleEndianWriteExt: Write {
|
||||
fn write_u16_le(&mut self, input: u16) -> io::Result<()> {
|
||||
self.write_all(&input.to_le_bytes())
|
||||
}
|
||||
|
||||
fn write_u32_le(&mut self, input: u32) -> io::Result<()> {
|
||||
self.write_all(&input.to_le_bytes())
|
||||
}
|
||||
|
||||
fn write_u64_le(&mut self, input: u64) -> io::Result<()> {
|
||||
self.write_all(&input.to_le_bytes())
|
||||
}
|
||||
|
||||
fn write_u128_le(&mut self, input: u128) -> io::Result<()> {
|
||||
self.write_all(&input.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> LittleEndianWriteExt for W {}
|
||||
|
||||
/// Helper methods for reading unsigned integers in little-endian form.
|
||||
pub trait LittleEndianReadExt: Read {
|
||||
fn read_u16_le(&mut self) -> io::Result<u16> {
|
||||
let mut out = [0u8; 2];
|
||||
self.read_exact(&mut out)?;
|
||||
Ok(u16::from_le_bytes(out))
|
||||
}
|
||||
|
||||
fn read_u32_le(&mut self) -> io::Result<u32> {
|
||||
let mut out = [0u8; 4];
|
||||
self.read_exact(&mut out)?;
|
||||
Ok(u32::from_le_bytes(out))
|
||||
}
|
||||
|
||||
fn read_u64_le(&mut self) -> io::Result<u64> {
|
||||
let mut out = [0u8; 8];
|
||||
self.read_exact(&mut out)?;
|
||||
Ok(u64::from_le_bytes(out))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> LittleEndianReadExt for R {}
|
||||
|
|
98
src/write.rs
98
src/write.rs
|
@ -5,7 +5,6 @@ use crate::read::{find_content, ZipArchive, ZipFile, ZipFileReader};
|
|||
use crate::result::{ZipError, ZipResult};
|
||||
use crate::spec;
|
||||
use crate::types::{ffi, DateTime, System, ZipFileData, DEFAULT_VERSION};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
#[cfg(any(feature = "_deflate-any", feature = "bzip2", feature = "zstd",))]
|
||||
use core::num::NonZeroU64;
|
||||
use crc32fast::Hasher;
|
||||
|
@ -126,6 +125,7 @@ use crate::result::ZipError::InvalidArchive;
|
|||
#[cfg(feature = "lzma")]
|
||||
use crate::result::ZipError::UnsupportedArchive;
|
||||
use crate::spec::path_to_string;
|
||||
use crate::unstable::LittleEndianWriteExt;
|
||||
use crate::write::GenericZipWriter::{Closed, Storer};
|
||||
use crate::zipcrypto::ZipCryptoKeys;
|
||||
use crate::CompressionMethod::Stored;
|
||||
|
@ -378,8 +378,8 @@ impl FileOptions<ExtendedFileOptions> {
|
|||
}
|
||||
};
|
||||
vec.reserve_exact(data.len() + 4);
|
||||
vec.write_u16::<LittleEndian>(header_id)?;
|
||||
vec.write_u16::<LittleEndian>(data.len() as u16)?;
|
||||
vec.write_u16_le(header_id)?;
|
||||
vec.write_u16_le(data.len() as u16)?;
|
||||
vec.write_all(data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -701,34 +701,34 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
let index = self.insert_file_data(file)?;
|
||||
let file = &mut self.files[index];
|
||||
let writer = self.inner.get_plain();
|
||||
writer.write_u32::<LittleEndian>(spec::LOCAL_FILE_HEADER_SIGNATURE)?;
|
||||
writer.write_u32_le(spec::LOCAL_FILE_HEADER_SIGNATURE)?;
|
||||
// version needed to extract
|
||||
writer.write_u16::<LittleEndian>(file.version_needed())?;
|
||||
writer.write_u16_le(file.version_needed())?;
|
||||
// general purpose bit flag
|
||||
let flag = if !file.file_name.is_ascii() {
|
||||
1u16 << 11
|
||||
} else {
|
||||
0
|
||||
} | if file.encrypted { 1u16 << 0 } else { 0 };
|
||||
writer.write_u16::<LittleEndian>(flag)?;
|
||||
writer.write_u16_le(flag)?;
|
||||
// Compression method
|
||||
#[allow(deprecated)]
|
||||
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
||||
writer.write_u16_le(file.compression_method.to_u16())?;
|
||||
// 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.datepart())?;
|
||||
writer.write_u16_le(file.last_modified_time.timepart())?;
|
||||
writer.write_u16_le(file.last_modified_time.datepart())?;
|
||||
// crc-32
|
||||
writer.write_u32::<LittleEndian>(file.crc32)?;
|
||||
writer.write_u32_le(file.crc32)?;
|
||||
// compressed size and uncompressed size
|
||||
if file.large_file {
|
||||
writer.write_u32::<LittleEndian>(spec::ZIP64_BYTES_THR as u32)?;
|
||||
writer.write_u32::<LittleEndian>(spec::ZIP64_BYTES_THR as u32)?;
|
||||
writer.write_u32_le(spec::ZIP64_BYTES_THR as u32)?;
|
||||
writer.write_u32_le(spec::ZIP64_BYTES_THR as u32)?;
|
||||
} else {
|
||||
writer.write_u32::<LittleEndian>(file.compressed_size as u32)?;
|
||||
writer.write_u32::<LittleEndian>(file.uncompressed_size as u32)?;
|
||||
writer.write_u32_le(file.compressed_size as u32)?;
|
||||
writer.write_u32_le(file.uncompressed_size as u32)?;
|
||||
}
|
||||
// file name length
|
||||
writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16)?;
|
||||
writer.write_u16_le(file.file_name.as_bytes().len() as u16)?;
|
||||
// extra field length
|
||||
let mut extra_field_length = file.extra_field_len();
|
||||
if file.large_file {
|
||||
|
@ -739,7 +739,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
return Err(InvalidArchive("Extra data field is too large"));
|
||||
}
|
||||
let extra_field_length = extra_field_length as u16;
|
||||
writer.write_u16::<LittleEndian>(extra_field_length)?;
|
||||
writer.write_u16_le(extra_field_length)?;
|
||||
// file name
|
||||
writer.write_all(file.file_name.as_bytes())?;
|
||||
// zip64 extra field
|
||||
|
@ -768,7 +768,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
let pad_body = vec![0; pad_length - 4];
|
||||
writer.write_all(b"za").map_err(ZipError::from)?; // 0x617a
|
||||
writer
|
||||
.write_u16::<LittleEndian>(pad_body.len() as u16)
|
||||
.write_u16_le(pad_body.len() as u16)
|
||||
.map_err(ZipError::from)?;
|
||||
writer.write_all(&pad_body).map_err(ZipError::from)?;
|
||||
} else {
|
||||
|
@ -781,7 +781,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
|
||||
// Update extra field length in local file header.
|
||||
writer.seek(SeekFrom::Start(file.header_start + 28))?;
|
||||
writer.write_u16::<LittleEndian>(new_extra_field_length)?;
|
||||
writer.write_u16_le(new_extra_field_length)?;
|
||||
writer.seek(SeekFrom::Start(header_end))?;
|
||||
debug_assert_eq!(header_end % align, 0);
|
||||
}
|
||||
|
@ -1522,7 +1522,7 @@ fn clamp_opt<T: Ord + Copy, U: Ord + Copy + TryFrom<T>>(
|
|||
fn update_local_file_header<T: Write + Seek>(writer: &mut T, file: &ZipFileData) -> ZipResult<()> {
|
||||
const CRC32_OFFSET: u64 = 14;
|
||||
writer.seek(SeekFrom::Start(file.header_start + CRC32_OFFSET))?;
|
||||
writer.write_u32::<LittleEndian>(file.crc32)?;
|
||||
writer.write_u32_le(file.crc32)?;
|
||||
if file.large_file {
|
||||
update_local_zip64_extra_field(writer, file)?;
|
||||
} else {
|
||||
|
@ -1533,9 +1533,9 @@ fn update_local_file_header<T: Write + Seek>(writer: &mut T, file: &ZipFileData)
|
|||
"Large file option has not been set",
|
||||
)));
|
||||
}
|
||||
writer.write_u32::<LittleEndian>(file.compressed_size as u32)?;
|
||||
writer.write_u32_le(file.compressed_size as u32)?;
|
||||
// uncompressed size is already checked on write to catch it as soon as possible
|
||||
writer.write_u32::<LittleEndian>(file.uncompressed_size as u32)?;
|
||||
writer.write_u32_le(file.uncompressed_size as u32)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1547,49 +1547,49 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
|
|||
write_central_zip64_extra_field(&mut zip64_extra_field.as_mut(), file)?;
|
||||
|
||||
// central file header signature
|
||||
writer.write_u32::<LittleEndian>(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)?;
|
||||
writer.write_u32_le(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)?;
|
||||
// version made by
|
||||
let version_made_by = (file.system as u16) << 8 | (file.version_made_by as u16);
|
||||
writer.write_u16::<LittleEndian>(version_made_by)?;
|
||||
writer.write_u16_le(version_made_by)?;
|
||||
// version needed to extract
|
||||
writer.write_u16::<LittleEndian>(file.version_needed())?;
|
||||
writer.write_u16_le(file.version_needed())?;
|
||||
// general purpose bit flag
|
||||
let flag = if !file.file_name.is_ascii() {
|
||||
1u16 << 11
|
||||
} else {
|
||||
0
|
||||
} | if file.encrypted { 1u16 << 0 } else { 0 };
|
||||
writer.write_u16::<LittleEndian>(flag)?;
|
||||
writer.write_u16_le(flag)?;
|
||||
// compression method
|
||||
#[allow(deprecated)]
|
||||
writer.write_u16::<LittleEndian>(file.compression_method.to_u16())?;
|
||||
writer.write_u16_le(file.compression_method.to_u16())?;
|
||||
// last mod file time + date
|
||||
writer.write_u16::<LittleEndian>(file.last_modified_time.timepart())?;
|
||||
writer.write_u16::<LittleEndian>(file.last_modified_time.datepart())?;
|
||||
writer.write_u16_le(file.last_modified_time.timepart())?;
|
||||
writer.write_u16_le(file.last_modified_time.datepart())?;
|
||||
// crc-32
|
||||
writer.write_u32::<LittleEndian>(file.crc32)?;
|
||||
writer.write_u32_le(file.crc32)?;
|
||||
// compressed size
|
||||
writer.write_u32::<LittleEndian>(file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
writer.write_u32_le(file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
// uncompressed size
|
||||
writer.write_u32::<LittleEndian>(file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
writer.write_u32_le(file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
// file name length
|
||||
writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16)?;
|
||||
writer.write_u16_le(file.file_name.as_bytes().len() as u16)?;
|
||||
// extra field length
|
||||
writer.write_u16::<LittleEndian>(
|
||||
writer.write_u16_le(
|
||||
zip64_extra_field_length
|
||||
+ file.extra_field_len() as u16
|
||||
+ file.central_extra_field_len() as u16,
|
||||
)?;
|
||||
// file comment length
|
||||
writer.write_u16::<LittleEndian>(0)?;
|
||||
writer.write_u16_le(0)?;
|
||||
// disk number start
|
||||
writer.write_u16::<LittleEndian>(0)?;
|
||||
writer.write_u16_le(0)?;
|
||||
// internal file attributes
|
||||
writer.write_u16::<LittleEndian>(0)?;
|
||||
writer.write_u16_le(0)?;
|
||||
// external file attributes
|
||||
writer.write_u32::<LittleEndian>(file.external_attributes)?;
|
||||
writer.write_u32_le(file.external_attributes)?;
|
||||
// relative offset of local header
|
||||
writer.write_u32::<LittleEndian>(file.header_start.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
writer.write_u32_le(file.header_start.min(spec::ZIP64_BYTES_THR) as u32)?;
|
||||
// file name
|
||||
writer.write_all(file.file_name.as_bytes())?;
|
||||
// zip64 extra field
|
||||
|
@ -1643,10 +1643,10 @@ fn validate_extra_data(header_id: u16, data: &[u8]) -> ZipResult<()> {
|
|||
fn write_local_zip64_extra_field<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()> {
|
||||
// This entry in the Local header MUST include BOTH original
|
||||
// and compressed file size fields.
|
||||
writer.write_u16::<LittleEndian>(0x0001)?;
|
||||
writer.write_u16::<LittleEndian>(16)?;
|
||||
writer.write_u64::<LittleEndian>(file.uncompressed_size)?;
|
||||
writer.write_u64::<LittleEndian>(file.compressed_size)?;
|
||||
writer.write_u16_le(0x0001)?;
|
||||
writer.write_u16_le(16)?;
|
||||
writer.write_u64_le(file.uncompressed_size)?;
|
||||
writer.write_u64_le(file.compressed_size)?;
|
||||
// Excluded fields:
|
||||
// u32: disk start number
|
||||
Ok(())
|
||||
|
@ -1658,8 +1658,8 @@ fn update_local_zip64_extra_field<T: Write + Seek>(
|
|||
) -> ZipResult<()> {
|
||||
let zip64_extra_field = file.header_start + 30 + file.file_name.as_bytes().len() as u64;
|
||||
writer.seek(SeekFrom::Start(zip64_extra_field + 4))?;
|
||||
writer.write_u64::<LittleEndian>(file.uncompressed_size)?;
|
||||
writer.write_u64::<LittleEndian>(file.compressed_size)?;
|
||||
writer.write_u64_le(file.uncompressed_size)?;
|
||||
writer.write_u64_le(file.compressed_size)?;
|
||||
// Excluded fields:
|
||||
// u32: disk start number
|
||||
Ok(())
|
||||
|
@ -1684,18 +1684,18 @@ fn write_central_zip64_extra_field<T: Write>(writer: &mut T, file: &ZipFileData)
|
|||
size += 8;
|
||||
}
|
||||
if size > 0 {
|
||||
writer.write_u16::<LittleEndian>(0x0001)?;
|
||||
writer.write_u16::<LittleEndian>(size)?;
|
||||
writer.write_u16_le(0x0001)?;
|
||||
writer.write_u16_le(size)?;
|
||||
size += 4;
|
||||
|
||||
if uncompressed_size {
|
||||
writer.write_u64::<LittleEndian>(file.uncompressed_size)?;
|
||||
writer.write_u64_le(file.uncompressed_size)?;
|
||||
}
|
||||
if compressed_size {
|
||||
writer.write_u64::<LittleEndian>(file.compressed_size)?;
|
||||
writer.write_u64_le(file.compressed_size)?;
|
||||
}
|
||||
if header_start {
|
||||
writer.write_u64::<LittleEndian>(file.header_start)?;
|
||||
writer.write_u64_le(file.header_start)?;
|
||||
}
|
||||
// Excluded fields:
|
||||
// u32: disk start number
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use std::collections::HashSet;
|
||||
use std::io::prelude::*;
|
||||
use std::io::Cursor;
|
||||
|
@ -159,8 +158,8 @@ fn check_test_archive<R: Read + Seek>(zip_file: R) -> ZipResult<zip::ZipArchive<
|
|||
{
|
||||
let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
|
||||
let mut extra_data = Vec::new();
|
||||
extra_data.write_u16::<LittleEndian>(0xbeef)?;
|
||||
extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
|
||||
extra_data.write_u16(0xbeef)?;
|
||||
extra_data.write_u16(EXTRA_DATA.len() as u16)?;
|
||||
extra_data.write_all(EXTRA_DATA)?;
|
||||
assert_eq!(
|
||||
file_with_extra_data.extra_data(),
|
||||
|
|
Loading…
Add table
Reference in a new issue