aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-08-06 16:09:18 +0100
committerGitHub <noreply@github.com>2025-08-06 16:09:18 +0100
commit09a1e170bc92a0ea48a8ee67599c2936e924fe4d (patch)
tree92b44b34a1f2f0c4a8c96a49ab61bb5177432ed7 /core
parentec7509430369eb5d57a081507792dc03b1c05bab (diff)
parentaf3184adc96cef59fff986ea6400caa6dbdb56ae (diff)
Merge pull request #5530 from odin-lang/bill/utf16-strings
UTF-16 string types: `string16` & `cstring16`
Diffstat (limited to 'core')
-rw-r--r--core/c/libc/locale.odin16
-rw-r--r--core/debug/trace/trace_windows.odin2
-rw-r--r--core/dynlib/lib_windows.odin2
-rw-r--r--core/encoding/cbor/tags.odin2
-rw-r--r--core/encoding/cbor/unmarshal.odin2
-rw-r--r--core/encoding/json/marshal.odin8
-rw-r--r--core/encoding/json/unmarshal.odin4
-rw-r--r--core/flags/internal_rtti.odin2
-rw-r--r--core/fmt/fmt.odin92
-rw-r--r--core/io/io.odin24
-rw-r--r--core/io/util.odin27
-rw-r--r--core/mem/virtual/virtual_windows.odin2
-rw-r--r--core/os/dir_windows.odin2
-rw-r--r--core/os/os2/dir_windows.odin14
-rw-r--r--core/os/os2/env_windows.odin2
-rw-r--r--core/os/os2/file_windows.odin70
-rw-r--r--core/os/os2/path_windows.odin8
-rw-r--r--core/os/os2/process_windows.odin8
-rw-r--r--core/os/os2/stat_windows.odin14
-rw-r--r--core/os/os2/temp_file_windows.odin4
-rw-r--r--core/os/os2/user_windows.odin3
-rw-r--r--core/os/stat_windows.odin4
-rw-r--r--core/path/filepath/path_windows.odin4
-rw-r--r--core/reflect/types.odin9
-rw-r--r--core/sys/info/platform_windows.odin12
-rw-r--r--core/sys/windows/comctl32.odin10
-rw-r--r--core/sys/windows/ip_helper.odin6
-rw-r--r--core/sys/windows/kernel32.odin2
-rw-r--r--core/sys/windows/types.odin8
-rw-r--r--core/sys/windows/util.odin50
-rw-r--r--core/time/timezone/tz_windows.odin8
-rw-r--r--core/unicode/utf16/utf16.odin52
32 files changed, 343 insertions, 130 deletions
diff --git a/core/c/libc/locale.odin b/core/c/libc/locale.odin
index 27317526c..3216e0f90 100644
--- a/core/c/libc/locale.odin
+++ b/core/c/libc/locale.odin
@@ -72,14 +72,14 @@ when ODIN_OS == .Windows {
n_sep_by_space: c.char,
p_sign_posn: c.char,
n_sign_posn: c.char,
- _W_decimal_point: [^]u16 `fmt:"s,0"`,
- _W_thousands_sep: [^]u16 `fmt:"s,0"`,
- _W_int_curr_symbol: [^]u16 `fmt:"s,0"`,
- _W_currency_symbol: [^]u16 `fmt:"s,0"`,
- _W_mon_decimal_point: [^]u16 `fmt:"s,0"`,
- _W_mon_thousands_sep: [^]u16 `fmt:"s,0"`,
- _W_positive_sign: [^]u16 `fmt:"s,0"`,
- _W_negative_sign: [^]u16 `fmt:"s,0"`,
+ _W_decimal_point: cstring16,
+ _W_thousands_sep: cstring16,
+ _W_int_curr_symbol: cstring16,
+ _W_currency_symbol: cstring16,
+ _W_mon_decimal_point: cstring16,
+ _W_mon_thousands_sep: cstring16,
+ _W_positive_sign: cstring16,
+ _W_negative_sign: cstring16,
}
} else {
lconv :: struct {
diff --git a/core/debug/trace/trace_windows.odin b/core/debug/trace/trace_windows.odin
index 96507714c..04e92f125 100644
--- a/core/debug/trace/trace_windows.odin
+++ b/core/debug/trace/trace_windows.odin
@@ -54,7 +54,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (
symbol.SizeOfStruct = size_of(symbol^)
symbol.MaxNameLen = 255
if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
- fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator)
+ fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator)
} else {
fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
}
diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin
index 05cd2cb3c..95372dac6 100644
--- a/core/dynlib/lib_windows.odin
+++ b/core/dynlib/lib_windows.odin
@@ -13,7 +13,7 @@ _LIBRARY_FILE_EXTENSION :: "dll"
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
wide_path := win32.utf8_to_wstring(path, allocator)
- defer free(wide_path, allocator)
+ defer free(rawptr(wide_path), allocator)
handle := cast(Library)win32.LoadLibraryW(wide_path)
return handle, handle != nil
}
diff --git a/core/encoding/cbor/tags.odin b/core/encoding/cbor/tags.odin
index 17420af46..ae1664dfc 100644
--- a/core/encoding/cbor/tags.odin
+++ b/core/encoding/cbor/tags.odin
@@ -298,7 +298,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number,
#partial switch t in ti.variant {
case reflect.Type_Info_String:
-
+ assert(t.encoding == .UTF_8)
if t.is_cstring {
length := base64.decoded_len(bytes)
builder := strings.builder_make(0, length+1)
diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin
index 365ac5d6f..043b2ec60 100644
--- a/core/encoding/cbor/unmarshal.odin
+++ b/core/encoding/cbor/unmarshal.odin
@@ -335,6 +335,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a
_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
#partial switch t in ti.variant {
case reflect.Type_Info_String:
+ assert(t.encoding == .UTF_8)
+
bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
if t.is_cstring {
diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin
index ebb9a639c..cdb00a354 100644
--- a/core/encoding/json/marshal.odin
+++ b/core/encoding/json/marshal.odin
@@ -353,10 +353,10 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch x in v {
- case string:
- return x == ""
- case cstring:
- return x == nil || x == ""
+ case string: return x == ""
+ case cstring: return x == nil || x == ""
+ case string16: return x == ""
+ case cstring16: return x == nil || x == ""
}
case runtime.Type_Info_Any:
return v.(any) == nil
diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin
index b9ed1476f..0b65adaac 100644
--- a/core/encoding/json/unmarshal.odin
+++ b/core/encoding/json/unmarshal.odin
@@ -570,7 +570,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
key_ptr: rawptr
#partial switch tk in t.key.variant {
- case runtime.Type_Info_String:
+ case runtime.Type_Info_String:
+ assert(tk.encoding == .UTF_8)
+
key_ptr = rawptr(&key)
key_cstr: cstring
if reflect.is_cstring(t.key) {
diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin
index 1c559ca55..a1b050597 100644
--- a/core/flags/internal_rtti.odin
+++ b/core/flags/internal_rtti.odin
@@ -127,6 +127,8 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
}
case runtime.Type_Info_String:
+ assert(specific_type_info.encoding == .UTF_8)
+
if specific_type_info.is_cstring {
cstr_ptr := (^cstring)(ptr)
if cstr_ptr != nil {
diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin
index 0f6470cca..9c245de94 100644
--- a/core/fmt/fmt.odin
+++ b/core/fmt/fmt.odin
@@ -1551,6 +1551,79 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) {
fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) {
fmt_string(fi, string(s), verb)
}
+
+// Formats a string UTF-16 with a specific format.
+//
+// Inputs:
+// - fi: Pointer to the Info struct containing format settings.
+// - s: The string to format.
+// - verb: The format specifier character (e.g. 's', 'v', 'q', 'x', 'X').
+//
+fmt_string16 :: proc(fi: ^Info, s: string16, verb: rune) {
+ s, verb := s, verb
+ if ol, ok := fi.optional_len.?; ok {
+ s = s[:clamp(ol, 0, len(s))]
+ }
+ if !fi.in_bad && fi.record_level > 0 && verb == 'v' {
+ verb = 'q'
+ }
+
+ switch verb {
+ case 's', 'v':
+ if fi.width_set {
+ if fi.width > len(s) {
+ if fi.minus {
+ io.write_string16(fi.writer, s, &fi.n)
+ }
+
+ for _ in 0..<fi.width - len(s) {
+ io.write_byte(fi.writer, ' ', &fi.n)
+ }
+
+ if !fi.minus {
+ io.write_string16(fi.writer, s, &fi.n)
+ }
+ } else {
+ io.write_string16(fi.writer, s, &fi.n)
+ }
+ } else {
+ io.write_string16(fi.writer, s, &fi.n)
+ }
+
+ case 'q', 'w': // quoted string
+ io.write_quoted_string16(fi.writer, s, '"', &fi.n)
+
+ case 'x', 'X':
+ space := fi.space
+ fi.space = false
+ defer fi.space = space
+
+ for i in 0..<len(s) {
+ if i > 0 && space {
+ io.write_byte(fi.writer, ' ', &fi.n)
+ }
+ char_set := __DIGITS_UPPER
+ if verb == 'x' {
+ char_set = __DIGITS_LOWER
+ }
+ _fmt_int(fi, u64(s[i]), 16, false, bit_size=16, digits=char_set)
+ }
+
+ case:
+ fmt_bad_verb(fi, verb)
+ }
+}
+// Formats a C-style UTF-16 string with a specific format.
+//
+// Inputs:
+// - fi: Pointer to the Info struct containing format settings.
+// - s: The C-style string to format.
+// - verb: The format specifier character (Ref fmt_string).
+//
+fmt_cstring16 :: proc(fi: ^Info, s: cstring16, verb: rune) {
+ fmt_string16(fi, string16(s), verb)
+}
+
// Formats a raw pointer with a specific format.
//
// Inputs:
@@ -2273,14 +2346,14 @@ fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflec
}
switch reflect.type_info_base(elem).id {
- case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return
- case u16: print_utf16(fi, ([^]u16)(data)[:n]); return
- case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
- case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
- case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
- case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
- case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
- case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
+ case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return
+ case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return
+ case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
+ case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
+ case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
+ case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
+ case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
+ case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
}
}
if verb == 'p' {
@@ -3210,6 +3283,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(fi, a, verb)
case cstring: fmt_cstring(fi, a, verb)
+ case string16: fmt_string16(fi, a, verb)
+ case cstring16: fmt_cstring16(fi, a, verb)
+
case typeid: reflect.write_typeid(fi.writer, a, &fi.n)
case i16le: fmt_int(fi, u64(a), true, 16, verb)
diff --git a/core/io/io.odin b/core/io/io.odin
index c2b44cbdb..c4eb6a073 100644
--- a/core/io/io.odin
+++ b/core/io/io.odin
@@ -5,6 +5,7 @@ package io
import "base:intrinsics"
import "core:unicode/utf8"
+import "core:unicode/utf16"
// Seek whence values
Seek_From :: enum {
@@ -314,6 +315,29 @@ write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int,
return write(s, transmute([]byte)str, n_written)
}
+// write_string16 writes the contents of the string16 s to w reencoded as utf-8
+write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: int, err: Error) {
+ for i := 0; i < len(str); i += 1 {
+ r := rune(utf16.REPLACEMENT_CHAR)
+ switch c := str[i]; {
+ case c < utf16._surr1, utf16._surr3 <= c:
+ r = rune(c)
+ case utf16._surr1 <= c && c < utf16._surr2 && i+1 < len(str) &&
+ utf16._surr2 <= str[i+1] && str[i+1] < utf16._surr3:
+ r = utf16.decode_surrogate_pair(rune(c), rune(str[i+1]))
+ i += 1
+ }
+
+ w: int
+ w, err = write_rune(s, r, n_written)
+ n += w
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
// write_rune writes a UTF-8 encoded rune to w.
write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
defer if err == nil && n_written != nil {
diff --git a/core/io/util.odin b/core/io/util.odin
index fa98e007b..72983523a 100644
--- a/core/io/util.odin
+++ b/core/io/util.odin
@@ -264,6 +264,33 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
return
}
+write_quoted_string16 :: proc(w: Writer, str: string16, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
+ defer if n_written != nil {
+ n_written^ += n
+ }
+ write_byte(w, quote, &n) or_return
+ for width, s := 0, str; len(s) > 0; s = s[width:] {
+ r := rune(s[0])
+ width = 1
+ if r >= utf8.RUNE_SELF {
+ r, width = utf16.decode_rune_in_string(s)
+ }
+ if width == 1 && r == utf8.RUNE_ERROR {
+ write_byte(w, '\\', &n) or_return
+ write_byte(w, 'x', &n) or_return
+ write_byte(w, DIGITS_LOWER[s[0]>>4], &n) or_return
+ write_byte(w, DIGITS_LOWER[s[0]&0xf], &n) or_return
+ continue
+ }
+
+ n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return
+
+ }
+ write_byte(w, quote, &n) or_return
+ return
+}
+
+
// writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin
index 0da8498d5..3fd4eeb68 100644
--- a/core/mem/virtual/virtual_windows.odin
+++ b/core/mem/virtual/virtual_windows.odin
@@ -72,7 +72,7 @@ foreign Kernel32 {
flProtect: u32,
dwMaximumSizeHigh: u32,
dwMaximumSizeLow: u32,
- lpName: [^]u16,
+ lpName: cstring16,
) -> rawptr ---
MapViewOfFile :: proc(
diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin
index ae3e6922c..40f4b9e9b 100644
--- a/core/os/dir_windows.odin
+++ b/core/os/dir_windows.odin
@@ -87,7 +87,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
defer delete(path)
find_data := &win32.WIN32_FIND_DATAW{}
- find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
+ find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
if find_handle == win32.INVALID_HANDLE_VALUE {
err = get_last_error()
return dfi[:], err
diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin
index 4cf1f8396..6c754a677 100644
--- a/core/os/os2/dir_windows.odin
+++ b/core/os/os2/dir_windows.odin
@@ -16,7 +16,7 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
}
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
- path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator) or_else ""}, allocator) or_return
+ path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
defer win32.CloseHandle(handle)
@@ -107,15 +107,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
return
}
- wpath: []u16
- {
- i := 0
- for impl.wname[i] != 0 {
- i += 1
- }
- wpath = impl.wname[:i]
- }
-
+ wpath := string16(impl.wname)
temp_allocator := TEMP_ALLOCATOR_GUARD({})
wpath_search := make([]u16, len(wpath)+3, temp_allocator)
@@ -124,7 +116,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
wpath_search[len(wpath)+1] = '*'
wpath_search[len(wpath)+2] = 0
- it.impl.find_handle = win32.FindFirstFileW(raw_data(wpath_search), &it.impl.find_data)
+ it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data)
if it.impl.find_handle == win32.INVALID_HANDLE_VALUE {
read_directory_iterator_set_error(it, impl.name, _get_platform_error())
return
diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin
index 55b2bb5ee..d389f8860 100644
--- a/core/os/os2/env_windows.odin
+++ b/core/os/os2/env_windows.odin
@@ -31,7 +31,7 @@ _lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value:
return "", false
}
- value = win32_utf16_to_utf8(b[:n], allocator) or_else ""
+ value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else ""
found = true
return
}
diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin
index dbac78d0e..25e9cb4b0 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/os2/file_windows.odin
@@ -247,7 +247,7 @@ _destroy :: proc(f: ^File_Impl) -> Error {
}
a := f.allocator
- err0 := free(f.wname, a)
+ err0 := free(rawptr(f.wname), a)
err1 := delete(f.name, a)
err2 := delete(f.r_buf, a)
err3 := delete(f.w_buf, a)
@@ -619,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error {
return .Unsupported
}
-_open_sym_link :: proc(p: [^]u16) -> (handle: win32.HANDLE, err: Error) {
+_open_sym_link :: proc(p: cstring16) -> (handle: win32.HANDLE, err: Error) {
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS)
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil)
@@ -661,7 +661,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
}
- handle := _open_sym_link(raw_data(p)) or_return
+ handle := _open_sym_link(cstring16(raw_data(p))) or_return
defer win32.CloseHandle(handle)
n := win32.GetFinalPathNameByHandleW(handle, nil, 0, win32.VOLUME_NAME_DOS)
@@ -672,7 +672,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
buf := make([]u16, n+1, temp_allocator)
- n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
+ n = win32.GetFinalPathNameByHandleW(handle, cstring16(raw_data(buf)), u32(len(buf)), win32.VOLUME_NAME_DOS)
if n == 0 {
return "", _get_platform_error()
}
@@ -713,7 +713,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
switch rdb.ReparseTag {
case win32.IO_REPARSE_TAG_SYMLINK:
rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest)
- pb := win32.wstring(&rb.PathBuffer)
+ pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 {
@@ -723,7 +723,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
case win32.IO_REPARSE_TAG_MOUNT_POINT:
rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest)
- pb := win32.wstring(&rb.PathBuffer)
+ pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
return _normalize_link_path(p, allocator)
@@ -874,8 +874,8 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
@(private="package", require_results)
-win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) {
- ws = raw_data(win32_utf8_to_utf16(s, allocator) or_return)
+win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: cstring16, err: runtime.Allocator_Error) {
+ ws = cstring16(raw_data(win32_utf8_to_utf16(s, allocator) or_return))
return
}
@@ -909,24 +909,60 @@ win32_utf8_to_utf16 :: proc(s: string, allocator: runtime.Allocator) -> (ws: []u
}
@(private="package", require_results)
-win32_wstring_to_utf8 :: proc(s: [^]u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
- if s == nil || s[0] == 0 {
+win32_wstring_to_utf8 :: proc(s: cstring16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
+ if s == nil || s == "" {
return "", nil
}
- n := 0
- for s[n] != 0 {
- n += 1
+ return win32_utf16_to_utf8(string16(s), allocator)
+}
+
+@(private="package")
+win32_utf16_to_utf8 :: proc{
+ win32_utf16_string16_to_utf8,
+ win32_utf16_u16_to_utf8,
+}
+
+@(private="package", require_results)
+win32_utf16_string16_to_utf8 :: proc(s: string16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
+ if len(s) == 0 {
+ return
}
- return win32_utf16_to_utf8(s[:n], allocator)
+
+ n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
+ if n == 0 {
+ return
+ }
+
+ // If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated
+ // and will scan it to find the first null terminated character. The resulting string will
+ // also be null terminated.
+ // If N > 0 it assumes the wide string is not null terminated and the resulting string
+ // will not be null terminated.
+ text := make([]byte, n, allocator) or_return
+
+ n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
+ if n1 == 0 {
+ delete(text, allocator)
+ return
+ }
+
+ for i in 0..<n {
+ if text[i] == 0 {
+ n = i
+ break
+ }
+ }
+ res = string(text[:n])
+ return
}
@(private="package", require_results)
-win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
+win32_utf16_u16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if len(s) == 0 {
return
}
- n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0, nil, nil)
+ n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
if n == 0 {
return
}
@@ -938,7 +974,7 @@ win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: str
// will not be null terminated.
text := make([]byte, n, allocator) or_return
- n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(text), n, nil, nil)
+ n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
if n1 == 0 {
delete(text, allocator)
return
diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin
index c2e51040f..e0a00b07a 100644
--- a/core/os/os2/path_windows.odin
+++ b/core/os/os2/path_windows.odin
@@ -91,11 +91,11 @@ _remove_all :: proc(path: string) -> Error {
nil,
win32.FO_DELETE,
dir,
- &empty[0],
+ cstring16(&empty[0]),
win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT,
false,
nil,
- &empty[0],
+ cstring16(&empty[0]),
}
res := win32.SHFileOperationW(&file_op)
if res != 0 {
@@ -303,13 +303,13 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
}
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator)
- n := win32.GetFullPathNameW(raw_data(rel_utf16), 0, nil, nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), 0, nil, nil)
if n == 0 {
return "", Platform_Error(win32.GetLastError())
}
buf := make([]u16, n, temp_allocator) or_return
- n = win32.GetFullPathNameW(raw_data(rel_utf16), u32(n), raw_data(buf), nil)
+ n = win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), u32(n), cstring16(raw_data(buf)), nil)
if n == 0 {
return "", Platform_Error(win32.GetLastError())
}
diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin
index 199e5ad74..990da6616 100644
--- a/core/os/os2/process_windows.odin
+++ b/core/os/os2/process_windows.odin
@@ -175,7 +175,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
info.fields += {.Command_Line}
}
if .Command_Args in selection {
- info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
+ info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
info.fields += {.Command_Args}
}
}
@@ -286,7 +286,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields += {.Command_Line}
}
if .Command_Args in selection {
- info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
+ info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
info.fields += {.Command_Args}
}
}
@@ -610,7 +610,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
err =_get_platform_error()
return
}
- return win32_wstring_to_utf8(raw_data(entry.szExePath[:]), allocator)
+ return win32_wstring_to_utf8(cstring16(raw_data(entry.szExePath[:])), allocator)
}
_get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) {
@@ -650,7 +650,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
return strings.concatenate({domain, "\\", username}, allocator)
}
-_parse_command_line :: proc(cmd_line_w: [^]u16, allocator: runtime.Allocator) -> (argv: []string, err: Error) {
+_parse_command_line :: proc(cmd_line_w: cstring16, allocator: runtime.Allocator) -> (argv: []string, err: Error) {
argc: i32
argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc)
if argv_w == nil {
diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin
index 3cdc80405..3dee42be6 100644
--- a/core/os/os2/stat_windows.odin
+++ b/core/os/os2/stat_windows.odin
@@ -49,12 +49,12 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
p := win32_utf8_to_utf16(name, temp_allocator) or_return
- n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 {
return "", _get_platform_error()
}
buf := make([]u16, n+1, temp_allocator)
- n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+ n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 {
return "", _get_platform_error()
}
@@ -140,8 +140,8 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
buf := make([]u16, max(n, 260)+1, temp_allocator)
- n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
- return _cleanpath_from_buf(buf[:n], allocator)
+ n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
+ return _cleanpath_from_buf(string16(buf[:n]), allocator)
}
_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
@@ -158,12 +158,12 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
buf := make([]u16, max(n, 260)+1, temp_allocator)
- n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
+ n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
return _cleanpath_strip_prefix(buf[:n]), nil
}
-_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
- buf := buf
+_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
+ buf := transmute([]u16)buf
buf = _cleanpath_strip_prefix(buf)
return win32_utf16_to_utf8(buf, allocator)
}
diff --git a/core/os/os2/temp_file_windows.odin b/core/os/os2/temp_file_windows.odin
index 9d75ef99d..91ea284a1 100644
--- a/core/os/os2/temp_file_windows.odin
+++ b/core/os/os2/temp_file_windows.odin
@@ -12,12 +12,12 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator)
- n = win32.GetTempPathW(u32(len(b)), raw_data(b))
+ n = win32.GetTempPathW(u32(len(b)), cstring16(raw_data(b)))
if n == 3 && b[1] == ':' && b[2] == '\\' {
} else if n > 0 && b[n-1] == '\\' {
n -= 1
}
- return win32_utf16_to_utf8(b[:n], allocator)
+ return win32_utf16_to_utf8(string16(b[:n]), allocator)
}
diff --git a/core/os/os2/user_windows.odin b/core/os/os2/user_windows.odin
index d68f933ce..75d0ba6ac 100644
--- a/core/os/os2/user_windows.odin
+++ b/core/os/os2/user_windows.odin
@@ -74,6 +74,5 @@ _get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.
return "", .Invalid_Path
}
- dir, _ = win32.wstring_to_utf8(path_w, -1, allocator)
- return
+ return win32_wstring_to_utf8(cstring16(path_w), allocator)
} \ No newline at end of file
diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin
index ca4f87668..662c9f9e6 100644
--- a/core/os/stat_windows.odin
+++ b/core/os/stat_windows.odin
@@ -17,7 +17,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
buf := make([dynamic]u16, 100)
defer delete(buf)
for {
- n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 {
return "", get_last_error()
}
@@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> (
return nil, get_last_error()
}
buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
- buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
+ buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
return buf[:buf_len], nil
}
@(private, require_results)
diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin
index 0dcb28cf8..24c6e00a5 100644
--- a/core/path/filepath/path_windows.odin
+++ b/core/path/filepath/path_windows.odin
@@ -61,13 +61,13 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
}
p := win32.utf8_to_utf16(name, ta)
- n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 {
return "", os.get_last_error()
}
buf := make([]u16, n, ta)
- n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+ n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 {
delete(buf)
return "", os.get_last_error()
diff --git a/core/reflect/types.odin b/core/reflect/types.odin
index 511c5c9bd..98b7b368f 100644
--- a/core/reflect/types.odin
+++ b/core/reflect/types.odin
@@ -511,9 +511,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
io.write_i64(w, i64(8*ti.size), 10, &n) or_return
case Type_Info_String:
if info.is_cstring {
- io.write_string(w, "cstring", &n) or_return
- } else {
- io.write_string(w, "string", &n) or_return
+ io.write_byte(w, 'c', &n) or_return
+ }
+ io.write_string(w, "string", &n) or_return
+ switch info.encoding {
+ case .UTF_8: /**/
+ case .UTF_16: io.write_string(w, "16", &n) or_return
}
case Type_Info_Boolean:
switch ti.id {
diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin
index 4c00ddadf..dd1441d30 100644
--- a/core/sys/info/platform_windows.odin
+++ b/core/sys/info/platform_windows.odin
@@ -324,8 +324,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_SZ,
nil,
raw_data(result_wide[:]),
@@ -359,8 +359,8 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool
result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_DWORD,
nil,
&res,
@@ -386,8 +386,8 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool
result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_QWORD,
nil,
&res,
diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin
index d954f952c..c7a166634 100644
--- a/core/sys/windows/comctl32.odin
+++ b/core/sys/windows/comctl32.odin
@@ -573,10 +573,10 @@ Button_GetTextMargin :: #force_inline proc "system" (hwnd: HWND, pmargin: ^RECT)
return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin))
}
Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(psz))
+ return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(rawptr(psz)))
}
Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(psz))
+ return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(rawptr(psz)))
}
Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT {
return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0)
@@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct {
PEDITBALLOONTIP :: ^EDITBALLOONTIP
Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(lpcwText))
+ return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(rawptr(lpcwText)))
}
Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(lpcwText))
+ return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(rawptr(lpcwText)))
}
Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText)
@@ -1197,7 +1197,7 @@ ListView_GetItemPosition :: #force_inline proc "system" (hwnd: HWND, i: c_int, p
return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt))
}
ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int {
- return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(psz))
+ return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(rawptr(psz)))
}
ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int {
return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo))
diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin
index 7a6e545ac..d2e75d531 100644
--- a/core/sys/windows/ip_helper.odin
+++ b/core/sys/windows/ip_helper.odin
@@ -38,9 +38,9 @@ IP_Adapter_Addresses :: struct {
FirstAnycastAddress: ^IP_ADAPTER_ANYCAST_ADDRESS_XP,
FirstMulticastAddress: ^IP_ADAPTER_MULTICAST_ADDRESS_XP,
FirstDnsServerAddress: ^IP_ADAPTER_DNS_SERVER_ADDRESS_XP,
- DnsSuffix: ^u16,
- Description: ^u16,
- FriendlyName: ^u16,
+ DnsSuffix: cstring16,
+ Description: cstring16,
+ FriendlyName: cstring16,
PhysicalAddress: [8]u8,
PhysicalAddressLength: u32,
Anonymous2: struct #raw_union {
diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin
index 76f2897ac..114e70b41 100644
--- a/core/sys/windows/kernel32.odin
+++ b/core/sys/windows/kernel32.odin
@@ -258,7 +258,7 @@ foreign kernel32 {
) -> BOOL ---
CreateProcessW :: proc(
lpApplicationName: LPCWSTR,
- lpCommandLine: LPWSTR,
+ lpCommandLine: LPCWSTR,
lpProcessAttributes: LPSECURITY_ATTRIBUTES,
lpThreadAttributes: LPSECURITY_ATTRIBUTES,
bInheritHandles: BOOL,
diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin
index 92b1cb15c..d5c9b1d20 100644
--- a/core/sys/windows/types.odin
+++ b/core/sys/windows/types.odin
@@ -107,8 +107,8 @@ PDWORD64 :: ^DWORD64
PDWORD_PTR :: ^DWORD_PTR
ATOM :: distinct WORD
-wstring :: [^]WCHAR
-PWSTR :: [^]WCHAR
+wstring :: cstring16
+PWSTR :: cstring16
PBYTE :: ^BYTE
LPBYTE :: ^BYTE
@@ -145,7 +145,7 @@ LPSTR :: ^CHAR
LPWSTR :: ^WCHAR
OLECHAR :: WCHAR
BSTR :: ^OLECHAR
-LPOLESTR :: ^OLECHAR
+LPOLESTR :: cstring16
LPCOLESTR :: LPCSTR
LPFILETIME :: ^FILETIME
LPWSABUF :: ^WSABUF
@@ -1698,7 +1698,7 @@ NM_FONTCHANGED :: NM_OUTOFMEMORY-22
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
-PCZZWSTR :: ^WCHAR
+PCZZWSTR :: cstring16
SHFILEOPSTRUCTW :: struct {
hwnd: HWND,
diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin
index 995e8e0e5..10dc907e7 100644
--- a/core/sys/windows/util.odin
+++ b/core/sys/windows/util.odin
@@ -122,14 +122,14 @@ utf8_to_utf16 :: proc{utf8_to_utf16_alloc, utf8_to_utf16_buf}
utf8_to_wstring_alloc :: proc(s: string, allocator := context.temp_allocator) -> wstring {
if res := utf8_to_utf16(s, allocator); len(res) > 0 {
- return raw_data(res)
+ return wstring(raw_data(res))
}
return nil
}
utf8_to_wstring_buf :: proc(buf: []u16, s: string) -> wstring {
if res := utf8_to_utf16(buf, s); len(res) > 0 {
- return raw_data(res)
+ return wstring(raw_data(res))
}
return nil
}
@@ -215,7 +215,7 @@ utf16_to_utf8_alloc :: proc(s: []u16, allocator := context.temp_allocator) -> (r
if len(s) == 0 {
return "", nil
}
- return wstring_to_utf8(raw_data(s), len(s), allocator)
+ return wstring_to_utf8(wstring(raw_data(s)), len(s), allocator)
}
/*
@@ -236,7 +236,7 @@ utf16_to_utf8_buf :: proc(buf: []u8, s: []u16) -> (res: string) {
if len(s) == 0 {
return
}
- return wstring_to_utf8(buf, raw_data(s), len(s))
+ return wstring_to_utf8(buf, wstring(raw_data(s)), len(s))
}
utf16_to_utf8 :: proc{utf16_to_utf8_alloc, utf16_to_utf8_buf}
@@ -298,7 +298,7 @@ _add_user :: proc(servername: string, username: string, password: string) -> (ok
servername_w = nil
} else {
server := utf8_to_utf16(servername, context.temp_allocator)
- servername_w = &server[0]
+ servername_w = wstring(&server[0])
}
if len(username) == 0 || len(username) > LM20_UNLEN {
@@ -348,7 +348,7 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s
res := LookupAccountNameW(
nil, // Look on this computer first
- &username_w[0],
+ wstring(&username_w[0]),
&sid,
&cbsid,
nil,
@@ -364,10 +364,10 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s
res = LookupAccountNameW(
nil,
- &username_w[0],
+ wstring(&username_w[0]),
&sid,
&cbsid,
- &cname_w[0],
+ wstring(&cname_w[0]),
&computer_name_size,
&pe_use,
)
@@ -390,7 +390,7 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) {
res := LookupAccountNameW(
nil, // Look on this computer first
- &username_w[0],
+ wstring(&username_w[0]),
sid,
&cbsid,
nil,
@@ -406,10 +406,10 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) {
res = LookupAccountNameW(
nil,
- &username_w[0],
+ wstring(&username_w[0]),
sid,
&cbsid,
- &cname_w[0],
+ wstring(&cname_w[0]),
&computer_name_size,
&pe_use,
)
@@ -428,7 +428,7 @@ add_user_to_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) {
group_name := utf8_to_utf16(group, context.temp_allocator)
ok = NetLocalGroupAddMembers(
nil,
- &group_name[0],
+ wstring(&group_name[0]),
0,
&group_member,
1,
@@ -443,7 +443,7 @@ add_del_from_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) {
group_name := utf8_to_utf16(group, context.temp_allocator)
ok = NetLocalGroupDelMembers(
nil,
- &group_name[0],
+ cstring16(&group_name[0]),
0,
&group_member,
1,
@@ -465,19 +465,19 @@ add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) {
if res == false {
return false, ""
}
- defer LocalFree(sb)
+ defer LocalFree(rawptr(sb))
pszProfilePath := make([]u16, 257, context.temp_allocator)
res2 := CreateProfile(
sb,
- &username_w[0],
- &pszProfilePath[0],
+ cstring16(&username_w[0]),
+ cstring16(&pszProfilePath[0]),
257,
)
if res2 != 0 {
return false, ""
}
- profile_path = wstring_to_utf8(&pszProfilePath[0], 257) or_else ""
+ profile_path = wstring_to_utf8(wstring(&pszProfilePath[0]), 257) or_else ""
return true, profile_path
}
@@ -495,7 +495,7 @@ delete_user_profile :: proc(username: string) -> (ok: bool) {
if res == false {
return false
}
- defer LocalFree(sb)
+ defer LocalFree(rawptr(sb))
res2 := DeleteProfileW(
sb,
@@ -548,13 +548,13 @@ delete_user :: proc(servername: string, username: string) -> (ok: bool) {
servername_w = nil
} else {
server := utf8_to_utf16(servername, context.temp_allocator)
- servername_w = &server[0]
+ servername_w = wstring(&server[0])
}
username_w := utf8_to_utf16(username)
res := NetUserDel(
servername_w,
- &username_w[0],
+ wstring(&username_w[0]),
)
if res != .Success {
return false
@@ -586,9 +586,9 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
user_token: HANDLE
ok = bool(LogonUserW(
- lpszUsername = &username_w[0],
- lpszDomain = &domain_w[0],
- lpszPassword = &password_w[0],
+ lpszUsername = wstring(&username_w[0]),
+ lpszDomain = wstring(&domain_w[0]),
+ lpszPassword = wstring(&password_w[0]),
dwLogonType = .NEW_CREDENTIALS,
dwLogonProvider = .WINNT50,
phToken = &user_token,
@@ -605,8 +605,8 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
ok = bool(CreateProcessAsUserW(
user_token,
- &app_w[0],
- &commandline_w[0],
+ wstring(&app_w[0]),
+ wstring(&commandline_w[0]),
nil, // lpProcessAttributes,
nil, // lpThreadAttributes,
false, // bInheritHandles,
diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin
index 8dc5f533c..fe00719a2 100644
--- a/core/time/timezone/tz_windows.odin
+++ b/core/time/timezone/tz_windows.odin
@@ -159,9 +159,9 @@ iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) ->
status: windows.UError
iana_name_wstr := windows.utf8_to_wstring(iana_name, allocator)
- defer free(iana_name_wstr, allocator)
+ defer free(rawptr(iana_name_wstr), allocator)
- wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, raw_data(wintz_name_buffer[:]), len(wintz_name_buffer), &status)
+ wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, cstring16(raw_data(wintz_name_buffer[:])), len(wintz_name_buffer), &status)
if status != .U_ZERO_ERROR {
return
}
@@ -178,7 +178,7 @@ local_tz_name :: proc(allocator := context.allocator) -> (name: string, success:
iana_name_buffer: [128]u16
status: windows.UError
- zone_str_len := windows.ucal_getDefaultTimeZone(raw_data(iana_name_buffer[:]), len(iana_name_buffer), &status)
+ zone_str_len := windows.ucal_getDefaultTimeZone(cstring16(raw_data(iana_name_buffer[:])), len(iana_name_buffer), &status)
if status != .U_ZERO_ERROR {
return
}
@@ -291,7 +291,7 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re
defer delete(tz_key, allocator)
tz_key_wstr := windows.utf8_to_wstring(tz_key, allocator)
- defer free(tz_key_wstr, allocator)
+ defer free(rawptr(tz_key_wstr), allocator)
key: windows.HKEY
res := windows.RegOpenKeyExW(windows.HKEY_LOCAL_MACHINE, tz_key_wstr, 0, windows.KEY_READ, &key)
diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin
index e2bcf7f68..d3f98584b 100644
--- a/core/unicode/utf16/utf16.odin
+++ b/core/unicode/utf16/utf16.odin
@@ -106,7 +106,57 @@ decode :: proc(d: []rune, s: []u16) -> (n: int) {
return
}
-rune_count :: proc(s: []u16) -> (n: int) {
+decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) {
+ r = rune(REPLACEMENT_CHAR)
+ n := len(s)
+ if n < 1 {
+ return
+ }
+ width = 1
+
+
+ switch c := s[0]; {
+ case c < _surr1, _surr3 <= c:
+ r = rune(c)
+ case _surr1 <= c && c < _surr2 && 1 < len(s) &&
+ _surr2 <= s[1] && s[1] < _surr3:
+ r = decode_surrogate_pair(rune(c), rune(s[1]))
+ width += 1
+ }
+ return
+}
+
+string_to_runes :: proc "odin" (s: string16, allocator := context.allocator) -> (runes: []rune) {
+ n := rune_count(s)
+
+ runes = make([]rune, n, allocator)
+ i := 0
+ for r in s {
+ runes[i] = r
+ i += 1
+ }
+ return
+}
+
+
+rune_count :: proc{
+ rune_count_in_string,
+ rune_count_in_slice,
+}
+rune_count_in_string :: proc(s: string16) -> (n: int) {
+ for i := 0; i < len(s); i += 1 {
+ c := s[i]
+ if _surr1 <= c && c < _surr2 && i+1 < len(s) &&
+ _surr2 <= s[i+1] && s[i+1] < _surr3 {
+ i += 1
+ }
+ n += 1
+ }
+ return
+}
+
+
+rune_count_in_slice :: proc(s: []u16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
c := s[i]
if _surr1 <= c && c < _surr2 && i+1 < len(s) &&