# nt-string
[![crates.io](https://img.shields.io/crates/v/nt-string)](https://crates.io/crates/nt-string)
[![docs.rs](https://img.shields.io/docsrs/nt-string)](https://docs.rs/nt-string)
![license: MIT OR Apache-2.0](https://img.shields.io/crates/l/nt-string)
*by Colin Finck <>*
Provides idiomatic Rust implementations for various Windows string types:
* [`NtUnicodeString`](https://docs.rs/nt-string/latest/nt_string/unicode_string/struct.NtUnicodeString.html) (with [`NtUnicodeStr`](https://docs.rs/nt-string/latest/nt_string/unicode_string/struct.NtUnicodeStr.html) and [`NtUnicodeStrMut`](https://docs.rs/nt-string/latest/nt_string/unicode_string/struct.NtUnicodeStrMut.html)):
For interfacing with the Windows kernel string type known as [`UNICODE_STRING`](https://learn.microsoft.com/windows/win32/api/ntdef/ns-ntdef-_unicode_string)
* [`U16StrLe`](https://docs.rs/nt-string/latest/nt_string/u16strle/struct.U16StrLe.html):
For working with byte slices of UTF-16 (little-endian) strings
Other useful UTF-16 string types are already provided by the excellent [`widestring`](https://crates.io/crates/widestring) crate.
This crate tries to integrate as best as possible with them.
## In Action
![](img/windbg.png)
Debugging a Rust application in WinDbg and using the [`dS`](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/ds--ds--display-string-) command to display a `UNICODE_STRING` created in Rust.
As you see, this crate's `NtUnicodeString` and the original `UNICODE_STRING` are fully compatible.
## Details
The `UNICODE_STRING` type was designed for the C programming language, which only knows about NUL-terminated buffers of characters.
To determine the length of such a buffer, you need to iterate over all characters until finding the NUL.
Bad enough?
It gets worse:
A classic buffer overflow occurs if the buffer contains no NUL, but an algorithm attempts to find it anyway.
To overcome these performance and security hazards, `UNICODE_STRING`s consist of a buffer, a buffer capacity ("maximum length"), and a field to indicate the actually used length.
Determining length and capacity is now as simple as querying the corresponding fields.
Length and capacity are 16-bit values and expressed in bytes.
`UNICODE_STRING` has been widely used by the Windows kernel team and also spilled over to some user-mode APIs.
This crate makes `UNICODE_STRING` a first-class Rust citizen.
Safety is achieved via the following measures:
* `UNICODE_STRING` is split into 3 Rust types to handle references, mutable references, and owned strings separately.
You should never need to call an `unsafe` method.
* All methods are fallible (except for allocations and traits like `Add`, where Rust currently does not provide fallible alternatives).
* The internal buffer is NUL-terminated whenever possible.
While not required according to the specification, this defensive approach guards against external applications that never understood `UNICODE_STRING` and mistakenly treat its internal buffer as a NUL-terminated string.
Additionally, this crate provides the `U16StrLe` type.
With UTF-16 being the ubiquitous character encoding in Windows, many on-disk strings are stored in UTF-16 Little-Endian.
`U16StrLe` allows to perform basic operations on byte slices of such strings without converting them to another string type first.
One user is the [ntfs](https://github.com/ColinFinck/ntfs) crate.
## Examples
You can work with these string types just like you work with other Rust string types:
```rust,no_run
let mut string = NtUnicodeString::try_from("Hello! ").unwrap();
string.try_push_str("Moin!").unwrap();
println!("{string}");
```
Conversions are also supported from raw `u16` string buffers as well as the [`U16CStr`](https://docs.rs/widestring/latest/widestring/ustr/struct.U16CStr.html) and [`U16Str`](https://docs.rs/widestring/latest/widestring/ustr/struct.U16Str.html) types of the `widestring` crate:
```rust,no_run
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();
```
Just like a `String` automatically dereferences to a `&str` when you pass it to an appropriate function, you can do the same with an `NtUnicodeString` and it will dereference to an `&NtUnicodeStr`:
```rust,no_run
let string = NtUnicodeString::try_from("My String").unwrap();
subfunction(&string);
fn subfunction(str_ref: &NtUnicodeStr) {
println!("Hello from subfunction with \"{str_ref}\".");
}
```
Constant `UNICODE_STRING`s can be created at compile-time.
This provides strings with a `'static` lifetime and saves a UTF-16 conversion at runtime:
```rust,no_run
const MY_CONSTANT_STRING: NtUnicodeStr<'static> = nt_unicode_str!("My Constant String");
```
Finally, you most likely want to pass your `NtUnicodeStr`, `NtUnicodeStrMut` or `NtUnicodeString` to an FFI function that expects a pointer to a `UNICODE_STRING`.
Use the [`as_ptr`](https://docs.rs/nt-string/latest/nt_string/unicode_string/struct.NtUnicodeStr.html#method.as_ptr) or [`as_mut_ptr`](https://docs.rs/nt-string/latest/nt_string/unicode_string/struct.NtUnicodeStrMut.html#method.as_mut_ptr) methods to get an immutable or mutable pointer.
## `no_std` support
The crate is `no_std`-compatible and therefore usable in all contexts.
However, the heap-allocating `NtUnicodeString` struct is only available via the `alloc` feature (enabled by default).
If you want to use the crate in a pure `no_std` environment without heap allocations, include it with `default-features = false` to disable the default `alloc` feature.
## License
This crate is licensed under either of
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.