2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Unicode Conversion Routines
5 * FILE: lib/rtl/unicode.c
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
11 /* INCLUDES *****************************************************************/
18 #include <wine/unicode.h>
20 /* GLOBALS *******************************************************************/
22 extern BOOLEAN NlsMbCodePageTag
;
23 extern BOOLEAN NlsMbOemCodePageTag
;
24 extern PUSHORT NlsLeadByteInfo
;
25 extern USHORT NlsOemDefaultChar
;
26 extern USHORT NlsUnicodeDefaultChar
;
29 /* FUNCTIONS *****************************************************************/
33 RtlMultiAppendUnicodeStringBuffer(IN PVOID Unknown
,
38 return STATUS_NOT_IMPLEMENTED
;
46 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR
*AnsiChar
)
50 WCHAR UnicodeChar
= L
' ';
55 Size
= (NlsLeadByteInfo
[**AnsiChar
] == 0) ? 1 : 2;
59 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
63 Status
= RtlMultiByteToUnicodeN(&UnicodeChar
,
69 if (!NT_SUCCESS(Status
))
82 * This function always writes a terminating '\0'.
83 * If the dest buffer is too small a partial copy is NOT performed!
87 RtlAnsiStringToUnicodeString(
88 IN OUT PUNICODE_STRING UniDest
,
89 IN PANSI_STRING AnsiSource
,
90 IN BOOLEAN AllocateDestinationString
)
98 if (NlsMbCodePageTag
== FALSE
)
100 Length
= AnsiSource
->Length
* 2 + sizeof(WCHAR
);
104 Length
= RtlxAnsiStringToUnicodeSize(AnsiSource
);
106 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
107 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
109 if (AllocateDestinationString
)
111 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
112 UniDest
->MaximumLength
= (USHORT
)Length
;
113 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
115 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
117 return STATUS_BUFFER_OVERFLOW
;
120 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
121 ASSERT(!(UniDest
->MaximumLength
& 1) && UniDest
->Length
<= UniDest
->MaximumLength
);
123 Status
= RtlMultiByteToUnicodeN(UniDest
->Buffer
,
129 if (!NT_SUCCESS(Status
))
131 if (AllocateDestinationString
)
133 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
134 UniDest
->Buffer
= NULL
;
140 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
148 * The calculated size in bytes including nullterm.
152 RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString
)
157 /* Convert from Mb String to Unicode Size */
158 RtlMultiByteToUnicodeSize(&Size
,
162 /* Return the size plus the null-char */
163 return(Size
+ sizeof(WCHAR
));
170 * If src->length is zero dest is unchanged.
171 * Dest is never nullterminated.
175 RtlAppendStringToString(IN PSTRING Destination
,
176 IN
const STRING
*Source
)
178 USHORT SourceLength
= Source
->Length
;
182 if (Destination
->Length
+ SourceLength
> Destination
->MaximumLength
)
184 return STATUS_BUFFER_TOO_SMALL
;
187 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
],
191 Destination
->Length
+= SourceLength
;
194 return STATUS_SUCCESS
;
201 * If src->length is zero dest is unchanged.
202 * Dest is nullterminated when the MaximumLength allowes it.
203 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
207 RtlAppendUnicodeStringToString(
208 IN OUT PUNICODE_STRING Destination
,
209 IN PCUNICODE_STRING Source
)
211 USHORT SourceLength
= Source
->Length
;
212 PWCHAR Buffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
216 if ((SourceLength
+ Destination
->Length
) > Destination
->MaximumLength
)
218 return STATUS_BUFFER_TOO_SMALL
;
221 RtlMoveMemory(Buffer
, Source
->Buffer
, SourceLength
);
222 Destination
->Length
+= SourceLength
;
224 /* append terminating '\0' if enough space */
225 if (Destination
->MaximumLength
> Destination
->Length
)
227 Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
231 return STATUS_SUCCESS
;
234 /**************************************************************************
235 * RtlCharToInteger (NTDLL.@)
237 * Converts a character string into its integer equivalent.
240 * Success: STATUS_SUCCESS. value contains the converted number
241 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
242 * STATUS_ACCESS_VIOLATION, if value is NULL.
245 * For base 0 it uses 10 as base and the string should be in the format
246 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
247 * For other bases the string should be in the format
248 * "{whitespace} [+|-] {digits}".
249 * No check is made for value overflow, only the lower 32 bits are assigned.
250 * If str is NULL it crashes, as the native function does.
253 * This function does not read garbage behind '\0' as the native version does.
258 PCSZ str
, /* [I] '\0' terminated single-byte string containing a number */
259 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
260 PULONG value
) /* [O] Destination for the converted value */
264 ULONG RunningTotal
= 0;
267 /* skip leading whitespaces */
268 while (*str
!= '\0' && *str
<= ' ') str
++;
275 else if (*str
== '-')
281 /* base = 0 means autobase */
293 else if (str
[1] == 'o')
298 else if (str
[1] == 'x')
305 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
307 return STATUS_INVALID_PARAMETER
;
310 if (value
== NULL
) return STATUS_ACCESS_VIOLATION
;
316 if (chCurrent
>= '0' && chCurrent
<= '9')
318 digit
= chCurrent
- '0';
320 else if (chCurrent
>= 'A' && chCurrent
<= 'Z')
322 digit
= chCurrent
- 'A' + 10;
324 else if (chCurrent
>= 'a' && chCurrent
<= 'z')
326 digit
= chCurrent
- 'a' + 10;
333 if (digit
< 0 || digit
>= (int)base
) break;
335 RunningTotal
= RunningTotal
* base
+ digit
;
339 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
340 return STATUS_SUCCESS
;
351 IN BOOLEAN CaseInsensitive
)
357 len
= min(s1
->Length
, s2
->Length
);
363 while (!ret
&& len
--)
364 ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
368 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
371 if (!ret
) ret
= s1
->Length
- s2
->Length
;
380 * TRUE if strings are equal.
387 IN BOOLEAN CaseInsensitive
)
389 if (s1
->Length
!= s2
->Length
) return FALSE
;
390 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
397 * TRUE if strings are equal.
401 RtlEqualUnicodeString(
402 IN CONST UNICODE_STRING
*s1
,
403 IN CONST UNICODE_STRING
*s2
,
404 IN BOOLEAN CaseInsensitive
)
406 if (s1
->Length
!= s2
->Length
) return FALSE
;
407 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
415 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
419 if (AnsiString
->Buffer
)
421 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
422 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
431 RtlFreeOemString(IN POEM_STRING OemString
)
435 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
443 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
447 if (UnicodeString
->Buffer
)
449 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
450 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
459 * Check the OEM string to match the Unicode string.
461 * Functions which convert Unicode strings to OEM strings will set a
462 * DefaultChar from the OEM codepage when the characters are unknown.
463 * So check it against the Unicode string and return false when the
464 * Unicode string does not contain a TransDefaultChar.
468 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
469 IN POEM_STRING OemString
)
473 if (NlsMbOemCodePageTag
== FALSE
)
475 /* single-byte code page */
476 /* Go through all characters of a string */
477 while (i
< OemString
->Length
)
479 /* Check if it got translated into a default char,
480 * but source char wasn't a default char equivalent
482 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
483 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
485 /* Yes, it means unmappable characters were found */
489 /* Move to the next char */
493 /* All chars were translated successfuly */
498 /* multibyte code page */
510 RtlIsValidOemCharacter(IN PWCHAR Char
)
520 * If source is NULL the length of source is assumed to be 0.
524 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
525 IN PCSZ SourceString
)
531 Size
= strlen(SourceString
);
532 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) Size
= MAXUSHORT
- sizeof(CHAR
);
533 DestinationString
->Length
= (USHORT
)Size
;
534 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
538 DestinationString
->Length
= 0;
539 DestinationString
->MaximumLength
= 0;
542 DestinationString
->Buffer
= (PCHAR
)SourceString
;
547 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
548 IN PCSZ SourceString
)
554 Size
= strlen(SourceString
);
555 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) return STATUS_NAME_TOO_LONG
;
556 DestinationString
->Length
= (USHORT
)Size
;
557 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
561 DestinationString
->Length
= 0;
562 DestinationString
->MaximumLength
= 0;
565 DestinationString
->Buffer
= (PCHAR
)SourceString
;
566 return STATUS_SUCCESS
;
573 * If source is NULL the length of source is assumed to be 0.
578 IN OUT PSTRING DestinationString
,
579 IN PCSZ SourceString
)
581 RtlInitAnsiString(DestinationString
, SourceString
);
588 * If source is NULL the length of source is assumed to be 0.
592 RtlInitUnicodeString(
593 IN OUT PUNICODE_STRING DestinationString
,
594 IN PCWSTR SourceString
)
597 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(UNICODE_NULL
); // an even number
601 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
602 __analysis_assume(Size
<= MaxSize
);
606 DestinationString
->Length
= (USHORT
)Size
;
607 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(UNICODE_NULL
);
611 DestinationString
->Length
= 0;
612 DestinationString
->MaximumLength
= 0;
615 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
623 RtlInitUnicodeStringEx(
624 OUT PUNICODE_STRING DestinationString
,
625 IN PCWSTR SourceString
)
628 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(WCHAR
); // an even number
632 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
633 if (Size
> MaxSize
) return STATUS_NAME_TOO_LONG
;
634 DestinationString
->Length
= (USHORT
)Size
;
635 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(WCHAR
);
639 DestinationString
->Length
= 0;
640 DestinationString
->MaximumLength
= 0;
643 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
644 return STATUS_SUCCESS
;
651 * Writes at most length characters to the string str.
652 * Str is nullterminated when length allowes it.
653 * When str fits exactly in length characters the nullterm is ommitted.
655 NTSTATUS NTAPI
RtlIntegerToChar(
656 ULONG value
, /* [I] Value to be converted */
657 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
658 ULONG length
, /* [I] Length of the str buffer in bytes */
659 PCHAR str
) /* [O] Destination for the converted value */
670 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
672 return STATUS_INVALID_PARAMETER
;
681 digit
= (CHAR
)(value
% base
);
682 value
= value
/ base
;
690 *pos
= 'A' + digit
- 10;
695 len
= &buffer
[32] - pos
;
699 return STATUS_BUFFER_OVERFLOW
;
701 else if (str
== NULL
)
703 return STATUS_ACCESS_VIOLATION
;
705 else if (len
== length
)
707 memcpy(str
, pos
, len
);
711 memcpy(str
, pos
, len
+ 1);
714 return STATUS_SUCCESS
;
724 IN ULONG Base OPTIONAL
,
725 IN ULONG Length OPTIONAL
,
726 IN OUT LPWSTR String
)
737 if (Radix
== 0) Radix
= 10;
739 if ((Radix
!= 2) && (Radix
!= 8) &&
740 (Radix
!= 10) && (Radix
!= 16))
742 return STATUS_INVALID_PARAMETER
;
747 while (v
|| tp
== temp
)
752 if (i
< 10) *tp
= (WCHAR
)(i
+ L
'0');
753 else *tp
= (WCHAR
)(i
+ L
'a' - 10);
758 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
760 return STATUS_BUFFER_TOO_SMALL
;
765 while (tp
> temp
) *sp
++ = *--tp
;
769 return STATUS_SUCCESS
;
777 RtlIntegerToUnicodeString(
779 IN ULONG Base OPTIONAL
,
780 IN OUT PUNICODE_STRING String
)
782 ANSI_STRING AnsiString
;
786 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
787 if (NT_SUCCESS(Status
))
789 AnsiString
.Buffer
= Buffer
;
790 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
791 AnsiString
.MaximumLength
= sizeof(Buffer
);
793 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
804 RtlInt64ToUnicodeString (
806 IN ULONG Base OPTIONAL
,
807 IN OUT PUNICODE_STRING String
)
809 LARGE_INTEGER LargeInt
;
810 ANSI_STRING AnsiString
;
814 LargeInt
.QuadPart
= Value
;
816 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
817 if (NT_SUCCESS(Status
))
819 AnsiString
.Buffer
= Buffer
;
820 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
821 AnsiString
.MaximumLength
= sizeof(Buffer
);
823 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
833 * TRUE if String2 contains String1 as a prefix.
838 const STRING
*String1
,
839 const STRING
*String2
,
840 BOOLEAN CaseInsensitive
)
846 if (String2
->Length
< String1
->Length
)
849 NumChars
= String1
->Length
;
850 pc1
= String1
->Buffer
;
851 pc2
= String2
->Buffer
;
859 if (RtlUpperChar(*pc1
++) != RtlUpperChar(*pc2
++))
867 if (*pc1
++ != *pc2
++)
882 * TRUE if String2 contains String1 as a prefix.
886 RtlPrefixUnicodeString(
887 PCUNICODE_STRING String1
,
888 PCUNICODE_STRING String2
,
889 BOOLEAN CaseInsensitive
)
895 if (String2
->Length
< String1
->Length
)
898 NumChars
= String1
->Length
/ sizeof(WCHAR
);
899 pc1
= String1
->Buffer
;
900 pc2
= String2
->Buffer
;
908 if (RtlUpcaseUnicodeChar(*pc1
++) !=
909 RtlUpcaseUnicodeChar(*pc2
++))
917 if (*pc1
++ != *pc2
++)
933 RtlUnicodeStringToInteger(
934 const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
935 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
936 ULONG
*value
) /* [O] Destination for the converted value */
938 LPWSTR lpwstr
= str
->Buffer
;
939 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
942 ULONG RunningTotal
= 0;
945 while (CharsRemaining
>= 1 && *lpwstr
<= ' ')
951 if (CharsRemaining
>= 1)
958 else if (*lpwstr
== '-')
970 if (CharsRemaining
>= 2 && lpwstr
[0] == '0')
972 if (lpwstr
[1] == 'b')
978 else if (lpwstr
[1] == 'o')
984 else if (lpwstr
[1] == 'x')
992 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
994 return STATUS_INVALID_PARAMETER
;
999 return STATUS_ACCESS_VIOLATION
;
1002 while (CharsRemaining
>= 1)
1004 wchCurrent
= *lpwstr
;
1006 if (wchCurrent
>= '0' && wchCurrent
<= '9')
1008 digit
= wchCurrent
- '0';
1010 else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z')
1012 digit
= wchCurrent
- 'A' + 10;
1014 else if (wchCurrent
>= 'a' && wchCurrent
<= 'z')
1016 digit
= wchCurrent
- 'a' + 10;
1023 if (digit
< 0 || (ULONG
)digit
>= base
) break;
1025 RunningTotal
= RunningTotal
* base
+ digit
;
1030 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
1031 return STATUS_SUCCESS
;
1038 * Bytes necessary for the conversion including nullterm.
1042 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
1046 /* Convert the Unicode String to Mb Size */
1047 RtlUnicodeToMultiByteSize(&Size
,
1048 UnicodeString
->Buffer
,
1049 UnicodeString
->Length
);
1051 /* Return the size + the null char */
1052 return (Size
+ sizeof(CHAR
));
1059 * This function always writes a terminating '\0'.
1060 * It performs a partial copy if ansi is too small.
1064 RtlUnicodeStringToAnsiString(
1065 IN OUT PANSI_STRING AnsiDest
,
1066 IN PCUNICODE_STRING UniSource
,
1067 IN BOOLEAN AllocateDestinationString
)
1069 NTSTATUS Status
= STATUS_SUCCESS
;
1070 NTSTATUS RealStatus
;
1076 ASSERT(!(UniSource
->Length
& 1));
1078 if (NlsMbCodePageTag
== FALSE
)
1080 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
1084 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
1087 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1089 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1091 if (AllocateDestinationString
)
1093 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1094 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1096 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1098 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1100 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1102 Status
= STATUS_BUFFER_OVERFLOW
;
1103 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1106 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1112 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1114 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1118 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1126 * This function always writes a terminating '\0'.
1127 * Does NOT perform a partial copy if unicode is too small!
1131 RtlOemStringToUnicodeString(
1132 IN OUT PUNICODE_STRING UniDest
,
1133 IN PCOEM_STRING OemSource
,
1134 IN BOOLEAN AllocateDestinationString
)
1142 Length
= RtlOemStringToUnicodeSize(OemSource
);
1144 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1146 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1148 if (AllocateDestinationString
)
1150 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1151 UniDest
->MaximumLength
= (USHORT
)Length
;
1153 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1155 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1157 return STATUS_BUFFER_OVERFLOW
;
1160 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1166 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1168 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1169 UniDest
->Buffer
= NULL
;
1173 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1181 * This function always '\0' terminates the string returned.
1185 RtlUnicodeStringToOemString(
1186 IN OUT POEM_STRING OemDest
,
1187 IN PCUNICODE_STRING UniSource
,
1188 IN BOOLEAN AllocateDestinationString
)
1196 Length
= RtlUnicodeStringToOemSize(UniSource
);
1198 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1200 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1202 if (AllocateDestinationString
)
1204 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1205 OemDest
->MaximumLength
= (USHORT
)Length
;
1207 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1209 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1211 return STATUS_BUFFER_OVERFLOW
;
1214 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1220 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1222 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1223 OemDest
->Buffer
= NULL
;
1227 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1231 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1237 * The length of the string if all tests were passed, 0 otherwise.
1241 RtlIsTextUnicode(CONST VOID
* buf
, INT len
, INT
* pf
)
1243 static const WCHAR std_control_chars
[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1244 static const WCHAR byterev_control_chars
[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1245 const WCHAR
*s
= buf
;
1247 unsigned int flags
= MAXULONG
, out_flags
= 0;
1248 UCHAR last_lo_byte
= 0;
1249 UCHAR last_hi_byte
= 0;
1250 ULONG hi_byte_diff
= 0;
1251 ULONG lo_byte_diff
= 0;
1253 ULONG lead_byte
= 0;
1255 if (len
< sizeof(WCHAR
))
1257 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1267 * Apply various tests to the text string. According to the
1268 * docs, each test "passed" sets the corresponding flag in
1269 * the output flags. But some of the tests are mutually
1270 * exclusive, so I don't see how you could pass all tests ...
1273 /* Check for an odd length ... pass if even. */
1274 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1276 if (((char *)buf
)[len
- 1] == 0)
1277 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1279 len
/= sizeof(WCHAR
);
1281 /* Windows only checks the first 256 characters */
1282 if (len
> 256) len
= 256;
1284 /* Check for the special byte order unicode marks. */
1285 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1286 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1288 for (i
= 0; i
< len
; i
++)
1290 UCHAR lo_byte
= LOBYTE(s
[i
]);
1291 UCHAR hi_byte
= HIBYTE(s
[i
]);
1293 lo_byte_diff
+= max(lo_byte
, last_lo_byte
) - min(lo_byte
, last_lo_byte
);
1294 hi_byte_diff
+= max(hi_byte
, last_hi_byte
) - min(hi_byte
, last_hi_byte
);
1296 last_lo_byte
= lo_byte
;
1297 last_hi_byte
= hi_byte
;
1301 case 0xFFFE: /* Reverse BOM */
1303 case 0x0A0D: /* ASCII CRLF (packed into one word) */
1304 case 0xFFFF: /* Unicode 0xFFFF */
1305 out_flags
|= IS_TEXT_UNICODE_ILLEGAL_CHARS
;
1310 if (NlsMbCodePageTag
)
1312 for (i
= 0; i
< len
; i
++)
1314 if (NlsLeadByteInfo
[s
[i
]])
1323 weight
= (len
/ 2) - 1;
1325 if (lead_byte
< (weight
/ 3))
1327 else if (lead_byte
< ((weight
* 2) / 3))
1332 if (*pf
&& (*pf
& IS_TEXT_UNICODE_DBCS_LEADBYTE
))
1333 out_flags
|= IS_TEXT_UNICODE_DBCS_LEADBYTE
;
1337 if (lo_byte_diff
< 127 && !hi_byte_diff
)
1339 out_flags
|= IS_TEXT_UNICODE_ASCII16
;
1342 if (hi_byte_diff
&& !lo_byte_diff
)
1344 out_flags
|= IS_TEXT_UNICODE_REVERSE_ASCII16
;
1347 if ((weight
* lo_byte_diff
) < hi_byte_diff
)
1349 out_flags
|= IS_TEXT_UNICODE_REVERSE_STATISTICS
;
1352 /* apply some statistical analysis */
1353 if ((flags
& IS_TEXT_UNICODE_STATISTICS
) &&
1354 ((weight
* hi_byte_diff
) < lo_byte_diff
))
1356 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1359 /* Check for unicode NULL chars */
1360 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1362 for (i
= 0; i
< len
; i
++)
1364 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1366 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1372 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1374 for (i
= 0; i
< len
; i
++)
1376 if (strchrW(std_control_chars
, s
[i
]))
1378 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1384 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1386 for (i
= 0; i
< len
; i
++)
1388 if (strchrW(byterev_control_chars
, s
[i
]))
1390 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1402 /* check for flags that indicate it's definitely not valid Unicode */
1403 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1405 /* now check for invalid ASCII, and assume Unicode if so */
1406 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1408 /* now check for Unicode flags */
1409 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1420 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1421 * A partial copy is NOT performed if the dest buffer is too small!
1425 RtlOemStringToCountedUnicodeString(
1426 IN OUT PUNICODE_STRING UniDest
,
1427 IN PCOEM_STRING OemSource
,
1428 IN BOOLEAN AllocateDestinationString
)
1436 /* Calculate size of the string */
1437 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1439 /* If it's 0 then zero out dest string and return */
1442 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1443 return STATUS_SUCCESS
;
1446 /* Check if length is a sane value */
1447 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1449 /* Store it in dest string */
1450 UniDest
->Length
= (USHORT
)Length
;
1452 /* If we're asked to alloc the string - do so */
1453 if (AllocateDestinationString
)
1455 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1456 UniDest
->MaximumLength
= (USHORT
)Length
;
1458 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1460 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1462 return STATUS_BUFFER_OVERFLOW
;
1465 /* Do the conversion */
1466 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1472 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1474 /* Conversion failed, free dest string and return status code */
1475 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1476 UniDest
->Buffer
= NULL
;
1480 return STATUS_SUCCESS
;
1487 * TRUE if the names are equal, FALSE if not
1490 * The comparison is case insensitive.
1494 RtlEqualComputerName(
1495 IN PUNICODE_STRING ComputerName1
,
1496 IN PUNICODE_STRING ComputerName2
)
1498 OEM_STRING OemString1
;
1499 OEM_STRING OemString2
;
1500 BOOLEAN Result
= FALSE
;
1502 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1506 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1510 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1511 RtlFreeOemString(&OemString2
);
1514 RtlFreeOemString(&OemString1
);
1524 * TRUE if the names are equal, FALSE if not
1527 * The comparison is case insensitive.
1531 RtlEqualDomainName (
1532 IN PUNICODE_STRING DomainName1
,
1533 IN PUNICODE_STRING DomainName2
)
1535 return RtlEqualComputerName(DomainName1
, DomainName2
);
1541 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1543 * Convert a string representation of a GUID into a GUID.
1546 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1547 * guid [O] Destination for the converted GUID
1550 * Success: STATUS_SUCCESS. guid contains the converted value.
1551 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1554 * See RtlStringFromGUID.
1559 IN UNICODE_STRING
*str
,
1563 const WCHAR
*lpszCLSID
= str
->Buffer
;
1564 BYTE
* lpOut
= (BYTE
*)guid
;
1566 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1568 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1569 * to memory: DWORD... WORD WORD BYTES............
1576 if (*lpszCLSID
!= '{')
1577 return STATUS_INVALID_PARAMETER
;
1584 if (*lpszCLSID
!= '-')
1585 return STATUS_INVALID_PARAMETER
;
1589 if (*lpszCLSID
!= '}')
1590 return STATUS_INVALID_PARAMETER
;
1596 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1599 /* Read two hex digits as a byte value */
1600 if (ch
>= '0' && ch
<= '9')
1602 else if (ch
>= 'a' && ch
<= 'f')
1604 else if (ch
>= 'A' && ch
<= 'F')
1607 return STATUS_INVALID_PARAMETER
;
1609 if (ch2
>= '0' && ch2
<= '9')
1611 else if (ch2
>= 'a' && ch2
<= 'f')
1612 ch2
= ch2
- 'a' + 10;
1613 else if (ch2
>= 'A' && ch2
<= 'F')
1614 ch2
= ch2
- 'A' + 10;
1616 return STATUS_INVALID_PARAMETER
;
1618 byte
= ch
<< 4 | ch2
;
1622 #ifndef WORDS_BIGENDIAN
1623 /* For Big Endian machines, we store the data such that the
1624 * dword/word members can be read as DWORDS and WORDS correctly. */
1657 lpszCLSID
++; /* Skip 2nd character of byte */
1666 return STATUS_SUCCESS
;
1674 RtlEraseUnicodeString(
1675 IN PUNICODE_STRING String
)
1677 if (String
->Buffer
&& String
->MaximumLength
)
1679 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1689 RtlHashUnicodeString(
1690 IN CONST UNICODE_STRING
*String
,
1691 IN BOOLEAN CaseInSensitive
,
1692 IN ULONG HashAlgorithm
,
1693 OUT PULONG HashValue
)
1695 if (String
!= NULL
&& HashValue
!= NULL
)
1697 switch (HashAlgorithm
)
1699 case HASH_STRING_ALGORITHM_DEFAULT
:
1700 case HASH_STRING_ALGORITHM_X65599
:
1705 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1707 if (CaseInSensitive
)
1709 for (c
= String
->Buffer
; c
!= end
; c
++)
1711 /* only uppercase characters if they are 'a' ... 'z'! */
1712 *HashValue
= ((65599 * (*HashValue
)) +
1713 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1714 (*c
) - L
'a' + L
'A' : (*c
)));
1719 for (c
= String
->Buffer
; c
!= end
; c
++)
1721 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1725 return STATUS_SUCCESS
;
1730 return STATUS_INVALID_PARAMETER
;
1737 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1738 * Does a partial copy if the dest buffer is too small
1742 RtlUnicodeStringToCountedOemString(
1743 IN OUT POEM_STRING OemDest
,
1744 IN PUNICODE_STRING UniSource
,
1745 IN BOOLEAN AllocateDestinationString
)
1753 /* Calculate size of the string */
1754 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1756 /* If it's 0 then zero out dest string and return */
1759 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1760 return STATUS_SUCCESS
;
1763 /* Check if length is a sane value */
1764 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1766 /* Store it in dest string */
1767 OemDest
->Length
= (USHORT
)Length
;
1769 /* If we're asked to alloc the string - do so */
1770 if (AllocateDestinationString
)
1772 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1773 OemDest
->MaximumLength
= (USHORT
)Length
;
1774 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1776 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1778 return STATUS_BUFFER_OVERFLOW
;
1781 /* Do the conversion */
1782 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1788 /* Check for unmapped character */
1789 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1790 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1792 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1794 /* Conversion failed, free dest string and return status code */
1795 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1796 OemDest
->Buffer
= NULL
;
1808 RtlLargeIntegerToChar(
1809 IN PLARGE_INTEGER Value
,
1812 IN OUT PCHAR String
)
1814 ULONGLONG Val
= Value
->QuadPart
;
1820 if (Base
== 0) Base
= 10;
1822 if ((Base
!= 2) && (Base
!= 8) && (Base
!= 10) && (Base
!= 16))
1824 return STATUS_INVALID_PARAMETER
;
1833 Digit
= (CHAR
)(Val
% Base
);
1839 *Pos
= 'A' + Digit
- 10;
1843 Len
= &Buffer
[64] - Pos
;
1846 return STATUS_BUFFER_OVERFLOW
;
1848 /* If possible, add the 0 termination */
1852 /* Copy the string to the target using SEH */
1853 return RtlpSafeCopyMemory(String
, Pos
, Len
);
1860 * dest is never '\0' terminated because it may be equal to src, and src
1861 * might not be '\0' terminated. dest->Length is only set upon success.
1865 RtlUpcaseUnicodeString(
1866 IN OUT PUNICODE_STRING UniDest
,
1867 IN PCUNICODE_STRING UniSource
,
1868 IN BOOLEAN AllocateDestinationString
)
1874 if (AllocateDestinationString
)
1876 UniDest
->MaximumLength
= UniSource
->Length
;
1877 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1878 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1880 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1882 return STATUS_BUFFER_OVERFLOW
;
1885 j
= UniSource
->Length
/ sizeof(WCHAR
);
1887 for (i
= 0; i
< j
; i
++)
1889 UniDest
->Buffer
[i
] = RtlUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1892 UniDest
->Length
= UniSource
->Length
;
1893 return STATUS_SUCCESS
;
1900 * This function always writes a terminating '\0'.
1901 * It performs a partial copy if ansi is too small.
1905 RtlUpcaseUnicodeStringToAnsiString(
1906 IN OUT PANSI_STRING AnsiDest
,
1907 IN PUNICODE_STRING UniSource
,
1908 IN BOOLEAN AllocateDestinationString
)
1915 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1916 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1918 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1920 if (AllocateDestinationString
)
1922 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1923 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1924 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1926 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1928 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1931 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1937 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1939 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1940 AnsiDest
->Buffer
= NULL
;
1944 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1952 * This function always writes a terminating '\0'.
1953 * It performs a partial copy if ansi is too small.
1957 RtlUpcaseUnicodeStringToCountedOemString(
1958 IN OUT POEM_STRING OemDest
,
1959 IN PCUNICODE_STRING UniSource
,
1960 IN BOOLEAN AllocateDestinationString
)
1967 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1971 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1974 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1976 OemDest
->Length
= (USHORT
)Length
;
1978 if (AllocateDestinationString
)
1980 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1981 OemDest
->MaximumLength
= (USHORT
)Length
;
1982 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1984 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1986 return STATUS_BUFFER_OVERFLOW
;
1989 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1995 /* Check for unmapped characters */
1996 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1997 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1999 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2001 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2002 OemDest
->Buffer
= NULL
;
2012 * OEM string is always nullterminated
2013 * It performs a partial copy if oem is too small.
2017 RtlUpcaseUnicodeStringToOemString (
2018 IN OUT POEM_STRING OemDest
,
2019 IN PCUNICODE_STRING UniSource
,
2020 IN BOOLEAN AllocateDestinationString
)
2027 Length
= RtlUnicodeStringToOemSize(UniSource
);
2028 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
2030 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
2032 if (AllocateDestinationString
)
2034 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
2035 OemDest
->MaximumLength
= (USHORT
)Length
;
2036 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
2038 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
2040 return STATUS_BUFFER_OVERFLOW
;
2043 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2049 /* Check for unmapped characters */
2050 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2051 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2053 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2055 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2056 OemDest
->Buffer
= NULL
;
2060 OemDest
->Buffer
[Index
] = ANSI_NULL
;
2068 * Bytes calculated including nullterm
2072 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
2076 /* Convert the Mb String to Unicode Size */
2077 RtlMultiByteToUnicodeSize(&Size
,
2081 /* Return the size + null-char */
2082 return (Size
+ sizeof(WCHAR
));
2090 RtlStringFromGUID (IN REFGUID Guid
,
2091 OUT PUNICODE_STRING GuidString
)
2093 /* Setup the string */
2094 GuidString
->Length
= 38 * sizeof(WCHAR
);
2095 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
2096 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
2098 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
2100 /* Now format the GUID */
2101 swprintf(GuidString
->Buffer
,
2102 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2114 return STATUS_SUCCESS
;
2121 * Bytes calculated including nullterm
2125 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
2130 ASSERT(!(UnicodeString
->Length
& 1));
2132 /* Convert the Unicode String to Mb Size */
2133 RtlUnicodeToMultiByteSize(&Size
,
2134 UnicodeString
->Buffer
,
2135 UnicodeString
->Length
);
2137 /* Return the size + null-char */
2138 return (Size
+ sizeof(CHAR
));
2146 RtlCompareUnicodeString(
2147 IN PCUNICODE_STRING s1
,
2148 IN PCUNICODE_STRING s2
,
2149 IN BOOLEAN CaseInsensitive
)
2155 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2159 if (CaseInsensitive
)
2161 while (!ret
&& len
--) ret
= RtlUpcaseUnicodeChar(*p1
++) - RtlUpcaseUnicodeChar(*p2
++);
2165 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2168 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2179 IN OUT PSTRING DestinationString
,
2180 IN
const STRING
*SourceString OPTIONAL
)
2185 /* Check if there was no source given */
2188 /* Simply return an empty string */
2189 DestinationString
->Length
= 0;
2193 /* Choose the smallest length */
2194 SourceLength
= min(DestinationString
->MaximumLength
,
2195 SourceString
->Length
);
2198 DestinationString
->Length
= (USHORT
)SourceLength
;
2200 /* Save the pointers to each buffer */
2201 p1
= DestinationString
->Buffer
;
2202 p2
= SourceString
->Buffer
;
2204 /* Loop the buffer */
2205 while (SourceLength
)
2207 /* Copy the character and move on */
2219 RtlCopyUnicodeString(
2220 IN OUT PUNICODE_STRING DestinationString
,
2221 IN PCUNICODE_STRING SourceString
)
2225 if(SourceString
== NULL
)
2227 DestinationString
->Length
= 0;
2231 SourceLength
= min(DestinationString
->MaximumLength
,
2232 SourceString
->Length
);
2233 DestinationString
->Length
= (USHORT
)SourceLength
;
2235 RtlCopyMemory(DestinationString
->Buffer
,
2236 SourceString
->Buffer
,
2239 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2241 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2250 * Creates a nullterminated UNICODE_STRING
2254 RtlCreateUnicodeString(
2255 IN OUT PUNICODE_STRING UniDest
,
2261 Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2262 if (Size
> MAXUSHORT
) return FALSE
;
2264 UniDest
->Buffer
= RtlpAllocateStringMemory((ULONG
)Size
, TAG_USTR
);
2266 if (UniDest
->Buffer
== NULL
) return FALSE
;
2268 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
2269 UniDest
->MaximumLength
= (USHORT
)Size
;
2270 UniDest
->Length
= (USHORT
)Size
- sizeof (WCHAR
);
2280 RtlCreateUnicodeStringFromAsciiz(
2281 OUT PUNICODE_STRING Destination
,
2284 ANSI_STRING AnsiString
;
2287 RtlInitAnsiString(&AnsiString
, Source
);
2289 Status
= RtlAnsiStringToUnicodeString(Destination
,
2293 return NT_SUCCESS(Status
);
2300 * Dest is never '\0' terminated because it may be equal to src, and src
2301 * might not be '\0' terminated.
2302 * Dest->Length is only set upon success.
2306 RtlDowncaseUnicodeString(
2307 IN OUT PUNICODE_STRING UniDest
,
2308 IN PCUNICODE_STRING UniSource
,
2309 IN BOOLEAN AllocateDestinationString
)
2315 if (AllocateDestinationString
)
2317 UniDest
->MaximumLength
= UniSource
->Length
;
2318 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2319 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2321 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2323 return STATUS_BUFFER_OVERFLOW
;
2326 UniDest
->Length
= UniSource
->Length
;
2327 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2329 for (i
= 0 ; i
< StopGap
; i
++)
2331 if (UniSource
->Buffer
[i
] < L
'A')
2333 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2335 else if (UniSource
->Buffer
[i
] <= L
'Z')
2337 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2341 UniDest
->Buffer
[i
] = RtlDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2345 return STATUS_SUCCESS
;
2352 * if src is NULL dest is unchanged.
2353 * dest is '\0' terminated when the MaximumLength allowes it.
2354 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2358 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2366 UNICODE_STRING UnicodeSource
;
2368 RtlInitUnicodeString(&UnicodeSource
, Source
);
2369 Length
= UnicodeSource
.Length
;
2371 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2373 return STATUS_BUFFER_TOO_SMALL
;
2376 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2377 RtlMoveMemory(DestBuffer
, Source
, Length
);
2378 Destination
->Length
+= Length
;
2380 /* append terminating '\0' if enough space */
2381 if(Destination
->MaximumLength
> Destination
->Length
)
2383 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2387 return STATUS_SUCCESS
;
2394 * if src is NULL dest is unchanged.
2395 * dest is never '\0' terminated.
2399 RtlAppendAsciizToString(
2400 IN OUT PSTRING Destination
,
2407 Size
= strlen(Source
);
2409 if (Destination
->Length
+ Size
> Destination
->MaximumLength
)
2411 return STATUS_BUFFER_TOO_SMALL
;
2414 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Size
);
2415 Destination
->Length
+= (USHORT
)Size
;
2418 return STATUS_SUCCESS
;
2426 RtlUpperString(PSTRING DestinationString
,
2427 const STRING
*SourceString
)
2432 Length
= min(SourceString
->Length
,
2433 DestinationString
->MaximumLength
);
2435 Src
= SourceString
->Buffer
;
2436 Dest
= DestinationString
->Buffer
;
2437 DestinationString
->Length
= Length
;
2441 *Dest
++ = RtlUpperChar(*Src
++);
2450 * See RtlpDuplicateUnicodeString
2454 RtlDuplicateUnicodeString(
2456 IN PCUNICODE_STRING SourceString
,
2457 OUT PUNICODE_STRING DestinationString
)
2461 if (SourceString
== NULL
|| DestinationString
== NULL
||
2462 SourceString
->Length
> SourceString
->MaximumLength
||
2463 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2464 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4)
2466 return STATUS_INVALID_PARAMETER
;
2470 if ((SourceString
->Length
== 0) &&
2471 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2472 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2474 DestinationString
->Length
= 0;
2475 DestinationString
->MaximumLength
= 0;
2476 DestinationString
->Buffer
= NULL
;
2480 UINT DestMaxLength
= SourceString
->Length
;
2482 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2483 DestMaxLength
+= sizeof(UNICODE_NULL
);
2485 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2487 if (DestinationString
->Buffer
== NULL
)
2488 return STATUS_NO_MEMORY
;
2490 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2491 DestinationString
->Length
= SourceString
->Length
;
2492 DestinationString
->MaximumLength
= DestMaxLength
;
2494 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2495 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2498 return STATUS_SUCCESS
;
2506 RtlValidateUnicodeString(IN ULONG Flags
,
2507 IN PCUNICODE_STRING UnicodeString
)
2509 /* currently no flags are supported! */
2513 ((UnicodeString
== NULL
) ||
2514 ((UnicodeString
->Length
!= 0) &&
2515 (UnicodeString
->Buffer
!= NULL
) &&
2516 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2517 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2518 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2520 /* a NULL pointer as a unicode string is considered to be a valid unicode
2522 return STATUS_SUCCESS
;
2526 return STATUS_INVALID_PARAMETER
;
2535 RtlpEnsureBufferSize(ULONG Unknown1
, ULONG Unknown2
, ULONG Unknown3
)
2537 DPRINT1("RtlpEnsureBufferSize: stub\n");
2538 return STATUS_NOT_IMPLEMENTED
;
2543 RtlpIsCharInUnicodeString(
2545 IN PCUNICODE_STRING MatchString
,
2546 IN BOOLEAN CaseInSensitive
)
2550 if (CaseInSensitive
)
2551 Char
= RtlUpcaseUnicodeChar(Char
);
2553 for (i
= 0; i
< MatchString
->Length
/ sizeof(WCHAR
); i
++)
2555 WCHAR OtherChar
= MatchString
->Buffer
[i
];
2556 if (CaseInSensitive
)
2557 OtherChar
= RtlUpcaseUnicodeChar(OtherChar
);
2559 if (Char
== OtherChar
)
2571 RtlFindCharInUnicodeString(
2573 IN PCUNICODE_STRING SearchString
,
2574 IN PCUNICODE_STRING MatchString
,
2575 OUT PUSHORT Position
)
2578 const BOOLEAN WantToFind
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
) == 0;
2579 const BOOLEAN CaseInSensitive
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
) != 0;
2582 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2583 Flags
, SearchString
, MatchString
, Position
);
2585 /* Parameter checks */
2586 if (Position
== NULL
)
2587 return STATUS_INVALID_PARAMETER
;
2591 if (Flags
& ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
|
2592 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
|
2593 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
))
2594 return STATUS_INVALID_PARAMETER
;
2597 Length
= SearchString
->Length
/ sizeof(WCHAR
);
2598 if (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
)
2600 for (i
= Length
- 1; (SHORT
)i
>= 0; i
--)
2602 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2603 if (Found
== WantToFind
)
2605 *Position
= i
* sizeof(WCHAR
);
2606 return STATUS_SUCCESS
;
2612 for (i
= 0; i
< Length
; i
++)
2614 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2615 if (Found
== WantToFind
)
2617 *Position
= (i
+ 1) * sizeof(WCHAR
);
2618 return STATUS_SUCCESS
;
2623 return STATUS_NOT_FOUND
;
2630 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2631 * Convert is to an uppercase oem string and check for unmapped characters.
2632 * Then convert the oem string back to an unicode string.
2636 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
, PUNICODE_STRING DnsHostName
, BOOLEAN AllocateComputerNameString
)
2640 ULONG ComputerNameLength
;
2641 ULONG ComputerNameOemNLength
;
2642 OEM_STRING ComputerNameOem
;
2643 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2645 Status
= STATUS_INVALID_COMPUTER_NAME
;
2646 ComputerNameLength
= DnsHostName
->Length
;
2648 /* find the first dot in the dns host name */
2649 for (Length
= 0; Length
< DnsHostName
->Length
/ sizeof(WCHAR
); Length
++)
2651 if (DnsHostName
->Buffer
[Length
] == L
'.')
2653 /* dot found, so set the length for the oem translation */
2654 ComputerNameLength
= Length
* sizeof(WCHAR
);
2659 /* the computername must have one character */
2660 if (ComputerNameLength
> 0)
2662 ComputerNameOemNLength
= 0;
2663 /* convert to oem string and use uppercase letters */
2664 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2665 MAX_COMPUTERNAME_LENGTH
,
2666 &ComputerNameOemNLength
,
2667 DnsHostName
->Buffer
,
2668 ComputerNameLength
);
2670 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2671 have MAX_COMPUTERNAME_LENGTH characters */
2672 if ((Status
== STATUS_SUCCESS
) ||
2673 (Status
== STATUS_BUFFER_OVERFLOW
))
2675 /* set the termination for the oem string */
2676 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2677 /* set status for the case the next function failed */
2678 Status
= STATUS_INVALID_COMPUTER_NAME
;
2679 /* fillup the oem string structure with the converted computername
2680 and check it for unmapped characters */
2681 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2682 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2683 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2685 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
))
2687 /* no unmapped character so convert it back to an unicode string */
2688 Status
= RtlOemStringToUnicodeString(ComputerName
,
2690 AllocateComputerNameString
);