Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3145 lines
81 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. nls.c
  5. Abstract:
  6. This module implements NLS support functions for NT.
  7. Author:
  8. Mark Lucovsky (markl) 16-Apr-1991
  9. Environment:
  10. Kernel or user-mode
  11. Revision History:
  12. 16-Feb-1993 JulieB Added Upcase Rtl Routines.
  13. 08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
  14. 02-Apr-1993 JulieB Fixed RtlAnsiCharToUnicodeChar to use transl. tbls.
  15. 02-Apr-1993 JulieB Fixed BUFFER_TOO_SMALL check.
  16. 28-May-1993 JulieB Fixed code to properly handle DBCS.
  17. --*/
  18. #include "ntrtlp.h"
  19. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  20. #pragma alloc_text(PAGE,RtlAnsiStringToUnicodeString)
  21. #pragma alloc_text(PAGE,RtlAnsiCharToUnicodeChar)
  22. #pragma alloc_text(PAGE,RtlUnicodeStringToAnsiString)
  23. #pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToAnsiString)
  24. #pragma alloc_text(PAGE,RtlOemStringToUnicodeString)
  25. #pragma alloc_text(PAGE,RtlUnicodeStringToOemString)
  26. #pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToOemString)
  27. #pragma alloc_text(PAGE,RtlOemStringToCountedUnicodeString)
  28. #pragma alloc_text(PAGE,RtlUnicodeStringToCountedOemString)
  29. #pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToCountedOemString)
  30. #pragma alloc_text(PAGE,RtlUpcaseUnicodeString)
  31. #pragma alloc_text(PAGE,RtlDowncaseUnicodeString)
  32. #pragma alloc_text(PAGE,RtlUpcaseUnicodeChar)
  33. #pragma alloc_text(PAGE,RtlDowncaseUnicodeChar)
  34. #pragma alloc_text(PAGE,RtlFreeUnicodeString)
  35. #pragma alloc_text(PAGE,RtlFreeAnsiString)
  36. #pragma alloc_text(PAGE,RtlFreeOemString)
  37. #pragma alloc_text(PAGE,RtlxUnicodeStringToAnsiSize)
  38. #pragma alloc_text(PAGE,RtlxUnicodeStringToOemSize)
  39. #pragma alloc_text(PAGE,RtlxAnsiStringToUnicodeSize)
  40. #pragma alloc_text(PAGE,RtlxOemStringToUnicodeSize)
  41. #pragma alloc_text(PAGE,RtlCompareUnicodeString)
  42. #pragma alloc_text(PAGE,RtlEqualUnicodeString)
  43. #pragma alloc_text(PAGE,RtlPrefixUnicodeString)
  44. #pragma alloc_text(PAGE,RtlCreateUnicodeString)
  45. #pragma alloc_text(PAGE,RtlEqualDomainName)
  46. #pragma alloc_text(PAGE,RtlEqualComputerName)
  47. #pragma alloc_text(PAGE,RtlIsTextUnicode)
  48. #pragma alloc_text(PAGE,RtlDnsHostNameToComputerName)
  49. #pragma alloc_text(PAGE,RtlHashUnicodeString)
  50. #pragma alloc_text(PAGE,RtlDuplicateUnicodeString)
  51. #pragma alloc_text(PAGE,RtlFindCharInUnicodeString)
  52. #endif
  53. //
  54. // Global data used for translations.
  55. //
  56. extern const PUSHORT NlsAnsiToUnicodeData; // Ansi CP to Unicode translation table
  57. extern const PUSHORT NlsLeadByteInfo; // Lead byte info for ACP
  58. //
  59. // Pulled from lmcons.h:
  60. //
  61. #ifndef NETBIOS_NAME_LEN
  62. #define NETBIOS_NAME_LEN 16 // NetBIOS net name (bytes)
  63. #endif // NETBIOS_NAME_LEN
  64. NTSTATUS
  65. RtlAnsiStringToUnicodeString(
  66. OUT PUNICODE_STRING DestinationString,
  67. IN PCANSI_STRING SourceString,
  68. IN BOOLEAN AllocateDestinationString
  69. )
  70. /*++
  71. Routine Description:
  72. This functions converts the specified ansi source string into a
  73. Unicode string. The translation is done with respect to the
  74. current system locale information.
  75. Arguments:
  76. DestinationString - Returns a unicode string that is equivalent to
  77. the ansi source string. The maximum length field is only
  78. set if AllocateDestinationString is TRUE.
  79. SourceString - Supplies the ansi source string that is to be
  80. converted to unicode.
  81. AllocateDestinationString - Supplies a flag that controls whether or
  82. not this API allocates the buffer space for the destination
  83. string. If it does, then the buffer must be deallocated using
  84. RtlFreeUnicodeString (note that only storage for
  85. DestinationString->Buffer is allocated by this API).
  86. Return Value:
  87. SUCCESS - The conversion was successful
  88. !SUCCESS - The operation failed. No storage was allocated and no
  89. conversion was done. None.
  90. --*/
  91. {
  92. ULONG UnicodeLength;
  93. ULONG Index;
  94. NTSTATUS st;
  95. RTL_PAGED_CODE();
  96. UnicodeLength = RtlAnsiStringToUnicodeSize(SourceString);
  97. if ( UnicodeLength > MAXUSHORT ) {
  98. return STATUS_INVALID_PARAMETER_2;
  99. }
  100. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  101. if ( AllocateDestinationString ) {
  102. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  103. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  104. if ( !DestinationString->Buffer ) {
  105. return STATUS_NO_MEMORY;
  106. }
  107. }
  108. else {
  109. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  110. return STATUS_BUFFER_OVERFLOW;
  111. }
  112. }
  113. st = RtlMultiByteToUnicodeN(
  114. DestinationString->Buffer,
  115. DestinationString->Length,
  116. &Index,
  117. SourceString->Buffer,
  118. SourceString->Length
  119. );
  120. if (!NT_SUCCESS(st)) {
  121. if ( AllocateDestinationString ) {
  122. (RtlFreeStringRoutine)(DestinationString->Buffer);
  123. DestinationString->Buffer = NULL;
  124. }
  125. return st;
  126. }
  127. DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
  128. return STATUS_SUCCESS;
  129. }
  130. WCHAR
  131. RtlAnsiCharToUnicodeChar(
  132. IN OUT PUCHAR *SourceCharacter
  133. )
  134. /*++
  135. Routine Description:
  136. This function translates the specified ansi character to unicode and
  137. returns the unicode value. The purpose for this routine is to allow
  138. for character by character ansi to unicode translation. The
  139. translation is done with respect to the current system locale
  140. information.
  141. Arguments:
  142. SourceCharacter - Supplies a pointer to an ansi character pointer.
  143. Through two levels of indirection, this supplies an ansi
  144. character that is to be translated to unicode. After
  145. translation, the ansi character pointer is modified to point to
  146. the next character to be converted. This is done to allow for
  147. dbcs ansi characters.
  148. Return Value:
  149. Returns the unicode equivalent of the specified ansi character.
  150. --*/
  151. {
  152. WCHAR UnicodeCharacter;
  153. ULONG cbCharSize;
  154. NTSTATUS st;
  155. RTL_PAGED_CODE();
  156. //
  157. // Translate the ansi character to unicode - this handles DBCS.
  158. //
  159. UnicodeCharacter = 0x0020;
  160. cbCharSize = NlsLeadByteInfo[ **SourceCharacter ] ? 2 : 1;
  161. st = RtlMultiByteToUnicodeN ( &UnicodeCharacter,
  162. sizeof ( WCHAR ),
  163. NULL,
  164. *SourceCharacter,
  165. cbCharSize );
  166. //
  167. // Check for error - The only time this will happen is if there is
  168. // a leadbyte without a trail byte.
  169. //
  170. if ( ! NT_SUCCESS( st ) )
  171. {
  172. // Use space as default.
  173. UnicodeCharacter = 0x0020;
  174. }
  175. //
  176. // Advance the source pointer and return the Unicode character.
  177. //
  178. (*SourceCharacter) += cbCharSize;
  179. return UnicodeCharacter;
  180. }
  181. NTSTATUS
  182. RtlUnicodeStringToAnsiString(
  183. OUT PANSI_STRING DestinationString,
  184. IN PCUNICODE_STRING SourceString,
  185. IN BOOLEAN AllocateDestinationString
  186. )
  187. /*++
  188. Routine Description:
  189. This functions converts the specified unicode source string into an
  190. ansi string. The translation is done with respect to the
  191. current system locale information.
  192. Arguments:
  193. DestinationString - Returns an ansi string that is equivalent to the
  194. unicode source string. If the translation can not be done,
  195. an error is returned. The maximum length field is only set if
  196. AllocateDestinationString is TRUE.
  197. SourceString - Supplies the unicode source string that is to be
  198. converted to ansi.
  199. AllocateDestinationString - Supplies a flag that controls whether or
  200. not this API allocates the buffer space for the destination
  201. string. If it does, then the buffer must be deallocated using
  202. RtlFreeAnsiString (note that only storage for
  203. DestinationString->Buffer is allocated by this API).
  204. Return Value:
  205. SUCCESS - The conversion was successful
  206. !SUCCESS - The operation failed. No storage was allocated and no
  207. conversion was done. None.
  208. --*/
  209. {
  210. ULONG AnsiLength;
  211. ULONG Index;
  212. NTSTATUS st;
  213. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  214. RTL_PAGED_CODE();
  215. AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
  216. if ( AnsiLength > MAXUSHORT ) {
  217. return STATUS_INVALID_PARAMETER_2;
  218. }
  219. DestinationString->Length = (USHORT)(AnsiLength - 1);
  220. if ( AllocateDestinationString ) {
  221. DestinationString->MaximumLength = (USHORT)AnsiLength;
  222. DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
  223. if ( !DestinationString->Buffer ) {
  224. return STATUS_NO_MEMORY;
  225. }
  226. }
  227. else {
  228. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  229. /*
  230. * Return STATUS_BUFFER_OVERFLOW, but translate as much as
  231. * will fit into the buffer first. This is the expected
  232. * behavior for routines such as GetProfileStringA.
  233. * Set the length of the buffer to one less than the maximum
  234. * (so that the trail byte of a double byte char is not
  235. * overwritten by doing DestinationString->Buffer[Index] = '\0').
  236. * RtlUnicodeToMultiByteN is careful not to truncate a
  237. * multibyte character.
  238. */
  239. if (!DestinationString->MaximumLength) {
  240. return STATUS_BUFFER_OVERFLOW;
  241. }
  242. ReturnStatus = STATUS_BUFFER_OVERFLOW;
  243. DestinationString->Length = DestinationString->MaximumLength - 1;
  244. }
  245. }
  246. st = RtlUnicodeToMultiByteN(
  247. DestinationString->Buffer,
  248. DestinationString->Length,
  249. &Index,
  250. SourceString->Buffer,
  251. SourceString->Length
  252. );
  253. if (!NT_SUCCESS(st)) {
  254. if ( AllocateDestinationString ) {
  255. (RtlFreeStringRoutine)(DestinationString->Buffer);
  256. DestinationString->Buffer = NULL;
  257. }
  258. return st;
  259. }
  260. DestinationString->Buffer[Index] = '\0';
  261. return ReturnStatus;
  262. }
  263. NTSTATUS
  264. RtlUpcaseUnicodeStringToAnsiString(
  265. OUT PANSI_STRING DestinationString,
  266. IN PCUNICODE_STRING SourceString,
  267. IN BOOLEAN AllocateDestinationString
  268. )
  269. /*++
  270. Routine Description:
  271. This functions upper cases the specified unicode source string and then
  272. converts it into an ansi string. The translation is done with respect
  273. to the current system locale information.
  274. Arguments:
  275. DestinationString - Returns an ansi string that is equivalent to the
  276. unicode source string. If the translation can not be done,
  277. an error is returned. The maximum length field is only set
  278. if AllocateDestinationString is TRUE.
  279. SourceString - Supplies the unicode source string that is to be
  280. converted to upper case ansi.
  281. AllocateDestinationString - Supplies a flag that controls whether or
  282. not this API allocates the buffer space for the destination
  283. string. If it does, then the buffer must be deallocated using
  284. RtlFreeAnsiString (note that only storage for
  285. DestinationString->Buffer is allocated by this API).
  286. Return Value:
  287. SUCCESS - The conversion was successful
  288. !SUCCESS - The operation failed. No storage was allocated and no
  289. conversion was done. None.
  290. --*/
  291. {
  292. ULONG AnsiLength;
  293. ULONG Index;
  294. NTSTATUS st;
  295. RTL_PAGED_CODE();
  296. AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
  297. if ( AnsiLength > MAXUSHORT ) {
  298. return STATUS_INVALID_PARAMETER_2;
  299. }
  300. DestinationString->Length = (USHORT)(AnsiLength - 1);
  301. if ( AllocateDestinationString ) {
  302. DestinationString->MaximumLength = (USHORT)AnsiLength;
  303. DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
  304. if ( !DestinationString->Buffer ) {
  305. return STATUS_NO_MEMORY;
  306. }
  307. }
  308. else {
  309. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  310. return STATUS_BUFFER_OVERFLOW;
  311. }
  312. }
  313. st = RtlUpcaseUnicodeToMultiByteN(
  314. DestinationString->Buffer,
  315. DestinationString->Length,
  316. &Index,
  317. SourceString->Buffer,
  318. SourceString->Length
  319. );
  320. if (!NT_SUCCESS(st)) {
  321. if ( AllocateDestinationString ) {
  322. (RtlFreeStringRoutine)(DestinationString->Buffer);
  323. DestinationString->Buffer = NULL;
  324. }
  325. return st;
  326. }
  327. DestinationString->Buffer[Index] = '\0';
  328. return STATUS_SUCCESS;
  329. }
  330. NTSTATUS
  331. RtlOemStringToUnicodeString(
  332. OUT PUNICODE_STRING DestinationString,
  333. IN PCOEM_STRING SourceString,
  334. IN BOOLEAN AllocateDestinationString
  335. )
  336. /*++
  337. Routine Description:
  338. This functions converts the specified oem source string into a
  339. Unicode string. The translation is done with respect to the
  340. installed OEM code page (OCP).
  341. Arguments:
  342. DestinationString - Returns a unicode string that is equivalent to
  343. the oem source string. The maximum length field is only
  344. set if AllocateDestinationString is TRUE.
  345. SourceString - Supplies the oem source string that is to be
  346. converted to unicode.
  347. AllocateDestinationString - Supplies a flag that controls whether or
  348. not this API allocates the buffer space for the destination
  349. string. If it does, then the buffer must be deallocated using
  350. RtlFreeUnicodeString (note that only storage for
  351. DestinationString->Buffer is allocated by this API).
  352. Return Value:
  353. SUCCESS - The conversion was successful
  354. !SUCCESS - The operation failed. No storage was allocated and no
  355. conversion was done. None.
  356. --*/
  357. {
  358. ULONG UnicodeLength;
  359. ULONG Index;
  360. NTSTATUS st;
  361. RTL_PAGED_CODE();
  362. UnicodeLength = RtlOemStringToUnicodeSize(SourceString);
  363. if ( UnicodeLength > MAXUSHORT ) {
  364. return STATUS_INVALID_PARAMETER_2;
  365. }
  366. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  367. if ( AllocateDestinationString ) {
  368. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  369. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  370. if ( !DestinationString->Buffer ) {
  371. return STATUS_NO_MEMORY;
  372. }
  373. }
  374. else {
  375. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  376. return STATUS_BUFFER_OVERFLOW;
  377. }
  378. }
  379. st = RtlOemToUnicodeN(
  380. DestinationString->Buffer,
  381. DestinationString->Length,
  382. &Index,
  383. SourceString->Buffer,
  384. SourceString->Length
  385. );
  386. if (!NT_SUCCESS(st)) {
  387. if ( AllocateDestinationString ) {
  388. (RtlFreeStringRoutine)(DestinationString->Buffer);
  389. DestinationString->Buffer = NULL;
  390. }
  391. return st;
  392. }
  393. DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
  394. return STATUS_SUCCESS;
  395. }
  396. NTSTATUS
  397. RtlUnicodeStringToOemString(
  398. OUT POEM_STRING DestinationString,
  399. IN PCUNICODE_STRING SourceString,
  400. IN BOOLEAN AllocateDestinationString
  401. )
  402. /*++
  403. Routine Description:
  404. This functions converts the specified unicode source string into an
  405. oem string. The translation is done with respect to the OEM code
  406. page (OCP).
  407. Arguments:
  408. DestinationString - Returns an oem string that is equivalent to the
  409. unicode source string. If the translation can not be done,
  410. an error is returned. The maximum length field is only set if
  411. AllocateDestinationString is TRUE.
  412. SourceString - Supplies the unicode source string that is to be
  413. converted to oem.
  414. AllocateDestinationString - Supplies a flag that controls whether or
  415. not this API allocates the buffer space for the destination
  416. string. If it does, then the buffer must be deallocated using
  417. RtlFreeAnsiString (note that only storage for
  418. DestinationString->Buffer is allocated by this API).
  419. Return Value:
  420. SUCCESS - The conversion was successful
  421. !SUCCESS - The operation failed. No storage was allocated and no
  422. conversion was done. None.
  423. --*/
  424. {
  425. ULONG OemLength;
  426. ULONG Index;
  427. NTSTATUS st;
  428. RTL_PAGED_CODE();
  429. OemLength = RtlUnicodeStringToOemSize(SourceString);
  430. if ( OemLength > MAXUSHORT ) {
  431. return STATUS_INVALID_PARAMETER_2;
  432. }
  433. DestinationString->Length = (USHORT)(OemLength - 1);
  434. if ( AllocateDestinationString ) {
  435. DestinationString->MaximumLength = (USHORT)OemLength;
  436. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  437. if ( !DestinationString->Buffer ) {
  438. return STATUS_NO_MEMORY;
  439. }
  440. }
  441. else {
  442. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  443. return STATUS_BUFFER_OVERFLOW;
  444. }
  445. }
  446. st = RtlUnicodeToOemN(
  447. DestinationString->Buffer,
  448. DestinationString->Length,
  449. &Index,
  450. SourceString->Buffer,
  451. SourceString->Length
  452. );
  453. if (!NT_SUCCESS(st)) {
  454. if ( AllocateDestinationString ) {
  455. (RtlFreeStringRoutine)(DestinationString->Buffer);
  456. DestinationString->Buffer = NULL;
  457. }
  458. return st;
  459. }
  460. DestinationString->Buffer[Index] = '\0';
  461. return STATUS_SUCCESS;
  462. }
  463. NTSTATUS
  464. RtlUpcaseUnicodeStringToOemString(
  465. OUT POEM_STRING DestinationString,
  466. IN PCUNICODE_STRING SourceString,
  467. IN BOOLEAN AllocateDestinationString
  468. )
  469. /*++
  470. Routine Description:
  471. This function upper cases the specified unicode source string and then
  472. converts it into an oem string. The translation is done with respect
  473. to the OEM code page (OCP).
  474. Arguments:
  475. DestinationString - Returns an oem string that is equivalent to the
  476. unicode source string. The maximum length field is only set if
  477. AllocateDestinationString is TRUE.
  478. SourceString - Supplies the unicode source string that is to be
  479. converted to oem.
  480. AllocateDestinationString - Supplies a flag that controls whether or
  481. not this API allocates the buffer space for the destination
  482. string. If it does, then the buffer must be deallocated using
  483. RtlFreeAnsiString (note that only storage for
  484. DestinationString->Buffer is allocated by this API).
  485. Return Value:
  486. SUCCESS - The conversion was successful
  487. !SUCCESS - The operation failed. No storage was allocated and no
  488. conversion was done. None.
  489. --*/
  490. {
  491. ULONG OemLength;
  492. ULONG Index;
  493. NTSTATUS st;
  494. RTL_PAGED_CODE();
  495. OemLength = RtlUnicodeStringToOemSize(SourceString);
  496. if ( OemLength > MAXUSHORT ) {
  497. return STATUS_INVALID_PARAMETER_2;
  498. }
  499. DestinationString->Length = (USHORT)(OemLength - 1);
  500. if ( AllocateDestinationString ) {
  501. DestinationString->MaximumLength = (USHORT)OemLength;
  502. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  503. if ( !DestinationString->Buffer ) {
  504. return STATUS_NO_MEMORY;
  505. }
  506. }
  507. else {
  508. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  509. return STATUS_BUFFER_OVERFLOW;
  510. }
  511. }
  512. st = RtlUpcaseUnicodeToOemN(
  513. DestinationString->Buffer,
  514. DestinationString->Length,
  515. &Index,
  516. SourceString->Buffer,
  517. SourceString->Length
  518. );
  519. //
  520. // Now do a check here to see if there was really a mapping for all
  521. // characters converted.
  522. //
  523. if (NT_SUCCESS(st) &&
  524. !RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
  525. st = STATUS_UNMAPPABLE_CHARACTER;
  526. }
  527. if (!NT_SUCCESS(st)) {
  528. if ( AllocateDestinationString ) {
  529. (RtlFreeStringRoutine)(DestinationString->Buffer);
  530. DestinationString->Buffer = NULL;
  531. }
  532. return st;
  533. }
  534. DestinationString->Buffer[Index] = '\0';
  535. return STATUS_SUCCESS;
  536. }
  537. NTSTATUS
  538. RtlOemStringToCountedUnicodeString(
  539. OUT PUNICODE_STRING DestinationString,
  540. IN PCOEM_STRING SourceString,
  541. IN BOOLEAN AllocateDestinationString
  542. )
  543. /*++
  544. Routine Description:
  545. This functions converts the specified oem source string into a
  546. Unicode string. The translation is done with respect to the
  547. installed OEM code page (OCP).
  548. The destination string is NOT unnaturally null terminated. It is a
  549. counted string as counted strings are meant to be.
  550. Arguments:
  551. DestinationString - Returns a unicode string that is equivalent to
  552. the oem source string. The maximum length field is only
  553. set if AllocateDestinationString is TRUE.
  554. SourceString - Supplies the oem source string that is to be
  555. converted to unicode.
  556. AllocateDestinationString - Supplies a flag that controls whether or
  557. not this API allocates the buffer space for the destination
  558. string. If it does, then the buffer must be deallocated using
  559. RtlFreeUnicodeString (note that only storage for
  560. DestinationString->Buffer is allocated by this API).
  561. Return Value:
  562. SUCCESS - The conversion was successful
  563. !SUCCESS - The operation failed. No storage was allocated and no
  564. conversion was done. None.
  565. --*/
  566. {
  567. ULONG UnicodeLength;
  568. ULONG Index;
  569. NTSTATUS st;
  570. RTL_PAGED_CODE();
  571. UnicodeLength = RtlOemStringToCountedUnicodeSize(SourceString);
  572. if ( UnicodeLength == 0 ) {
  573. DestinationString->Length = 0;
  574. DestinationString->MaximumLength = 0;
  575. DestinationString->Buffer = NULL;
  576. return STATUS_SUCCESS;
  577. }
  578. if ( UnicodeLength > MAXUSHORT ) {
  579. return STATUS_INVALID_PARAMETER_2;
  580. }
  581. DestinationString->Length = (USHORT)(UnicodeLength);
  582. if ( AllocateDestinationString ) {
  583. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  584. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  585. if ( !DestinationString->Buffer ) {
  586. return STATUS_NO_MEMORY;
  587. }
  588. }
  589. else {
  590. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  591. return STATUS_BUFFER_OVERFLOW;
  592. }
  593. }
  594. st = RtlOemToUnicodeN(
  595. DestinationString->Buffer,
  596. DestinationString->Length,
  597. &Index,
  598. SourceString->Buffer,
  599. SourceString->Length
  600. );
  601. if (!NT_SUCCESS(st)) {
  602. if ( AllocateDestinationString ) {
  603. (RtlFreeStringRoutine)(DestinationString->Buffer);
  604. DestinationString->Buffer = NULL;
  605. }
  606. return st;
  607. }
  608. return STATUS_SUCCESS;
  609. }
  610. NTSTATUS
  611. RtlUnicodeStringToCountedOemString(
  612. OUT POEM_STRING DestinationString,
  613. IN PCUNICODE_STRING SourceString,
  614. IN BOOLEAN AllocateDestinationString
  615. )
  616. /*++
  617. Routine Description:
  618. This functions converts the specified unicode source string into an
  619. oem string. The translation is done with respect to the OEM code
  620. page (OCP).
  621. The destination string is NOT unnaturally null terminated. It is a
  622. counted string as counted strings are meant to be.
  623. Arguments:
  624. DestinationString - Returns an oem string that is equivalent to the
  625. unicode source string. If the translation can not be done,
  626. an error is returned. The maximum length field is only set if
  627. AllocateDestinationString is TRUE.
  628. SourceString - Supplies the unicode source string that is to be
  629. converted to oem.
  630. AllocateDestinationString - Supplies a flag that controls whether or
  631. not this API allocates the buffer space for the destination
  632. string. If it does, then the buffer must be deallocated using
  633. RtlFreeAnsiString (note that only storage for
  634. DestinationString->Buffer is allocated by this API).
  635. Return Value:
  636. SUCCESS - The conversion was successful
  637. !SUCCESS - The operation failed. No storage was allocated and no
  638. conversion was done. None.
  639. --*/
  640. {
  641. ULONG OemLength;
  642. ULONG Index;
  643. NTSTATUS st;
  644. RTL_PAGED_CODE();
  645. OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
  646. if ( OemLength == 0 ) {
  647. DestinationString->Length = 0;
  648. DestinationString->MaximumLength = 0;
  649. DestinationString->Buffer = NULL;
  650. return STATUS_SUCCESS;
  651. }
  652. if ( OemLength > MAXUSHORT ) {
  653. return STATUS_INVALID_PARAMETER_2;
  654. }
  655. DestinationString->Length = (USHORT)(OemLength);
  656. if ( AllocateDestinationString ) {
  657. DestinationString->MaximumLength = (USHORT)OemLength;
  658. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  659. if ( !DestinationString->Buffer ) {
  660. return STATUS_NO_MEMORY;
  661. }
  662. }
  663. else {
  664. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  665. return STATUS_BUFFER_OVERFLOW;
  666. }
  667. }
  668. st = RtlUnicodeToOemN(
  669. DestinationString->Buffer,
  670. DestinationString->Length,
  671. &Index,
  672. SourceString->Buffer,
  673. SourceString->Length
  674. );
  675. //
  676. // Now do a check here to see if there was really a mapping for all
  677. // characters converted.
  678. //
  679. if (NT_SUCCESS(st) &&
  680. !RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
  681. st = STATUS_UNMAPPABLE_CHARACTER;
  682. }
  683. if (!NT_SUCCESS(st)) {
  684. if ( AllocateDestinationString ) {
  685. (RtlFreeStringRoutine)(DestinationString->Buffer);
  686. DestinationString->Buffer = NULL;
  687. }
  688. return st;
  689. }
  690. return STATUS_SUCCESS;
  691. }
  692. NTSTATUS
  693. RtlUpcaseUnicodeStringToCountedOemString(
  694. OUT POEM_STRING DestinationString,
  695. IN PCUNICODE_STRING SourceString,
  696. IN BOOLEAN AllocateDestinationString
  697. )
  698. /*++
  699. Routine Description:
  700. This functions upper cases the specified unicode source string and
  701. then converts it into an oem string. The translation is done with
  702. respect to the OEM code page (OCP).
  703. The destination string is NOT unnaturally null terminated. It is a
  704. counted string as counted strings are meant to be.
  705. Arguments:
  706. DestinationString - Returns an oem string that is equivalent to the
  707. unicode source string. If the translation can not be done,
  708. an error is returned. The maximum length field is only set
  709. if AllocateDestinationString is TRUE.
  710. SourceString - Supplies the unicode source string that is to be
  711. converted to oem.
  712. AllocateDestinationString - Supplies a flag that controls whether or
  713. not this API allocates the buffer space for the destination
  714. string. If it does, then the buffer must be deallocated using
  715. RtlFreeAnsiString (note that only storage for
  716. DestinationString->Buffer is allocated by this API).
  717. Return Value:
  718. SUCCESS - The conversion was successful
  719. !SUCCESS - The operation failed. No storage was allocated and no
  720. conversion was done. None.
  721. --*/
  722. {
  723. ULONG OemLength;
  724. ULONG Index;
  725. NTSTATUS st;
  726. RTL_PAGED_CODE();
  727. OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
  728. if ( OemLength == 0 ) {
  729. DestinationString->Length = 0;
  730. DestinationString->MaximumLength = 0;
  731. DestinationString->Buffer = NULL;
  732. return STATUS_SUCCESS;
  733. }
  734. if ( OemLength > MAXUSHORT ) {
  735. return STATUS_INVALID_PARAMETER_2;
  736. }
  737. DestinationString->Length = (USHORT)(OemLength);
  738. if ( AllocateDestinationString ) {
  739. DestinationString->MaximumLength = (USHORT)OemLength;
  740. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  741. if ( !DestinationString->Buffer ) {
  742. return STATUS_NO_MEMORY;
  743. }
  744. }
  745. else {
  746. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  747. return STATUS_BUFFER_OVERFLOW;
  748. }
  749. }
  750. st = RtlUpcaseUnicodeToOemN(
  751. DestinationString->Buffer,
  752. DestinationString->Length,
  753. &Index,
  754. SourceString->Buffer,
  755. SourceString->Length
  756. );
  757. //
  758. // Now do a check here to see if there was really a mapping for all
  759. // characters converted.
  760. //
  761. if (NT_SUCCESS(st) &&
  762. !RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
  763. st = STATUS_UNMAPPABLE_CHARACTER;
  764. }
  765. if (!NT_SUCCESS(st)) {
  766. if ( AllocateDestinationString ) {
  767. (RtlFreeStringRoutine)(DestinationString->Buffer);
  768. DestinationString->Buffer = NULL;
  769. }
  770. return st;
  771. }
  772. return STATUS_SUCCESS;
  773. }
  774. NTSTATUS
  775. RtlUpcaseUnicodeString(
  776. OUT PUNICODE_STRING DestinationString,
  777. IN PCUNICODE_STRING SourceString,
  778. IN BOOLEAN AllocateDestinationString
  779. )
  780. /*++
  781. Routine Description:
  782. This functions converts the specified unicode source string into an
  783. upcased unicode string. The translation is done with respect to the
  784. current system locale information.
  785. Arguments:
  786. DestinationString - Returns a unicode string that is the upcased equivalent
  787. to the unicode source string. The maximum length field is only set if
  788. AllocateDestinationString is TRUE.
  789. SourceString - Supplies the unicode source string that is to being
  790. upcased.
  791. AllocateDestinationString - Supplies a flag that controls whether or
  792. not this API allocates the buffer space for the destination
  793. string. If it does, then the buffer must be deallocated using
  794. RtlFreeUnicodeString (note that only storage for
  795. DestinationString->Buffer is allocated by this API).
  796. Return Value:
  797. SUCCESS - The conversion was successful
  798. !SUCCESS - The operation failed. No storage was allocated and no
  799. conversion was done. None.
  800. --*/
  801. {
  802. ULONG Index;
  803. ULONG StopIndex;
  804. RTL_PAGED_CODE();
  805. if ( AllocateDestinationString ) {
  806. DestinationString->MaximumLength = SourceString->Length;
  807. DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
  808. if ( !DestinationString->Buffer ) {
  809. return STATUS_NO_MEMORY;
  810. }
  811. }
  812. else {
  813. if ( SourceString->Length > DestinationString->MaximumLength ) {
  814. return STATUS_BUFFER_OVERFLOW;
  815. }
  816. }
  817. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  818. for (Index = 0; Index < StopIndex; Index++) {
  819. DestinationString->Buffer[Index] = (WCHAR)NLS_UPCASE(SourceString->Buffer[Index]);
  820. }
  821. DestinationString->Length = SourceString->Length;
  822. return STATUS_SUCCESS;
  823. }
  824. NTSTATUS
  825. RtlDowncaseUnicodeString(
  826. OUT PUNICODE_STRING DestinationString,
  827. IN PCUNICODE_STRING SourceString,
  828. IN BOOLEAN AllocateDestinationString
  829. )
  830. /*++
  831. Routine Description:
  832. This functions converts the specified unicode source string into a
  833. downcased unicode string. The translation is done with respect to the
  834. current system locale information.
  835. Arguments:
  836. DestinationString - Returns a unicode string that is the downcased
  837. equivalent to the unicode source string. The maximum length field
  838. is only set if AllocateDestinationString is TRUE.
  839. SourceString - Supplies the unicode source string that is to being
  840. downcased.
  841. AllocateDestinationString - Supplies a flag that controls whether or
  842. not this API allocates the buffer space for the destination
  843. string. If it does, then the buffer must be deallocated using
  844. RtlFreeUnicodeString (note that only storage for
  845. DestinationString->Buffer is allocated by this API).
  846. Return Value:
  847. SUCCESS - The conversion was successful
  848. !SUCCESS - The operation failed. No storage was allocated and no
  849. conversion was done. None.
  850. --*/
  851. {
  852. ULONG Index;
  853. ULONG StopIndex;
  854. RTL_PAGED_CODE();
  855. if ( AllocateDestinationString ) {
  856. DestinationString->MaximumLength = SourceString->Length;
  857. DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
  858. if ( !DestinationString->Buffer ) {
  859. return STATUS_NO_MEMORY;
  860. }
  861. }
  862. else {
  863. if ( SourceString->Length > DestinationString->MaximumLength ) {
  864. return STATUS_BUFFER_OVERFLOW;
  865. }
  866. }
  867. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  868. for (Index = 0; Index < StopIndex; Index++) {
  869. DestinationString->Buffer[Index] = (WCHAR)NLS_DOWNCASE(SourceString->Buffer[Index]);
  870. }
  871. DestinationString->Length = SourceString->Length;
  872. return STATUS_SUCCESS;
  873. }
  874. WCHAR
  875. RtlUpcaseUnicodeChar(
  876. IN WCHAR SourceCharacter
  877. )
  878. /*++
  879. Routine Description:
  880. This function translates the specified unicode character to its
  881. equivalent upcased unicode chararacter. The purpose for this routine
  882. is to allow for character by character upcase translation. The
  883. translation is done with respect to the current system locale
  884. information.
  885. Arguments:
  886. SourceCharacter - Supplies the unicode character to be upcased.
  887. Return Value:
  888. Returns the upcased unicode equivalent of the specified input character.
  889. --*/
  890. {
  891. RTL_PAGED_CODE();
  892. //
  893. // Note that this needs to reference the translation table !
  894. //
  895. return (WCHAR)NLS_UPCASE(SourceCharacter);
  896. }
  897. WCHAR
  898. RtlDowncaseUnicodeChar(
  899. IN WCHAR SourceCharacter
  900. )
  901. /*++
  902. Routine Description:
  903. This function translates the specified unicode character to its
  904. equivalent downcased unicode chararacter. The purpose for this routine
  905. is to allow for character by character downcase translation. The
  906. translation is done with respect to the current system locale
  907. information.
  908. Arguments:
  909. SourceCharacter - Supplies the unicode character to be downcased.
  910. Return Value:
  911. Returns the downcased unicode equivalent of the specified input character.
  912. --*/
  913. {
  914. RTL_PAGED_CODE();
  915. //
  916. // Note that this needs to reference the translation table !
  917. //
  918. return (WCHAR)NLS_DOWNCASE(SourceCharacter);
  919. }
  920. VOID
  921. RtlFreeUnicodeString(
  922. IN OUT PUNICODE_STRING UnicodeString
  923. )
  924. /*++
  925. Routine Description:
  926. This API is used to free storage allocated by
  927. RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
  928. is free'd by this routine.
  929. Arguments:
  930. UnicodeString - Supplies the address of the unicode string whose
  931. buffer was previously allocated by RtlAnsiStringToUnicodeString.
  932. Return Value:
  933. None.
  934. --*/
  935. {
  936. RTL_PAGED_CODE();
  937. if (UnicodeString->Buffer) {
  938. (RtlFreeStringRoutine)(UnicodeString->Buffer);
  939. memset( UnicodeString, 0, sizeof( *UnicodeString ) );
  940. }
  941. }
  942. VOID
  943. RtlFreeAnsiString(
  944. IN OUT PANSI_STRING AnsiString
  945. )
  946. /*++
  947. Routine Description:
  948. This API is used to free storage allocated by
  949. RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
  950. is free'd by this routine.
  951. Arguments:
  952. AnsiString - Supplies the address of the ansi string whose buffer
  953. was previously allocated by RtlUnicodeStringToAnsiString.
  954. Return Value:
  955. None.
  956. --*/
  957. {
  958. RTL_PAGED_CODE();
  959. if (AnsiString->Buffer) {
  960. (RtlFreeStringRoutine)(AnsiString->Buffer);
  961. memset( AnsiString, 0, sizeof( *AnsiString ) );
  962. }
  963. }
  964. VOID
  965. RtlFreeOemString(
  966. IN OUT POEM_STRING OemString
  967. )
  968. /*++
  969. Routine Description:
  970. This API is used to free storage allocated by
  971. RtlUnicodeStringToOemString. Note that only OemString->Buffer
  972. is free'd by this routine.
  973. Arguments:
  974. OemString - Supplies the address of the oem string whose buffer
  975. was previously allocated by RtlUnicodeStringToOemString.
  976. Return Value:
  977. None.
  978. --*/
  979. {
  980. RTL_PAGED_CODE();
  981. if (OemString->Buffer) {(RtlFreeStringRoutine)(OemString->Buffer);}
  982. }
  983. ULONG
  984. RtlxUnicodeStringToAnsiSize(
  985. IN PCUNICODE_STRING UnicodeString
  986. )
  987. /*++
  988. Routine Description:
  989. This function computes the number of bytes required to store
  990. a NULL terminated ansi string that is equivalent to the specified
  991. unicode string. If an ansi string can not be formed, the return value
  992. is 0.
  993. Arguments:
  994. UnicodeString - Supplies a unicode string whose equivalent size as
  995. an ansi string is to be calculated.
  996. Return Value:
  997. 0 - The operation failed, the unicode string can not be translated
  998. into ansi using the current system locale therefore no storage
  999. is needed for the ansi string.
  1000. !0 - The operation was successful. The return value specifies the
  1001. number of bytes required to hold an NULL terminated ansi string
  1002. equivalent to the specified unicode string.
  1003. --*/
  1004. {
  1005. ULONG cbMultiByteString;
  1006. RTL_PAGED_CODE();
  1007. //
  1008. // Get the size of the string - this call handles DBCS.
  1009. //
  1010. RtlUnicodeToMultiByteSize( &cbMultiByteString,
  1011. UnicodeString->Buffer,
  1012. UnicodeString->Length );
  1013. //
  1014. // Return the size in bytes.
  1015. //
  1016. return (cbMultiByteString + 1);
  1017. }
  1018. ULONG
  1019. RtlxUnicodeStringToOemSize(
  1020. IN PCUNICODE_STRING UnicodeString
  1021. )
  1022. /*++
  1023. Routine Description:
  1024. This function computes the number of bytes required to store
  1025. a NULL terminated oem string that is equivalent to the specified
  1026. unicode string. If an oem string can not be formed, the return value
  1027. is 0.
  1028. Arguments:
  1029. UnicodeString - Supplies a unicode string whose equivalent size as
  1030. an oem string is to be calculated.
  1031. Return Value:
  1032. 0 - The operation failed, the unicode string can not be translated
  1033. into oem using the OEM code page therefore no storage is
  1034. needed for the oem string.
  1035. !0 - The operation was successful. The return value specifies the
  1036. number of bytes required to hold an NULL terminated oem string
  1037. equivalent to the specified unicode string.
  1038. --*/
  1039. {
  1040. ULONG cbMultiByteString;
  1041. RTL_PAGED_CODE();
  1042. //
  1043. // LATER: Define an RtlUnicodeToOemSize.
  1044. // In the Japanese version, it's safe to call
  1045. // RtlUnicodeToMultiByteSize because the Ansi code page
  1046. // and the OEM code page are the same.
  1047. //
  1048. //
  1049. // Get the size of the string - this call handles DBCS.
  1050. //
  1051. RtlUnicodeToMultiByteSize( &cbMultiByteString,
  1052. UnicodeString->Buffer,
  1053. UnicodeString->Length );
  1054. //
  1055. // Return the size in bytes.
  1056. //
  1057. return (cbMultiByteString + 1);
  1058. }
  1059. ULONG
  1060. RtlxAnsiStringToUnicodeSize(
  1061. IN PCANSI_STRING AnsiString
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This function computes the number of bytes required to store a NULL
  1066. terminated unicode string that is equivalent to the specified ansi
  1067. string.
  1068. Arguments:
  1069. AnsiString - Supplies an ansi string whose equivalent size as a
  1070. unicode string is to be calculated. The ansi string is
  1071. interpreted relative to the current system locale.
  1072. Return Value:
  1073. The return value specifies the number of bytes required to hold a
  1074. NULL terminated unicode string equivalent to the specified ansi
  1075. string.
  1076. --*/
  1077. {
  1078. ULONG cbConverted;
  1079. RTL_PAGED_CODE();
  1080. //
  1081. // Get the size of the string - this call handles DBCS.
  1082. //
  1083. RtlMultiByteToUnicodeSize( &cbConverted ,
  1084. AnsiString->Buffer,
  1085. AnsiString->Length );
  1086. //
  1087. // Return the size in bytes.
  1088. //
  1089. return ( cbConverted + sizeof(UNICODE_NULL) );
  1090. }
  1091. ULONG
  1092. RtlxOemStringToUnicodeSize(
  1093. IN PCOEM_STRING OemString
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. This function computes the number of bytes required to store a NULL
  1098. terminated unicode string that is equivalent to the specified oem
  1099. string.
  1100. Arguments:
  1101. OemString - Supplies an oem string whose equivalent size as a
  1102. unicode string is to be calculated. The oem string is
  1103. interpreted relative to the current oem code page (OCP).
  1104. Return Value:
  1105. The return value specifies the number of bytes required to hold a
  1106. NULL terminated unicode string equivalent to the specified oem
  1107. string.
  1108. --*/
  1109. {
  1110. ULONG cbConverted;
  1111. RTL_PAGED_CODE();
  1112. //
  1113. // LATER: Define an RtlOemToUnicodeSize.
  1114. // In the Japanese version, it's safe to call
  1115. // RtlMultiByteToUnicodeSize because the Ansi code page
  1116. // and the OEM code page are the same.
  1117. //
  1118. //
  1119. // Get the size of the string - this call handles DBCS.
  1120. //
  1121. RtlMultiByteToUnicodeSize( &cbConverted,
  1122. OemString->Buffer,
  1123. OemString->Length );
  1124. //
  1125. // Return the size in bytes.
  1126. //
  1127. return ( cbConverted + sizeof(UNICODE_NULL) );
  1128. }
  1129. LONG
  1130. RtlCompareUnicodeString(
  1131. IN PCUNICODE_STRING String1,
  1132. IN PCUNICODE_STRING String2,
  1133. IN BOOLEAN CaseInSensitive
  1134. )
  1135. /*++
  1136. Routine Description:
  1137. The RtlCompareUnicodeString function compares two counted strings. The
  1138. return value indicates if the strings are equal or String1 is less than
  1139. String2 or String1 is greater than String2.
  1140. The CaseInSensitive parameter specifies if case is to be ignored when
  1141. doing the comparison.
  1142. Arguments:
  1143. String1 - Pointer to the first string.
  1144. String2 - Pointer to the second string.
  1145. CaseInsensitive - TRUE if case should be ignored when doing the
  1146. comparison.
  1147. Return Value:
  1148. Signed value that gives the results of the comparison:
  1149. Zero - String1 equals String2
  1150. < Zero - String1 less than String2
  1151. > Zero - String1 greater than String2
  1152. --*/
  1153. {
  1154. PCWSTR s1, s2, Limit;
  1155. LONG n1, n2;
  1156. WCHAR c1, c2;
  1157. RTL_PAGED_CODE();
  1158. s1 = String1->Buffer;
  1159. s2 = String2->Buffer;
  1160. n1 = String1->Length;
  1161. n2 = String2->Length;
  1162. ASSERT((n1 & 1) == 0);
  1163. ASSERT((n2 & 1) == 0);
  1164. ASSERT(!(((((ULONG_PTR)s1 & 1) != 0) || (((ULONG_PTR)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
  1165. Limit = (PWCHAR)((PCHAR)s1 + (n1 <= n2 ? n1 : n2));
  1166. if (CaseInSensitive) {
  1167. while (s1 < Limit) {
  1168. c1 = *s1++;
  1169. c2 = *s2++;
  1170. if (c1 != c2) {
  1171. //
  1172. // Note that this needs to reference the translation table!
  1173. //
  1174. c1 = NLS_UPCASE(c1);
  1175. c2 = NLS_UPCASE(c2);
  1176. if (c1 != c2) {
  1177. return (LONG)(c1) - (LONG)(c2);
  1178. }
  1179. }
  1180. }
  1181. } else {
  1182. while (s1 < Limit) {
  1183. c1 = *s1++;
  1184. c2 = *s2++;
  1185. if (c1 != c2) {
  1186. return (LONG)(c1) - (LONG)(c2);
  1187. }
  1188. }
  1189. }
  1190. return n1 - n2;
  1191. }
  1192. BOOLEAN
  1193. RtlEqualUnicodeString(
  1194. IN PCUNICODE_STRING String1,
  1195. IN PCUNICODE_STRING String2,
  1196. IN BOOLEAN CaseInSensitive
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. The RtlEqualUnicodeString function compares two counted unicode strings for
  1201. equality.
  1202. The CaseInSensitive parameter specifies if case is to be ignored when
  1203. doing the comparison.
  1204. Arguments:
  1205. String1 - Pointer to the first string.
  1206. String2 - Pointer to the second string.
  1207. CaseInsensitive - TRUE if case should be ignored when doing the
  1208. comparison.
  1209. Return Value:
  1210. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1211. --*/
  1212. {
  1213. PWCHAR s1, s2, Limit;
  1214. LONG n1, n2;
  1215. WCHAR c1, c2;
  1216. RTL_PAGED_CODE();
  1217. n1 = String1->Length;
  1218. n2 = String2->Length;
  1219. if (n1 == n2) {
  1220. s1 = String1->Buffer;
  1221. s2 = String2->Buffer;
  1222. Limit = (PWCHAR)((PCHAR)s1 + (n1&~(sizeof(WCHAR) - 1)));
  1223. if (CaseInSensitive) {
  1224. while (s1 < Limit) {
  1225. c1 = *s1++;
  1226. c2 = *s2++;
  1227. if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
  1228. return FALSE;
  1229. }
  1230. }
  1231. return TRUE;
  1232. } else {
  1233. while (s1 < Limit) {
  1234. c1 = *s1++;
  1235. c2 = *s2++;
  1236. if (c1 != c2) {
  1237. return FALSE;
  1238. }
  1239. }
  1240. return TRUE;
  1241. }
  1242. } else {
  1243. return FALSE;
  1244. }
  1245. }
  1246. BOOLEAN
  1247. RtlPrefixUnicodeString(
  1248. IN PUNICODE_STRING String1,
  1249. IN PUNICODE_STRING String2,
  1250. IN BOOLEAN CaseInSensitive
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. The RtlPrefixUnicodeString function determines if the String1
  1255. counted string parameter is a prefix of the String2 counted string
  1256. parameter.
  1257. The CaseInSensitive parameter specifies if case is to be ignored when
  1258. doing the comparison.
  1259. Arguments:
  1260. String1 - Pointer to the first unicode string.
  1261. String2 - Pointer to the second unicode string.
  1262. CaseInsensitive - TRUE if case should be ignored when doing the
  1263. comparison.
  1264. Return Value:
  1265. Boolean value that is TRUE if String1 equals a prefix of String2 and
  1266. FALSE otherwise.
  1267. --*/
  1268. {
  1269. PWSTR s1, s2;
  1270. ULONG n;
  1271. WCHAR c1, c2;
  1272. RTL_PAGED_CODE();
  1273. s1 = String1->Buffer;
  1274. s2 = String2->Buffer;
  1275. n = String1->Length;
  1276. if (String2->Length < n) {
  1277. return( FALSE );
  1278. }
  1279. n = n / sizeof(c1);
  1280. if (CaseInSensitive) {
  1281. while (n) {
  1282. c1 = *s1++;
  1283. c2 = *s2++;
  1284. if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
  1285. return( FALSE );
  1286. }
  1287. n--;
  1288. }
  1289. }
  1290. else {
  1291. while (n) {
  1292. if (*s1++ != *s2++) {
  1293. return( FALSE );
  1294. }
  1295. n--;
  1296. }
  1297. }
  1298. return TRUE;
  1299. }
  1300. VOID
  1301. RtlCopyUnicodeString(
  1302. OUT PUNICODE_STRING DestinationString,
  1303. IN PCUNICODE_STRING SourceString OPTIONAL
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. The RtlCopyString function copies the SourceString to the
  1308. DestinationString. If SourceString is not specified, then
  1309. the Length field of DestinationString is set to zero. The
  1310. MaximumLength and Buffer fields of DestinationString are not
  1311. modified by this function.
  1312. The number of bytes copied from the SourceString is either the
  1313. Length of SourceString or the MaximumLength of DestinationString,
  1314. whichever is smaller.
  1315. Arguments:
  1316. DestinationString - Pointer to the destination string.
  1317. SourceString - Optional pointer to the source string.
  1318. Return Value:
  1319. None.
  1320. --*/
  1321. {
  1322. UNALIGNED WCHAR *src, *dst;
  1323. ULONG n;
  1324. if (ARGUMENT_PRESENT(SourceString)) {
  1325. dst = DestinationString->Buffer;
  1326. src = SourceString->Buffer;
  1327. n = SourceString->Length;
  1328. if ((USHORT)n > DestinationString->MaximumLength) {
  1329. n = DestinationString->MaximumLength;
  1330. }
  1331. DestinationString->Length = (USHORT)n;
  1332. RtlCopyMemory(dst, src, n);
  1333. if (DestinationString->Length < DestinationString->MaximumLength) {
  1334. dst[n / sizeof(WCHAR)] = UNICODE_NULL;
  1335. }
  1336. } else {
  1337. DestinationString->Length = 0;
  1338. }
  1339. return;
  1340. }
  1341. NTSTATUS
  1342. RtlAppendUnicodeToString (
  1343. IN PUNICODE_STRING Destination,
  1344. IN PCWSTR Source OPTIONAL
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. This routine appends the supplied UNICODE string to an existing
  1349. PUNICODE_STRING.
  1350. It will copy bytes from the Source PSZ to the destination PSTRING up to
  1351. the destinations PUNICODE_STRING->MaximumLength field.
  1352. Arguments:
  1353. IN PUNICODE_STRING Destination, - Supplies a pointer to the destination
  1354. string
  1355. IN PWSTR Source - Supplies the string to append to the destination
  1356. Return Value:
  1357. STATUS_SUCCESS - The source string was successfully appended to the
  1358. destination counted string.
  1359. STATUS_BUFFER_TOO_SMALL - The destination string length was not big
  1360. enough to allow the source string to be appended. The Destination
  1361. string length is not updated.
  1362. --*/
  1363. {
  1364. USHORT n;
  1365. UNALIGNED WCHAR *dst;
  1366. if (ARGUMENT_PRESENT( Source )) {
  1367. UNICODE_STRING UniSource;
  1368. RtlInitUnicodeString(&UniSource, Source);
  1369. n = UniSource.Length;
  1370. if ((n + Destination->Length) > Destination->MaximumLength) {
  1371. return( STATUS_BUFFER_TOO_SMALL );
  1372. }
  1373. dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
  1374. RtlMoveMemory( dst, Source, n );
  1375. Destination->Length += n;
  1376. if (Destination->Length < Destination->MaximumLength) {
  1377. dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
  1378. }
  1379. }
  1380. return( STATUS_SUCCESS );
  1381. }
  1382. NTSTATUS
  1383. RtlAppendUnicodeStringToString (
  1384. IN OUT PUNICODE_STRING Destination,
  1385. IN PCUNICODE_STRING Source
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. This routine will concatinate two PSTRINGs together. It will copy
  1390. bytes from the source up to the MaximumLength of the destination.
  1391. Arguments:
  1392. IN PSTRING Destination, - Supplies the destination string
  1393. IN PSTRING Source - Supplies the source for the string copy
  1394. Return Value:
  1395. STATUS_SUCCESS - The source string was successfully appended to the
  1396. destination counted string.
  1397. STATUS_BUFFER_TOO_SMALL - The destination string length was not big
  1398. enough to allow the source string to be appended. The Destination
  1399. string length is not updated.
  1400. --*/
  1401. {
  1402. USHORT n = Source->Length;
  1403. UNALIGNED WCHAR *dst;
  1404. if (n) {
  1405. if ((n + Destination->Length) > Destination->MaximumLength) {
  1406. return( STATUS_BUFFER_TOO_SMALL );
  1407. }
  1408. dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
  1409. RtlMoveMemory( dst, Source->Buffer, n );
  1410. Destination->Length += n;
  1411. if (Destination->Length < Destination->MaximumLength) {
  1412. dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
  1413. }
  1414. }
  1415. return( STATUS_SUCCESS );
  1416. }
  1417. BOOLEAN
  1418. RtlCreateUnicodeString(
  1419. OUT PUNICODE_STRING DestinationString,
  1420. IN PCWSTR SourceString
  1421. )
  1422. {
  1423. ULONG cb;
  1424. RTL_PAGED_CODE();
  1425. cb = (wcslen( SourceString ) + 1) * sizeof( WCHAR );
  1426. DestinationString->Buffer = (RtlAllocateStringRoutine)( cb );
  1427. if (DestinationString->Buffer) {
  1428. RtlCopyMemory( DestinationString->Buffer, SourceString, cb );
  1429. DestinationString->MaximumLength = (USHORT)cb;
  1430. DestinationString->Length = (USHORT)(cb - sizeof( UNICODE_NULL ));
  1431. return( TRUE );
  1432. }
  1433. else {
  1434. return( FALSE );
  1435. }
  1436. }
  1437. BOOLEAN
  1438. RtlEqualDomainName(
  1439. IN PCUNICODE_STRING String1,
  1440. IN PCUNICODE_STRING String2
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. The RtlEqualDomainName function compares two domain names for equality.
  1445. The comparison is a case insensitive comparison of the OEM equivalent
  1446. strings.
  1447. The domain name is not validated for length nor invalid characters.
  1448. Arguments:
  1449. String1 - Pointer to the first string.
  1450. String2 - Pointer to the second string.
  1451. Return Value:
  1452. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1453. --*/
  1454. {
  1455. NTSTATUS Status;
  1456. BOOLEAN ReturnValue = FALSE;
  1457. OEM_STRING OemString1;
  1458. OEM_STRING OemString2;
  1459. RTL_PAGED_CODE();
  1460. //
  1461. // Upper case and convert the first string to OEM
  1462. //
  1463. Status = RtlUpcaseUnicodeStringToOemString( &OemString1,
  1464. String1,
  1465. TRUE ); // Allocate Dest
  1466. if ( NT_SUCCESS( Status ) ) {
  1467. //
  1468. // Upper case and convert the second string to OEM
  1469. //
  1470. Status = RtlUpcaseUnicodeStringToOemString( &OemString2,
  1471. String2,
  1472. TRUE ); // Allocate Dest
  1473. if ( NT_SUCCESS( Status ) ) {
  1474. //
  1475. // Do a case insensitive comparison.
  1476. //
  1477. ReturnValue = RtlEqualString( &OemString1,
  1478. &OemString2,
  1479. FALSE );
  1480. RtlFreeOemString( &OemString2 );
  1481. }
  1482. RtlFreeOemString( &OemString1 );
  1483. }
  1484. return ReturnValue;
  1485. }
  1486. BOOLEAN
  1487. RtlEqualComputerName(
  1488. IN PCUNICODE_STRING String1,
  1489. IN PCUNICODE_STRING String2
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. The RtlEqualComputerName function compares two computer names for equality.
  1494. The comparison is a case insensitive comparison of the OEM equivalent
  1495. strings.
  1496. The domain name is not validated for length nor invalid characters.
  1497. Arguments:
  1498. String1 - Pointer to the first string.
  1499. String2 - Pointer to the second string.
  1500. Return Value:
  1501. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1502. --*/
  1503. {
  1504. return RtlEqualDomainName( String1, String2 );
  1505. }
  1506. /**
  1507. **/
  1508. #define UNICODE_FFFF 0xFFFF
  1509. #define REVERSE_BYTE_ORDER_MARK 0xFFFE
  1510. #define BYTE_ORDER_MARK 0xFEFF
  1511. #define PARAGRAPH_SEPARATOR 0x2029
  1512. #define LINE_SEPARATOR 0x2028
  1513. #define UNICODE_TAB 0x0009
  1514. #define UNICODE_LF 0x000A
  1515. #define UNICODE_CR 0x000D
  1516. #define UNICODE_SPACE 0x0020
  1517. #define UNICODE_CJK_SPACE 0x3000
  1518. #define UNICODE_R_TAB 0x0900
  1519. #define UNICODE_R_LF 0x0A00
  1520. #define UNICODE_R_CR 0x0D00
  1521. #define UNICODE_R_SPACE 0x2000
  1522. #define UNICODE_R_CJK_SPACE 0x0030 /* Ambiguous - same as ASCII '0' */
  1523. #define ASCII_CRLF 0x0A0D
  1524. #define __max(a,b) (((a) > (b)) ? (a) : (b))
  1525. #define __min(a,b) (((a) < (b)) ? (a) : (b))
  1526. BOOLEAN
  1527. RtlIsTextUnicode(
  1528. IN PVOID Buffer,
  1529. IN ULONG Size,
  1530. IN OUT PULONG Result OPTIONAL
  1531. )
  1532. /*++
  1533. Routine Description:
  1534. IsTextUnicode performs a series of inexpensive heuristic checks
  1535. on a buffer in order to verify that it contains Unicode data.
  1536. [[ need to fix this section, see at the end ]]
  1537. Found Return Result
  1538. BOM TRUE BOM
  1539. RBOM FALSE RBOM
  1540. FFFF FALSE Binary
  1541. NULL FALSE Binary
  1542. null TRUE null bytes
  1543. ASCII_CRLF FALSE CRLF
  1544. UNICODE_TAB etc. TRUE Zero Ext Controls
  1545. UNICODE_TAB_R FALSE Reversed Controls
  1546. UNICODE_ZW etc. TRUE Unicode specials
  1547. 1/3 as little variation in hi-byte as in lo byte: TRUE Correl
  1548. 3/1 or worse " FALSE AntiCorrel
  1549. Arguments:
  1550. Buffer - pointer to buffer containing text to examine.
  1551. Size - size of buffer in bytes. At most 256 characters in this will
  1552. be examined. If the size is less than the size of a unicode
  1553. character, then this function returns FALSE.
  1554. Result - optional pointer to a flag word that contains additional information
  1555. about the reason for the return value. If specified, this value on
  1556. input is a mask that is used to limit the factors this routine uses
  1557. to make its decision. On output, this flag word is set to contain
  1558. those flags that were used to make its decision.
  1559. Return Value:
  1560. Boolean value that is TRUE if Buffer contains unicode characters.
  1561. --*/
  1562. {
  1563. UNALIGNED WCHAR *lpBuff = Buffer;
  1564. PUCHAR lpb = Buffer;
  1565. ULONG iBOM = 0;
  1566. ULONG iCR = 0;
  1567. ULONG iLF = 0;
  1568. ULONG iTAB = 0;
  1569. ULONG iSPACE = 0;
  1570. ULONG iCJK_SPACE = 0;
  1571. ULONG iFFFF = 0;
  1572. ULONG iPS = 0;
  1573. ULONG iLS = 0;
  1574. ULONG iRBOM = 0;
  1575. ULONG iR_CR = 0;
  1576. ULONG iR_LF = 0;
  1577. ULONG iR_TAB = 0;
  1578. ULONG iR_SPACE = 0;
  1579. ULONG iNull = 0;
  1580. ULONG iUNULL = 0;
  1581. ULONG iCRLF = 0;
  1582. ULONG iTmp;
  1583. ULONG LastLo = 0;
  1584. ULONG LastHi = 0;
  1585. ULONG iHi, iLo;
  1586. ULONG HiDiff = 0;
  1587. ULONG LoDiff = 0;
  1588. ULONG cLeadByte = 0;
  1589. ULONG cWeird = 0;
  1590. ULONG iResult = 0;
  1591. ULONG iMaxTmp = __min(256, Size / sizeof(WCHAR));
  1592. //
  1593. // Special case when the size is less than or equal to 2.
  1594. // Make sure we don't have a character followed by a null byte.
  1595. //
  1596. if ((Size < 2) ||
  1597. ((Size == 2) && (lpBuff[0] != 0) && (lpb[1] == 0)))
  1598. {
  1599. if (ARGUMENT_PRESENT(Result))
  1600. {
  1601. *Result = IS_TEXT_UNICODE_ASCII16 | IS_TEXT_UNICODE_CONTROLS;
  1602. }
  1603. return (FALSE);
  1604. }
  1605. else if ((Size > 2) && ((Size / sizeof(WCHAR)) <= 256))
  1606. {
  1607. //
  1608. // If the Size passed in is an even number, we don't want to
  1609. // use the last WCHAR because it will contain the final null
  1610. // byte.
  1611. //
  1612. if (((Size % sizeof(WCHAR)) == 0) &&
  1613. ((lpBuff[iMaxTmp - 1] & 0xff00) == 0))
  1614. {
  1615. iMaxTmp--;
  1616. }
  1617. }
  1618. //
  1619. // Check at most 256 wide characters, collect various statistics.
  1620. //
  1621. for (iTmp = 0; iTmp < iMaxTmp; iTmp++)
  1622. {
  1623. switch (lpBuff[iTmp])
  1624. {
  1625. case BYTE_ORDER_MARK:
  1626. iBOM++;
  1627. break;
  1628. case PARAGRAPH_SEPARATOR:
  1629. iPS++;
  1630. break;
  1631. case LINE_SEPARATOR:
  1632. iLS++;
  1633. break;
  1634. case UNICODE_LF:
  1635. iLF++;
  1636. break;
  1637. case UNICODE_TAB:
  1638. iTAB++;
  1639. break;
  1640. case UNICODE_SPACE:
  1641. iSPACE++;
  1642. break;
  1643. case UNICODE_CJK_SPACE:
  1644. iCJK_SPACE++;
  1645. break;
  1646. case UNICODE_CR:
  1647. iCR++;
  1648. break;
  1649. //
  1650. // The following codes are expected to show up in
  1651. // byte reversed files.
  1652. //
  1653. case REVERSE_BYTE_ORDER_MARK:
  1654. iRBOM++;
  1655. break;
  1656. case UNICODE_R_LF:
  1657. iR_LF++;
  1658. break;
  1659. case UNICODE_R_TAB:
  1660. iR_TAB++;
  1661. break;
  1662. case UNICODE_R_CR:
  1663. iR_CR++;
  1664. break;
  1665. case UNICODE_R_SPACE:
  1666. iR_SPACE++;
  1667. break;
  1668. //
  1669. // The following codes are illegal and should never occur.
  1670. //
  1671. case UNICODE_FFFF:
  1672. iFFFF++;
  1673. break;
  1674. case UNICODE_NULL:
  1675. iUNULL++;
  1676. break;
  1677. //
  1678. // The following is not currently a Unicode character
  1679. // but is expected to show up accidentally when reading
  1680. // in ASCII files which use CRLF on a little endian machine.
  1681. //
  1682. case ASCII_CRLF:
  1683. iCRLF++;
  1684. break; /* little endian */
  1685. }
  1686. //
  1687. // Collect statistics on the fluctuations of high bytes
  1688. // versus low bytes.
  1689. //
  1690. iHi = HIBYTE(lpBuff[iTmp]);
  1691. iLo = LOBYTE(lpBuff[iTmp]);
  1692. //
  1693. // Count cr/lf and lf/cr that cross two words.
  1694. //
  1695. if ((iLo == '\r' && LastHi == '\n') ||
  1696. (iLo == '\n' && LastHi == '\r'))
  1697. {
  1698. cWeird++;
  1699. }
  1700. iNull += (iHi ? 0 : 1) + (iLo ? 0 : 1); /* count Null bytes */
  1701. HiDiff += __max(iHi, LastHi) - __min(LastHi, iHi);
  1702. LoDiff += __max(iLo, LastLo) - __min(LastLo, iLo);
  1703. LastLo = iLo;
  1704. LastHi = iHi;
  1705. }
  1706. //
  1707. // Count cr/lf and lf/cr that cross two words.
  1708. //
  1709. if ((iLo == '\r' && LastHi == '\n') ||
  1710. (iLo == '\n' && LastHi == '\r'))
  1711. {
  1712. cWeird++;
  1713. }
  1714. if (iHi == '\0') /* don't count the last null */
  1715. iNull--;
  1716. if (iHi == 26) /* count ^Z at end as weird */
  1717. cWeird++;
  1718. iMaxTmp = __min(256 * sizeof(WCHAR), Size);
  1719. if (NlsMbCodePageTag)
  1720. {
  1721. for (iTmp = 0; iTmp < iMaxTmp; iTmp++)
  1722. {
  1723. if (NlsLeadByteInfo[lpb[iTmp]])
  1724. {
  1725. cLeadByte++;
  1726. iTmp++; /* should check for trailing-byte range */
  1727. }
  1728. }
  1729. }
  1730. //
  1731. // Sift through the statistical evidence.
  1732. //
  1733. if (LoDiff < 127 && HiDiff == 0)
  1734. {
  1735. iResult |= IS_TEXT_UNICODE_ASCII16; /* likely 16-bit ASCII */
  1736. }
  1737. if (HiDiff && LoDiff == 0)
  1738. {
  1739. iResult |= IS_TEXT_UNICODE_REVERSE_ASCII16; /* reverse 16-bit ASCII */
  1740. }
  1741. //
  1742. // Use leadbyte info to weight statistics.
  1743. //
  1744. if (!NlsMbCodePageTag || cLeadByte == 0 ||
  1745. !ARGUMENT_PRESENT(Result) || !(*Result & IS_TEXT_UNICODE_DBCS_LEADBYTE))
  1746. {
  1747. iHi = 3;
  1748. }
  1749. else
  1750. {
  1751. //
  1752. // A ratio of cLeadByte:cb of 1:2 ==> dbcs
  1753. // Very crude - should have a nice eq.
  1754. //
  1755. iHi = __min(256, Size / sizeof(WCHAR)) / 2;
  1756. if (cLeadByte < (iHi - 1) / 3)
  1757. {
  1758. iHi = 3;
  1759. }
  1760. else if (cLeadByte < (2 * (iHi - 1)) / 3)
  1761. {
  1762. iHi = 2;
  1763. }
  1764. else
  1765. {
  1766. iHi = 1;
  1767. }
  1768. iResult |= IS_TEXT_UNICODE_DBCS_LEADBYTE;
  1769. }
  1770. if (iHi * HiDiff < LoDiff)
  1771. {
  1772. iResult |= IS_TEXT_UNICODE_STATISTICS;
  1773. }
  1774. if (iHi * LoDiff < HiDiff)
  1775. {
  1776. iResult |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
  1777. }
  1778. //
  1779. // Any control codes widened to 16 bits? Any Unicode character
  1780. // which contain one byte in the control code range?
  1781. //
  1782. if (iCR + iLF + iTAB + iSPACE + iCJK_SPACE /*+iPS+iLS*/)
  1783. {
  1784. iResult |= IS_TEXT_UNICODE_CONTROLS;
  1785. }
  1786. if (iR_LF + iR_CR + iR_TAB + iR_SPACE)
  1787. {
  1788. iResult |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
  1789. }
  1790. //
  1791. // Any characters that are illegal for Unicode?
  1792. //
  1793. if ((iRBOM + iFFFF + iUNULL + iCRLF) != 0 ||
  1794. (cWeird != 0 && cWeird >= iMaxTmp/40))
  1795. {
  1796. iResult |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
  1797. }
  1798. //
  1799. // Odd buffer length cannot be Unicode.
  1800. //
  1801. if (Size & 1)
  1802. {
  1803. iResult |= IS_TEXT_UNICODE_ODD_LENGTH;
  1804. }
  1805. //
  1806. // Any NULL bytes? (Illegal in ANSI)
  1807. //
  1808. if (iNull)
  1809. {
  1810. iResult |= IS_TEXT_UNICODE_NULL_BYTES;
  1811. }
  1812. //
  1813. // POSITIVE evidence, BOM or RBOM used as signature.
  1814. //
  1815. if (*lpBuff == BYTE_ORDER_MARK)
  1816. {
  1817. iResult |= IS_TEXT_UNICODE_SIGNATURE;
  1818. }
  1819. else if (*lpBuff == REVERSE_BYTE_ORDER_MARK)
  1820. {
  1821. iResult |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
  1822. }
  1823. //
  1824. // Limit to desired categories if requested.
  1825. //
  1826. if (ARGUMENT_PRESENT(Result))
  1827. {
  1828. iResult &= *Result;
  1829. *Result = iResult;
  1830. }
  1831. //
  1832. // There are four separate conclusions:
  1833. //
  1834. // 1: The file APPEARS to be Unicode AU
  1835. // 2: The file CANNOT be Unicode CU
  1836. // 3: The file CANNOT be ANSI CA
  1837. //
  1838. //
  1839. // This gives the following possible results
  1840. //
  1841. // CU
  1842. // + -
  1843. //
  1844. // AU AU
  1845. // + - + -
  1846. // -------- --------
  1847. // CA +| 0 0 2 3
  1848. // |
  1849. // -| 1 1 4 5
  1850. //
  1851. //
  1852. // Note that there are only 6 really different cases, not 8.
  1853. //
  1854. // 0 - This must be a binary file
  1855. // 1 - ANSI file
  1856. // 2 - Unicode file (High probability)
  1857. // 3 - Unicode file (more than 50% chance)
  1858. // 5 - No evidence for Unicode (ANSI is default)
  1859. //
  1860. // The whole thing is more complicated if we allow the assumption
  1861. // of reverse polarity input. At this point we have a simplistic
  1862. // model: some of the reverse Unicode evidence is very strong,
  1863. // we ignore most weak evidence except statistics. If this kind of
  1864. // strong evidence is found together with Unicode evidence, it means
  1865. // its likely NOT Text at all. Furthermore if a REVERSE_BYTE_ORDER_MARK
  1866. // is found, it precludes normal Unicode. If both byte order marks are
  1867. // found it's not Unicode.
  1868. //
  1869. //
  1870. // Unicode signature : uncontested signature outweighs reverse evidence.
  1871. //
  1872. if ((iResult & IS_TEXT_UNICODE_SIGNATURE) &&
  1873. !(iResult & (IS_TEXT_UNICODE_NOT_UNICODE_MASK&(~IS_TEXT_UNICODE_DBCS_LEADBYTE))))
  1874. {
  1875. return (TRUE);
  1876. }
  1877. //
  1878. // If we have conflicting evidence, it's not Unicode.
  1879. //
  1880. if (iResult & IS_TEXT_UNICODE_REVERSE_MASK)
  1881. {
  1882. return (FALSE);
  1883. }
  1884. //
  1885. // Statistical and other results (cases 2 and 3).
  1886. //
  1887. if (!(iResult & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
  1888. ((iResult & IS_TEXT_UNICODE_NOT_ASCII_MASK) ||
  1889. (iResult & IS_TEXT_UNICODE_UNICODE_MASK)))
  1890. {
  1891. return (TRUE);
  1892. }
  1893. return (FALSE);
  1894. }
  1895. NTSTATUS
  1896. RtlDnsHostNameToComputerName(
  1897. OUT PUNICODE_STRING ComputerNameString,
  1898. IN PCUNICODE_STRING DnsHostNameString,
  1899. IN BOOLEAN AllocateComputerNameString
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. The RtlDnsHostNameToComputerName API converts a DNS-style host name to a
  1904. Netbios-style computer name.
  1905. This API does a syntactical mapping of the name. As such, it should not
  1906. be used to convert a DNS domain name to a Netbios domain name.
  1907. There is no syntactical mapping for domain names.
  1908. DNS-style names consist of one or more "labels" separated by a period
  1909. (e.g., xxx.nt.microsoft.com). Each label can be up to 63 bytes of
  1910. UTF-8 characters and must consist only of characters specified
  1911. by the DnsValidateDnsName API. Upper and lower case characters are treated
  1912. as the same character. DNS names are represented in the UTF-8 character set
  1913. or UNICODE.
  1914. Netbios computer names consist of up to 15 bytes of OEM characters
  1915. including letters, digits, hyphens, periods and various other characters.
  1916. Some of these characters are specific to the character set. Netbios names
  1917. are typically represented in the OEM character set. The OEM character
  1918. set is different depending on the locale of the particular version of the OS
  1919. (e.g., the German version has a different character set than the US version).
  1920. Some OEM character sets represent certain characters as 2 bytes
  1921. (e.g., Japanese). Netbios names, by convention, are represented in
  1922. uppercase where the translation algorithm from lowercase to uppercase
  1923. is OEM character set dependent.
  1924. These characteristics make translating between DNS name and Netbios name
  1925. difficult.
  1926. RtlDnsHostNameToComputerName enforces a textual convention for
  1927. mapping between the two names. This convention limits the names of
  1928. computers to be the common subset of the names. Specifically, the leftmost
  1929. label of the DNS name is truncated to 15-bytes of OEM characters.
  1930. As such, RtlDnsHostNameToComputerName simply interprets the leftmost label
  1931. of the DNS name as the Netbios name. If the DNS name doesn't meet the
  1932. criteria of a valid translatable name, a distinct error code is returned.
  1933. Arguments:
  1934. ComputerNameString - Returns a unicode string that is equivalent to
  1935. the DNS source string. The maximum length field is only
  1936. set if AllocateComputerNameString is TRUE.
  1937. DnsHostNameString - Supplies the DNS host name source string that is to be
  1938. converted to a netbios computer name.
  1939. This routine does NOT attempt to validate that the passed in DnsHostNameString
  1940. is a valid DNS host a DNS host name. Rather it assumes that the passed in
  1941. name is valid and converts it on a best effort basis.
  1942. AllocateComputerNameString - Supplies a flag that controls whether or
  1943. not this API allocates the buffer space for the destination
  1944. string. If it does, then the buffer must be deallocated using
  1945. RtlFreeUnicodeString (note that only storage for
  1946. DestinationString->Buffer is allocated by this API).
  1947. Return Value:
  1948. SUCCESS - The conversion was successful
  1949. STATUS_NO_MEMORY - There is not enough memory to allocate the return buffer.
  1950. STATUS_INVALID_COMPUTER_NAME - The DnsHostName has no first label or
  1951. one or more characters of the DnsHostName could not be converted to
  1952. the OEM character set.
  1953. --*/
  1954. {
  1955. NTSTATUS Status;
  1956. UNICODE_STRING LocalDnsHostNameString;
  1957. OEM_STRING OemString;
  1958. ULONG ActualOemLength;
  1959. CHAR OemStringBuffer[16];
  1960. ULONG i;
  1961. RTL_PAGED_CODE();
  1962. //
  1963. // Truncate the dns name to the first label
  1964. //
  1965. LocalDnsHostNameString = *DnsHostNameString;
  1966. for ( i=0; i<LocalDnsHostNameString.Length/sizeof(WCHAR); i++ ) {
  1967. if ( LocalDnsHostNameString.Buffer[i] == L'.' ) {
  1968. LocalDnsHostNameString.Length = (USHORT)(i * sizeof(WCHAR));
  1969. break;
  1970. }
  1971. }
  1972. if ( LocalDnsHostNameString.Length < sizeof(WCHAR) ) {
  1973. return STATUS_INVALID_COMPUTER_NAME;
  1974. }
  1975. //
  1976. // Convert the DNS name to OEM truncating at 15 OEM bytes.
  1977. //
  1978. Status = RtlUpcaseUnicodeToOemN(
  1979. OemStringBuffer,
  1980. NETBIOS_NAME_LEN-1, // truncate to 15 bytes
  1981. &ActualOemLength,
  1982. LocalDnsHostNameString.Buffer,
  1983. LocalDnsHostNameString.Length );
  1984. if ( !NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW ) {
  1985. return Status;
  1986. }
  1987. //
  1988. // Check to see if any characters are not valid OEM characters.
  1989. //
  1990. OemString.Buffer = OemStringBuffer;
  1991. OemString.MaximumLength = OemString.Length = (USHORT) ActualOemLength;
  1992. if ( !RtlpDidUnicodeToOemWork( &OemString, &LocalDnsHostNameString )) {
  1993. return STATUS_INVALID_COMPUTER_NAME;
  1994. }
  1995. //
  1996. // Convert the OEM string back to UNICODE
  1997. //
  1998. Status = RtlOemStringToUnicodeString(
  1999. ComputerNameString,
  2000. &OemString,
  2001. AllocateComputerNameString );
  2002. if ( !NT_SUCCESS(Status) ) {
  2003. return Status;
  2004. }
  2005. return STATUS_SUCCESS;
  2006. }
  2007. NTSTATUS
  2008. RtlHashUnicodeString(
  2009. const UNICODE_STRING *String,
  2010. BOOLEAN CaseInSensitive,
  2011. ULONG HashAlgorithm,
  2012. PULONG HashValue
  2013. )
  2014. {
  2015. NTSTATUS Status = STATUS_SUCCESS;
  2016. ULONG TmpHashValue = 0;
  2017. ULONG Chars;
  2018. PCWSTR Buffer;
  2019. if ((String == NULL) ||
  2020. (HashValue == NULL))
  2021. {
  2022. Status = STATUS_INVALID_PARAMETER;
  2023. goto Exit;
  2024. }
  2025. Buffer = String->Buffer;
  2026. *HashValue = 0;
  2027. Chars = String->Length / sizeof(WCHAR);
  2028. switch (HashAlgorithm)
  2029. {
  2030. default:
  2031. Status = STATUS_INVALID_PARAMETER;
  2032. goto Exit;
  2033. break;
  2034. case HASH_STRING_ALGORITHM_DEFAULT:
  2035. case HASH_STRING_ALGORITHM_X65599:
  2036. if (CaseInSensitive)
  2037. {
  2038. while (Chars-- != 0)
  2039. {
  2040. WCHAR Char = *Buffer++;
  2041. TmpHashValue = (TmpHashValue * 65599) + NLS_UPCASE(Char);
  2042. }
  2043. }
  2044. else
  2045. {
  2046. while (Chars-- != 0)
  2047. TmpHashValue = (TmpHashValue * 65599) + *Buffer++;
  2048. }
  2049. break;
  2050. }
  2051. *HashValue = TmpHashValue;
  2052. Status = STATUS_SUCCESS;
  2053. Exit:
  2054. return Status;
  2055. }
  2056. NTSTATUS
  2057. RtlValidateUnicodeString(
  2058. ULONG Flags,
  2059. const UNICODE_STRING *String
  2060. )
  2061. {
  2062. NTSTATUS Status = STATUS_SUCCESS;
  2063. ASSERT(Flags == 0);
  2064. if (Flags != 0) {
  2065. Status = STATUS_INVALID_PARAMETER;
  2066. goto Exit;
  2067. }
  2068. if (String != NULL) {
  2069. if (((String->Length % 2) != 0) ||
  2070. ((String->MaximumLength % 2) != 0) ||
  2071. (String->Length > String->MaximumLength)) {
  2072. Status = STATUS_INVALID_PARAMETER;
  2073. goto Exit;
  2074. }
  2075. if (((String->Length != 0) ||
  2076. (String->MaximumLength != 0)) &&
  2077. (String->Buffer == NULL)) {
  2078. Status = STATUS_INVALID_PARAMETER;
  2079. goto Exit;
  2080. }
  2081. }
  2082. Status = STATUS_SUCCESS;
  2083. Exit:
  2084. return Status;
  2085. }
  2086. NTSTATUS
  2087. RtlDuplicateUnicodeString(
  2088. ULONG Flags,
  2089. PCUNICODE_STRING StringIn,
  2090. PUNICODE_STRING StringOut
  2091. )
  2092. {
  2093. NTSTATUS Status = STATUS_SUCCESS;
  2094. USHORT Length = 0;
  2095. USHORT NewMaximumLength = 0;
  2096. PWSTR Buffer = NULL;
  2097. if (((Flags & ~(
  2098. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
  2099. RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)) != 0) ||
  2100. (StringOut == NULL)) {
  2101. Status = STATUS_INVALID_PARAMETER;
  2102. goto Exit;
  2103. }
  2104. // It doesn't make sense to force allocation of a null string unless you
  2105. // want null termination.
  2106. if ((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) &&
  2107. !(Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)) {
  2108. Status = STATUS_INVALID_PARAMETER;
  2109. goto Exit;
  2110. }
  2111. Status = RtlValidateUnicodeString(0, StringIn);
  2112. if (!NT_SUCCESS(Status))
  2113. goto Exit;
  2114. if (StringIn != NULL)
  2115. Length = StringIn->Length;
  2116. if ((Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) &&
  2117. (Length == UNICODE_STRING_MAX_BYTES)) {
  2118. Status = STATUS_NAME_TOO_LONG;
  2119. goto Exit;
  2120. }
  2121. if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
  2122. NewMaximumLength = (USHORT) (Length + sizeof(WCHAR));
  2123. else
  2124. NewMaximumLength = Length;
  2125. // If it's a zero length string in, force the allocation length to zero
  2126. // unless the caller said that they want zero length strings allocated.
  2127. if (((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) == 0) &&
  2128. (Length == 0)) {
  2129. NewMaximumLength = 0;
  2130. }
  2131. if (NewMaximumLength != 0) {
  2132. Buffer = (RtlAllocateStringRoutine)(NewMaximumLength);
  2133. if (Buffer == NULL) {
  2134. Status = STATUS_NO_MEMORY;
  2135. goto Exit;
  2136. }
  2137. // If there's anything to copy, copy it. We explicitly test Length because
  2138. // StringIn could be a NULL pointer, so dereferencing it to get the Buffer
  2139. // pointer would access violate.
  2140. if (Length != 0) {
  2141. RtlCopyMemory(
  2142. Buffer,
  2143. StringIn->Buffer,
  2144. Length);
  2145. }
  2146. if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) {
  2147. Buffer[Length / sizeof(WCHAR)] = L'\0';
  2148. }
  2149. }
  2150. StringOut->Buffer = Buffer;
  2151. StringOut->MaximumLength = NewMaximumLength;
  2152. StringOut->Length = Length;
  2153. Status = STATUS_SUCCESS;
  2154. Exit:
  2155. return Status;
  2156. }
  2157. NTSTATUS
  2158. RtlFindCharInUnicodeString(
  2159. ULONG Flags,
  2160. PCUNICODE_STRING StringToSearch,
  2161. PCUNICODE_STRING CharSet,
  2162. USHORT *NonInclusivePrefixLength
  2163. )
  2164. {
  2165. NTSTATUS Status;
  2166. USHORT PrefixLengthFound = 0;
  2167. USHORT CharsToSearch = 0;
  2168. int MovementDirection = 0;
  2169. PCWSTR Cursor = NULL;
  2170. BOOLEAN Found = FALSE;
  2171. USHORT CharSetChars = 0;
  2172. PCWSTR CharSetBuffer = NULL;
  2173. USHORT i;
  2174. if (NonInclusivePrefixLength != 0)
  2175. *NonInclusivePrefixLength = 0;
  2176. if (((Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
  2177. RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
  2178. RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE)) != 0) ||
  2179. (NonInclusivePrefixLength == NULL)) {
  2180. Status = STATUS_INVALID_PARAMETER;
  2181. goto Exit;
  2182. }
  2183. Status = RtlValidateUnicodeString(0, StringToSearch);
  2184. if (!NT_SUCCESS(Status))
  2185. goto Exit;
  2186. Status = RtlValidateUnicodeString(0, CharSet);
  2187. if (!NT_SUCCESS(Status))
  2188. goto Exit;
  2189. CharsToSearch = StringToSearch->Length / sizeof(WCHAR);
  2190. CharSetChars = CharSet->Length / sizeof(WCHAR);
  2191. CharSetBuffer = CharSet->Buffer;
  2192. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) {
  2193. MovementDirection = -1;
  2194. Cursor = StringToSearch->Buffer + CharsToSearch - 1;
  2195. } else {
  2196. MovementDirection = 1;
  2197. Cursor = StringToSearch->Buffer;
  2198. }
  2199. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) {
  2200. // Unicode standard says to always do case insensitive comparisons in lower case since the case mappings are
  2201. // asymmetric.
  2202. WCHAR CharSetStackBuffer[32]; // optimized pre-downcased for case insensitive
  2203. // Optimization for the case of a relatively small char set to match
  2204. if (CharSetChars <= RTL_NUMBER_OF(CharSetStackBuffer)) {
  2205. for (i=0; i<CharSetChars; i++)
  2206. CharSetStackBuffer[i] = RtlDowncaseUnicodeChar(CharSetBuffer[i]);
  2207. while (CharsToSearch != 0) {
  2208. const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
  2209. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  2210. for (i=0; i<CharSetChars; i++) {
  2211. if (wch == CharSetStackBuffer[i])
  2212. break;
  2213. }
  2214. if (i == CharSetChars)
  2215. break;
  2216. } else {
  2217. for (i=0; i<CharSetChars; i++) {
  2218. if (wch == CharSetStackBuffer[i])
  2219. break;
  2220. }
  2221. if (i != CharSetChars)
  2222. break;
  2223. }
  2224. CharsToSearch--;
  2225. Cursor += MovementDirection;
  2226. }
  2227. } else {
  2228. while (CharsToSearch != 0) {
  2229. const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
  2230. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  2231. for (i=0; i<CharSetChars; i++) {
  2232. if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
  2233. break;
  2234. }
  2235. }
  2236. if (i == CharSetChars)
  2237. break;
  2238. } else {
  2239. for (i=0; i<CharSetChars; i++) {
  2240. if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
  2241. break;
  2242. }
  2243. }
  2244. if (i != CharSetChars)
  2245. break;
  2246. }
  2247. CharsToSearch--;
  2248. Cursor += MovementDirection;
  2249. }
  2250. }
  2251. } else {
  2252. if (CharSetChars == 1) {
  2253. // Significant optimization for looking for one character.
  2254. const WCHAR wchSearchChar = CharSetBuffer[0];
  2255. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  2256. while (CharsToSearch != 0) {
  2257. if (*Cursor != wchSearchChar)
  2258. break;
  2259. CharsToSearch--;
  2260. Cursor += MovementDirection;
  2261. }
  2262. } else {
  2263. while (CharsToSearch != 0) {
  2264. if (*Cursor == wchSearchChar)
  2265. break;
  2266. CharsToSearch--;
  2267. Cursor += MovementDirection;
  2268. }
  2269. }
  2270. } else {
  2271. while (CharsToSearch != 0) {
  2272. const WCHAR wch = *Cursor;
  2273. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  2274. for (i=0; i<CharSetChars; i++) {
  2275. if (wch == CharSetBuffer[i])
  2276. break;
  2277. }
  2278. if (i == CharSetChars)
  2279. break;
  2280. } else {
  2281. for (i=0; i<CharSetChars; i++) {
  2282. if (wch == CharSetBuffer[i])
  2283. break;
  2284. }
  2285. if (i != CharSetChars)
  2286. break;
  2287. }
  2288. CharsToSearch--;
  2289. Cursor += MovementDirection;
  2290. }
  2291. }
  2292. }
  2293. if (CharsToSearch == 0) {
  2294. Status = STATUS_NOT_FOUND;
  2295. goto Exit;
  2296. }
  2297. CharsToSearch--;
  2298. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
  2299. PrefixLengthFound = (USHORT) (CharsToSearch * sizeof(WCHAR));
  2300. else
  2301. PrefixLengthFound = (USHORT) (StringToSearch->Length - (CharsToSearch * sizeof(WCHAR)));
  2302. *NonInclusivePrefixLength = PrefixLengthFound;
  2303. Status = STATUS_SUCCESS;
  2304. Exit:
  2305. return Status;
  2306. }
  2307. NTSTATUS
  2308. NTAPI
  2309. RtlFindAndReplaceCharacterInString(
  2310. ULONG Flags,
  2311. PVOID Reserved,
  2312. PUNICODE_STRING String,
  2313. WCHAR Find,
  2314. WCHAR Replace
  2315. )
  2316. {
  2317. NTSTATUS Status = STATUS_SUCCESS;
  2318. ULONG Index = 0;
  2319. ULONG Length = 0;
  2320. typedef WCHAR TChar;
  2321. if (Flags & ~RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE) {
  2322. Status = STATUS_INVALID_PARAMETER;
  2323. goto Exit;
  2324. }
  2325. if (Reserved != NULL) {
  2326. Status = STATUS_INVALID_PARAMETER;
  2327. goto Exit;
  2328. }
  2329. if (String == NULL
  2330. || Find == Replace
  2331. ) {
  2332. Status = STATUS_SUCCESS;
  2333. goto Exit;
  2334. }
  2335. Length = RTL_STRING_GET_LENGTH_CHARS(String);
  2336. if (Length == 0) {
  2337. Status = STATUS_SUCCESS;
  2338. goto Exit;
  2339. }
  2340. if ((Flags & RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE) != 0) {
  2341. for (Index = 0 ; Index != Length ; ++Index) {
  2342. if ( String->Buffer[Index] == Find
  2343. ) {
  2344. String->Buffer[Index] = Replace;
  2345. }
  2346. }
  2347. }
  2348. else {
  2349. TChar DownFind = RtlDowncaseUnicodeChar(Find);
  2350. TChar UpFind = RtlUpcaseUnicodeChar(Find);
  2351. for (Index = 0 ; Index != Length ; ++Index) {
  2352. const TChar Char = String->Buffer[Index];
  2353. if ( Char == Find
  2354. || Char == UpFind
  2355. || Char == DownFind
  2356. ) {
  2357. String->Buffer[Index] = Replace;
  2358. }
  2359. else {
  2360. TChar DownChar = RtlDowncaseUnicodeChar(Char);
  2361. if ( DownChar == Find
  2362. //|| DownChar == UpFind // presumably not possible
  2363. || DownChar == DownFind
  2364. ) {
  2365. String->Buffer[Index] = Replace;
  2366. }
  2367. else if (DownChar != Char) {
  2368. TChar UpChar = RtlUpcaseUnicodeChar(Char);
  2369. if ( UpChar == Find
  2370. || UpChar == UpFind
  2371. //||UpChar == DownFind // presumably not possible
  2372. ) {
  2373. String->Buffer[Index] = Replace;
  2374. }
  2375. }
  2376. }
  2377. }
  2378. }
  2379. Status = STATUS_SUCCESS;
  2380. Exit:
  2381. return Status;
  2382. }