| ... | @@ -6,8 +6,13 @@ | ... | @@ -6,8 +6,13 @@ |
| 6 | */ | 6 | */ |
| 7 | | 7 | |
| 8 | #include "os.hpp" | 8 | #include "os.hpp" |
| | 9 | #include "buffer.hpp" |
| | 10 | #include "heap.hpp" |
| 9 | #include "util.hpp" | 11 | #include "util.hpp" |
| 10 | #include "error.hpp" | 12 | #include "error.hpp" |
| | 13 | #include "util_base.hpp" |
| | 14 | #include <stdint.h> |
| | 15 | #include <stdio.h> |
| 11 | | 16 | |
| 12 | #if defined(_WIN32) | 17 | #if defined(_WIN32) |
| 13 | | 18 | |
| ... | @@ -73,6 +78,8 @@ typedef SSIZE_T ssize_t; | ... | @@ -73,6 +78,8 @@ typedef SSIZE_T ssize_t; |
| 73 | #endif | 78 | #endif |
| 74 | | 79 | |
| 75 | #if defined(ZIG_OS_WINDOWS) | 80 | #if defined(ZIG_OS_WINDOWS) |
| | 81 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le); |
| | 82 | static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice<uint8_t> utf8); |
| 76 | static uint64_t windows_perf_freq; | 83 | static uint64_t windows_perf_freq; |
| 77 | #elif defined(__MACH__) | 84 | #elif defined(__MACH__) |
| 78 | static clock_serv_t macos_calendar_clock; | 85 | static clock_serv_t macos_calendar_clock; |
| ... | @@ -148,15 +155,21 @@ static void os_spawn_process_windows(ZigList<const char *> &args, Termination *t | ... | @@ -148,15 +155,21 @@ static void os_spawn_process_windows(ZigList<const char *> &args, Termination *t |
| 148 | os_windows_create_command_line(&command_line, args); | 155 | os_windows_create_command_line(&command_line, args); |
| 149 | | 156 | |
| 150 | PROCESS_INFORMATION piProcInfo = {0}; | 157 | PROCESS_INFORMATION piProcInfo = {0}; |
| 151 | STARTUPINFO siStartInfo = {0}; | 158 | STARTUPINFOW siStartInfo = {0}; |
| 152 | siStartInfo.cb = sizeof(STARTUPINFO); | 159 | siStartInfo.cb = sizeof(STARTUPINFOW); |
| 153 | | 160 | |
| 154 | const char *exe = args.at(0); | 161 | Slice<uint8_t> exe_slice = str(args.at(0)); |
| 155 | BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr, | 162 | auto exe_utf16_slice = Slice<WCHAR>::alloc(exe_slice.len + 1); |
| | 163 | exe_utf16_slice.ptr[utf8_to_utf16le(exe_utf16_slice.ptr, exe_slice)] = 0; |
| | 164 | |
| | 165 | auto command_line_utf16 = Slice<WCHAR>::alloc(buf_len(&command_line) + 1); |
| | 166 | command_line_utf16.ptr[utf8_to_utf16le(command_line_utf16.ptr, buf_to_slice(&command_line))] = 0; |
| | 167 | |
| | 168 | BOOL success = CreateProcessW(exe_utf16_slice.ptr, command_line_utf16.ptr, nullptr, nullptr, TRUE, CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, |
| 156 | &siStartInfo, &piProcInfo); | 169 | &siStartInfo, &piProcInfo); |
| 157 | | 170 | |
| 158 | if (!success) { | 171 | if (!success) { |
| 159 | zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line)); | 172 | zig_panic("CreateProcess failed. exe: %s command_line: %s", args.at(0), buf_ptr(&command_line)); |
| 160 | } | 173 | } |
| 161 | | 174 | |
| 162 | WaitForSingleObject(piProcInfo.hProcess, INFINITE); | 175 | WaitForSingleObject(piProcInfo.hProcess, INFINITE); |
| ... | @@ -269,11 +282,13 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { | ... | @@ -269,11 +282,13 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { |
| 269 | | 282 | |
| 270 | Error os_path_real(Buf *rel_path, Buf *out_abs_path) { | 283 | Error os_path_real(Buf *rel_path, Buf *out_abs_path) { |
| 271 | #if defined(ZIG_OS_WINDOWS) | 284 | #if defined(ZIG_OS_WINDOWS) |
| 272 | buf_resize(out_abs_path, 4096); | 285 | PathSpace rel_path_space = slice_to_prefixed_file_w(buf_to_slice(rel_path)); |
| 273 | if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) { | 286 | PathSpace out_abs_path_space; |
| 274 | zig_panic("_fullpath failed"); | 287 | |
| | 288 | if (_wfullpath(&out_abs_path_space.data.items[0], &rel_path_space.data.items[0], PATH_MAX_WIDE) == nullptr) { |
| | 289 | zig_panic("_wfullpath failed"); |
| 275 | } | 290 | } |
| 276 | buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path))); | 291 | utf16le_ptr_to_utf8(out_abs_path, &out_abs_path_space.data.items[0]); |
| 277 | return ErrorNone; | 292 | return ErrorNone; |
| 278 | #elif defined(ZIG_OS_POSIX) | 293 | #elif defined(ZIG_OS_POSIX) |
| 279 | buf_resize(out_abs_path, PATH_MAX + 1); | 294 | buf_resize(out_abs_path, PATH_MAX + 1); |
| ... | @@ -773,7 +788,8 @@ Error os_fetch_file(FILE *f, Buf *out_buf) { | ... | @@ -773,7 +788,8 @@ Error os_fetch_file(FILE *f, Buf *out_buf) { |
| 773 | | 788 | |
| 774 | Error os_file_exists(Buf *full_path, bool *result) { | 789 | Error os_file_exists(Buf *full_path, bool *result) { |
| 775 | #if defined(ZIG_OS_WINDOWS) | 790 | #if defined(ZIG_OS_WINDOWS) |
| 776 | *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES; | 791 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| | 792 | *result = GetFileAttributesW(&path_space.data.items[0]) != INVALID_FILE_ATTRIBUTES; |
| 777 | return ErrorNone; | 793 | return ErrorNone; |
| 778 | #else | 794 | #else |
| 779 | *result = access(buf_ptr(full_path), F_OK) != -1; | 795 | *result = access(buf_ptr(full_path), F_OK) != -1; |
| ... | @@ -1021,7 +1037,12 @@ Error os_exec_process(ZigList<const char *> &args, | ... | @@ -1021,7 +1037,12 @@ Error os_exec_process(ZigList<const char *> &args, |
| 1021 | } | 1037 | } |
| 1022 | | 1038 | |
| 1023 | Error os_write_file(Buf *full_path, Buf *contents) { | 1039 | Error os_write_file(Buf *full_path, Buf *contents) { |
| | 1040 | #if defined(ZIG_OS_WINDOWS) |
| | 1041 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| | 1042 | FILE *f = _wfopen(&path_space.data.items[0], L"wb"); |
| | 1043 | #else |
| 1024 | FILE *f = fopen(buf_ptr(full_path), "wb"); | 1044 | FILE *f = fopen(buf_ptr(full_path), "wb"); |
| | 1045 | #endif |
| 1025 | if (!f) { | 1046 | if (!f) { |
| 1026 | zig_panic("os_write_file failed for %s", buf_ptr(full_path)); | 1047 | zig_panic("os_write_file failed for %s", buf_ptr(full_path)); |
| 1027 | } | 1048 | } |
| ... | @@ -1056,7 +1077,12 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) { | ... | @@ -1056,7 +1077,12 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) { |
| 1056 | Error os_dump_file(Buf *src_path, FILE *dest_file) { | 1077 | Error os_dump_file(Buf *src_path, FILE *dest_file) { |
| 1057 | Error err; | 1078 | Error err; |
| 1058 | | 1079 | |
| | 1080 | #if defined(ZIG_OS_WINDOWS) |
| | 1081 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| | 1082 | FILE *src_f = _wfopen(&path_space.data.items[0], L"rb"); |
| | 1083 | #else |
| 1059 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); | 1084 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); |
| | 1085 | #endif |
| 1060 | if (!src_f) { | 1086 | if (!src_f) { |
| 1061 | int err = errno; | 1087 | int err = errno; |
| 1062 | if (err == ENOENT) { | 1088 | if (err == ENOENT) { |
| ... | @@ -1173,7 +1199,12 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { | ... | @@ -1173,7 +1199,12 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { |
| 1173 | } | 1199 | } |
| 1174 | | 1200 | |
| 1175 | Error os_copy_file(Buf *src_path, Buf *dest_path) { | 1201 | Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| | 1202 | #if defined(ZIG_OS_WINDOWS) |
| | 1203 | PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| | 1204 | FILE *src_f = _wfopen(&src_path_space.data.items[0], L"rb"); |
| | 1205 | #else |
| 1176 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); | 1206 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); |
| | 1207 | #endif |
| 1177 | if (!src_f) { | 1208 | if (!src_f) { |
| 1178 | int err = errno; | 1209 | int err = errno; |
| 1179 | if (err == ENOENT) { | 1210 | if (err == ENOENT) { |
| ... | @@ -1184,7 +1215,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { | ... | @@ -1184,7 +1215,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1184 | return ErrorFileSystem; | 1215 | return ErrorFileSystem; |
| 1185 | } | 1216 | } |
| 1186 | } | 1217 | } |
| | 1218 | #if defined(ZIG_OS_WINDOWS) |
| | 1219 | PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); |
| | 1220 | FILE *dest_f = _wfopen(&dest_path_space.data.items[0], L"wb"); |
| | 1221 | #else |
| 1187 | FILE *dest_f = fopen(buf_ptr(dest_path), "wb"); | 1222 | FILE *dest_f = fopen(buf_ptr(dest_path), "wb"); |
| | 1223 | #endif |
| 1188 | if (!dest_f) { | 1224 | if (!dest_f) { |
| 1189 | int err = errno; | 1225 | int err = errno; |
| 1190 | if (err == ENOENT) { | 1226 | if (err == ENOENT) { |
| ... | @@ -1205,7 +1241,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { | ... | @@ -1205,7 +1241,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1205 | } | 1241 | } |
| 1206 | | 1242 | |
| 1207 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { | 1243 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| | 1244 | #if defined(ZIG_OS_WINDOWS) |
| | 1245 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| | 1246 | FILE *f = _wfopen(&path_space.data.items[0], L"rb"); |
| | 1247 | #else |
| 1208 | FILE *f = fopen(buf_ptr(full_path), "rb"); | 1248 | FILE *f = fopen(buf_ptr(full_path), "rb"); |
| | 1249 | #endif |
| 1209 | if (!f) { | 1250 | if (!f) { |
| 1210 | switch (errno) { | 1251 | switch (errno) { |
| 1211 | case EACCES: | 1252 | case EACCES: |
| ... | @@ -1230,11 +1271,11 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { | ... | @@ -1230,11 +1271,11 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| 1230 | | 1271 | |
| 1231 | Error os_get_cwd(Buf *out_cwd) { | 1272 | Error os_get_cwd(Buf *out_cwd) { |
| 1232 | #if defined(ZIG_OS_WINDOWS) | 1273 | #if defined(ZIG_OS_WINDOWS) |
| 1233 | char buf[4096]; | 1274 | PathSpace path_space; |
| 1234 | if (GetCurrentDirectory(4096, buf) == 0) { | 1275 | if (GetCurrentDirectoryW(PATH_MAX_WIDE, &path_space.data.items[0]) == 0) { |
| 1235 | zig_panic("GetCurrentDirectory failed"); | 1276 | zig_panic("GetCurrentDirectory failed"); |
| 1236 | } | 1277 | } |
| 1237 | buf_init_from_str(out_cwd, buf); | 1278 | utf16le_ptr_to_utf8(out_cwd, &path_space.data.items[0]); |
| 1238 | return ErrorNone; | 1279 | return ErrorNone; |
| 1239 | #elif defined(ZIG_OS_POSIX) | 1280 | #elif defined(ZIG_OS_POSIX) |
| 1240 | char buf[PATH_MAX]; | 1281 | char buf[PATH_MAX]; |
| ... | @@ -1330,7 +1371,9 @@ Error os_rename(Buf *src_path, Buf *dest_path) { | ... | @@ -1330,7 +1371,9 @@ Error os_rename(Buf *src_path, Buf *dest_path) { |
| 1330 | return ErrorNone; | 1371 | return ErrorNone; |
| 1331 | } | 1372 | } |
| 1332 | #if defined(ZIG_OS_WINDOWS) | 1373 | #if defined(ZIG_OS_WINDOWS) |
| 1333 | if (!MoveFileExA(buf_ptr(src_path), buf_ptr(dest_path), MOVEFILE_REPLACE_EXISTING)) { | 1374 | PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| | 1375 | PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); |
| | 1376 | if (!MoveFileExW(&src_path_space.data.items[0], &dest_path_space.data.items[0], MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { |
| 1334 | return ErrorFileSystem; | 1377 | return ErrorFileSystem; |
| 1335 | } | 1378 | } |
| 1336 | #else | 1379 | #else |
| ... | @@ -1426,7 +1469,15 @@ Error os_make_path(Buf *path) { | ... | @@ -1426,7 +1469,15 @@ Error os_make_path(Buf *path) { |
| 1426 | | 1469 | |
| 1427 | Error os_make_dir(Buf *path) { | 1470 | Error os_make_dir(Buf *path) { |
| 1428 | #if defined(ZIG_OS_WINDOWS) | 1471 | #if defined(ZIG_OS_WINDOWS) |
| 1429 | if (!CreateDirectory(buf_ptr(path), NULL)) { | 1472 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(path)); |
| | 1473 | if (memEql(buf_to_slice(path), str("C:\\dev\\tést"))) { |
| | 1474 | for (size_t i = 0; i < path_space.len; i++) { |
| | 1475 | fprintf(stderr, "%d ", path_space.data.items[i]); |
| | 1476 | } |
| | 1477 | fprintf(stderr, "\n"); |
| | 1478 | } |
| | 1479 | |
| | 1480 | if (!CreateDirectoryW(&path_space.data.items[0], NULL)) { |
| 1430 | if (GetLastError() == ERROR_ALREADY_EXISTS) | 1481 | if (GetLastError() == ERROR_ALREADY_EXISTS) |
| 1431 | return ErrorPathAlreadyExists; | 1482 | return ErrorPathAlreadyExists; |
| 1432 | if (GetLastError() == ERROR_PATH_NOT_FOUND) | 1483 | if (GetLastError() == ERROR_PATH_NOT_FOUND) |
| ... | @@ -1531,18 +1582,13 @@ int os_init(void) { | ... | @@ -1531,18 +1582,13 @@ int os_init(void) { |
| 1531 | | 1582 | |
| 1532 | Error os_self_exe_path(Buf *out_path) { | 1583 | Error os_self_exe_path(Buf *out_path) { |
| 1533 | #if defined(ZIG_OS_WINDOWS) | 1584 | #if defined(ZIG_OS_WINDOWS) |
| 1534 | buf_resize(out_path, 256); | 1585 | PathSpace path_space; |
| 1535 | for (;;) { | 1586 | DWORD copied_amt = GetModuleFileNameW(nullptr, &path_space.data.items[0], PATH_MAX_WIDE); |
| 1536 | DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path)); | 1587 | if (copied_amt <= 0) { |
| 1537 | if (copied_amt <= 0) { | 1588 | return ErrorFileNotFound; |
| 1538 | return ErrorFileNotFound; | | |
| 1539 | } | | |
| 1540 | if (copied_amt < buf_len(out_path)) { | | |
| 1541 | buf_resize(out_path, copied_amt); | | |
| 1542 | return ErrorNone; | | |
| 1543 | } | | |
| 1544 | buf_resize(out_path, buf_len(out_path) * 2); | | |
| 1545 | } | 1589 | } |
| | 1590 | utf16le_ptr_to_utf8(out_path, &path_space.data.items[0]); |
| | 1591 | return ErrorNone; |
| 1546 | | 1592 | |
| 1547 | #elif defined(ZIG_OS_DARWIN) | 1593 | #elif defined(ZIG_OS_DARWIN) |
| 1548 | // How long is the executable's path? | 1594 | // How long is the executable's path? |
| ... | @@ -1719,6 +1765,15 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { | ... | @@ -1719,6 +1765,15 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { |
| 1719 | zig_unreachable(); | 1765 | zig_unreachable(); |
| 1720 | } | 1766 | } |
| 1721 | | 1767 | |
| | 1768 | // Ported from std.unicode.utf8ByteSequenceLength |
| | 1769 | static uint8_t utf8ByteSequenceLength(uint8_t first_byte) { |
| | 1770 | if (first_byte < 0b10000000) return 1; |
| | 1771 | if ((first_byte & 0b11100000) == 0b11000000) return 2; |
| | 1772 | if ((first_byte & 0b11110000) == 0b11100000) return 3; |
| | 1773 | if ((first_byte & 0b11111000) == 0b11110000) return 4; |
| | 1774 | zig_unreachable(); |
| | 1775 | } |
| | 1776 | |
| 1722 | // Ported from std/unicode.zig | 1777 | // Ported from std/unicode.zig |
| 1723 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { | 1778 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1724 | size_t length = utf8CodepointSequenceLength(c); | 1779 | size_t length = utf8CodepointSequenceLength(c); |
| ... | @@ -1753,6 +1808,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { | ... | @@ -1753,6 +1808,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1753 | return length; | 1808 | return length; |
| 1754 | } | 1809 | } |
| 1755 | | 1810 | |
| | 1811 | // Ported from std.unicode.utf8Decode2 |
| | 1812 | static uint32_t utf8Decode2(Slice<uint8_t> bytes) { |
| | 1813 | assert(bytes.len == 2); |
| | 1814 | assert((bytes.at(0) & 0b11100000) == 0b11000000); |
| | 1815 | |
| | 1816 | uint32_t value = bytes.at(0) & 0b00011111; |
| | 1817 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| | 1818 | value <<= 6; |
| | 1819 | value |= bytes.at(1) & 0b00111111; |
| | 1820 | |
| | 1821 | assert(value >= 0x80); |
| | 1822 | return value; |
| | 1823 | } |
| | 1824 | |
| | 1825 | // Ported from std.unicode.utf8Decode3 |
| | 1826 | static uint32_t utf8Decode3(Slice<uint8_t> bytes) { |
| | 1827 | assert(bytes.len == 3); |
| | 1828 | assert((bytes.at(0) & 0b11110000) == 0b11100000); |
| | 1829 | |
| | 1830 | uint32_t value = bytes.at(0) & 0b00001111; |
| | 1831 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| | 1832 | value <<= 6; |
| | 1833 | value |= bytes.at(1) & 0b00111111; |
| | 1834 | |
| | 1835 | assert((bytes.at(2) & 0b11000000) == 0b10000000); |
| | 1836 | value <<= 6; |
| | 1837 | value |= bytes.at(2) & 0b00111111; |
| | 1838 | |
| | 1839 | assert(value >= 0x80); |
| | 1840 | assert(value < 0xd800 || value > 0xdfff); |
| | 1841 | return value; |
| | 1842 | } |
| | 1843 | |
| | 1844 | // Ported from std.unicode.utf8Decode4 |
| | 1845 | static uint32_t utf8Decode4(Slice<uint8_t> bytes) { |
| | 1846 | assert(bytes.len == 4); |
| | 1847 | assert((bytes.at(0) & 0b11111000) == 0b11110000); |
| | 1848 | |
| | 1849 | uint32_t value = bytes.at(0) & 0b00000111; |
| | 1850 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| | 1851 | value <<= 6; |
| | 1852 | value |= bytes.at(1) & 0b00111111; |
| | 1853 | |
| | 1854 | assert((bytes.at(2) & 0b11000000) == 0b10000000); |
| | 1855 | value <<= 6; |
| | 1856 | value |= bytes.at(2) & 0b00111111; |
| | 1857 | |
| | 1858 | assert((bytes.at(3) & 0b11000000) == 0b10000000); |
| | 1859 | value <<= 6; |
| | 1860 | value |= bytes.at(3) & 0b00111111; |
| | 1861 | |
| | 1862 | assert(value >= 0x10000 && value <= 0x10FFFF); |
| | 1863 | return value; |
| | 1864 | } |
| | 1865 | |
| | 1866 | // Ported from std.unicode.utf8Decode |
| | 1867 | static uint32_t utf8Decode(Slice<uint8_t> bytes) { |
| | 1868 | switch (bytes.len) { |
| | 1869 | case 1: |
| | 1870 | return bytes.at(0); |
| | 1871 | break; |
| | 1872 | case 2: |
| | 1873 | return utf8Decode2(bytes); |
| | 1874 | break; |
| | 1875 | case 3: |
| | 1876 | return utf8Decode3(bytes); |
| | 1877 | break; |
| | 1878 | case 4: |
| | 1879 | return utf8Decode4(bytes); |
| | 1880 | break; |
| | 1881 | default: |
| | 1882 | zig_unreachable(); |
| | 1883 | } |
| | 1884 | } |
| 1756 | // Ported from std.unicode.utf16leToUtf8Alloc | 1885 | // Ported from std.unicode.utf16leToUtf8Alloc |
| 1757 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { | 1886 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1758 | // optimistically guess that it will all be ascii. | 1887 | // optimistically guess that it will all be ascii. |
| ... | @@ -1770,6 +1899,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { | ... | @@ -1770,6 +1899,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1770 | out_index += utf8_len; | 1899 | out_index += utf8_len; |
| 1771 | } | 1900 | } |
| 1772 | } | 1901 | } |
| | 1902 | |
| | 1903 | // Ported from std.unicode.utf8ToUtf16Le |
| | 1904 | static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice<uint8_t> utf8) { |
| | 1905 | size_t dest_i = 0; |
| | 1906 | size_t src_i = 0; |
| | 1907 | while (src_i < utf8.len) { |
| | 1908 | uint8_t n = utf8ByteSequenceLength(utf8.at(src_i)); |
| | 1909 | size_t next_src_i = src_i + n; |
| | 1910 | uint32_t codepoint = utf8Decode(utf8.slice(src_i, next_src_i)); |
| | 1911 | if (codepoint < 0x10000) { |
| | 1912 | utf16_le[dest_i] = codepoint; |
| | 1913 | dest_i += 1; |
| | 1914 | } else { |
| | 1915 | WCHAR high = ((codepoint - 0x10000) >> 10) + 0xD800; |
| | 1916 | WCHAR low = (codepoint & 0x3FF) + 0xDC00; |
| | 1917 | utf16_le[dest_i] = high; |
| | 1918 | utf16_le[dest_i + 1] = low; |
| | 1919 | dest_i += 2; |
| | 1920 | } |
| | 1921 | src_i = next_src_i; |
| | 1922 | } |
| | 1923 | return dest_i; |
| | 1924 | } |
| | 1925 | |
| | 1926 | // Ported from std.os.windows.sliceToPrefixedFileW |
| | 1927 | PathSpace slice_to_prefixed_file_w(Slice<uint8_t> path) { |
| | 1928 | PathSpace path_space; |
| | 1929 | for (size_t idx = 0; idx < path.len; idx++) { |
| | 1930 | assert(path.ptr[idx] != '*' && path.ptr[idx] != '?' && path.ptr[idx] != '"' && |
| | 1931 | path.ptr[idx] != '<' && path.ptr[idx] != '>' && path.ptr[idx] != '|'); |
| | 1932 | } |
| | 1933 | |
| | 1934 | size_t start_index; |
| | 1935 | if (memStartsWith(path, str("\\?")) || !isAbsoluteWindows(path)) { |
| | 1936 | start_index = 0; |
| | 1937 | } else { |
| | 1938 | static WCHAR prefix[4] = { u'\\', u'?', u'?', u'\\' }; |
| | 1939 | memCopy(path_space.data.slice(), Slice<WCHAR> { prefix, 4 }); |
| | 1940 | start_index = 4; |
| | 1941 | } |
| | 1942 | |
| | 1943 | path_space.len = start_index + utf8_to_utf16le(path_space.data.slice().sliceFrom(start_index).ptr, path); |
| | 1944 | assert(path_space.len <= path_space.data.len); |
| | 1945 | |
| | 1946 | Slice<WCHAR> path_slice = path_space.data.slice().slice(0, path_space.len); |
| | 1947 | for (size_t elem_idx = 0; elem_idx < path_slice.len; elem_idx += 1) { |
| | 1948 | if (path_slice.at(elem_idx) == '/') { |
| | 1949 | path_slice.at(elem_idx) = '\\'; |
| | 1950 | } |
| | 1951 | } |
| | 1952 | |
| | 1953 | path_space.data.items[path_space.len] = 0; |
| | 1954 | return path_space; |
| | 1955 | } |
| 1773 | #endif | 1956 | #endif |
| 1774 | | 1957 | |
| 1775 | // Ported from std.os.getAppDataDir | 1958 | // Ported from std.os.getAppDataDir |
| ... | @@ -1862,8 +2045,8 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { | ... | @@ -1862,8 +2045,8 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { |
| 1862 | | 2045 | |
| 1863 | Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { | 2046 | Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { |
| 1864 | #if defined(ZIG_OS_WINDOWS) | 2047 | #if defined(ZIG_OS_WINDOWS) |
| 1865 | // TODO use CreateFileW | 2048 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 1866 | HANDLE result = CreateFileA(buf_ptr(full_path), | 2049 | HANDLE result = CreateFileW(&path_space.data.items[0], |
| 1867 | need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, | 2050 | need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, |
| 1868 | need_write ? 0 : FILE_SHARE_READ, | 2051 | need_write ? 0 : FILE_SHARE_READ, |
| 1869 | nullptr, | 2052 | nullptr, |
| ... | @@ -1967,8 +2150,9 @@ Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_ | ... | @@ -1967,8 +2150,9 @@ Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_ |
| 1967 | | 2150 | |
| 1968 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | 2151 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1969 | #if defined(ZIG_OS_WINDOWS) | 2152 | #if defined(ZIG_OS_WINDOWS) |
| | 2153 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 1970 | for (;;) { | 2154 | for (;;) { |
| 1971 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE, | 2155 | HANDLE result = CreateFileW(&path_space.data.items[0], GENERIC_READ | GENERIC_WRITE, |
| 1972 | 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | 2156 | 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| 1973 | | 2157 | |
| 1974 | if (result == INVALID_HANDLE_VALUE) { | 2158 | if (result == INVALID_HANDLE_VALUE) { |