Skip to content

Commit c9b4538

Browse files
committed
str: add a function for truncating a vector of u16 at NUL.
Many of the functions interacting with Windows APIs allocate a vector of 0's and do not retrieve a length directly from the API call, and so need to be sure to remove the unmodified junk at the end of the vector.
1 parent 4f841ee commit c9b4538

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

src/libnative/io/file.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,8 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
571571
else {
572572
let fp_vec = vec::from_buf(
573573
fp_buf, wcslen(fp_buf) as uint);
574-
let fp_str = str::from_utf16(fp_vec)
574+
let fp_trimmed = str::truncate_utf16_at_nul(fp_vec);
575+
let fp_str = str::from_utf16(fp_trimmed)
575576
.expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
576577
paths.push(Path::new(fp_str));
577578
}

src/libstd/os.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ pub fn getcwd() -> Path {
8888
fail!();
8989
}
9090
}
91-
Path::new(str::from_utf16(buf).expect("GetCurrentDirectoryW returned invalid UTF-16"))
91+
Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
92+
.expect("GetCurrentDirectoryW returned invalid UTF-16"))
9293
}
9394

9495
#[cfg(windows)]
@@ -744,7 +745,8 @@ pub fn last_os_error() -> ~str {
744745
fail!("[{}] FormatMessage failure", errno());
745746
}
746747

747-
str::from_utf16(buf).expect("FormatMessageW returned invalid UTF-16")
748+
str::from_utf16(str::truncate_utf16_at_nul(buf))
749+
.expect("FormatMessageW returned invalid UTF-16")
748750
}
749751
}
750752

@@ -833,7 +835,9 @@ fn real_args() -> ~[~str] {
833835
while *ptr.offset(len as int) != 0 { len += 1; }
834836

835837
// Push it onto the list.
836-
let opt_s = vec::raw::buf_as_slice(ptr, len, str::from_utf16);
838+
let opt_s = vec::raw::buf_as_slice(ptr, len, |buf| {
839+
str::from_utf16(str::truncate_utf16_at_nul(buf))
840+
});
837841
args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
838842
}
839843
}

src/libstd/str.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,32 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
920920
UTF16Items { iter : v.iter() }
921921
}
922922

923+
/// Return a slice of `v` ending at (and not including) the first NUL
924+
/// (0).
925+
///
926+
/// # Example
927+
///
928+
/// ```rust
929+
/// use std::str;
930+
///
931+
/// // "abcd"
932+
/// let mut v = ['a' as u16, 'b' as u16, 'c' as u16, 'd' as u16];
933+
/// // no NULs so no change
934+
/// assert_eq!(str::truncate_utf16_at_nul(v), v.as_slice());
935+
///
936+
/// // "ab\0d"
937+
/// v[2] = 0;
938+
/// assert_eq!(str::truncate_utf16_at_nul(v),
939+
/// &['a' as u16, 'b' as u16]);
940+
/// ```
941+
pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
942+
match v.iter().position(|c| *c == 0) {
943+
// don't include the 0
944+
Some(i) => v.slice_to(i),
945+
None => v
946+
}
947+
}
948+
923949
/// Decode a UTF-16 encoded vector `v` into a string, returning `None`
924950
/// if `v` contains any invalid data.
925951
///
@@ -3875,6 +3901,24 @@ mod tests {
38753901
assert_eq!(from_utf16_lossy([0xD800, 0xd801, 0xdc8b, 0xD800]), ~"\uFFFD𐒋\uFFFD");
38763902
}
38773903

3904+
#[test]
3905+
fn test_truncate_utf16_at_nul() {
3906+
let v = [];
3907+
assert_eq!(truncate_utf16_at_nul(v), &[]);
3908+
3909+
let v = [0, 2, 3];
3910+
assert_eq!(truncate_utf16_at_nul(v), &[]);
3911+
3912+
let v = [1, 0, 3];
3913+
assert_eq!(truncate_utf16_at_nul(v), &[1]);
3914+
3915+
let v = [1, 2, 0];
3916+
assert_eq!(truncate_utf16_at_nul(v), &[1, 2]);
3917+
3918+
let v = [1, 2, 3];
3919+
assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]);
3920+
}
3921+
38783922
#[test]
38793923
fn test_char_at() {
38803924
let s = ~"ศไทย中华Việt Nam";

0 commit comments

Comments
 (0)