Windows NT 4.0 source code leak
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.

2429 lines
61 KiB

4 years ago
  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,RtlOemStringToUnicodeString)
  23. #pragma alloc_text(PAGE,RtlUnicodeStringToAnsiString)
  24. #pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToAnsiString)
  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,RtlFreeUnicodeString)
  34. #pragma alloc_text(PAGE,RtlFreeAnsiString)
  35. #pragma alloc_text(PAGE,RtlFreeOemString)
  36. #pragma alloc_text(PAGE,RtlCreateUnicodeString)
  37. #pragma alloc_text(PAGE,RtlEqualDomainName)
  38. #pragma alloc_text(PAGE,RtlEqualComputerName)
  39. #pragma alloc_text(PAGE,RtlEqualUnicodeString)
  40. #pragma alloc_text(PAGE,RtlxUnicodeStringToOemSize)
  41. #pragma alloc_text(PAGE,RtlxAnsiStringToUnicodeSize)
  42. #pragma alloc_text(PAGE,RtlxUnicodeStringToAnsiSize)
  43. #pragma alloc_text(PAGE,RtlxOemStringToUnicodeSize)
  44. #pragma alloc_text(PAGE,RtlIsTextUnicode)
  45. #endif
  46. //
  47. // Global data used for translations.
  48. //
  49. extern PUSHORT NlsAnsiToUnicodeData; // Ansi CP to Unicode translation table
  50. extern PUSHORT NlsLeadByteInfo; // Lead byte info for ACP
  51. NTSTATUS
  52. RtlAnsiStringToUnicodeString(
  53. OUT PUNICODE_STRING DestinationString,
  54. IN PANSI_STRING SourceString,
  55. IN BOOLEAN AllocateDestinationString
  56. )
  57. /*++
  58. Routine Description:
  59. This functions converts the specified ansi source string into a
  60. Unicode string. The translation is done with respect to the
  61. current system locale information.
  62. Arguments:
  63. DestinationString - Returns a unicode string that is equivalent to
  64. the ansi source string. The maximum length field is only
  65. set if AllocateDestinationString is TRUE.
  66. SourceString - Supplies the ansi source string that is to be
  67. converted to unicode.
  68. AllocateDestinationString - Supplies a flag that controls whether or
  69. not this API allocates the buffer space for the destination
  70. string. If it does, then the buffer must be deallocated using
  71. RtlFreeUnicodeString (note that only storage for
  72. DestinationString->Buffer is allocated by this API).
  73. Return Value:
  74. SUCCESS - The conversion was successful
  75. !SUCCESS - The operation failed. No storage was allocated and no
  76. conversion was done. None.
  77. --*/
  78. {
  79. ULONG UnicodeLength;
  80. ULONG Index;
  81. NTSTATUS st;
  82. RTL_PAGED_CODE();
  83. UnicodeLength = RtlAnsiStringToUnicodeSize(SourceString);
  84. if ( UnicodeLength > MAXUSHORT ) {
  85. return STATUS_INVALID_PARAMETER_2;
  86. }
  87. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  88. if ( AllocateDestinationString ) {
  89. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  90. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  91. if ( !DestinationString->Buffer ) {
  92. return STATUS_NO_MEMORY;
  93. }
  94. }
  95. else {
  96. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  97. return STATUS_BUFFER_OVERFLOW;
  98. }
  99. }
  100. st = RtlMultiByteToUnicodeN(
  101. DestinationString->Buffer,
  102. DestinationString->Length,
  103. &Index,
  104. SourceString->Buffer,
  105. SourceString->Length
  106. );
  107. if (!NT_SUCCESS(st)) {
  108. if ( AllocateDestinationString ) {
  109. (RtlFreeStringRoutine)(DestinationString->Buffer);
  110. }
  111. return st;
  112. }
  113. DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
  114. return STATUS_SUCCESS;
  115. }
  116. WCHAR
  117. RtlAnsiCharToUnicodeChar(
  118. IN OUT PUCHAR *SourceCharacter
  119. )
  120. /*++
  121. Routine Description:
  122. This function translates the specified ansi character to unicode and
  123. returns the unicode value. The purpose for this routine is to allow
  124. for character by character ansi to unicode translation. The
  125. translation is done with respect to the current system locale
  126. information.
  127. Arguments:
  128. SourceCharacter - Supplies a pointer to an ansi character pointer.
  129. Through two levels of indirection, this supplies an ansi
  130. character that is to be translated to unicode. After
  131. translation, the ansi character pointer is modified to point to
  132. the next character to be converted. This is done to allow for
  133. dbcs ansi characters.
  134. Return Value:
  135. Returns the unicode equivalent of the specified ansi character.
  136. --*/
  137. {
  138. WCHAR UnicodeCharacter;
  139. ULONG cbCharSize;
  140. NTSTATUS st;
  141. RTL_PAGED_CODE();
  142. #if 0
  143. UnicodeCharacter = NlsAnsiToUnicodeData[(UCHAR)(**SourceCharacter)];
  144. (*SourceCharacter)++;
  145. return UnicodeCharacter;
  146. #endif
  147. //
  148. // Translate the ansi character to unicode - this handles DBCS.
  149. //
  150. cbCharSize = NlsLeadByteInfo[ **SourceCharacter ] ? 2 : 1;
  151. st = RtlMultiByteToUnicodeN ( &UnicodeCharacter,
  152. sizeof ( WCHAR ),
  153. NULL,
  154. *SourceCharacter,
  155. cbCharSize );
  156. //
  157. // Check for error - The only time this will happen is if there is
  158. // a leadbyte without a trail byte.
  159. //
  160. if ( ! NT_SUCCESS( st ) )
  161. {
  162. // Use space as default.
  163. UnicodeCharacter = 0x0020;
  164. }
  165. //
  166. // Advance the source pointer and return the Unicode character.
  167. //
  168. (*SourceCharacter) += cbCharSize;
  169. return UnicodeCharacter;
  170. }
  171. NTSTATUS
  172. RtlUnicodeStringToAnsiString(
  173. OUT PANSI_STRING DestinationString,
  174. IN PUNICODE_STRING SourceString,
  175. IN BOOLEAN AllocateDestinationString
  176. )
  177. /*++
  178. Routine Description:
  179. This functions converts the specified unicode source string into an
  180. ansi string. The translation is done with respect to the
  181. current system locale information.
  182. Arguments:
  183. DestinationString - Returns an ansi string that is equivalent to the
  184. unicode source string. If the translation can not be done,
  185. an error is returned. The maximum length field is only set if
  186. AllocateDestinationString is TRUE.
  187. SourceString - Supplies the unicode source string that is to be
  188. converted to ansi.
  189. AllocateDestinationString - Supplies a flag that controls whether or
  190. not this API allocates the buffer space for the destination
  191. string. If it does, then the buffer must be deallocated using
  192. RtlFreeAnsiString (note that only storage for
  193. DestinationString->Buffer is allocated by this API).
  194. Return Value:
  195. SUCCESS - The conversion was successful
  196. !SUCCESS - The operation failed. No storage was allocated and no
  197. conversion was done. None.
  198. --*/
  199. {
  200. ULONG AnsiLength;
  201. ULONG Index;
  202. NTSTATUS st;
  203. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  204. RTL_PAGED_CODE();
  205. AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
  206. if ( AnsiLength > MAXUSHORT ) {
  207. return STATUS_INVALID_PARAMETER_2;
  208. }
  209. DestinationString->Length = (USHORT)(AnsiLength - 1);
  210. if ( AllocateDestinationString ) {
  211. DestinationString->MaximumLength = (USHORT)AnsiLength;
  212. DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
  213. if ( !DestinationString->Buffer ) {
  214. return STATUS_NO_MEMORY;
  215. }
  216. }
  217. else {
  218. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  219. /*
  220. * Return STATUS_BUFFER_OVERFLOW, but translate as much as
  221. * will fit into the buffer first. This is the expected
  222. * behavior for routines such as GetProfileStringA.
  223. * Set the length of the buffer to one less than the maximum
  224. * (so that the trail byte of a double byte char is not
  225. * overwritten by doing DestinationString->Buffer[Index] = '\0').
  226. * RtlUnicodeToMultiByteN is careful not to truncate a
  227. * multibyte character.
  228. */
  229. if (!DestinationString->MaximumLength) {
  230. return STATUS_BUFFER_OVERFLOW;
  231. }
  232. ReturnStatus = STATUS_BUFFER_OVERFLOW;
  233. DestinationString->Length = DestinationString->MaximumLength - 1;
  234. }
  235. }
  236. st = RtlUnicodeToMultiByteN(
  237. DestinationString->Buffer,
  238. DestinationString->Length,
  239. &Index,
  240. SourceString->Buffer,
  241. SourceString->Length
  242. );
  243. if (!NT_SUCCESS(st)) {
  244. if ( AllocateDestinationString ) {
  245. (RtlFreeStringRoutine)(DestinationString->Buffer);
  246. }
  247. return st;
  248. }
  249. DestinationString->Buffer[Index] = '\0';
  250. return ReturnStatus;
  251. }
  252. NTSTATUS
  253. RtlUpcaseUnicodeStringToAnsiString(
  254. OUT PANSI_STRING DestinationString,
  255. IN PUNICODE_STRING SourceString,
  256. IN BOOLEAN AllocateDestinationString
  257. )
  258. /*++
  259. Routine Description:
  260. This functions upper cases the specified unicode source string and then
  261. converts it into an ansi string. The translation is done with respect
  262. to the current system locale information.
  263. Arguments:
  264. DestinationString - Returns an ansi string that is equivalent to the
  265. unicode source string. If the translation can not be done,
  266. an error is returned. The maximum length field is only set
  267. if AllocateDestinationString is TRUE.
  268. SourceString - Supplies the unicode source string that is to be
  269. converted to upper case ansi.
  270. AllocateDestinationString - Supplies a flag that controls whether or
  271. not this API allocates the buffer space for the destination
  272. string. If it does, then the buffer must be deallocated using
  273. RtlFreeAnsiString (note that only storage for
  274. DestinationString->Buffer is allocated by this API).
  275. Return Value:
  276. SUCCESS - The conversion was successful
  277. !SUCCESS - The operation failed. No storage was allocated and no
  278. conversion was done. None.
  279. --*/
  280. {
  281. ULONG AnsiLength;
  282. ULONG Index;
  283. NTSTATUS st;
  284. RTL_PAGED_CODE();
  285. AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
  286. if ( AnsiLength > MAXUSHORT ) {
  287. return STATUS_INVALID_PARAMETER_2;
  288. }
  289. DestinationString->Length = (USHORT)(AnsiLength - 1);
  290. if ( AllocateDestinationString ) {
  291. DestinationString->MaximumLength = (USHORT)AnsiLength;
  292. DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
  293. if ( !DestinationString->Buffer ) {
  294. return STATUS_NO_MEMORY;
  295. }
  296. }
  297. else {
  298. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  299. return STATUS_BUFFER_OVERFLOW;
  300. }
  301. }
  302. st = RtlUpcaseUnicodeToMultiByteN(
  303. DestinationString->Buffer,
  304. DestinationString->Length,
  305. &Index,
  306. SourceString->Buffer,
  307. SourceString->Length
  308. );
  309. if (!NT_SUCCESS(st)) {
  310. if ( AllocateDestinationString ) {
  311. (RtlFreeStringRoutine)(DestinationString->Buffer);
  312. }
  313. return st;
  314. }
  315. DestinationString->Buffer[Index] = '\0';
  316. return STATUS_SUCCESS;
  317. }
  318. NTSTATUS
  319. RtlOemStringToUnicodeString(
  320. OUT PUNICODE_STRING DestinationString,
  321. IN POEM_STRING SourceString,
  322. IN BOOLEAN AllocateDestinationString
  323. )
  324. /*++
  325. Routine Description:
  326. This functions converts the specified oem source string into a
  327. Unicode string. The translation is done with respect to the
  328. installed OEM code page (OCP).
  329. Arguments:
  330. DestinationString - Returns a unicode string that is equivalent to
  331. the oem source string. The maximum length field is only
  332. set if AllocateDestinationString is TRUE.
  333. SourceString - Supplies the oem source string that is to be
  334. converted to unicode.
  335. AllocateDestinationString - Supplies a flag that controls whether or
  336. not this API allocates the buffer space for the destination
  337. string. If it does, then the buffer must be deallocated using
  338. RtlFreeUnicodeString (note that only storage for
  339. DestinationString->Buffer is allocated by this API).
  340. Return Value:
  341. SUCCESS - The conversion was successful
  342. !SUCCESS - The operation failed. No storage was allocated and no
  343. conversion was done. None.
  344. --*/
  345. {
  346. ULONG UnicodeLength;
  347. ULONG Index;
  348. NTSTATUS st;
  349. RTL_PAGED_CODE();
  350. UnicodeLength = RtlOemStringToUnicodeSize(SourceString);
  351. if ( UnicodeLength > MAXUSHORT ) {
  352. return STATUS_INVALID_PARAMETER_2;
  353. }
  354. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  355. if ( AllocateDestinationString ) {
  356. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  357. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  358. if ( !DestinationString->Buffer ) {
  359. return STATUS_NO_MEMORY;
  360. }
  361. }
  362. else {
  363. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  364. return STATUS_BUFFER_OVERFLOW;
  365. }
  366. }
  367. st = RtlOemToUnicodeN(
  368. DestinationString->Buffer,
  369. DestinationString->Length,
  370. &Index,
  371. SourceString->Buffer,
  372. SourceString->Length
  373. );
  374. if (!NT_SUCCESS(st)) {
  375. if ( AllocateDestinationString ) {
  376. (RtlFreeStringRoutine)(DestinationString->Buffer);
  377. }
  378. return st;
  379. }
  380. DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
  381. return STATUS_SUCCESS;
  382. }
  383. NTSTATUS
  384. RtlUnicodeStringToOemString(
  385. OUT POEM_STRING DestinationString,
  386. IN PUNICODE_STRING SourceString,
  387. IN BOOLEAN AllocateDestinationString
  388. )
  389. /*++
  390. Routine Description:
  391. This functions converts the specified unicode source string into an
  392. oem string. The translation is done with respect to the OEM code
  393. page (OCP).
  394. Arguments:
  395. DestinationString - Returns an oem string that is equivalent to the
  396. unicode source string. If the translation can not be done,
  397. an error is returned. The maximum length field is only set if
  398. AllocateDestinationString is TRUE.
  399. SourceString - Supplies the unicode source string that is to be
  400. converted to oem.
  401. AllocateDestinationString - Supplies a flag that controls whether or
  402. not this API allocates the buffer space for the destination
  403. string. If it does, then the buffer must be deallocated using
  404. RtlFreeAnsiString (note that only storage for
  405. DestinationString->Buffer is allocated by this API).
  406. Return Value:
  407. SUCCESS - The conversion was successful
  408. !SUCCESS - The operation failed. No storage was allocated and no
  409. conversion was done. None.
  410. --*/
  411. {
  412. ULONG OemLength;
  413. ULONG Index;
  414. NTSTATUS st;
  415. RTL_PAGED_CODE();
  416. OemLength = RtlUnicodeStringToOemSize(SourceString);
  417. if ( OemLength > MAXUSHORT ) {
  418. return STATUS_INVALID_PARAMETER_2;
  419. }
  420. DestinationString->Length = (USHORT)(OemLength - 1);
  421. if ( AllocateDestinationString ) {
  422. DestinationString->MaximumLength = (USHORT)OemLength;
  423. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  424. if ( !DestinationString->Buffer ) {
  425. return STATUS_NO_MEMORY;
  426. }
  427. }
  428. else {
  429. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  430. return STATUS_BUFFER_OVERFLOW;
  431. }
  432. }
  433. st = RtlUnicodeToOemN(
  434. DestinationString->Buffer,
  435. DestinationString->Length,
  436. &Index,
  437. SourceString->Buffer,
  438. SourceString->Length
  439. );
  440. if (!NT_SUCCESS(st)) {
  441. if ( AllocateDestinationString ) {
  442. (RtlFreeStringRoutine)(DestinationString->Buffer);
  443. }
  444. return st;
  445. }
  446. DestinationString->Buffer[Index] = '\0';
  447. return STATUS_SUCCESS;
  448. }
  449. NTSTATUS
  450. RtlUpcaseUnicodeStringToOemString(
  451. OUT POEM_STRING DestinationString,
  452. IN PUNICODE_STRING SourceString,
  453. IN BOOLEAN AllocateDestinationString
  454. )
  455. /*++
  456. Routine Description:
  457. This function upper cases the specified unicode source string and then
  458. converts it into an oem string. The translation is done with respect
  459. to the OEM code page (OCP).
  460. Arguments:
  461. DestinationString - Returns an oem string that is equivalent to the
  462. unicode source string. The maximum length field is only set if
  463. AllocateDestinationString is TRUE.
  464. SourceString - Supplies the unicode source string that is to be
  465. converted to oem.
  466. AllocateDestinationString - Supplies a flag that controls whether or
  467. not this API allocates the buffer space for the destination
  468. string. If it does, then the buffer must be deallocated using
  469. RtlFreeAnsiString (note that only storage for
  470. DestinationString->Buffer is allocated by this API).
  471. Return Value:
  472. SUCCESS - The conversion was successful
  473. !SUCCESS - The operation failed. No storage was allocated and no
  474. conversion was done. None.
  475. --*/
  476. {
  477. ULONG OemLength;
  478. ULONG Index;
  479. NTSTATUS st;
  480. RTL_PAGED_CODE();
  481. OemLength = RtlUnicodeStringToOemSize(SourceString);
  482. if ( OemLength > MAXUSHORT ) {
  483. return STATUS_INVALID_PARAMETER_2;
  484. }
  485. DestinationString->Length = (USHORT)(OemLength - 1);
  486. if ( AllocateDestinationString ) {
  487. DestinationString->MaximumLength = (USHORT)OemLength;
  488. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  489. if ( !DestinationString->Buffer ) {
  490. return STATUS_NO_MEMORY;
  491. }
  492. }
  493. else {
  494. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  495. return STATUS_BUFFER_OVERFLOW;
  496. }
  497. }
  498. st = RtlUpcaseUnicodeToOemN(
  499. DestinationString->Buffer,
  500. DestinationString->Length,
  501. &Index,
  502. SourceString->Buffer,
  503. SourceString->Length
  504. );
  505. if (!NT_SUCCESS(st)) {
  506. if ( AllocateDestinationString ) {
  507. (RtlFreeStringRoutine)(DestinationString->Buffer);
  508. }
  509. return st;
  510. }
  511. DestinationString->Buffer[Index] = '\0';
  512. return STATUS_SUCCESS;
  513. }
  514. NTSTATUS
  515. RtlOemStringToCountedUnicodeString(
  516. OUT PUNICODE_STRING DestinationString,
  517. IN POEM_STRING SourceString,
  518. IN BOOLEAN AllocateDestinationString
  519. )
  520. /*++
  521. Routine Description:
  522. This functions converts the specified oem source string into a
  523. Unicode string. The translation is done with respect to the
  524. installed OEM code page (OCP).
  525. The destination string is NOT unnaturally null terminated. It is a
  526. counted string as counted strings are meant to be.
  527. Arguments:
  528. DestinationString - Returns a unicode string that is equivalent to
  529. the oem source string. The maximum length field is only
  530. set if AllocateDestinationString is TRUE.
  531. SourceString - Supplies the oem source string that is to be
  532. converted to unicode.
  533. AllocateDestinationString - Supplies a flag that controls whether or
  534. not this API allocates the buffer space for the destination
  535. string. If it does, then the buffer must be deallocated using
  536. RtlFreeUnicodeString (note that only storage for
  537. DestinationString->Buffer is allocated by this API).
  538. Return Value:
  539. SUCCESS - The conversion was successful
  540. !SUCCESS - The operation failed. No storage was allocated and no
  541. conversion was done. None.
  542. --*/
  543. {
  544. ULONG UnicodeLength;
  545. ULONG Index;
  546. NTSTATUS st;
  547. RTL_PAGED_CODE();
  548. UnicodeLength = RtlOemStringToCountedUnicodeSize(SourceString);
  549. if ( UnicodeLength == 0 ) {
  550. DestinationString->Length = 0;
  551. DestinationString->MaximumLength = 0;
  552. DestinationString->Buffer = NULL;
  553. return STATUS_SUCCESS;
  554. }
  555. if ( UnicodeLength > MAXUSHORT ) {
  556. return STATUS_INVALID_PARAMETER_2;
  557. }
  558. DestinationString->Length = (USHORT)(UnicodeLength);
  559. if ( AllocateDestinationString ) {
  560. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  561. DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
  562. if ( !DestinationString->Buffer ) {
  563. return STATUS_NO_MEMORY;
  564. }
  565. }
  566. else {
  567. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  568. return STATUS_BUFFER_OVERFLOW;
  569. }
  570. }
  571. st = RtlOemToUnicodeN(
  572. DestinationString->Buffer,
  573. DestinationString->Length,
  574. &Index,
  575. SourceString->Buffer,
  576. SourceString->Length
  577. );
  578. if (!NT_SUCCESS(st)) {
  579. if ( AllocateDestinationString ) {
  580. (RtlFreeStringRoutine)(DestinationString->Buffer);
  581. }
  582. return st;
  583. }
  584. return STATUS_SUCCESS;
  585. }
  586. NTSTATUS
  587. RtlUnicodeStringToCountedOemString(
  588. OUT POEM_STRING DestinationString,
  589. IN PUNICODE_STRING SourceString,
  590. IN BOOLEAN AllocateDestinationString
  591. )
  592. /*++
  593. Routine Description:
  594. This functions converts the specified unicode source string into an
  595. oem string. The translation is done with respect to the OEM code
  596. page (OCP).
  597. The destination string is NOT unnaturally null terminated. It is a
  598. counted string as counted strings are meant to be.
  599. Arguments:
  600. DestinationString - Returns an oem string that is equivalent to the
  601. unicode source string. If the translation can not be done,
  602. an error is returned. The maximum length field is only set if
  603. AllocateDestinationString is TRUE.
  604. SourceString - Supplies the unicode source string that is to be
  605. converted to oem.
  606. AllocateDestinationString - Supplies a flag that controls whether or
  607. not this API allocates the buffer space for the destination
  608. string. If it does, then the buffer must be deallocated using
  609. RtlFreeAnsiString (note that only storage for
  610. DestinationString->Buffer is allocated by this API).
  611. Return Value:
  612. SUCCESS - The conversion was successful
  613. !SUCCESS - The operation failed. No storage was allocated and no
  614. conversion was done. None.
  615. --*/
  616. {
  617. ULONG OemLength;
  618. ULONG Index;
  619. NTSTATUS st;
  620. RTL_PAGED_CODE();
  621. OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
  622. if ( OemLength == 0 ) {
  623. DestinationString->Length = 0;
  624. DestinationString->MaximumLength = 0;
  625. DestinationString->Buffer = NULL;
  626. return STATUS_SUCCESS;
  627. }
  628. if ( OemLength > MAXUSHORT ) {
  629. return STATUS_INVALID_PARAMETER_2;
  630. }
  631. DestinationString->Length = (USHORT)(OemLength);
  632. if ( AllocateDestinationString ) {
  633. DestinationString->MaximumLength = (USHORT)OemLength;
  634. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  635. if ( !DestinationString->Buffer ) {
  636. return STATUS_NO_MEMORY;
  637. }
  638. }
  639. else {
  640. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  641. return STATUS_BUFFER_OVERFLOW;
  642. }
  643. }
  644. st = RtlUnicodeToOemN(
  645. DestinationString->Buffer,
  646. DestinationString->Length,
  647. &Index,
  648. SourceString->Buffer,
  649. SourceString->Length
  650. );
  651. //
  652. // Now do a check here to see if there was really a mapping for all
  653. // characters converted.
  654. //
  655. if (NT_SUCCESS(st) &&
  656. !RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
  657. st = STATUS_UNMAPPABLE_CHARACTER;
  658. }
  659. if (!NT_SUCCESS(st)) {
  660. if ( AllocateDestinationString ) {
  661. (RtlFreeStringRoutine)(DestinationString->Buffer);
  662. }
  663. return st;
  664. }
  665. return STATUS_SUCCESS;
  666. }
  667. NTSTATUS
  668. RtlUpcaseUnicodeStringToCountedOemString(
  669. OUT POEM_STRING DestinationString,
  670. IN PUNICODE_STRING SourceString,
  671. IN BOOLEAN AllocateDestinationString
  672. )
  673. /*++
  674. Routine Description:
  675. This functions upper cases the specified unicode source string and
  676. then converts it into an oem string. The translation is done with
  677. respect to the OEM code page (OCP).
  678. The destination string is NOT unnaturally null terminated. It is a
  679. counted string as counted strings are meant to be.
  680. Arguments:
  681. DestinationString - Returns an oem string that is equivalent to the
  682. unicode source string. If the translation can not be done,
  683. an error is returned. The maximum length field is only set
  684. if AllocateDestinationString is TRUE.
  685. SourceString - Supplies the unicode source string that is to be
  686. converted to oem.
  687. AllocateDestinationString - Supplies a flag that controls whether or
  688. not this API allocates the buffer space for the destination
  689. string. If it does, then the buffer must be deallocated using
  690. RtlFreeAnsiString (note that only storage for
  691. DestinationString->Buffer is allocated by this API).
  692. Return Value:
  693. SUCCESS - The conversion was successful
  694. !SUCCESS - The operation failed. No storage was allocated and no
  695. conversion was done. None.
  696. --*/
  697. {
  698. ULONG OemLength;
  699. ULONG Index;
  700. NTSTATUS st;
  701. RTL_PAGED_CODE();
  702. OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
  703. if ( OemLength == 0 ) {
  704. DestinationString->Length = 0;
  705. DestinationString->MaximumLength = 0;
  706. DestinationString->Buffer = NULL;
  707. return STATUS_SUCCESS;
  708. }
  709. if ( OemLength > MAXUSHORT ) {
  710. return STATUS_INVALID_PARAMETER_2;
  711. }
  712. DestinationString->Length = (USHORT)(OemLength);
  713. if ( AllocateDestinationString ) {
  714. DestinationString->MaximumLength = (USHORT)OemLength;
  715. DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
  716. if ( !DestinationString->Buffer ) {
  717. return STATUS_NO_MEMORY;
  718. }
  719. }
  720. else {
  721. if ( DestinationString->Length > DestinationString->MaximumLength ) {
  722. return STATUS_BUFFER_OVERFLOW;
  723. }
  724. }
  725. st = RtlUpcaseUnicodeToOemN(
  726. DestinationString->Buffer,
  727. DestinationString->Length,
  728. &Index,
  729. SourceString->Buffer,
  730. SourceString->Length
  731. );
  732. //
  733. // Now do a check here to see if there was really a mapping for all
  734. // characters converted.
  735. //
  736. if (NT_SUCCESS(st) &&
  737. !RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
  738. st = STATUS_UNMAPPABLE_CHARACTER;
  739. }
  740. if (!NT_SUCCESS(st)) {
  741. if ( AllocateDestinationString ) {
  742. (RtlFreeStringRoutine)(DestinationString->Buffer);
  743. }
  744. return st;
  745. }
  746. return STATUS_SUCCESS;
  747. }
  748. NTSTATUS
  749. RtlUpcaseUnicodeString(
  750. OUT PUNICODE_STRING DestinationString,
  751. IN PUNICODE_STRING SourceString,
  752. IN BOOLEAN AllocateDestinationString
  753. )
  754. /*++
  755. Routine Description:
  756. This functions converts the specified unicode source string into an
  757. upcased unicode string. The translation is done with respect to the
  758. current system locale information.
  759. Arguments:
  760. DestinationString - Returns a unicode string that is the upcased equivalent
  761. to the unicode source string. The maximum length field is only set if
  762. AllocateDestinationString is TRUE.
  763. SourceString - Supplies the unicode source string that is to being
  764. upcased.
  765. AllocateDestinationString - Supplies a flag that controls whether or
  766. not this API allocates the buffer space for the destination
  767. string. If it does, then the buffer must be deallocated using
  768. RtlFreeUnicodeString (note that only storage for
  769. DestinationString->Buffer is allocated by this API).
  770. Return Value:
  771. SUCCESS - The conversion was successful
  772. !SUCCESS - The operation failed. No storage was allocated and no
  773. conversion was done. None.
  774. --*/
  775. {
  776. ULONG Index;
  777. ULONG StopIndex;
  778. RTL_PAGED_CODE();
  779. if ( AllocateDestinationString ) {
  780. DestinationString->MaximumLength = SourceString->Length;
  781. DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
  782. if ( !DestinationString->Buffer ) {
  783. return STATUS_NO_MEMORY;
  784. }
  785. }
  786. else {
  787. if ( SourceString->Length > DestinationString->MaximumLength ) {
  788. return STATUS_BUFFER_OVERFLOW;
  789. }
  790. }
  791. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  792. for (Index = 0; Index < StopIndex; Index++) {
  793. DestinationString->Buffer[Index] = (WCHAR)NLS_UPCASE(SourceString->Buffer[Index]);
  794. }
  795. DestinationString->Length = SourceString->Length;
  796. return STATUS_SUCCESS;
  797. }
  798. NTSTATUS
  799. RtlDowncaseUnicodeString(
  800. OUT PUNICODE_STRING DestinationString,
  801. IN PUNICODE_STRING SourceString,
  802. IN BOOLEAN AllocateDestinationString
  803. )
  804. /*++
  805. Routine Description:
  806. This functions converts the specified unicode source string into a
  807. downcased unicode string. The translation is done with respect to the
  808. current system locale information.
  809. Arguments:
  810. DestinationString - Returns a unicode string that is the downcased
  811. equivalent to the unicode source string. The maximum length field
  812. is only set if AllocateDestinationString is TRUE.
  813. SourceString - Supplies the unicode source string that is to being
  814. downcased.
  815. AllocateDestinationString - Supplies a flag that controls whether or
  816. not this API allocates the buffer space for the destination
  817. string. If it does, then the buffer must be deallocated using
  818. RtlFreeUnicodeString (note that only storage for
  819. DestinationString->Buffer is allocated by this API).
  820. Return Value:
  821. SUCCESS - The conversion was successful
  822. !SUCCESS - The operation failed. No storage was allocated and no
  823. conversion was done. None.
  824. --*/
  825. {
  826. ULONG Index;
  827. ULONG StopIndex;
  828. RTL_PAGED_CODE();
  829. if ( AllocateDestinationString ) {
  830. DestinationString->MaximumLength = SourceString->Length;
  831. DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
  832. if ( !DestinationString->Buffer ) {
  833. return STATUS_NO_MEMORY;
  834. }
  835. }
  836. else {
  837. if ( SourceString->Length > DestinationString->MaximumLength ) {
  838. return STATUS_BUFFER_OVERFLOW;
  839. }
  840. }
  841. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  842. for (Index = 0; Index < StopIndex; Index++) {
  843. DestinationString->Buffer[Index] = (WCHAR)NLS_DOWNCASE(SourceString->Buffer[Index]);
  844. }
  845. DestinationString->Length = SourceString->Length;
  846. return STATUS_SUCCESS;
  847. }
  848. WCHAR
  849. RtlUpcaseUnicodeChar(
  850. IN WCHAR SourceCharacter
  851. )
  852. /*++
  853. Routine Description:
  854. This function translates the specified unicode character to its
  855. equivalent upcased unicode chararacter. The purpose for this routine
  856. is to allow for character by character upcase translation. The
  857. translation is done with respect to the current system locale
  858. information.
  859. Arguments:
  860. SourceCharacter - Supplies the unicode character to be upcased.
  861. Return Value:
  862. Returns the upcased unicode equivalent of the specified input character.
  863. --*/
  864. {
  865. RTL_PAGED_CODE();
  866. //
  867. // Note that this needs to reference the translation table !
  868. //
  869. return (WCHAR)NLS_UPCASE(SourceCharacter);
  870. }
  871. VOID
  872. RtlFreeUnicodeString(
  873. IN OUT PUNICODE_STRING UnicodeString
  874. )
  875. /*++
  876. Routine Description:
  877. This API is used to free storage allocated by
  878. RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
  879. is free'd by this routine.
  880. Arguments:
  881. UnicodeString - Supplies the address of the unicode string whose
  882. buffer was previously allocated by RtlAnsiStringToUnicodeString.
  883. Return Value:
  884. None.
  885. --*/
  886. {
  887. RTL_PAGED_CODE();
  888. if (UnicodeString->Buffer) { (RtlFreeStringRoutine)(UnicodeString->Buffer); }
  889. }
  890. VOID
  891. RtlFreeAnsiString(
  892. IN OUT PANSI_STRING AnsiString
  893. )
  894. /*++
  895. Routine Description:
  896. This API is used to free storage allocated by
  897. RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
  898. is free'd by this routine.
  899. Arguments:
  900. AnsiString - Supplies the address of the ansi string whose buffer
  901. was previously allocated by RtlUnicodeStringToAnsiString.
  902. Return Value:
  903. None.
  904. --*/
  905. {
  906. RTL_PAGED_CODE();
  907. if (AnsiString->Buffer) { (RtlFreeStringRoutine)(AnsiString->Buffer); }
  908. }
  909. VOID
  910. RtlFreeOemString(
  911. IN OUT POEM_STRING OemString
  912. )
  913. /*++
  914. Routine Description:
  915. This API is used to free storage allocated by
  916. RtlUnicodeStringToOemString. Note that only OemString->Buffer
  917. is free'd by this routine.
  918. Arguments:
  919. OemString - Supplies the address of the oem string whose buffer
  920. was previously allocated by RtlUnicodeStringToOemString.
  921. Return Value:
  922. None.
  923. --*/
  924. {
  925. RTL_PAGED_CODE();
  926. if (OemString->Buffer) {(RtlFreeStringRoutine)(OemString->Buffer);}
  927. }
  928. ULONG
  929. RtlxUnicodeStringToAnsiSize(
  930. IN PUNICODE_STRING UnicodeString
  931. )
  932. /*++
  933. Routine Description:
  934. This function computes the number of bytes required to store
  935. a NULL terminated ansi string that is equivalent to the specified
  936. unicode string. If an ansi string can not be formed, the return value
  937. is 0.
  938. Arguments:
  939. UnicodeString - Supplies a unicode string whose equivalent size as
  940. an ansi string is to be calculated.
  941. Return Value:
  942. 0 - The operation failed, the unicode string can not be translated
  943. into ansi using the current system locale therefore no storage
  944. is needed for the ansi string.
  945. !0 - The operation was successful. The return value specifies the
  946. number of bytes required to hold an NULL terminated ansi string
  947. equivalent to the specified unicode string.
  948. --*/
  949. {
  950. ULONG cbMultiByteString;
  951. RTL_PAGED_CODE();
  952. //
  953. // Get the size of the string - this call handles DBCS.
  954. //
  955. RtlUnicodeToMultiByteSize( &cbMultiByteString,
  956. UnicodeString->Buffer,
  957. UnicodeString->Length );
  958. //
  959. // Return the size in bytes.
  960. //
  961. return (cbMultiByteString + 1);
  962. }
  963. ULONG
  964. RtlxUnicodeStringToOemSize(
  965. IN PUNICODE_STRING UnicodeString
  966. )
  967. /*++
  968. Routine Description:
  969. This function computes the number of bytes required to store
  970. a NULL terminated oem string that is equivalent to the specified
  971. unicode string. If an oem string can not be formed, the return value
  972. is 0.
  973. Arguments:
  974. UnicodeString - Supplies a unicode string whose equivalent size as
  975. an oem string is to be calculated.
  976. Return Value:
  977. 0 - The operation failed, the unicode string can not be translated
  978. into oem using the OEM code page therefore no storage is
  979. needed for the oem string.
  980. !0 - The operation was successful. The return value specifies the
  981. number of bytes required to hold an NULL terminated oem string
  982. equivalent to the specified unicode string.
  983. --*/
  984. {
  985. ULONG cbMultiByteString;
  986. RTL_PAGED_CODE();
  987. //
  988. // LATER: Define an RtlUnicodeToOemSize.
  989. // In the Japanese version, it's safe to call
  990. // RtlUnicodeToMultiByteSize because the Ansi code page
  991. // and the OEM code page are the same.
  992. //
  993. //
  994. // Get the size of the string - this call handles DBCS.
  995. //
  996. RtlUnicodeToMultiByteSize( &cbMultiByteString,
  997. UnicodeString->Buffer,
  998. UnicodeString->Length );
  999. //
  1000. // Return the size in bytes.
  1001. //
  1002. return (cbMultiByteString + 1);
  1003. }
  1004. ULONG
  1005. RtlxAnsiStringToUnicodeSize(
  1006. IN PANSI_STRING AnsiString
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. This function computes the number of bytes required to store a NULL
  1011. terminated unicode string that is equivalent to the specified ansi
  1012. string.
  1013. Arguments:
  1014. AnsiString - Supplies an ansi string whose equivalent size as a
  1015. unicode string is to be calculated. The ansi string is
  1016. interpreted relative to the current system locale.
  1017. Return Value:
  1018. The return value specifies the number of bytes required to hold a
  1019. NULL terminated unicode string equivalent to the specified ansi
  1020. string.
  1021. --*/
  1022. {
  1023. ULONG cbConverted;
  1024. RTL_PAGED_CODE();
  1025. //
  1026. // Get the size of the string - this call handles DBCS.
  1027. //
  1028. RtlMultiByteToUnicodeSize( &cbConverted ,
  1029. AnsiString->Buffer,
  1030. AnsiString->Length );
  1031. //
  1032. // Return the size in bytes.
  1033. //
  1034. return ( cbConverted + sizeof(UNICODE_NULL) );
  1035. }
  1036. ULONG
  1037. RtlxOemStringToUnicodeSize(
  1038. IN POEM_STRING OemString
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. This function computes the number of bytes required to store a NULL
  1043. terminated unicode string that is equivalent to the specified oem
  1044. string.
  1045. Arguments:
  1046. OemString - Supplies an oem string whose equivalent size as a
  1047. unicode string is to be calculated. The oem string is
  1048. interpreted relative to the current oem code page (OCP).
  1049. Return Value:
  1050. The return value specifies the number of bytes required to hold a
  1051. NULL terminated unicode string equivalent to the specified oem
  1052. string.
  1053. --*/
  1054. {
  1055. ULONG cbConverted;
  1056. RTL_PAGED_CODE();
  1057. //
  1058. // LATER: Define an RtlOemToUnicodeSize.
  1059. // In the Japanese version, it's safe to call
  1060. // RtlMultiByteToUnicodeSize because the Ansi code page
  1061. // and the OEM code page are the same.
  1062. //
  1063. //
  1064. // Get the size of the string - this call handles DBCS.
  1065. //
  1066. RtlMultiByteToUnicodeSize( &cbConverted,
  1067. OemString->Buffer,
  1068. OemString->Length );
  1069. //
  1070. // Return the size in bytes.
  1071. //
  1072. return ( cbConverted + sizeof(UNICODE_NULL) );
  1073. }
  1074. LONG
  1075. RtlCompareUnicodeString(
  1076. IN PUNICODE_STRING String1,
  1077. IN PUNICODE_STRING String2,
  1078. IN BOOLEAN CaseInSensitive
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. The RtlCompareUnicodeString function compares two counted strings. The
  1083. return value indicates if the strings are equal or String1 is less than
  1084. String2 or String1 is greater than String2.
  1085. The CaseInSensitive parameter specifies if case is to be ignored when
  1086. doing the comparison.
  1087. Arguments:
  1088. String1 - Pointer to the first string.
  1089. String2 - Pointer to the second string.
  1090. CaseInsensitive - TRUE if case should be ignored when doing the
  1091. comparison.
  1092. Return Value:
  1093. Signed value that gives the results of the comparison:
  1094. Zero - String1 equals String2
  1095. < Zero - String1 less than String2
  1096. > Zero - String1 greater than String2
  1097. --*/
  1098. {
  1099. PWCHAR s1, s2, Limit;
  1100. LONG n1, n2;
  1101. WCHAR c1, c2;
  1102. s1 = String1->Buffer;
  1103. s2 = String2->Buffer;
  1104. n1 = String1->Length;
  1105. n2 = String2->Length;
  1106. ASSERT((n1 & 1) == 0);
  1107. ASSERT((n2 & 1) == 0);
  1108. ASSERT(!(((((ULONG)s1 & 1) != 0) || (((ULONG)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
  1109. Limit = (PWCHAR)((PCHAR)s1 + (n1 <= n2 ? n1 : n2));
  1110. if (CaseInSensitive) {
  1111. while (s1 < Limit) {
  1112. c1 = *s1++;
  1113. c2 = *s2++;
  1114. if (c1 != c2) {
  1115. //
  1116. // Note that this needs to reference the translation table!
  1117. //
  1118. c1 = NLS_UPCASE(c1);
  1119. c2 = NLS_UPCASE(c2);
  1120. if (c1 != c2) {
  1121. return (LONG)(c1) - (LONG)(c2);
  1122. }
  1123. }
  1124. }
  1125. } else {
  1126. while (s1 < Limit) {
  1127. c1 = *s1++;
  1128. c2 = *s2++;
  1129. if (c1 != c2) {
  1130. return (LONG)(c1) - (LONG)(c2);
  1131. }
  1132. }
  1133. }
  1134. return n1 - n2;
  1135. }
  1136. BOOLEAN
  1137. RtlEqualUnicodeString(
  1138. IN PUNICODE_STRING String1,
  1139. IN PUNICODE_STRING String2,
  1140. IN BOOLEAN CaseInSensitive
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. The RtlEqualUnicodeString function compares two counted unicode strings for
  1145. equality.
  1146. The CaseInSensitive parameter specifies if case is to be ignored when
  1147. doing the comparison.
  1148. Arguments:
  1149. String1 - Pointer to the first string.
  1150. String2 - Pointer to the second string.
  1151. CaseInsensitive - TRUE if case should be ignored when doing the
  1152. comparison.
  1153. Return Value:
  1154. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1155. --*/
  1156. {
  1157. PWCHAR s1, s2, Limit;
  1158. LONG n1, n2;
  1159. WCHAR c1, c2;
  1160. RTL_PAGED_CODE();
  1161. n1 = String1->Length;
  1162. n2 = String2->Length;
  1163. ASSERT((n1 & 1) == 0);
  1164. ASSERT((n2 & 1) == 0);
  1165. if (n1 == n2) {
  1166. s1 = String1->Buffer;
  1167. s2 = String2->Buffer;
  1168. ASSERT(!(((((ULONG)s1 & 1) != 0) || (((ULONG)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
  1169. Limit = (PWCHAR)((PCHAR)s1 + n1);
  1170. if (CaseInSensitive) {
  1171. while (s1 < Limit) {
  1172. c1 = *s1++;
  1173. c2 = *s2++;
  1174. if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
  1175. return FALSE;
  1176. }
  1177. }
  1178. return TRUE;
  1179. } else {
  1180. while (s1 < Limit) {
  1181. c1 = *s1++;
  1182. c2 = *s2++;
  1183. if (c1 != c2) {
  1184. return FALSE;
  1185. }
  1186. }
  1187. return TRUE;
  1188. }
  1189. } else {
  1190. return FALSE;
  1191. }
  1192. }
  1193. BOOLEAN
  1194. RtlPrefixUnicodeString(
  1195. IN PUNICODE_STRING String1,
  1196. IN PUNICODE_STRING String2,
  1197. IN BOOLEAN CaseInSensitive
  1198. )
  1199. /*++
  1200. Routine Description:
  1201. The RtlPrefixUnicodeString function determines if the String1
  1202. counted string parameter is a prefix of the String2 counted string
  1203. parameter.
  1204. The CaseInSensitive parameter specifies if case is to be ignored when
  1205. doing the comparison.
  1206. Arguments:
  1207. String1 - Pointer to the first unicode string.
  1208. String2 - Pointer to the second unicode string.
  1209. CaseInsensitive - TRUE if case should be ignored when doing the
  1210. comparison.
  1211. Return Value:
  1212. Boolean value that is TRUE if String1 equals a prefix of String2 and
  1213. FALSE otherwise.
  1214. --*/
  1215. {
  1216. PWSTR s1, s2;
  1217. ULONG n;
  1218. WCHAR c1, c2;
  1219. s1 = String1->Buffer;
  1220. s2 = String2->Buffer;
  1221. n = String1->Length;
  1222. if (String2->Length < n) {
  1223. return( FALSE );
  1224. }
  1225. n = n / sizeof(c1);
  1226. if (CaseInSensitive) {
  1227. while (n) {
  1228. c1 = *s1++;
  1229. c2 = *s2++;
  1230. if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
  1231. return( FALSE );
  1232. }
  1233. n--;
  1234. }
  1235. }
  1236. else {
  1237. while (n) {
  1238. if (*s1++ != *s2++) {
  1239. return( FALSE );
  1240. }
  1241. n--;
  1242. }
  1243. }
  1244. return TRUE;
  1245. }
  1246. VOID
  1247. RtlCopyUnicodeString(
  1248. OUT PUNICODE_STRING DestinationString,
  1249. IN PUNICODE_STRING SourceString OPTIONAL
  1250. )
  1251. /*++
  1252. Routine Description:
  1253. The RtlCopyString function copies the SourceString to the
  1254. DestinationString. If SourceString is not specified, then
  1255. the Length field of DestinationString is set to zero. The
  1256. MaximumLength and Buffer fields of DestinationString are not
  1257. modified by this function.
  1258. The number of bytes copied from the SourceString is either the
  1259. Length of SourceString or the MaximumLength of DestinationString,
  1260. whichever is smaller.
  1261. Arguments:
  1262. DestinationString - Pointer to the destination string.
  1263. SourceString - Optional pointer to the source string.
  1264. Return Value:
  1265. None.
  1266. --*/
  1267. {
  1268. UNALIGNED WCHAR *src, *dst;
  1269. ULONG n;
  1270. if (ARGUMENT_PRESENT(SourceString)) {
  1271. dst = DestinationString->Buffer;
  1272. src = SourceString->Buffer;
  1273. n = SourceString->Length;
  1274. if ((USHORT)n > DestinationString->MaximumLength) {
  1275. n = DestinationString->MaximumLength;
  1276. }
  1277. DestinationString->Length = (USHORT)n;
  1278. RtlCopyMemory(dst, src, n);
  1279. if (DestinationString->Length < DestinationString->MaximumLength) {
  1280. dst[n / sizeof(WCHAR)] = UNICODE_NULL;
  1281. }
  1282. } else {
  1283. DestinationString->Length = 0;
  1284. }
  1285. return;
  1286. }
  1287. NTSTATUS
  1288. RtlAppendUnicodeToString (
  1289. IN PUNICODE_STRING Destination,
  1290. IN PWSTR Source OPTIONAL
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. This routine appends the supplied UNICODE string to an existing
  1295. PUNICODE_STRING.
  1296. It will copy bytes from the Source PSZ to the destination PSTRING up to
  1297. the destinations PUNICODE_STRING->MaximumLength field.
  1298. Arguments:
  1299. IN PUNICODE_STRING Destination, - Supplies a pointer to the destination
  1300. string
  1301. IN PWSTR Source - Supplies the string to append to the destination
  1302. Return Value:
  1303. STATUS_SUCCESS - The source string was successfully appended to the
  1304. destination counted string.
  1305. STATUS_BUFFER_TOO_SMALL - The destination string length was not big
  1306. enough to allow the source string to be appended. The Destination
  1307. string length is not updated.
  1308. --*/
  1309. {
  1310. USHORT n;
  1311. UNALIGNED WCHAR *dst;
  1312. if (ARGUMENT_PRESENT( Source )) {
  1313. UNICODE_STRING UniSource;
  1314. RtlInitUnicodeString(&UniSource, Source);
  1315. n = UniSource.Length;
  1316. if ((n + Destination->Length) > Destination->MaximumLength) {
  1317. return( STATUS_BUFFER_TOO_SMALL );
  1318. }
  1319. dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
  1320. RtlMoveMemory( dst, Source, n );
  1321. Destination->Length += n;
  1322. if (Destination->Length < Destination->MaximumLength) {
  1323. dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
  1324. }
  1325. }
  1326. return( STATUS_SUCCESS );
  1327. }
  1328. NTSTATUS
  1329. RtlAppendUnicodeStringToString (
  1330. IN PUNICODE_STRING Destination,
  1331. IN PUNICODE_STRING Source
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This routine will concatinate two PSTRINGs together. It will copy
  1336. bytes from the source up to the MaximumLength of the destination.
  1337. Arguments:
  1338. IN PSTRING Destination, - Supplies the destination string
  1339. IN PSTRING Source - Supplies the source for the string copy
  1340. Return Value:
  1341. STATUS_SUCCESS - The source string was successfully appended to the
  1342. destination counted string.
  1343. STATUS_BUFFER_TOO_SMALL - The destination string length was not big
  1344. enough to allow the source string to be appended. The Destination
  1345. string length is not updated.
  1346. --*/
  1347. {
  1348. USHORT n = Source->Length;
  1349. UNALIGNED WCHAR *dst;
  1350. if (n) {
  1351. if ((n + Destination->Length) > Destination->MaximumLength) {
  1352. return( STATUS_BUFFER_TOO_SMALL );
  1353. }
  1354. dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
  1355. RtlMoveMemory( dst, Source->Buffer, n );
  1356. Destination->Length += n;
  1357. if (Destination->Length < Destination->MaximumLength) {
  1358. dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
  1359. }
  1360. }
  1361. return( STATUS_SUCCESS );
  1362. }
  1363. BOOLEAN
  1364. RtlCreateUnicodeString(
  1365. OUT PUNICODE_STRING DestinationString,
  1366. IN PCWSTR SourceString
  1367. )
  1368. {
  1369. ULONG cb;
  1370. RTL_PAGED_CODE();
  1371. cb = (wcslen( SourceString ) + 1) * sizeof( WCHAR );
  1372. DestinationString->Buffer = (RtlAllocateStringRoutine)( cb );
  1373. if (DestinationString->Buffer) {
  1374. RtlMoveMemory( DestinationString->Buffer, SourceString, cb );
  1375. DestinationString->MaximumLength = (USHORT)cb;
  1376. DestinationString->Length = (USHORT)(cb - sizeof( UNICODE_NULL ));
  1377. return( TRUE );
  1378. }
  1379. else {
  1380. return( FALSE );
  1381. }
  1382. }
  1383. BOOLEAN
  1384. RtlEqualDomainName(
  1385. IN PUNICODE_STRING String1,
  1386. IN PUNICODE_STRING String2
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. The RtlEqualDomainName function compares two domain names for equality.
  1391. The comparison is a case insensitive comparison of the OEM equivalent
  1392. strings.
  1393. The domain name is not validated for length nor invalid characters.
  1394. Arguments:
  1395. String1 - Pointer to the first string.
  1396. String2 - Pointer to the second string.
  1397. Return Value:
  1398. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1399. --*/
  1400. {
  1401. NTSTATUS Status;
  1402. BOOLEAN ReturnValue = FALSE;
  1403. OEM_STRING OemString1;
  1404. OEM_STRING OemString2;
  1405. RTL_PAGED_CODE();
  1406. //
  1407. // Upper case and convert the first string to OEM
  1408. //
  1409. Status = RtlUpcaseUnicodeStringToOemString( &OemString1,
  1410. String1,
  1411. TRUE ); // Allocate Dest
  1412. if ( NT_SUCCESS( Status ) ) {
  1413. //
  1414. // Upper case and convert the second string to OEM
  1415. //
  1416. Status = RtlUpcaseUnicodeStringToOemString( &OemString2,
  1417. String2,
  1418. TRUE ); // Allocate Dest
  1419. if ( NT_SUCCESS( Status ) ) {
  1420. //
  1421. // Do a case insensitive comparison.
  1422. //
  1423. ReturnValue = RtlEqualString( &OemString1,
  1424. &OemString2,
  1425. FALSE );
  1426. RtlFreeOemString( &OemString2 );
  1427. }
  1428. RtlFreeOemString( &OemString1 );
  1429. }
  1430. return ReturnValue;
  1431. }
  1432. BOOLEAN
  1433. RtlEqualComputerName(
  1434. IN PUNICODE_STRING String1,
  1435. IN PUNICODE_STRING String2
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. The RtlEqualComputerName function compares two computer names for equality.
  1440. The comparison is a case insensitive comparison of the OEM equivalent
  1441. strings.
  1442. The domain name is not validated for length nor invalid characters.
  1443. Arguments:
  1444. String1 - Pointer to the first string.
  1445. String2 - Pointer to the second string.
  1446. Return Value:
  1447. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1448. --*/
  1449. {
  1450. return RtlEqualDomainName( String1, String2 );
  1451. }
  1452. /**
  1453. **/
  1454. #define UNICODE_FFFF 0xFFFF
  1455. #define REVERSE_BYTE_ORDER_MARK 0xFFFE
  1456. #define BYTE_ORDER_MARK 0xFEFF
  1457. #define PARAGRAPH_SEPARATOR 0x2029
  1458. #define LINE_SEPARATOR 0x2028
  1459. #define UNICODE_TAB 0x0009
  1460. #define UNICODE_LF 0x000A
  1461. #define UNICODE_CR 0x000D
  1462. #define UNICODE_SPACE 0x0020
  1463. #define UNICODE_CJK_SPACE 0x3000
  1464. #define UNICODE_R_TAB 0x0900
  1465. #define UNICODE_R_LF 0x0A00
  1466. #define UNICODE_R_CR 0x0D00
  1467. #define UNICODE_R_SPACE 0x2000
  1468. #define UNICODE_R_CJK_SPACE 0x0030 /* Ambiguous - same as ASCII '0' */
  1469. #define ASCII_CRLF 0x0A0D
  1470. #define __max(a,b) (((a) > (b)) ? (a) : (b))
  1471. #define __min(a,b) (((a) < (b)) ? (a) : (b))
  1472. BOOLEAN
  1473. RtlIsTextUnicode(
  1474. IN PVOID Buffer,
  1475. IN ULONG Size,
  1476. IN OUT PULONG Result OPTIONAL
  1477. )
  1478. /*++
  1479. Routine Description:
  1480. IsTextUnicode performs a series of inexpensive heuristic checks
  1481. on a buffer in order to verify that it contains Unicode data.
  1482. [[ need to fix this section, see at the end ]]
  1483. Found Return Result
  1484. BOM TRUE BOM
  1485. RBOM FALSE RBOM
  1486. FFFF FALSE Binary
  1487. NULL FALSE Binary
  1488. null TRUE null bytes
  1489. ASCII_CRLF FALSE CRLF
  1490. UNICODE_TAB etc. TRUE Zero Ext Controls
  1491. UNICODE_TAB_R FALSE Reversed Controls
  1492. UNICODE_ZW etc. TRUE Unicode specials
  1493. 1/3 as little variation in hi-byte as in lo byte: TRUE Correl
  1494. 3/1 or worse " FALSE AntiCorrel
  1495. Arguments:
  1496. Buffer - pointer to buffer containing text to examine.
  1497. Size - size of buffer in bytes. At most 256 characters in this will
  1498. be examined. If the size is less than the size of a unicode
  1499. character, then this function returns FALSE.
  1500. Result - optional pointer to a flag word that contains additional information
  1501. about the reason for the return value. If specified, this value on
  1502. input is a mask that is used to limit the factors this routine uses
  1503. to make it decision. On output, this flag word is set to contain
  1504. those flags that were used to make its decision.
  1505. Return Value:
  1506. Boolean value that is TRUE if Buffer contains unicode characters.
  1507. --*/
  1508. {
  1509. UNALIGNED WCHAR *lpBuff = Buffer;
  1510. PCHAR lpb = Buffer;
  1511. ULONG iBOM = 0;
  1512. ULONG iCR = 0;
  1513. ULONG iLF = 0;
  1514. ULONG iTAB = 0;
  1515. ULONG iSPACE = 0;
  1516. ULONG iCJK_SPACE = 0;
  1517. ULONG iFFFF = 0;
  1518. ULONG iPS = 0;
  1519. ULONG iLS = 0;
  1520. ULONG iRBOM = 0;
  1521. ULONG iR_CR = 0;
  1522. ULONG iR_LF = 0;
  1523. ULONG iR_TAB = 0;
  1524. ULONG iR_SPACE = 0;
  1525. ULONG iNull = 0;
  1526. ULONG iUNULL = 0;
  1527. ULONG iCRLF = 0;
  1528. ULONG iTmp;
  1529. ULONG LastLo = 0;
  1530. ULONG LastHi = 0;
  1531. ULONG iHi, iLo;
  1532. ULONG HiDiff = 0;
  1533. ULONG LoDiff = 0;
  1534. ULONG cLeadByte = 0;
  1535. ULONG cWeird = 0;
  1536. ULONG iResult = 0;
  1537. ULONG iMaxTmp = __min(256, Size / sizeof(WCHAR));
  1538. if (Size < 2 ) {
  1539. if (ARGUMENT_PRESENT( Result )) {
  1540. *Result = IS_TEXT_UNICODE_ASCII16 | IS_TEXT_UNICODE_CONTROLS;
  1541. }
  1542. return FALSE;
  1543. }
  1544. // Check at most 256 wide character, collect various statistics
  1545. for (iTmp = 0; iTmp < iMaxTmp; iTmp++) {
  1546. switch (lpBuff[iTmp]) {
  1547. case BYTE_ORDER_MARK:
  1548. iBOM++;
  1549. break;
  1550. case PARAGRAPH_SEPARATOR:
  1551. iPS++;
  1552. break;
  1553. case LINE_SEPARATOR:
  1554. iLS++;
  1555. break;
  1556. case UNICODE_LF:
  1557. iLF++;
  1558. break;
  1559. case UNICODE_TAB:
  1560. iTAB++;
  1561. break;
  1562. case UNICODE_SPACE:
  1563. iSPACE++;
  1564. break;
  1565. case UNICODE_CJK_SPACE:
  1566. iCJK_SPACE++;
  1567. break;
  1568. case UNICODE_CR:
  1569. iCR++;
  1570. break;
  1571. // The following codes are expected to show up in
  1572. // byte reversed files
  1573. case REVERSE_BYTE_ORDER_MARK:
  1574. iRBOM++;
  1575. break;
  1576. case UNICODE_R_LF:
  1577. iR_LF++;
  1578. break;
  1579. case UNICODE_R_TAB:
  1580. iR_TAB++;
  1581. break;
  1582. case UNICODE_R_CR:
  1583. iR_CR++;
  1584. break;
  1585. case UNICODE_R_SPACE:
  1586. iR_SPACE++;
  1587. break;
  1588. // The following codes are illegal and should never occur
  1589. case UNICODE_FFFF:
  1590. iFFFF++;
  1591. break;
  1592. case UNICODE_NULL:
  1593. iUNULL++;
  1594. break;
  1595. // The following is not currently a Unicode character
  1596. // but is expected to show up accidentally when reading
  1597. // in ASCII files which use CRLF on a little endian machine
  1598. case ASCII_CRLF:
  1599. iCRLF++;
  1600. break; /* little endian */
  1601. }
  1602. // Collect statistics on the fluctuations of high bytes
  1603. // versus low bytes
  1604. iHi = HIBYTE (lpBuff[iTmp]);
  1605. iLo = LOBYTE (lpBuff[iTmp]);
  1606. // Count cr/lf and lf/cr that cross two words
  1607. if ((iLo == '\r' && LastHi == '\n') ||
  1608. (iLo == '\n' && LastHi == '\r')) {
  1609. cWeird++;
  1610. }
  1611. iNull += (iHi ? 0 : 1) + (iLo ? 0 : 1); /* count Null bytes */
  1612. HiDiff += __max( iHi, LastHi ) - __min( LastHi, iHi );
  1613. LoDiff += __max( iLo, LastLo ) - __min( LastLo, iLo );
  1614. LastLo = iLo;
  1615. LastHi = iHi;
  1616. }
  1617. // Count cr/lf and lf/cr that cross two words
  1618. if ((iLo == '\r' && LastHi == '\n') ||
  1619. (iLo == '\n' && LastHi == '\r')) {
  1620. cWeird++;
  1621. }
  1622. if (iHi == '\0') /* don't count the last null */
  1623. iNull--;
  1624. if (iHi == 26) /* count ^Z at end as weird */
  1625. cWeird++;
  1626. iMaxTmp = __min(256 * sizeof(WCHAR), Size);
  1627. if (NlsMbCodePageTag) {
  1628. for (iTmp = 0; iTmp < iMaxTmp; iTmp++) {
  1629. if (NlsLeadByteInfo[lpb[iTmp]]) {
  1630. cLeadByte++;
  1631. iTmp++; /* should check for trailing-byte range */
  1632. }
  1633. }
  1634. }
  1635. // sift the statistical evidence
  1636. if (LoDiff < 127 && HiDiff == 0) {
  1637. iResult |= IS_TEXT_UNICODE_ASCII16; /* likely 16-bit ASCII */
  1638. }
  1639. if (HiDiff && LoDiff == 0) {
  1640. iResult |= IS_TEXT_UNICODE_REVERSE_ASCII16; /* reverse 16-bit ASCII */
  1641. }
  1642. // Use leadbyte info to weight statistics.
  1643. if (!NlsMbCodePageTag || cLeadByte == 0 ||
  1644. !ARGUMENT_PRESENT(Result) || !(*Result & IS_TEXT_UNICODE_DBCS_LEADBYTE)) {
  1645. iHi = 3;
  1646. }
  1647. else {
  1648. // A ratio of cLeadByte:cb of 1:2 ==> dbcs
  1649. // Very crude - should have a nice eq.
  1650. iHi = __min(256, Size/sizeof(WCHAR)) / 2;
  1651. if (cLeadByte < (iHi-1) / 3) {
  1652. iHi = 3;
  1653. }
  1654. else if (cLeadByte < (2 * (iHi-1)) / 3) {
  1655. iHi = 2;
  1656. }
  1657. else {
  1658. iHi = 1;
  1659. }
  1660. iResult |= IS_TEXT_UNICODE_DBCS_LEADBYTE;
  1661. }
  1662. if (iHi * HiDiff < LoDiff) {
  1663. iResult |= IS_TEXT_UNICODE_STATISTICS;
  1664. }
  1665. if (iHi * LoDiff < HiDiff) {
  1666. iResult |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
  1667. }
  1668. //
  1669. // Any control codes widened to 16 bits? Any Unicode character
  1670. // which contain one byte in the control code range?
  1671. //
  1672. if (iCR + iLF + iTAB + iSPACE + iCJK_SPACE /*+iPS+iLS*/) {
  1673. iResult |= IS_TEXT_UNICODE_CONTROLS;
  1674. }
  1675. if (iR_LF + iR_CR + iR_TAB + iR_SPACE) {
  1676. iResult |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
  1677. }
  1678. //
  1679. // Any characters that are illegal for Unicode?
  1680. //
  1681. if ((iRBOM + iFFFF + iUNULL + iCRLF) != 0 ||
  1682. (cWeird != 0 && cWeird >= iMaxTmp/40 )) {
  1683. iResult |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
  1684. }
  1685. //
  1686. // Odd buffer length cannot be Unicode
  1687. //
  1688. if (Size & 1) {
  1689. iResult |= IS_TEXT_UNICODE_ODD_LENGTH;
  1690. }
  1691. //
  1692. // Any NULL bytes? (Illegal in ANSI)
  1693. //
  1694. if (iNull) {
  1695. iResult |= IS_TEXT_UNICODE_NULL_BYTES;
  1696. }
  1697. //
  1698. // POSITIVE evidence, BOM or RBOM used as signature
  1699. //
  1700. if (*lpBuff == BYTE_ORDER_MARK) {
  1701. iResult |= IS_TEXT_UNICODE_SIGNATURE;
  1702. }
  1703. else if (*lpBuff == REVERSE_BYTE_ORDER_MARK) {
  1704. iResult |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
  1705. }
  1706. //
  1707. // limit to desired categories if requested.
  1708. //
  1709. if (ARGUMENT_PRESENT( Result )) {
  1710. iResult &= *Result;
  1711. *Result = iResult;
  1712. }
  1713. //
  1714. // There are four separate conclusions:
  1715. //
  1716. // 1: The file APPEARS to be Unicode AU
  1717. // 2: The file CANNOT be Unicode CU
  1718. // 3: The file CANNOT be ANSI CA
  1719. //
  1720. //
  1721. // This gives the following possible results
  1722. //
  1723. // CU
  1724. // + -
  1725. //
  1726. // AU AU
  1727. // + - + -
  1728. // -------- --------
  1729. // CA +| 0 0 2 3
  1730. // |
  1731. // -| 1 1 4 5
  1732. //
  1733. //
  1734. // Note that there are only 6 really different cases, not 8.
  1735. //
  1736. // 0 - This must be a binary file
  1737. // 1 - ANSI file
  1738. // 2 - Unicode file (High probability)
  1739. // 3 - Unicode file (more than 50% chance)
  1740. // 5 - No evidence for Unicode (ANSI is default)
  1741. //
  1742. // The whole thing is more complicated if we allow the assumption
  1743. // of reverse polarity input. At this point we have a simplistic
  1744. // model: some of the reverse Unicode evidence is very strong,
  1745. // we ignore most weak evidence except statistics. If this kind of
  1746. // strong evidence is found together with Unicode evidence, it means
  1747. // its likely NOT Text at all. Furthermore if a REVERSE_BYTE_ORDER_MARK
  1748. // is found, it precludes normal Unicode. If both byte order marks are
  1749. // found it's not Unicode.
  1750. //
  1751. //
  1752. // Unicode signature : uncontested signature outweighs reverse evidence
  1753. //
  1754. if ((iResult & IS_TEXT_UNICODE_SIGNATURE) &&
  1755. !(iResult & (IS_TEXT_UNICODE_NOT_UNICODE_MASK&(~IS_TEXT_UNICODE_DBCS_LEADBYTE)))
  1756. ) {
  1757. return TRUE;
  1758. }
  1759. //
  1760. // If we have conflicting evidence, it's not Unicode
  1761. //
  1762. if (iResult & IS_TEXT_UNICODE_REVERSE_MASK) {
  1763. return FALSE;
  1764. }
  1765. //
  1766. // Statistical and other results (cases 2 and 3)
  1767. //
  1768. if (!(iResult & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
  1769. ((iResult & IS_TEXT_UNICODE_NOT_ASCII_MASK) ||
  1770. (iResult & IS_TEXT_UNICODE_UNICODE_MASK)
  1771. )
  1772. ) {
  1773. return TRUE;
  1774. }
  1775. return FALSE;
  1776. }