diff --git a/Cargo.toml b/Cargo.toml index 5e3f6e5f..09c02f23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ crc32fast = { version = "1.2", optional = true } flate2 = { version = "1", optional = true } indexmap = { version = "1.1", optional = true } wasmparser = { version = "0.57", optional = true } +memchr = { version = "2.4", optional = true, default-features = false } # Internal feature, only used when building as part of libstd, not part of the # stable interface of this crate. @@ -45,7 +46,7 @@ write = ["write_core", "coff", "elf", "macho"] # Enable things that require libstd. # Currently, this provides an `Error` implementation. -std = [] +std = ["memchr/std"] # Enable decompression of compressed sections. # This feature is not required if you want to do your own decompression. compression = ["flate2", "std"] @@ -58,7 +59,7 @@ unaligned = [] #======================================= # File format features. -archive = [] +archive = ["memchr"] coff = [] elf = [] macho = [] diff --git a/src/read/archive.rs b/src/read/archive.rs index fb6dd362..2f507cb9 100644 --- a/src/read/archive.rs +++ b/src/read/archive.rs @@ -197,13 +197,13 @@ impl<'data> ArchiveMember<'data> { parse_bsd_extended_name(&header.name[3..], data, &mut file_offset, &mut file_size) .read_error("Invalid archive extended name length")? } else if header.name[0] == b'/' { - let name_len = - (header.name.iter().position(|&x| x == b' ')).unwrap_or_else(|| header.name.len()); + let name_len = memchr::memchr(b' ', &header.name).unwrap_or(header.name.len()); &header.name[..name_len] } else { - let name_len = (header.name.iter().position(|&x| x == b'/')) - .or_else(|| header.name.iter().position(|&x| x == b' ')) - .unwrap_or_else(|| header.name.len()); + // FIXME: can `memchr::memchr2` be used here? + let name_len = memchr::memchr(b'/', &header.name) + .or_else(|| memchr::memchr(b' ', &header.name)) + .unwrap_or(header.name.len()); &header.name[..name_len] }; @@ -268,20 +268,19 @@ impl<'data> ArchiveMember<'data> { // Ignores bytes starting from the first space. fn parse_u64_digits(digits: &[u8], radix: u32) -> Option { - let len = digits - .iter() - .position(|&x| x == b' ') - .unwrap_or_else(|| digits.len()); - let digits = &digits[..len]; - if digits.is_empty() { + if let [b' ', ..] = digits { return None; } let mut result: u64 = 0; for &c in digits { - let x = (c as char).to_digit(radix)?; - result = result - .checked_mul(u64::from(radix))? - .checked_add(u64::from(x))?; + if c == b' ' { + return Some(result); + } else { + let x = (c as char).to_digit(radix)?; + result = result + .checked_mul(u64::from(radix))? + .checked_add(u64::from(x))?; + } } Some(result) } @@ -290,7 +289,7 @@ fn parse_sysv_extended_name<'data>(digits: &[u8], names: &'data [u8]) -> Result< let offset = parse_u64_digits(digits, 10).ok_or(())?; let offset = offset.try_into().map_err(|_| ())?; let name_data = names.get(offset..).ok_or(())?; - let name = match name_data.iter().position(|&x| x == b'/' || x == 0) { + let name = match memchr::memchr2(b'/', b'\0', name_data) { Some(len) => &name_data[..len], None => name_data, }; @@ -307,7 +306,7 @@ fn parse_bsd_extended_name<'data, R: ReadRef<'data>>( let len = parse_u64_digits(digits, 10).ok_or(())?; *size = size.checked_sub(len).ok_or(())?; let name_data = data.read_bytes(offset, len)?; - let name = match name_data.iter().position(|&x| x == 0) { + let name = match memchr::memchr(b'\0', name_data) { Some(len) => &name_data[..len], None => name_data, };