| ... | @@ -6,8 +6,11 @@ | ... | @@ -6,8 +6,11 @@ |
| 6 | */ | 6 | */ |
| 7 | | 7 | |
| 8 | #include "os.hpp" | 8 | #include "os.hpp" |
| | 9 | #include "buffer.hpp" |
| 9 | #include "util.hpp" | 10 | #include "util.hpp" |
| 10 | #include "error.hpp" | 11 | #include "error.hpp" |
| | 12 | #include "util_base.hpp" |
| | 13 | #include <stdint.h> |
| 11 | | 14 | |
| 12 | #if defined(_WIN32) | 15 | #if defined(_WIN32) |
| 13 | | 16 | |
| ... | @@ -1426,7 +1429,8 @@ Error os_make_path(Buf *path) { | ... | @@ -1426,7 +1429,8 @@ Error os_make_path(Buf *path) { |
| 1426 | | 1429 | |
| 1427 | Error os_make_dir(Buf *path) { | 1430 | Error os_make_dir(Buf *path) { |
| 1428 | #if defined(ZIG_OS_WINDOWS) | 1431 | #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)) { |
| 1430 | if (GetLastError() == ERROR_ALREADY_EXISTS) | 1434 | if (GetLastError() == ERROR_ALREADY_EXISTS) |
| 1431 | return ErrorPathAlreadyExists; | 1435 | return ErrorPathAlreadyExists; |
| 1432 | if (GetLastError() == ERROR_PATH_NOT_FOUND) | 1436 | if (GetLastError() == ERROR_PATH_NOT_FOUND) |
| ... | @@ -1719,6 +1723,26 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { | ... | @@ -1719,6 +1723,26 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { |
| 1719 | zig_unreachable(); | 1723 | zig_unreachable(); |
| 1720 | } | 1724 | } |
| 1721 | | 1725 | |
| | 1726 | // Ported from std.unicode.utf8ByteSequenceLength |
| | 1727 | static 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 | |
| 1722 | // Ported from std/unicode.zig | 1746 | // Ported from std/unicode.zig |
| 1723 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { | 1747 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1724 | size_t length = utf8CodepointSequenceLength(c); | 1748 | size_t length = utf8CodepointSequenceLength(c); |
| ... | @@ -1753,6 +1777,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { | ... | @@ -1753,6 +1777,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1753 | return length; | 1777 | return length; |
| 1754 | } | 1778 | } |
| 1755 | | 1779 | |
| | 1780 | // Ported from std.unicode.utf8Decode2 |
| | 1781 | static 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 |
| | 1795 | static 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 |
| | 1814 | static 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 |
| | 1836 | static 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 | } |
| 1756 | // Ported from std.unicode.utf16leToUtf8Alloc | 1854 | // Ported from std.unicode.utf16leToUtf8Alloc |
| 1757 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { | 1855 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1758 | // optimistically guess that it will all be ascii. | 1856 | // optimistically guess that it will all be ascii. |
| ... | @@ -1770,6 +1868,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { | ... | @@ -1770,6 +1868,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1770 | out_index += utf8_len; | 1868 | out_index += utf8_len; |
| 1771 | } | 1869 | } |
| 1772 | } | 1870 | } |
| | 1871 | |
| | 1872 | // Ported from std.unicode.utf8ToUtf16Le |
| | 1873 | static 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 |
| | 1896 | PathSpace 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 | } |
| 1773 | #endif | 1925 | #endif |
| 1774 | | 1926 | |
| 1775 | // Ported from std.os.getAppDataDir | 1927 | // Ported from std.os.getAppDataDir |