#string #utf-16 #nt #byte-slice #wide #windows

no-std nt-string

各种Windows字符串类型的惯用Rust实现

2个版本

0.1.1 2023年6月13日
0.1.0 2023年5月31日

#52 in Windows APIs

Download history 2977/week @ 2024-03-14 2363/week @ 2024-03-21 2681/week @ 2024-03-28 3850/week @ 2024-04-04 2325/week @ 2024-04-11 3171/week @ 2024-04-18 3425/week @ 2024-04-25 1817/week @ 2024-05-02 2214/week @ 2024-05-09 2253/week @ 2024-05-16 2111/week @ 2024-05-23 3040/week @ 2024-05-30 2807/week @ 2024-06-06 2074/week @ 2024-06-13 2031/week @ 2024-06-20 898/week @ 2024-06-27

8,374 monthly downloads
用于 7 个crate(3个直接)

MIT/Apache

82KB
1K SLoC

nt-string

crates.io docs.rs license: MIT OR Apache-2.0

由 Colin Finck <[email protected]>

为各种Windows字符串类型提供惯用的Rust实现

其他有用的UTF-16字符串类型已由优秀的 widestring crate 提供。这个crate试图尽可能地与它们集成。

使用示例


在WinDbg中调试Rust应用程序并使用 dS 命令来显示在Rust中创建的 UNICODE_STRING。如您所见,这个crate的 NtUnicodeString 和原始的 UNICODE_STRING 完全兼容。

详细信息

UNICODE_STRING 类型是为C编程语言设计的,该语言只知道NUL终止的字符缓冲区。为了确定缓冲区的长度,需要遍历所有字符直到找到NUL。这还不够糟吗?更糟的是,如果一个缓冲区没有NUL,但算法仍然尝试找到它,则会发生经典的缓冲区溢出。

为了克服这些性能和安全风险,UNICODE_STRING由一个缓冲区、一个缓冲区容量(“最大长度”)以及一个表示实际使用长度的字段组成。现在确定长度和容量就像查询相应的字段一样简单。长度和容量是16位值,以字节为单位表示。

UNICODE_STRING已被Windows内核团队广泛使用,并扩展到一些用户模式API。这个crate使UNICODE_STRING成为Rust的第一类公民。通过以下措施实现安全性

  • UNICODE_STRING被拆分为3个Rust类型,分别用于处理引用、可变引用和所有者字符串。你永远不需要调用一个unsafe方法。
  • 所有方法都是可失败的(除了分配和像Add这样的特性,因为Rust目前没有提供可失败的选择)。
  • 内部缓冲区在可能的情况下总是以NUL结尾。虽然根据规范不是必需的,但这种防御性的方法可以防止外部应用程序错误地将内部缓冲区作为NUL结尾的字符串处理。

此外,此crate还提供了U16StrLe类型。由于UTF-16是Windows上无处不在的字符编码,许多磁盘上的字符串都是以UTF-16小端存储的。U16StrLe允许在不将它们转换为其他字符串类型之前对这种字符串的字节切片执行基本操作。ntfs crate是它的一个用户。

示例

你可以像处理其他Rust字符串类型一样处理这些字符串类型

let mut string = NtUnicodeString::try_from("Hello! ").unwrap();
string.try_push_str("Moin!").unwrap();
println!("{string}");

也支持从原始的u16字符串缓冲区以及widestring crate中的U16CStrU16Str类型转换

let abc = NtUnicodeString::try_from_u16(&[b'A' as u16, b'B' as u16, b'C' as u16]).unwrap();
let de = NtUnicodeString::try_from_u16_until_nul(&[b'D' as u16, b'E' as u16, 0]).unwrap();
let fgh = NtUnicodeString::try_from(u16cstr!("FGH")).unwrap();
let ijk = NtUnicodeString::try_from(u16str!("IJK")).unwrap();

就像一个String在传递给适当的函数时自动解引用到一个&str一样,你可以用NtUnicodeString做到同样的效果,它将解引用到&NtUnicodeStr

let string = NtUnicodeString::try_from("My String").unwrap();
subfunction(&string);

fn subfunction(str_ref: &NtUnicodeStr) {
    println!("Hello from subfunction with \"{str_ref}\".");
}

可以在编译时创建常量UNICODE_STRING。这提供了具有'static生命周期的字符串,并在运行时节省了UTF-16转换

const MY_CONSTANT_STRING: NtUnicodeStr<'static> = nt_unicode_str!("My Constant String");

最后,你很可能想将你的NtUnicodeStrNtUnicodeStrMutNtUnicodeString传递给一个期望一个指向UNICODE_STRING指针的FFI函数。使用as_ptras_mut_ptr方法来获取不可变或可变指针。

no_std支持

此crate与no_std兼容,因此可以在所有上下文中使用。

但是,堆分配的NtUnicodeString结构仅在alloc功能(默认启用)下可用。如果你想在没有堆分配的纯no_std环境中使用此crate,请使用default-features = false来禁用默认的alloc功能。

许可证

此crate的许可证为以下之一

您可选择。

除非您明确声明,否则您根据Apache-2.0许可证定义的任何有意提交以包含在作品中的贡献,将如上双许可,没有任何附加条款或条件。

依赖项

~0.8–1.2MB
~24K SLoC