1 /* 2 * PROJECT: FreeLoader 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: "Poor-man" boot-time National Language Support (NLS) functions. 5 * COPYRIGHT: Copyright 2022 Hermès Bélusca-Maïto 6 * 7 * NOTE: This code is used at boot-time when no NLS tables are loaded. 8 * Adapted from lib/rtl/nls.c 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <rtl.h> 14 15 /* GLOBALS *******************************************************************/ 16 17 BOOLEAN NlsMbCodePageTag = FALSE; 18 19 BOOLEAN NlsMbOemCodePageTag = FALSE; 20 PUSHORT NlsOemToUnicodeTable = NULL; 21 PCHAR NlsUnicodeToOemTable = NULL; 22 PUSHORT NlsUnicodeToMbOemTable = NULL; 23 PUSHORT NlsOemLeadByteInfo = NULL; 24 25 USHORT NlsOemDefaultChar = '\0'; 26 USHORT NlsUnicodeDefaultChar = 0; 27 28 /* FUNCTIONS *****************************************************************/ 29 30 WCHAR 31 NTAPI 32 RtlpDowncaseUnicodeChar( 33 _In_ WCHAR Source) 34 { 35 USHORT Offset = 0; 36 37 if (Source < L'A') 38 return Source; 39 40 if (Source <= L'Z') 41 return Source + (L'a' - L'A'); 42 43 #if 0 44 if (Source < 0x80) 45 return Source; 46 #endif 47 48 return Source + (SHORT)Offset; 49 } 50 51 WCHAR 52 NTAPI 53 RtlDowncaseUnicodeChar( 54 _In_ WCHAR Source) 55 { 56 return RtlpDowncaseUnicodeChar(Source); 57 } 58 59 _Use_decl_annotations_ 60 NTSTATUS 61 NTAPI 62 RtlMultiByteToUnicodeN( 63 _Out_ PWCH UnicodeString, 64 _In_ ULONG UnicodeSize, 65 _Out_opt_ PULONG ResultSize, 66 _In_ PCCH MbString, 67 _In_ ULONG MbSize) 68 { 69 ULONG Size = 0; 70 ULONG i; 71 72 /* single-byte code page */ 73 if (MbSize > (UnicodeSize / sizeof(WCHAR))) 74 Size = UnicodeSize / sizeof(WCHAR); 75 else 76 Size = MbSize; 77 78 if (ResultSize) 79 *ResultSize = Size * sizeof(WCHAR); 80 81 for (i = 0; i < Size; i++) 82 { 83 /* Trivially zero-extend */ 84 UnicodeString[i] = (WCHAR)MbString[i]; 85 } 86 87 return STATUS_SUCCESS; 88 } 89 90 _Use_decl_annotations_ 91 NTSTATUS 92 NTAPI 93 RtlMultiByteToUnicodeSize( 94 _Out_ PULONG UnicodeSize, 95 _In_ PCCH MbString, 96 _In_ ULONG MbSize) 97 { 98 /* single-byte code page */ 99 *UnicodeSize = MbSize * sizeof(WCHAR); 100 101 return STATUS_SUCCESS; 102 } 103 104 _Use_decl_annotations_ 105 NTSTATUS 106 NTAPI 107 RtlUnicodeToMultiByteN( 108 _Out_ PCHAR MbString, 109 _In_ ULONG MbSize, 110 _Out_opt_ PULONG ResultSize, 111 _In_ PCWCH UnicodeString, 112 _In_ ULONG UnicodeSize) 113 { 114 ULONG Size = 0; 115 ULONG i; 116 117 /* single-byte code page */ 118 Size = (UnicodeSize > (MbSize * sizeof(WCHAR))) 119 ? MbSize : (UnicodeSize / sizeof(WCHAR)); 120 121 if (ResultSize) 122 *ResultSize = Size; 123 124 for (i = 0; i < Size; i++) 125 { 126 /* Check for characters that cannot be trivially demoted to ANSI */ 127 if (*((PCHAR)UnicodeString + 1) == 0) 128 { 129 *MbString++ = (CHAR)*UnicodeString++; 130 } 131 else 132 { 133 /* Invalid character, use default */ 134 *MbString++ = NlsOemDefaultChar; 135 UnicodeString++; 136 } 137 } 138 139 return STATUS_SUCCESS; 140 } 141 142 _Use_decl_annotations_ 143 NTSTATUS 144 NTAPI 145 RtlUnicodeToMultiByteSize( 146 _Out_ PULONG MbSize, 147 _In_ PCWCH UnicodeString, 148 _In_ ULONG UnicodeSize) 149 { 150 ULONG UnicodeLength = UnicodeSize / sizeof(WCHAR); 151 152 /* single-byte code page */ 153 *MbSize = UnicodeLength; 154 155 return STATUS_SUCCESS; 156 } 157 158 WCHAR 159 NTAPI 160 RtlpUpcaseUnicodeChar( 161 _In_ WCHAR Source) 162 { 163 USHORT Offset = 0; 164 165 if (Source < 'a') 166 return Source; 167 168 if (Source <= 'z') 169 return (Source - ('a' - 'A')); 170 171 return Source + (SHORT)Offset; 172 } 173 174 WCHAR 175 NTAPI 176 RtlUpcaseUnicodeChar( 177 _In_ WCHAR Source) 178 { 179 return RtlpUpcaseUnicodeChar(Source); 180 } 181 182 _Use_decl_annotations_ 183 NTSTATUS 184 NTAPI 185 RtlUpcaseUnicodeToMultiByteN( 186 _Out_ PCHAR MbString, 187 _In_ ULONG MbSize, 188 _Out_opt_ PULONG ResultSize, 189 _In_ PCWCH UnicodeString, 190 _In_ ULONG UnicodeSize) 191 { 192 WCHAR UpcaseChar; 193 ULONG Size = 0; 194 ULONG i; 195 196 /* single-byte code page */ 197 if (UnicodeSize > (MbSize * sizeof(WCHAR))) 198 Size = MbSize; 199 else 200 Size = UnicodeSize / sizeof(WCHAR); 201 202 if (ResultSize) 203 *ResultSize = Size; 204 205 for (i = 0; i < Size; i++) 206 { 207 UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString); 208 209 /* Check for characters that cannot be trivially demoted to ANSI */ 210 if (*((PCHAR)&UpcaseChar + 1) == 0) 211 { 212 *MbString = (CHAR)UpcaseChar; 213 } 214 else 215 { 216 /* Invalid character, use default */ 217 *MbString = NlsOemDefaultChar; 218 } 219 220 MbString++; 221 UnicodeString++; 222 } 223 224 return STATUS_SUCCESS; 225 } 226 227 CHAR 228 NTAPI 229 RtlUpperChar( 230 _In_ CHAR Source) 231 { 232 /* Check for simple ANSI case */ 233 if (Source <= 'z') 234 { 235 /* Check for simple downcase a-z case */ 236 if (Source >= 'a') 237 { 238 /* Just XOR with the difference */ 239 return Source ^ ('a' - 'A'); 240 } 241 else 242 { 243 /* Otherwise return the same char, it's already upcase */ 244 return Source; 245 } 246 } 247 else 248 { 249 /* single-byte code page */ 250 return (CHAR)RtlpUpcaseUnicodeChar((WCHAR)Source); 251 } 252 } 253 254 255 /** 256 * Stubbed OEM helpers that should not be used in the OS boot loader, 257 * but are necessary for linking with the rest of the RTL unicode.c. 258 **/ 259 260 _Use_decl_annotations_ 261 NTSTATUS 262 NTAPI 263 RtlUnicodeToOemN( 264 _Out_ PCHAR OemString, 265 _In_ ULONG OemSize, 266 _Out_opt_ PULONG ResultSize, 267 _In_ PCWCH UnicodeString, 268 _In_ ULONG UnicodeSize) 269 { 270 if (OemSize) 271 *OemString = ANSI_NULL; 272 273 if (ResultSize) 274 *ResultSize = 0; 275 276 return STATUS_NOT_IMPLEMENTED; 277 } 278 279 _Use_decl_annotations_ 280 NTSTATUS 281 NTAPI 282 RtlOemToUnicodeN( 283 _Out_ PWCHAR UnicodeString, 284 _In_ ULONG UnicodeSize, 285 _Out_opt_ PULONG ResultSize, 286 _In_ PCCH OemString, 287 _In_ ULONG OemSize) 288 { 289 if (UnicodeString) 290 *UnicodeString = UNICODE_NULL; 291 292 if (ResultSize) 293 *ResultSize = 0; 294 295 return STATUS_NOT_IMPLEMENTED; 296 } 297 298 _Use_decl_annotations_ 299 NTSTATUS 300 NTAPI 301 RtlUpcaseUnicodeToOemN( 302 _Out_ PCHAR OemString, 303 _In_ ULONG OemSize, 304 _Out_opt_ PULONG ResultSize, 305 _In_ PCWCH UnicodeString, 306 _In_ ULONG UnicodeSize) 307 { 308 if (OemSize) 309 *OemString = ANSI_NULL; 310 311 if (ResultSize) 312 *ResultSize = 0; 313 314 return STATUS_NOT_IMPLEMENTED; 315 } 316 317 /* EOF */ 318