Skip to content

Commit 0329d9d

Browse files
fix: allow for [u8] as filename (#775)
* use bytes direclty * cargo fmt * fix * also on read * add as bytes * fmt
1 parent ddcf854 commit 0329d9d

4 files changed

Lines changed: 24 additions & 26 deletions

File tree

src/read.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub(crate) fn make_writable_dir_all<T: AsRef<Path>>(outpath: T) -> Result<(), Zi
7878
pub(crate) fn make_symlink_impl<T>(
7979
outpath: &Path,
8080
target_str: &str,
81-
_existing_files: &IndexMap<Box<str>, T>,
81+
_existing_files: &IndexMap<Box<[u8]>, T>,
8282
) -> ZipResult<()> {
8383
std::os::unix::fs::symlink(Path::new(&target_str), outpath)?;
8484
Ok(())
@@ -88,10 +88,11 @@ pub(crate) fn make_symlink_impl<T>(
8888
pub(crate) fn make_symlink_impl<T>(
8989
outpath: &Path,
9090
target_str: &str,
91-
existing_files: &IndexMap<Box<str>, T>,
91+
existing_files: &IndexMap<Box<[u8]>, T>,
9292
) -> ZipResult<()> {
9393
let target = Path::new(OsStr::new(&target_str));
94-
let target_is_dir_from_archive = existing_files.contains_key(target_str) && is_dir(target_str);
94+
let target_is_dir_from_archive =
95+
existing_files.contains_key(target_str.as_bytes()) && is_dir(target_str);
9596
let target_is_dir = if target_is_dir_from_archive {
9697
true
9798
} else if let Ok(meta) = std::fs::metadata(target) {
@@ -111,7 +112,7 @@ pub(crate) fn make_symlink_impl<T>(
111112
pub(crate) fn make_symlink<T>(
112113
outpath: &Path,
113114
target: &[u8],
114-
#[cfg_attr(not(any(windows, unix)), allow(unused))] existing_files: &IndexMap<Box<str>, T>,
115+
#[cfg_attr(not(any(windows, unix)), allow(unused))] existing_files: &IndexMap<Box<[u8]>, T>,
115116
) -> ZipResult<()> {
116117
let Ok(target_str) = std::str::from_utf8(target) else {
117118
return Err(invalid!("Invalid UTF-8 as symlink target"));
@@ -123,7 +124,7 @@ pub(crate) fn make_symlink<T>(
123124
pub(crate) fn make_symlink<T>(
124125
outpath: &Path,
125126
target: &[u8],
126-
#[cfg_attr(not(any(windows, unix)), allow(unused))] existing_files: &IndexMap<Box<str>, T>,
127+
#[cfg_attr(not(any(windows, unix)), allow(unused))] existing_files: &IndexMap<Box<[u8]>, T>,
127128
) -> ZipResult<()> {
128129
let Ok(_) = std::str::from_utf8(target) else {
129130
return Err(invalid!("Invalid UTF-8 as symlink target"));
@@ -217,7 +218,7 @@ impl<R: Read + Seek> ZipArchive<R> {
217218
pub(crate) fn merge_contents<W: Write + Seek>(
218219
&mut self,
219220
mut w: W,
220-
) -> ZipResult<IndexMap<Box<str>, ZipFileData>> {
221+
) -> ZipResult<IndexMap<Box<[u8]>, ZipFileData>> {
221222
if self.shared.files.is_empty() {
222223
return Ok(IndexMap::new());
223224
}

src/read/stream.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ impl<R: Read> ZipStreamReader<R> {
6161
/// Extraction is not atomic; If an error is encountered, some of the files
6262
/// may be left on disk.
6363
pub fn extract<P: AsRef<Path>>(self, directory: P) -> ZipResult<()> {
64-
struct Extractor(PathBuf, IndexMap<Box<str>, ()>);
64+
struct Extractor(PathBuf, IndexMap<Box<[u8]>, ()>);
6565
impl ZipStreamVisitor for Extractor {
6666
fn visit_file<R: Read>(&mut self, file: &mut ZipFile<'_, R>) -> ZipResult<()> {
67-
self.1.insert(file.name().into(), ());
67+
self.1.insert(file.name_raw().into(), ());
6868
let mut outpath = self.0.clone();
6969
file.safe_prepare_path(&self.0, &mut outpath, None::<&(_, fn(&Path) -> bool)>)?;
7070

src/read/zip_archive.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::sync::Arc;
2020
/// Immutable metadata about a `ZipArchive`.
2121
#[derive(Debug)]
2222
pub struct ZipArchiveMetadata {
23-
pub(crate) files: IndexMap<Box<str>, ZipFileData>,
23+
pub(crate) files: IndexMap<Box<[u8]>, ZipFileData>,
2424
pub(crate) offset: u64,
2525
pub(crate) dir_start: u64,
2626
// This isn't yet used anywhere, but it is here for use cases in the future.
@@ -48,7 +48,7 @@ impl SharedBuilder {
4848
) -> ZipArchiveMetadata {
4949
let mut index_map = IndexMap::with_capacity(self.files.len());
5050
self.files.into_iter().for_each(|file| {
51-
index_map.insert(file.file_name.clone(), file);
51+
index_map.insert(file.file_name_raw.clone(), file);
5252
});
5353
ZipArchiveMetadata {
5454
files: index_map,
@@ -89,7 +89,7 @@ pub struct ZipArchive<R> {
8989

9090
impl<R> ZipArchive<R> {
9191
pub(crate) fn from_finalized_writer(
92-
files: IndexMap<Box<str>, ZipFileData>,
92+
files: IndexMap<Box<[u8]>, ZipFileData>,
9393
comment: Box<[u8]>,
9494
zip64_extensible_data_sector: Option<Box<[u8]>>,
9595
reader: R,
@@ -363,7 +363,7 @@ impl<R: Read + Seek> ZipArchive<R> {
363363

364364
/// Returns an iterator over all the file and directory names in this archive.
365365
pub fn file_names(&self) -> impl Iterator<Item = &str> {
366-
self.shared.files.keys().map(std::convert::AsRef::as_ref)
366+
self.shared.files.values().map(|f| f.file_name.as_ref())
367367
}
368368

369369
/// Returns Ok(true) if any compressed data in this archive belongs to more than one file. This
@@ -413,7 +413,7 @@ impl<R: Read + Seek> ZipArchive<R> {
413413
/// Get the index of a file entry by name, if it's present.
414414
#[inline]
415415
pub fn index_for_name(&self, name: &str) -> Option<usize> {
416-
self.shared.files.get_index_of(name)
416+
self.shared.files.get_index_of(name.as_bytes())
417417
}
418418

419419
/// Search for a file entry by path, decrypt with given password
@@ -461,7 +461,7 @@ impl<R: Read + Seek> ZipArchive<R> {
461461
self.shared
462462
.files
463463
.get_index(index)
464-
.map(|(name, _)| name.as_ref())
464+
.map(|(_, file)| file.file_name.as_ref())
465465
}
466466

467467
/// Search for a file entry by name and return a seekable object.
@@ -499,7 +499,7 @@ impl<R: Read + Seek> ZipArchive<R> {
499499
name: &str,
500500
password: Option<&[u8]>,
501501
) -> ZipResult<ZipFile<'a, R>> {
502-
let Some(index) = self.shared.files.get_index_of(name) else {
502+
let Some(index) = self.shared.files.get_index_of(name.as_bytes()) else {
503503
return Err(ZipError::FileNotFound);
504504
};
505505
self.by_index_with_options(index, ZipReadOptions::new().password(password))

src/write.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ pub(crate) mod zip_writer {
172172
/// ```
173173
pub struct ZipWriter<W: Write + Seek> {
174174
pub(super) inner: GenericZipWriter<W>,
175-
pub(super) files: IndexMap<Box<str>, ZipFileData>,
175+
pub(super) files: IndexMap<Box<[u8]>, ZipFileData>,
176176
pub(super) stats: ZipWriterStats,
177177
pub(super) writing_to_file: bool,
178178
pub(super) writing_raw: bool,
@@ -835,7 +835,6 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
835835
pub fn new_append_with_config(config: Config, mut readwriter: A) -> ZipResult<ZipWriter<A>> {
836836
readwriter.seek(SeekFrom::Start(0))?;
837837
let shared = ZipArchive::get_metadata(config, &mut readwriter)?;
838-
839838
Ok(ZipWriter {
840839
inner: GenericZipWriter::Storer(MaybeEncrypted::Unencrypted(readwriter)),
841840
files: shared.files,
@@ -873,11 +872,11 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
873872
/// widely-compatible archive compared to [`Self::shallow_copy_file`]. Does not copy alignment.
874873
pub fn deep_copy_file(&mut self, src_name: &str, dest_name: &str) -> ZipResult<()> {
875874
self.finish_file()?;
876-
if src_name == dest_name || self.files.contains_key(dest_name) {
875+
if src_name == dest_name || self.files.contains_key(dest_name.as_bytes()) {
877876
return Err(invalid!("That file already exists"));
878877
}
879878
let write_position = self.inner.try_inner_mut()?.stream_position()?;
880-
let src_index = self.index_by_name(src_name)?;
879+
let src_index = self.index_by_name(src_name.as_bytes())?;
881880
let src_data = &mut self.files[src_index];
882881
let src_data_start = src_data.data_start(self.inner.try_inner_mut()?)?;
883882
debug_assert!(src_data_start <= write_position);
@@ -894,9 +893,8 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
894893
.try_inner_mut()?
895894
.seek(SeekFrom::Start(write_position))?;
896895
let mut new_data = src_data.clone();
897-
let dest_name_raw = dest_name.as_bytes();
896+
new_data.file_name_raw = dest_name.as_bytes().into();
898897
new_data.file_name = dest_name.into();
899-
new_data.file_name_raw = dest_name_raw.into();
900898
new_data.header_start = write_position;
901899
let extra_data_start = write_position
902900
+ (size_of::<Magic>() + size_of::<ZipLocalEntryBlock>()) as u64
@@ -989,7 +987,6 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
989987
let comment = mem::take(&mut self.comment);
990988
let zip64_extensible_data_sector = mem::take(&mut self.zip64_extensible_data_sector);
991989
let files = mem::take(&mut self.files);
992-
993990
Ok(ZipArchive::from_finalized_writer(
994991
files,
995992
comment,
@@ -1381,10 +1378,10 @@ impl<W: Write + Seek> ZipWriter<W> {
13811378
}
13821379

13831380
fn insert_file_data(&mut self, file: ZipFileData) -> ZipResult<usize> {
1384-
if self.files.contains_key(&file.file_name) {
1381+
if self.files.contains_key(&file.file_name_raw) {
13851382
return Err(invalid!("Duplicate filename: {}", file.file_name));
13861383
}
1387-
let (index, _) = self.files.insert_full(file.file_name.clone(), file);
1384+
let (index, _) = self.files.insert_full(file.file_name_raw.clone(), file);
13881385
Ok(index)
13891386
}
13901387

@@ -1962,7 +1959,7 @@ impl<W: Write + Seek> ZipWriter<W> {
19621959
Ok(central_start)
19631960
}
19641961

1965-
fn index_by_name(&self, name: &str) -> ZipResult<usize> {
1962+
fn index_by_name(&self, name: &[u8]) -> ZipResult<usize> {
19661963
self.files.get_index_of(name).ok_or(ZipError::FileNotFound)
19671964
}
19681965

@@ -1976,7 +1973,7 @@ impl<W: Write + Seek> ZipWriter<W> {
19761973
if src_name == dest_name {
19771974
return Err(invalid!("Trying to copy a file to itself"));
19781975
}
1979-
let src_index = self.index_by_name(src_name)?;
1976+
let src_index = self.index_by_name(src_name.as_bytes())?;
19801977
let mut dest_data = self.files[src_index].clone();
19811978
dest_data.file_name = dest_name.into();
19821979
dest_data.file_name_raw = dest_name.as_bytes().into();

0 commit comments

Comments
 (0)