use crate::{
alloc::NSTD_ALLOCATOR,
core::{
alloc::NSTDAllocError::NSTD_ALLOC_ERROR_NONE,
optional::NSTDOptional,
str::{nstd_core_str_as_ptr, nstd_core_str_byte_len, NSTDStr},
},
vec::{
nstd_vec_as_ptr_mut, nstd_vec_new, nstd_vec_new_with_cap, nstd_vec_push, nstd_vec_set_len,
NSTDOptionalVec,
},
NSTDChar16, NSTDUInt,
};
use core::ptr::addr_of;
use nstdapi::nstdapi;
use windows_sys::Win32::Globalization::{u_strFromUTF8, U_BUFFER_OVERFLOW_ERROR, U_ZERO_ERROR};
#[nstdapi]
pub unsafe fn nstd_os_windows_str_to_utf16(str: &NSTDStr) -> NSTDOptionalVec<'_> {
const CHAR_SIZE: NSTDUInt = core::mem::size_of::<NSTDChar16>();
const CHAR_ALIGN: NSTDUInt = core::mem::align_of::<NSTDChar16>();
if let Ok(len) = nstd_core_str_byte_len(str).try_into() {
if len == 0 {
let mut v = nstd_vec_new(&NSTD_ALLOCATOR, CHAR_SIZE, CHAR_ALIGN);
let nul: NSTDChar16 = 0;
return match nstd_vec_push(&mut v, addr_of!(nul).cast()) {
NSTD_ALLOC_ERROR_NONE => NSTDOptional::Some(v),
_ => NSTDOptional::None,
};
}
let mut u16_len = 0;
let str_ptr = nstd_core_str_as_ptr(str);
let mut errc = U_ZERO_ERROR;
u_strFromUTF8(
core::ptr::null_mut(),
0,
&mut u16_len,
str_ptr,
len,
&mut errc,
);
#[allow(clippy::arithmetic_side_effects, clippy::cast_sign_loss)]
if errc == U_ZERO_ERROR || errc == U_BUFFER_OVERFLOW_ERROR {
u16_len += 1;
if let NSTDOptional::Some(mut buf) =
nstd_vec_new_with_cap(&NSTD_ALLOCATOR, CHAR_SIZE, CHAR_ALIGN, u16_len as _)
{
let buf_ptr = nstd_vec_as_ptr_mut(&mut buf).cast();
errc = U_ZERO_ERROR;
u_strFromUTF8(
buf_ptr,
u16_len,
core::ptr::null_mut(),
str_ptr,
len,
&mut errc,
);
if errc == U_ZERO_ERROR {
nstd_vec_set_len(&mut buf, u16_len as _);
return NSTDOptional::Some(buf);
}
}
}
}
NSTDOptional::None
}