| ... | ... | @@ -6,8 +6,11 @@ |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include "os.hpp" |
| 9 | #include "buffer.hpp" |
| 9 | 10 | #include "util.hpp" |
| 10 | 11 | #include "error.hpp" |
| 12 | #include "util_base.hpp" |
| 13 | #include <stdint.h> |
| 11 | 14 | |
| 12 | 15 | #if defined(_WIN32) |
| 13 | 16 | |
| ... | ... | @@ -1426,7 +1429,8 @@ Error os_make_path(Buf *path) { |
| 1426 | 1429 | |
| 1427 | 1430 | Error os_make_dir(Buf *path) { |
| 1428 | 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 | 1434 | if (GetLastError() == ERROR_ALREADY_EXISTS) |
| 1431 | 1435 | return ErrorPathAlreadyExists; |
| 1432 | 1436 | if (GetLastError() == ERROR_PATH_NOT_FOUND) |
| ... | ... | @@ -1719,6 +1723,26 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { |
| 1719 | 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 | 1746 | // Ported from std/unicode.zig |
| 1723 | 1747 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1724 | 1748 | size_t length = utf8CodepointSequenceLength(c); |
| ... | ... | @@ -1753,6 +1777,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1753 | 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 | 1854 | // Ported from std.unicode.utf16leToUtf8Alloc |
| 1757 | 1855 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1758 | 1856 | // optimistically guess that it will all be ascii. |
| ... | ... | @@ -1770,6 +1868,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1770 | 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 | 1925 | #endif |
| 1774 | 1926 | |
| 1775 | 1927 | // Ported from std.os.getAppDataDir |