authorgravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-06-15 15:52:59+03:00
committergravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-06-15 15:52:59+03:00
log037c72fe6781df317a6c8cc04739d277cb96979f
treef4e307449f0606db628c2a71820aea508656c979
parente7207bc267d90b5be009fcd937b86cde9bf9ae77

Convert paths to UTF-16 before calling CreateDirectory on windows


3 files changed, 160 insertions(+), 2 deletions(-)

src/os.cpp+153-1
......@@ -6,8 +6,11 @@
66 */
77
88#include "os.hpp"
9#include "buffer.hpp"
910#include "util.hpp"
1011#include "error.hpp"
12#include "util_base.hpp"
13#include <stdint.h>
1114
1215#if defined(_WIN32)
1316
......@@ -1426,7 +1429,8 @@ Error os_make_path(Buf *path) {
14261429
14271430Error os_make_dir(Buf *path) {
14281431#if defined(ZIG_OS_WINDOWS)
1429 if (!CreateDirectory(buf_ptr(path), NULL)) {
1432 PathSpace path_space = slice_to_prefixed_file_w({ (uint8_t*)buf_ptr(path), buf_len(path) });
1433 if (!CreateDirectoryW(&path_space.data.items[0], NULL)) {
14301434 if (GetLastError() == ERROR_ALREADY_EXISTS)
14311435 return ErrorPathAlreadyExists;
14321436 if (GetLastError() == ERROR_PATH_NOT_FOUND)
......@@ -1719,6 +1723,26 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) {
17191723 zig_unreachable();
17201724}
17211725
1726// Ported from std.unicode.utf8ByteSequenceLength
1727static uint8_t utf8ByteSequenceLength(uint8_t first_byte) {
1728 switch (clzll(~first_byte)) {
1729 case 0:
1730 return 1;
1731 break;
1732 case 2:
1733 return 2;
1734 break;
1735 case 3:
1736 return 3;
1737 break;
1738 case 4:
1739 return 4;
1740 break;
1741 default:
1742 zig_unreachable();
1743 }
1744}
1745
17221746// Ported from std/unicode.zig
17231747static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) {
17241748 size_t length = utf8CodepointSequenceLength(c);
......@@ -1753,6 +1777,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) {
17531777 return length;
17541778}
17551779
1780// Ported from std.unicode.utf8Decode2
1781static uint32_t utf8Decode2(Slice<uint8_t> bytes) {
1782 assert(bytes.len == 2);
1783 assert((bytes.at(0) & 0b11100000) == 0b11000000);
1784
1785 uint32_t value = bytes.at(0) & 0b00011111;
1786 assert((bytes.at(1) & 0b11000000) == 0b10000000);
1787 value <<= 6;
1788 value |= bytes.at(1) & 0b00111111;
1789
1790 assert(value >= 0x80);
1791 return value;
1792}
1793
1794// Ported from std.unicode.utf8Decode3
1795static uint32_t utf8Decode3(Slice<uint8_t> bytes) {
1796 assert(bytes.len == 3);
1797 assert((bytes.at(0) & 0b11110000) == 0b11100000);
1798
1799 uint32_t value = bytes.at(0) & 0b00001111;
1800 assert((bytes.at(1) & 0b11000000) == 0b10000000);
1801 value <<= 6;
1802 value |= bytes.at(1) & 0b00111111;
1803
1804 assert((bytes.at(2) & 0b11000000) == 0b10000000);
1805 value <<= 6;
1806 value |= bytes.at(2) & 0b00111111;
1807
1808 assert(value >= 0x80);
1809 assert(value < 0xd800 || value > 0xdfff);
1810 return value;
1811}
1812
1813// Ported from std.unicode.utf8Decode4
1814static uint32_t utf8Decode4(Slice<uint8_t> bytes) {
1815 assert(bytes.len == 4);
1816 assert((bytes.at(0) & 0b11111000) == 0b11110000);
1817
1818 uint32_t value = bytes.at(0) & 0b00000111;
1819 assert((bytes.at(1) & 0b11000000) == 0b10000000);
1820 value <<= 6;
1821 value |= bytes.at(1) & 0b00111111;
1822
1823 assert((bytes.at(2) & 0b11000000) == 0b10000000);
1824 value <<= 6;
1825 value |= bytes.at(2) & 0b00111111;
1826
1827 assert((bytes.at(3) & 0b11000000) == 0b10000000);
1828 value <<= 6;
1829 value |= bytes.at(3) & 0b00111111;
1830
1831 assert(value >= 0x10000 && value <= 0x10FFFF);
1832 return value;
1833}
1834
1835// Ported from std.unicode.utf8Decode
1836static uint32_t utf8Decode(Slice<uint8_t> bytes) {
1837 switch (bytes.len) {
1838 case 1:
1839 return bytes.at(0);
1840 break;
1841 case 2:
1842 return utf8Decode2(bytes);
1843 break;
1844 case 3:
1845 return utf8Decode3(bytes);
1846 break;
1847 case 4:
1848 return utf8Decode4(bytes);
1849 break;
1850 default:
1851 zig_unreachable();
1852 }
1853}
17561854// Ported from std.unicode.utf16leToUtf8Alloc
17571855static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) {
17581856 // optimistically guess that it will all be ascii.
......@@ -1770,6 +1868,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) {
17701868 out_index += utf8_len;
17711869 }
17721870}
1871
1872// Ported from std.unicode.utf8ToUtf16Le
1873static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice<uint8_t> utf8) {
1874 size_t dest_i = 0;
1875 size_t src_i = 0;
1876 while (src_i < utf8.len) {
1877 uint8_t n = utf8ByteSequenceLength(utf8.at(src_i));
1878 size_t next_src_i = src_i + n;
1879 uint32_t codepoint = utf8Decode(utf8.slice(src_i, next_src_i));
1880 if (codepoint < 0x10000) {
1881 utf16_le[dest_i] = codepoint;
1882 dest_i += 1;
1883 } else {
1884 WCHAR high = ((codepoint - 0x10000) >> 10) + 0xD800;
1885 WCHAR low = (codepoint & 0x3FF) + 0xDC00;
1886 utf16_le[dest_i] = high;
1887 utf16_le[dest_i + 1] = low;
1888 dest_i += 2;
1889 }
1890 src_i = next_src_i;
1891 }
1892 return dest_i;
1893}
1894
1895// Ported from std.os.windows.sliceToPrefixedFileW
1896PathSpace slice_to_prefixed_file_w(Slice<uint8_t> path) {
1897 PathSpace path_space;
1898 for (size_t idx = 0; idx < path.len; idx++) {
1899 assert(path.ptr[idx] != '*' && path.ptr[idx] != '?' && path.ptr[idx] != '"' &&
1900 path.ptr[idx] != '<' && path.ptr[idx] != '>' && path.ptr[idx] != '|');
1901 }
1902
1903 size_t start_index;
1904 if (memStartsWith(path, str("\\?")) || !isAbsoluteWindows(path)) {
1905 start_index = 0;
1906 } else {
1907 static WCHAR prefix[4] = { u'\\', u'?', u'?', u'\\' };
1908 memCopy(path_space.data.slice(), Slice<WCHAR> { prefix, 4 });
1909 start_index = 4;
1910 }
1911
1912 path_space.len = start_index + utf8_to_utf16le(path_space.data.slice().sliceFrom(start_index).ptr, path);
1913 assert(path_space.len <= path_space.data.len);
1914
1915 Slice<WCHAR> path_slice = path_space.data.slice().slice(0, path_space.len);
1916 for (size_t elem_idx = 0; elem_idx < path_slice.len; elem_idx += 1) {
1917 if (path_slice.at(elem_idx) == '/') {
1918 path_slice.at(elem_idx) = '\\';
1919 }
1920 }
1921
1922 path_space.data.items[path_space.len] = 0;
1923 return path_space;
1924}
17731925#endif
17741926
17751927// Ported from std.os.getAppDataDir
src/os.hpp+6
......@@ -155,4 +155,10 @@ Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname)
155155
156156Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
157157
158struct PathSpace {
159 Array<wchar_t, 32767> data;
160 size_t len;
161};
162
163PathSpace slice_to_prefixed_file_w(Slice<uint8_t> path);
158164#endif
src/util.hpp+1-1
......@@ -159,7 +159,7 @@ struct Slice {
159159
160160 inline T &at(size_t i) {
161161 assert(i < len);
162 return &ptr[i];
162 return ptr[i];
163163 }
164164
165165 inline Slice<T> slice(size_t start, size_t end) {