master
  1//! Implementations of functionality related to National Language Support
  2//! on Windows.
  3
  4const builtin = @import("builtin");
  5const std = @import("../../std.zig");
  6
  7/// This corresponds to the uppercase table within the locale-independent
  8/// l_intl.nls data (found at system32\l_intl.nls).
  9/// - In l_intl.nls, this data starts at offset 0x04.
 10/// - In the PEB, this data starts at index [2] of peb.UnicodeCaseTableData when
 11///   it is casted to `[*]u16`.
 12///
 13/// Note: This data has not changed since Windows 8.1, and has become out-of-sync with
 14///       the Unicode standard.
 15const uppercase_table = [2544]u16{
 16    272,   288,   304,   320,   336,   352,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 17    256,   256,   256,   256,   256,   368,   384,   400,   256,   416,   256,   256,   432,   256,   256,   256,   256,   256,   256,   256,   448,   464,   256,   256,
 18    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 19    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 20    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 21    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 22    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   480,   496,
 23    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 24    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 25    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
 26    256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   256,   512,   528,   528,   528,   528,   528,   528,   528,   528,
 27    528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   544,   560,   528,   528,   528,   576,   528,   528,   592,   608,
 28    624,   640,   656,   672,   688,   704,   720,   736,   752,   768,   784,   800,   816,   832,   848,   864,   880,   896,   912,   928,   944,   960,   976,   992,
 29    1008,  1024,  528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   1040,  528,   528,   1056,  528,   528,   1072,  1088,  1104,  1120,  1136,  1152,
 30    528,   528,   528,   1168,  1184,  1200,  1216,  1232,  1248,  1264,  1280,  1296,  1312,  1328,  1344,  1360,  1376,  1392,  1408,  528,   528,   528,   1424,  1440,
 31    1456,  528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   1472,  528,   528,   528,   528,   528,   528,   528,   528,
 32    1488,  1504,  1520,  1536,  1552,  1568,  1584,  1600,  1616,  1632,  1648,  1664,  1680,  1696,  1712,  1728,  1744,  1760,  1776,  1792,  1808,  1824,  1840,  1856,
 33    1872,  1888,  1904,  1920,  1936,  1952,  1968,  1984,  528,   528,   528,   528,   2000,  528,   528,   2016,  2032,  528,   528,   528,   528,   528,   528,   528,
 34    528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   2048,  2064,  528,   528,   528,   528,   2080,  2096,  2112,  2128,  2144,
 35    2160,  2176,  2192,  2208,  2224,  2240,  2256,  528,   2272,  2288,  2304,  528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,
 36    528,   528,   528,   528,   2320,  2336,  2352,  528,   2368,  2384,  528,   528,   528,   528,   528,   528,   528,   528,   2400,  2416,  2432,  2448,  2464,  2480,
 37    2496,  528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   528,   2512,  2528,  528,   528,   528,   528,   528,   528,   528,   528,   528,   528,
 38    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65504, 65504, 65504, 65504, 65504, 65504, 65504,
 39    65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 0,     0,     0,     0,     0,
 40    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504,
 41    65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 0,     65504, 65504, 65504, 65504, 65504, 65504, 65504, 121,
 42    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 43    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 44    0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,
 45    65535, 0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 46    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 47    0,     0,     65535, 0,     65535, 0,     65535, 0,     195,   0,     0,     65535, 0,     65535, 0,     0,     65535, 0,     0,     0,     65535, 0,     0,     0,
 48    0,     0,     65535, 0,     0,     97,    0,     0,     0,     65535, 163,   0,     0,     0,     130,   0,     0,     65535, 0,     65535, 0,     65535, 0,     0,
 49    65535, 0,     0,     0,     0,     65535, 0,     0,     65535, 0,     0,     0,     65535, 0,     65535, 0,     0,     65535, 0,     0,     0,     65535, 0,     56,
 50    0,     0,     0,     0,     0,     0,     65534, 0,     0,     65534, 0,     0,     65534, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,
 51    65535, 0,     65535, 0,     65535, 65457, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 52    0,     0,     0,     65534, 0,     65535, 0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 53    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 54    0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,
 55    0,     0,     0,     0,     65535, 0,     0,     0,     0,     0,     65535, 0,     0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 56    10783, 10780, 0,     65326, 65330, 0,     65331, 65331, 0,     65334, 0,     65333, 0,     0,     0,     0,     65331, 0,     0,     65329, 0,     0,     0,     0,
 57    65327, 65325, 0,     10743, 0,     0,     0,     65325, 0,     10749, 65323, 0,     0,     65322, 0,     0,     0,     0,     0,     0,     0,     10727, 0,     0,
 58    65318, 0,     0,     65318, 0,     0,     0,     0,     65318, 65467, 65319, 65319, 65465, 0,     0,     0,     0,     0,     65317, 0,     0,     0,     0,     0,
 59    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 60    0,     65535, 0,     65535, 0,     0,     0,     65535, 0,     0,     0,     130,   130,   130,   0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 61    0,     0,     0,     0,     65498, 65499, 65499, 65499, 0,     65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504,
 62    65504, 65504, 0,     65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65472, 65473, 65473, 0,     0,     0,     0,     0,     0,     0,     0,     65528,
 63    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 64    0,     0,     7,     0,     0,     0,     0,     0,     65535, 0,     0,     65535, 0,     0,     0,     0,     65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504,
 65    65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504,
 66    65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 65456, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 67    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 68    0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 69    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 70    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     65535, 0,     65535, 0,     65535, 0,
 71    65535, 0,     65535, 0,     65535, 0,     65535, 65521, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 72    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 73    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 74    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,
 75    0,     0,     0,     0,     0,     0,     0,     0,     0,     65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488,
 76    65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 0,
 77    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     35332, 0,     0,     0,     3814,  0,     0,
 78    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 79    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 80    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 81    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 82    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 83    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 84    0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535,
 85    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 86    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 87    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
 88    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 8,     8,     8,     8,     8,     8,     8,     8,
 89    0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 90    8,     8,     8,     8,     8,     8,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     8,     8,
 91    0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 92    0,     8,     0,     8,     0,     8,     0,     8,     0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     8,     8,
 93    0,     0,     0,     0,     0,     0,     0,     0,     74,    74,    86,    86,    86,    86,    100,   100,   128,   128,   112,   112,   126,   126,   0,     0,
 94    8,     8,     8,     8,     8,     8,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     8,     8,
 95    0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     8,     8,     8,     8,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,
 96    8,     8,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,
 97    0,     0,     0,     0,     0,     0,     0,     0,     8,     8,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 98    8,     8,     0,     0,     0,     7,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,
 99    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65508, 0,
100    65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 65520, 0,     0,     0,     0,     65535, 0,     0,     0,
101    0,     0,     0,     0,     0,     0,     0,     0,     65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510,
102    65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 65510, 0,     0,     0,     0,     0,     0,     65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488,
103    65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488,
104    65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 65488, 0,     0,     65535, 0,     0,     0,     54741, 54744, 0,
105    65535, 0,     65535, 0,     65535, 0,     0,     0,     0,     0,     0,     65535, 0,     0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,
106    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
107    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
108    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
109    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
110    0,     65535, 0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272,
111    58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272, 58272,
112    58272, 58272, 58272, 58272, 58272, 58272, 0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535,
113    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
114    0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535,
115    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,
116    0,     0,     0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     65535, 0,     65535, 0,     65535,
117    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
118    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     65535,
119    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65535, 0,     65535, 0,     0,     65535,
120    0,     65535, 0,     65535, 0,     65535, 0,     65535, 0,     0,     0,     0,     65535, 0,     0,     0,     0,     65504, 65504, 65504, 65504, 65504, 65504, 65504,
121    65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 65504, 0,     0,     0,     0,     0,
122};
123
124/// Cross-platform implementation of `ntdll.RtlUpcaseUnicodeChar`.
125/// Transforms the UTF-16 code unit in `c` to its uppercased version
126/// if there is one. Otherwise, returns `c` unmodified.
127///
128/// Note: When this function is referenced, it will need to include
129///       `uppercase_table.len * 2` bytes of data in the resulting binary
130///       since it depends on the `uppercase_table` data. When
131///       targeting Windows, `ntdll.RtlUpcaseUnicodeChar` can be
132///       used instead to avoid having to include a copy of this data.
133pub fn upcaseW(c: u16) u16 {
134    if (c < 'a') {
135        return c;
136    }
137    if (c <= 'z') {
138        return c - ('a' - 'A');
139    }
140    if (c >= 0xC0) {
141        var offset: u16 = 0;
142
143        offset += @as(u8, @truncate(c >> 8));
144        offset = uppercase_table[offset];
145        offset += @as(u4, @truncate(c >> 4));
146        offset = uppercase_table[offset];
147        offset += @as(u4, @truncate(c));
148        offset = uppercase_table[offset];
149
150        return c +% offset;
151    }
152    return c;
153}
154
155test "upcaseW matches RtlUpcaseUnicodeChar" {
156    if (builtin.os.tag != .windows) return error.SkipZigTest;
157
158    var c: u16 = 0;
159    while (true) : (c += 1) {
160        std.testing.expectEqual(std.os.windows.ntdll.RtlUpcaseUnicodeChar(c), upcaseW(c)) catch |err| {
161            std.debug.print("mismatch for codepoint U+{X}\n", .{c});
162            return err;
163        };
164        if (c == 0xFFFF) break;
165    }
166}