diff --git a/Cargo.toml b/Cargo.toml index 5e3f6e5f..1c8c1543 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", 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"] diff --git a/src/pod.rs b/src/pod.rs index 41b2c4d9..d745a1fa 100644 --- a/src/pod.rs +++ b/src/pod.rs @@ -284,7 +284,7 @@ impl<'data> Bytes<'data> { /// Reads past the null byte, but doesn't return it. #[inline] pub fn read_string(&mut self) -> Result<&'data [u8]> { - match self.0.iter().position(|&x| x == 0) { + match memchr::memchr(b'\0', self.0) { Some(null) => { // These will never fail. let bytes = self.read_bytes(null)?; diff --git a/src/read/archive.rs b/src/read/archive.rs index fb6dd362..15d921d0 100644 --- a/src/read/archive.rs +++ b/src/read/archive.rs @@ -197,13 +197,12 @@ 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()); + 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 +267,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 +288,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 +305,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, }; diff --git a/src/read/coff/section.rs b/src/read/coff/section.rs index bcd20cf3..4a1667a6 100644 --- a/src/read/coff/section.rs +++ b/src/read/coff/section.rs @@ -347,7 +347,7 @@ impl pe::ImageSectionHeader { /// Return the raw section name. pub fn raw_name(&self) -> &[u8] { let bytes = &self.name; - match bytes.iter().position(|&x| x == 0) { + match memchr::memchr(b'\0', bytes) { Some(end) => &bytes[..end], None => &bytes[..], } diff --git a/src/read/coff/symbol.rs b/src/read/coff/symbol.rs index 9dc3ba52..5e827342 100644 --- a/src/read/coff/symbol.rs +++ b/src/read/coff/symbol.rs @@ -114,7 +114,7 @@ impl<'data> SymbolTable<'data> { .read_error("Invalid COFF symbol index")?; let bytes = bytes_of_slice(entries); // The name is padded with nulls. - Ok(match bytes.iter().position(|&x| x == 0) { + Ok(match memchr::memchr(b'\0', bytes) { Some(end) => &bytes[..end], None => &bytes[..], }) @@ -182,7 +182,7 @@ impl pe::ImageSymbol { .read_error("Invalid COFF symbol name offset") } else { // The name is inline and padded with nulls. - Ok(match self.name.iter().position(|&x| x == 0) { + Ok(match memchr::memchr(b'\0', &self.name) { Some(end) => &self.name[..end], None => &self.name[..], }) diff --git a/src/read/macho/section.rs b/src/read/macho/section.rs index 20385039..7862a354 100644 --- a/src/read/macho/section.rs +++ b/src/read/macho/section.rs @@ -245,7 +245,7 @@ pub trait Section: Debug + Pod { /// Return the `sectname` bytes up until the null terminator. fn name(&self) -> &[u8] { let sectname = &self.sectname()[..]; - match sectname.iter().position(|&x| x == 0) { + match memchr::memchr(b'\0', sectname) { Some(end) => §name[..end], None => sectname, } @@ -254,7 +254,7 @@ pub trait Section: Debug + Pod { /// Return the `segname` bytes up until the null terminator. fn segment_name(&self) -> &[u8] { let segname = &self.segname()[..]; - match segname.iter().position(|&x| x == 0) { + match memchr::memchr(b'\0', segname) { Some(end) => &segname[..end], None => segname, } diff --git a/src/read/macho/segment.rs b/src/read/macho/segment.rs index c08fe871..6686c101 100644 --- a/src/read/macho/segment.rs +++ b/src/read/macho/segment.rs @@ -158,7 +158,7 @@ pub trait Segment: Debug + Pod { /// Return the `segname` bytes up until the null terminator. fn name(&self) -> &[u8] { let segname = &self.segname()[..]; - match segname.iter().position(|&x| x == 0) { + match memchr::memchr(b'\0', segname) { Some(end) => &segname[..end], None => segname, }