Leaked source code of windows server 2003
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.

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