Skip to content

Commit 9985a55

Browse files
uklotzdeSerial-ATA
authored andcommitted
Add utf8_decode_str()/trim_end_nulls_str() to avoid/defer allocations
1 parent 7398602 commit 9985a55

File tree

10 files changed

+35
-21
lines changed

10 files changed

+35
-21
lines changed

src/id3/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod v2;
88

99
use crate::error::{ErrorKind, LoftyError, Result};
1010
use crate::macros::try_vec;
11+
use crate::util::text::utf8_decode_str;
1112
use v2::header::Id3v2Header;
1213

1314
use std::io::{Read, Seek, SeekFrom};
@@ -30,7 +31,7 @@ where
3031
if &lyrics3v2[7..] == b"LYRICS200" {
3132
header = Some(());
3233

33-
let lyrics_size = std::str::from_utf8(&lyrics3v2[..7])?;
34+
let lyrics_size = utf8_decode_str(&lyrics3v2[..7])?;
3435
let lyrics_size = lyrics_size.parse::<u32>().map_err(|_| {
3536
LoftyError::new(ErrorKind::TextDecode(
3637
"Lyrics3v2 tag has an invalid size string",

src/id3/v2/frame/header.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::error::{Id3v2Error, Id3v2ErrorKind, Result};
33
use crate::id3::v2::util::synchsafe::SynchsafeInteger;
44
use crate::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
55
use crate::id3::v2::FrameId;
6+
use crate::util::text::utf8_decode_str;
67

78
use std::borrow::Cow;
89
use std::io::Read;
@@ -74,7 +75,7 @@ where
7475
}
7576

7677
let id_bytes = &header[..id_end];
77-
let id_str = std::str::from_utf8(id_bytes)
78+
let id_str = utf8_decode_str(id_bytes)
7879
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(id_bytes.to_vec())))?;
7980

8081
// Now upgrade the FrameId

src/id3/v2/items/ownership_frame.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::error::{ErrorKind, Id3v2Error, Id3v2ErrorKind, LoftyError, Result};
2-
use crate::util::text::{decode_text, encode_text, utf8_decode, TextEncoding};
2+
use crate::util::text::{decode_text, encode_text, utf8_decode_str, TextEncoding};
33

44
use std::hash::Hash;
55
use std::io::Read;
@@ -47,10 +47,10 @@ impl OwnershipFrame {
4747
.ok_or_else(|| LoftyError::new(ErrorKind::TextDecode("Found invalid encoding")))?;
4848
let price_paid = decode_text(reader, TextEncoding::Latin1, true)?.content;
4949

50-
let mut date_bytes = vec![0u8; 8];
50+
let mut date_bytes = [0u8; 8];
5151
reader.read_exact(&mut date_bytes)?;
5252

53-
let date_of_purchase = utf8_decode(date_bytes)?;
53+
let date_of_purchase = utf8_decode_str(&date_bytes)?.to_owned();
5454

5555
let seller = decode_text(reader, encoding, false)?.content;
5656

src/iff/chunk.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ impl<B: ByteOrder> Chunks<B> {
4949
let cont = self.content(data)?;
5050
self.correct_position(data)?;
5151

52-
let value_str = std::str::from_utf8(&cont)?;
53-
54-
Ok(value_str.trim_end_matches('\0').to_string())
52+
utf8_decode(cont)
5553
}
5654

5755
pub fn read_pstring<R>(&mut self, data: &mut R, size: Option<u32>) -> Result<String>

src/iff/wav/tag/read.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::RIFFInfoList;
22
use crate::error::Result;
33
use crate::iff::chunk::Chunks;
44
use crate::macros::decode_err;
5+
use crate::util::text::utf8_decode_str;
56

67
use std::io::{Read, Seek};
78

@@ -17,15 +18,15 @@ where
1718
R: Read + Seek,
1819
{
1920
while data.stream_position()? != end && chunks.next(data).is_ok() {
20-
let key_str = String::from_utf8(chunks.fourcc.to_vec())
21+
let key_str = utf8_decode_str(&chunks.fourcc)
2122
.map_err(|_| decode_err!(Wav, "Non UTF-8 item key found in RIFF INFO"))?;
2223

23-
if !verify_key(&key_str) {
24+
if !verify_key(key_str) {
2425
decode_err!(@BAIL Wav, "RIFF INFO item key contains invalid characters");
2526
}
2627

2728
tag.items.push((
28-
key_str,
29+
key_str.to_owned(),
2930
chunks
3031
.read_cstring(data)
3132
.map_err(|_| decode_err!(Wav, "Failed to read RIFF INFO item value"))?,

src/mp4/atom_info.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::macros::{err, try_vec};
33
use crate::probe::ParsingMode;
44
use crate::tag::item::ItemKey;
55
use crate::tag::TagType;
6+
use crate::util::text::utf8_decode;
67

78
use std::borrow::Cow;
89
use std::io::{Read, Seek, SeekFrom};
@@ -247,7 +248,7 @@ where
247248
let mut content = try_vec![0; (len - 12) as usize];
248249
data.read_exact(&mut content)?;
249250

250-
String::from_utf8(content).map_err(|_| {
251+
utf8_decode(content).map_err(|_| {
251252
LoftyError::new(ErrorKind::BadAtom(
252253
"Found a non UTF-8 string while reading freeform identifier",
253254
))

src/mp4/read.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::error::{ErrorKind, LoftyError, Result};
66
use crate::macros::{decode_err, err};
77
use crate::probe::{ParseOptions, ParsingMode};
88
use crate::traits::SeekStreamLen;
9+
use crate::util::text::utf8_decode_str;
910

1011
use std::io::{Read, Seek, SeekFrom};
1112

@@ -163,12 +164,13 @@ where
163164
decode_err!(@BAIL Mp4, "\"ftyp\" atom too short");
164165
}
165166

166-
let mut major_brand = vec![0; 4];
167+
let mut major_brand = [0u8; 4];
167168
reader.read_exact(&mut major_brand)?;
168169

169170
reader.seek(SeekFrom::Current((atom.len - 12) as i64))?;
170171

171-
String::from_utf8(major_brand)
172+
utf8_decode_str(&major_brand)
173+
.map(ToOwned::to_owned)
172174
.map_err(|_| LoftyError::new(ErrorKind::BadAtom("Unable to parse \"ftyp\"'s major brand")))
173175
}
174176

src/ogg/read.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::error::{ErrorKind, LoftyError, Result};
44
use crate::macros::{decode_err, err, parse_mode_choice};
55
use crate::picture::{MimeType, Picture, PictureInformation, PictureType};
66
use crate::probe::ParsingMode;
7-
use crate::util::text::{utf16_decode, utf8_decode};
7+
use crate::util::text::{utf16_decode, utf8_decode, utf8_decode_str};
88

99
use std::borrow::Cow;
1010
use std::io::{Read, Seek, SeekFrom};
@@ -149,8 +149,8 @@ where
149149
// SAFETY: We just verified that all of the bytes fall within the subset of ASCII
150150
let key = unsafe { String::from_utf8_unchecked(k.to_vec()) };
151151

152-
match utf8_decode(value.to_vec()) {
153-
Ok(value) => tag.items.push((key, value)),
152+
match utf8_decode_str(value) {
153+
Ok(value) => tag.items.push((key, value.to_owned())),
154154
Err(e) => {
155155
if parse_mode == ParsingMode::Strict {
156156
return Err(e);

src/picture.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::error::{ErrorKind, LoftyError, Result};
22
use crate::macros::err;
33
use crate::probe::ParsingMode;
4-
use crate::util::text::utf8_decode;
4+
use crate::util::text::utf8_decode_str;
55

66
use std::borrow::Cow;
77
use std::fmt::{Debug, Formatter};
@@ -672,7 +672,7 @@ impl Picture {
672672
err!(SizeMismatch);
673673
}
674674

675-
let mime_type_str = std::str::from_utf8(&content[8..8 + mime_len])?;
675+
let mime_type_str = utf8_decode_str(&content[8..8 + mime_len])?;
676676
size -= mime_len;
677677

678678
reader.seek(SeekFrom::Current(mime_len as i64))?;
@@ -684,8 +684,8 @@ impl Picture {
684684
if desc_len > 0 && desc_len < size {
685685
let pos = 12 + mime_len;
686686

687-
if let Ok(desc) = utf8_decode(content[pos..pos + desc_len].to_vec()) {
688-
description = Some(desc.into());
687+
if let Ok(desc) = utf8_decode_str(&content[pos..pos + desc_len]) {
688+
description = Some(desc.to_owned().into());
689689
}
690690

691691
size -= desc_len;

src/util/text.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ pub(crate) fn utf8_decode(bytes: Vec<u8>) -> Result<String> {
185185
.map_err(Into::into)
186186
}
187187

188+
pub(crate) fn utf8_decode_str(bytes: &[u8]) -> Result<&str> {
189+
std::str::from_utf8(bytes)
190+
.map(trim_end_nulls_str)
191+
.map_err(Into::into)
192+
}
193+
188194
pub(crate) fn utf16_decode(words: &[u16]) -> Result<String> {
189195
String::from_utf16(words)
190196
.map(|mut text| {
@@ -242,6 +248,10 @@ pub(crate) fn trim_end_nulls(text: &mut String) {
242248
}
243249
}
244250

251+
pub(crate) fn trim_end_nulls_str(text: &str) -> &str {
252+
text.trim_end_matches('\0')
253+
}
254+
245255
fn utf16_encode(
246256
text: &str,
247257
endianness: fn(u16) -> [u8; 2],

0 commit comments

Comments
 (0)