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
;
27 extern PUSHORT NlsOemLeadByteInfo
;
28 extern PWCHAR NlsOemToUnicodeTable
;
29 extern PCHAR NlsUnicodeToOemTable
;
30 extern PUSHORT NlsUnicodeToMbOemTable
;
33 /* FUNCTIONS *****************************************************************/
37 RtlMultiAppendUnicodeStringBuffer(OUT PRTL_UNICODE_STRING_BUFFER StringBuffer
,
38 IN ULONG NumberOfAddends
,
39 IN PCUNICODE_STRING Addends
)
42 return STATUS_NOT_IMPLEMENTED
;
50 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR
*AnsiChar
)
54 WCHAR UnicodeChar
= L
' ';
59 Size
= (NlsLeadByteInfo
[**AnsiChar
] == 0) ? 1 : 2;
63 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
67 Status
= RtlMultiByteToUnicodeN(&UnicodeChar
,
73 if (!NT_SUCCESS(Status
))
86 * This function always writes a terminating '\0'.
87 * If the dest buffer is too small a partial copy is NOT performed!
91 RtlAnsiStringToUnicodeString(
92 IN OUT PUNICODE_STRING UniDest
,
93 IN PANSI_STRING AnsiSource
,
94 IN BOOLEAN AllocateDestinationString
)
102 if (NlsMbCodePageTag
== FALSE
)
104 Length
= AnsiSource
->Length
* 2 + sizeof(WCHAR
);
108 Length
= RtlxAnsiStringToUnicodeSize(AnsiSource
);
110 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
111 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
113 if (AllocateDestinationString
)
115 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
116 UniDest
->MaximumLength
= (USHORT
)Length
;
117 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
119 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
121 return STATUS_BUFFER_OVERFLOW
;
124 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
125 ASSERT(!(UniDest
->MaximumLength
& 1) && UniDest
->Length
<= UniDest
->MaximumLength
);
127 Status
= RtlMultiByteToUnicodeN(UniDest
->Buffer
,
133 if (!NT_SUCCESS(Status
))
135 if (AllocateDestinationString
)
137 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
138 UniDest
->Buffer
= NULL
;
144 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
152 * The calculated size in bytes including nullterm.
156 RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString
)
161 /* Convert from Mb String to Unicode Size */
162 RtlMultiByteToUnicodeSize(&Size
,
166 /* Return the size plus the null-char */
167 return(Size
+ sizeof(WCHAR
));
174 * If src->length is zero dest is unchanged.
175 * Dest is never nullterminated.
179 RtlAppendStringToString(IN PSTRING Destination
,
180 IN
const STRING
*Source
)
182 USHORT SourceLength
= Source
->Length
;
186 if (Destination
->Length
+ SourceLength
> Destination
->MaximumLength
)
188 return STATUS_BUFFER_TOO_SMALL
;
191 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
],
195 Destination
->Length
+= SourceLength
;
198 return STATUS_SUCCESS
;
205 * If src->length is zero dest is unchanged.
206 * Dest is nullterminated when the MaximumLength allowes it.
207 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
211 RtlAppendUnicodeStringToString(
212 IN OUT PUNICODE_STRING Destination
,
213 IN PCUNICODE_STRING Source
)
215 USHORT SourceLength
= Source
->Length
;
216 PWCHAR Buffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
220 if ((SourceLength
+ Destination
->Length
) > Destination
->MaximumLength
)
222 return STATUS_BUFFER_TOO_SMALL
;
225 RtlMoveMemory(Buffer
, Source
->Buffer
, SourceLength
);
226 Destination
->Length
+= SourceLength
;
228 /* append terminating '\0' if enough space */
229 if (Destination
->MaximumLength
> Destination
->Length
)
231 Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
235 return STATUS_SUCCESS
;
238 /**************************************************************************
239 * RtlCharToInteger (NTDLL.@)
241 * Converts a character string into its integer equivalent.
244 * Success: STATUS_SUCCESS. value contains the converted number
245 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
246 * STATUS_ACCESS_VIOLATION, if value is NULL.
249 * For base 0 it uses 10 as base and the string should be in the format
250 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
251 * For other bases the string should be in the format
252 * "{whitespace} [+|-] {digits}".
253 * No check is made for value overflow, only the lower 32 bits are assigned.
254 * If str is NULL it crashes, as the native function does.
257 * This function does not read garbage behind '\0' as the native version does.
262 PCSZ str
, /* [I] '\0' terminated single-byte string containing a number */
263 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
264 PULONG value
) /* [O] Destination for the converted value */
268 ULONG RunningTotal
= 0;
271 /* skip leading whitespaces */
272 while (*str
!= '\0' && *str
<= ' ') str
++;
279 else if (*str
== '-')
285 /* base = 0 means autobase */
297 else if (str
[1] == 'o')
302 else if (str
[1] == 'x')
309 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
311 return STATUS_INVALID_PARAMETER
;
314 if (value
== NULL
) return STATUS_ACCESS_VIOLATION
;
320 if (chCurrent
>= '0' && chCurrent
<= '9')
322 digit
= chCurrent
- '0';
324 else if (chCurrent
>= 'A' && chCurrent
<= 'Z')
326 digit
= chCurrent
- 'A' + 10;
328 else if (chCurrent
>= 'a' && chCurrent
<= 'z')
330 digit
= chCurrent
- 'a' + 10;
337 if (digit
< 0 || digit
>= (int)base
) break;
339 RunningTotal
= RunningTotal
* base
+ digit
;
343 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
344 return STATUS_SUCCESS
;
355 IN BOOLEAN CaseInsensitive
)
361 len
= min(s1
->Length
, s2
->Length
);
367 while (!ret
&& len
--)
368 ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
372 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
375 if (!ret
) ret
= s1
->Length
- s2
->Length
;
384 * TRUE if strings are equal.
391 IN BOOLEAN CaseInsensitive
)
393 if (s1
->Length
!= s2
->Length
) return FALSE
;
394 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
401 * TRUE if strings are equal.
405 RtlEqualUnicodeString(
406 IN CONST UNICODE_STRING
*s1
,
407 IN CONST UNICODE_STRING
*s2
,
408 IN BOOLEAN CaseInsensitive
)
410 if (s1
->Length
!= s2
->Length
) return FALSE
;
411 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
419 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
423 if (AnsiString
->Buffer
)
425 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
426 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
435 RtlFreeOemString(IN POEM_STRING OemString
)
439 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
447 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
451 if (UnicodeString
->Buffer
)
453 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
454 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
463 * Check the OEM string to match the Unicode string.
465 * Functions which convert Unicode strings to OEM strings will set a
466 * DefaultChar from the OEM codepage when the characters are unknown.
467 * So check it against the Unicode string and return false when the
468 * Unicode string does not contain a TransDefaultChar.
472 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
473 IN POEM_STRING OemString
)
477 if (NlsMbOemCodePageTag
== FALSE
)
479 /* single-byte code page */
480 /* Go through all characters of a string */
481 while (i
< OemString
->Length
)
483 /* Check if it got translated into a default char,
484 * but source char wasn't a default char equivalent
486 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
487 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
489 /* Yes, it means unmappable characters were found */
493 /* Move to the next char */
497 /* All chars were translated successfuly */
502 /* multibyte code page */
514 RtlIsValidOemCharacter(IN PWCHAR Char
)
519 /* If multi-byte code page present */
520 if (NlsMbOemCodePageTag
)
524 OemChar
= NlsUnicodeToMbOemTable
[*Char
];
526 /* If character has Lead Byte */
527 if (NlsOemLeadByteInfo
[HIBYTE(OemChar
)])
528 Offset
= NlsOemLeadByteInfo
[HIBYTE(OemChar
)];
530 /* Receive Unicode character from the table */
531 UnicodeChar
= RtlpUpcaseUnicodeChar(NlsOemToUnicodeTable
[LOBYTE(OemChar
) + Offset
]);
533 /* Receive OEM character from the table */
534 OemChar
= NlsUnicodeToMbOemTable
[UnicodeChar
];
538 /* Receive Unicode character from the table */
539 UnicodeChar
= RtlpUpcaseUnicodeChar(NlsOemToUnicodeTable
[(UCHAR
)NlsUnicodeToOemTable
[*Char
]]);
541 /* Receive OEM character from the table */
542 OemChar
= NlsUnicodeToOemTable
[UnicodeChar
];
545 /* Not valid character, failed */
546 if (OemChar
== NlsOemDefaultChar
)
558 * If source is NULL the length of source is assumed to be 0.
562 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
563 IN PCSZ SourceString
)
569 Size
= strlen(SourceString
);
570 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) Size
= MAXUSHORT
- sizeof(CHAR
);
571 DestinationString
->Length
= (USHORT
)Size
;
572 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
576 DestinationString
->Length
= 0;
577 DestinationString
->MaximumLength
= 0;
580 DestinationString
->Buffer
= (PCHAR
)SourceString
;
585 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
586 IN PCSZ SourceString
)
592 Size
= strlen(SourceString
);
593 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) return STATUS_NAME_TOO_LONG
;
594 DestinationString
->Length
= (USHORT
)Size
;
595 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
599 DestinationString
->Length
= 0;
600 DestinationString
->MaximumLength
= 0;
603 DestinationString
->Buffer
= (PCHAR
)SourceString
;
604 return STATUS_SUCCESS
;
611 * If source is NULL the length of source is assumed to be 0.
616 IN OUT PSTRING DestinationString
,
617 IN PCSZ SourceString
)
619 RtlInitAnsiString(DestinationString
, SourceString
);
626 * If source is NULL the length of source is assumed to be 0.
630 RtlInitUnicodeString(
631 IN OUT PUNICODE_STRING DestinationString
,
632 IN PCWSTR SourceString
)
635 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(UNICODE_NULL
); // an even number
639 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
640 __analysis_assume(Size
<= MaxSize
);
644 DestinationString
->Length
= (USHORT
)Size
;
645 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(UNICODE_NULL
);
649 DestinationString
->Length
= 0;
650 DestinationString
->MaximumLength
= 0;
653 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
661 RtlInitUnicodeStringEx(
662 OUT PUNICODE_STRING DestinationString
,
663 IN PCWSTR SourceString
)
666 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(WCHAR
); // an even number
670 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
671 if (Size
> MaxSize
) return STATUS_NAME_TOO_LONG
;
672 DestinationString
->Length
= (USHORT
)Size
;
673 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(WCHAR
);
677 DestinationString
->Length
= 0;
678 DestinationString
->MaximumLength
= 0;
681 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
682 return STATUS_SUCCESS
;
689 * Writes at most length characters to the string str.
690 * Str is nullterminated when length allowes it.
691 * When str fits exactly in length characters the nullterm is ommitted.
693 NTSTATUS NTAPI
RtlIntegerToChar(
694 ULONG value
, /* [I] Value to be converted */
695 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
696 ULONG length
, /* [I] Length of the str buffer in bytes */
697 PCHAR str
) /* [O] Destination for the converted value */
708 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
710 return STATUS_INVALID_PARAMETER
;
719 digit
= (CHAR
)(value
% base
);
720 value
= value
/ base
;
728 *pos
= 'A' + digit
- 10;
733 len
= &buffer
[32] - pos
;
737 return STATUS_BUFFER_OVERFLOW
;
739 else if (str
== NULL
)
741 return STATUS_ACCESS_VIOLATION
;
743 else if (len
== length
)
745 RtlCopyMemory(str
, pos
, len
);
749 RtlCopyMemory(str
, pos
, len
+ 1);
752 return STATUS_SUCCESS
;
762 IN ULONG Base OPTIONAL
,
763 IN ULONG Length OPTIONAL
,
764 IN OUT LPWSTR String
)
775 if (Radix
== 0) Radix
= 10;
777 if ((Radix
!= 2) && (Radix
!= 8) &&
778 (Radix
!= 10) && (Radix
!= 16))
780 return STATUS_INVALID_PARAMETER
;
785 while (v
|| tp
== temp
)
790 if (i
< 10) *tp
= (WCHAR
)(i
+ L
'0');
791 else *tp
= (WCHAR
)(i
+ L
'a' - 10);
796 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
798 return STATUS_BUFFER_TOO_SMALL
;
803 while (tp
> temp
) *sp
++ = *--tp
;
807 return STATUS_SUCCESS
;
815 RtlIntegerToUnicodeString(
817 IN ULONG Base OPTIONAL
,
818 IN OUT PUNICODE_STRING String
)
820 ANSI_STRING AnsiString
;
824 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
825 if (NT_SUCCESS(Status
))
827 AnsiString
.Buffer
= Buffer
;
828 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
829 AnsiString
.MaximumLength
= sizeof(Buffer
);
831 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
842 RtlInt64ToUnicodeString (
844 IN ULONG Base OPTIONAL
,
845 IN OUT PUNICODE_STRING String
)
847 LARGE_INTEGER LargeInt
;
848 ANSI_STRING AnsiString
;
852 LargeInt
.QuadPart
= Value
;
854 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
855 if (NT_SUCCESS(Status
))
857 AnsiString
.Buffer
= Buffer
;
858 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
859 AnsiString
.MaximumLength
= sizeof(Buffer
);
861 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
871 * TRUE if String2 contains String1 as a prefix.
876 const STRING
*String1
,
877 const STRING
*String2
,
878 BOOLEAN CaseInsensitive
)
884 if (String2
->Length
< String1
->Length
)
887 NumChars
= String1
->Length
;
888 pc1
= String1
->Buffer
;
889 pc2
= String2
->Buffer
;
897 if (RtlUpperChar(*pc1
++) != RtlUpperChar(*pc2
++))
905 if (*pc1
++ != *pc2
++)
920 * TRUE if String2 contains String1 as a prefix.
924 RtlPrefixUnicodeString(
925 PCUNICODE_STRING String1
,
926 PCUNICODE_STRING String2
,
927 BOOLEAN CaseInsensitive
)
933 if (String2
->Length
< String1
->Length
)
936 NumChars
= String1
->Length
/ sizeof(WCHAR
);
937 pc1
= String1
->Buffer
;
938 pc2
= String2
->Buffer
;
946 if (RtlpUpcaseUnicodeChar(*pc1
++) !=
947 RtlpUpcaseUnicodeChar(*pc2
++))
955 if (*pc1
++ != *pc2
++)
971 RtlUnicodeStringToInteger(
972 const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
973 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
974 ULONG
*value
) /* [O] Destination for the converted value */
976 LPWSTR lpwstr
= str
->Buffer
;
977 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
980 ULONG RunningTotal
= 0;
983 while (CharsRemaining
>= 1 && *lpwstr
<= ' ')
989 if (CharsRemaining
>= 1)
996 else if (*lpwstr
== '-')
1008 if (CharsRemaining
>= 2 && lpwstr
[0] == '0')
1010 if (lpwstr
[1] == 'b')
1013 CharsRemaining
-= 2;
1016 else if (lpwstr
[1] == 'o')
1019 CharsRemaining
-= 2;
1022 else if (lpwstr
[1] == 'x')
1025 CharsRemaining
-= 2;
1030 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
1032 return STATUS_INVALID_PARAMETER
;
1037 return STATUS_ACCESS_VIOLATION
;
1040 while (CharsRemaining
>= 1)
1042 wchCurrent
= *lpwstr
;
1044 if (wchCurrent
>= '0' && wchCurrent
<= '9')
1046 digit
= wchCurrent
- '0';
1048 else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z')
1050 digit
= wchCurrent
- 'A' + 10;
1052 else if (wchCurrent
>= 'a' && wchCurrent
<= 'z')
1054 digit
= wchCurrent
- 'a' + 10;
1061 if (digit
< 0 || (ULONG
)digit
>= base
) break;
1063 RunningTotal
= RunningTotal
* base
+ digit
;
1068 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
1069 return STATUS_SUCCESS
;
1076 * Bytes necessary for the conversion including nullterm.
1080 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
1084 /* Convert the Unicode String to Mb Size */
1085 RtlUnicodeToMultiByteSize(&Size
,
1086 UnicodeString
->Buffer
,
1087 UnicodeString
->Length
);
1089 /* Return the size + the null char */
1090 return (Size
+ sizeof(CHAR
));
1097 * This function always writes a terminating '\0'.
1098 * It performs a partial copy if ansi is too small.
1102 RtlUnicodeStringToAnsiString(
1103 IN OUT PANSI_STRING AnsiDest
,
1104 IN PCUNICODE_STRING UniSource
,
1105 IN BOOLEAN AllocateDestinationString
)
1107 NTSTATUS Status
= STATUS_SUCCESS
;
1108 NTSTATUS RealStatus
;
1114 ASSERT(!(UniSource
->Length
& 1));
1116 if (NlsMbCodePageTag
== FALSE
)
1118 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
1122 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
1125 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1127 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1129 if (AllocateDestinationString
)
1131 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1132 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1134 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1136 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1138 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1140 Status
= STATUS_BUFFER_OVERFLOW
;
1141 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1144 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1150 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1152 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1156 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1164 * This function always writes a terminating '\0'.
1165 * Does NOT perform a partial copy if unicode is too small!
1169 RtlOemStringToUnicodeString(
1170 IN OUT PUNICODE_STRING UniDest
,
1171 IN PCOEM_STRING OemSource
,
1172 IN BOOLEAN AllocateDestinationString
)
1180 Length
= RtlOemStringToUnicodeSize(OemSource
);
1182 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1184 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1186 if (AllocateDestinationString
)
1188 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1189 UniDest
->MaximumLength
= (USHORT
)Length
;
1191 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1193 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1195 return STATUS_BUFFER_OVERFLOW
;
1198 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1204 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1206 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1207 UniDest
->Buffer
= NULL
;
1211 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1219 * This function always '\0' terminates the string returned.
1223 RtlUnicodeStringToOemString(
1224 IN OUT POEM_STRING OemDest
,
1225 IN PCUNICODE_STRING UniSource
,
1226 IN BOOLEAN AllocateDestinationString
)
1234 Length
= RtlUnicodeStringToOemSize(UniSource
);
1236 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1238 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1240 if (AllocateDestinationString
)
1242 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1243 OemDest
->MaximumLength
= (USHORT
)Length
;
1245 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1247 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1249 return STATUS_BUFFER_OVERFLOW
;
1252 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1258 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1260 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1261 OemDest
->Buffer
= NULL
;
1265 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1269 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1275 * The length of the string if all tests were passed, 0 otherwise.
1279 RtlIsTextUnicode(CONST VOID
* buf
, INT len
, INT
* pf
)
1281 static const WCHAR std_control_chars
[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1282 static const WCHAR byterev_control_chars
[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1283 const WCHAR
*s
= buf
;
1285 unsigned int flags
= MAXULONG
, out_flags
= 0;
1286 UCHAR last_lo_byte
= 0;
1287 UCHAR last_hi_byte
= 0;
1288 ULONG hi_byte_diff
= 0;
1289 ULONG lo_byte_diff
= 0;
1291 ULONG lead_byte
= 0;
1293 if (len
< sizeof(WCHAR
))
1295 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1305 * Apply various tests to the text string. According to the
1306 * docs, each test "passed" sets the corresponding flag in
1307 * the output flags. But some of the tests are mutually
1308 * exclusive, so I don't see how you could pass all tests ...
1311 /* Check for an odd length ... pass if even. */
1312 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1314 if (((char *)buf
)[len
- 1] == 0)
1315 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1317 len
/= sizeof(WCHAR
);
1319 /* Windows only checks the first 256 characters */
1320 if (len
> 256) len
= 256;
1322 /* Check for the special byte order unicode marks. */
1323 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1324 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1326 for (i
= 0; i
< len
; i
++)
1328 UCHAR lo_byte
= LOBYTE(s
[i
]);
1329 UCHAR hi_byte
= HIBYTE(s
[i
]);
1331 lo_byte_diff
+= max(lo_byte
, last_lo_byte
) - min(lo_byte
, last_lo_byte
);
1332 hi_byte_diff
+= max(hi_byte
, last_hi_byte
) - min(hi_byte
, last_hi_byte
);
1334 last_lo_byte
= lo_byte
;
1335 last_hi_byte
= hi_byte
;
1339 case 0xFFFE: /* Reverse BOM */
1341 case 0x0A0D: /* ASCII CRLF (packed into one word) */
1342 case 0xFFFF: /* Unicode 0xFFFF */
1343 out_flags
|= IS_TEXT_UNICODE_ILLEGAL_CHARS
;
1348 if (NlsMbCodePageTag
)
1350 for (i
= 0; i
< len
; i
++)
1352 if (NlsLeadByteInfo
[s
[i
]])
1361 weight
= (len
/ 2) - 1;
1363 if (lead_byte
< (weight
/ 3))
1365 else if (lead_byte
< ((weight
* 2) / 3))
1370 if (pf
&& (*pf
& IS_TEXT_UNICODE_DBCS_LEADBYTE
))
1371 out_flags
|= IS_TEXT_UNICODE_DBCS_LEADBYTE
;
1375 if (lo_byte_diff
< 127 && !hi_byte_diff
)
1377 out_flags
|= IS_TEXT_UNICODE_ASCII16
;
1380 if (hi_byte_diff
&& !lo_byte_diff
)
1382 out_flags
|= IS_TEXT_UNICODE_REVERSE_ASCII16
;
1385 if ((weight
* lo_byte_diff
) < hi_byte_diff
)
1387 out_flags
|= IS_TEXT_UNICODE_REVERSE_STATISTICS
;
1390 /* apply some statistical analysis */
1391 if ((flags
& IS_TEXT_UNICODE_STATISTICS
) &&
1392 ((weight
* hi_byte_diff
) < lo_byte_diff
))
1394 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1397 /* Check for unicode NULL chars */
1398 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1400 for (i
= 0; i
< len
; i
++)
1402 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1404 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1410 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1412 for (i
= 0; i
< len
; i
++)
1414 if (strchrW(std_control_chars
, s
[i
]))
1416 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1422 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1424 for (i
= 0; i
< len
; i
++)
1426 if (strchrW(byterev_control_chars
, s
[i
]))
1428 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1440 /* check for flags that indicate it's definitely not valid Unicode */
1441 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1443 /* now check for invalid ASCII, and assume Unicode if so */
1444 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1446 /* now check for Unicode flags */
1447 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1458 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1459 * A partial copy is NOT performed if the dest buffer is too small!
1463 RtlOemStringToCountedUnicodeString(
1464 IN OUT PUNICODE_STRING UniDest
,
1465 IN PCOEM_STRING OemSource
,
1466 IN BOOLEAN AllocateDestinationString
)
1474 /* Calculate size of the string */
1475 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1477 /* If it's 0 then zero out dest string and return */
1480 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1481 return STATUS_SUCCESS
;
1484 /* Check if length is a sane value */
1485 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1487 /* Store it in dest string */
1488 UniDest
->Length
= (USHORT
)Length
;
1490 /* If we're asked to alloc the string - do so */
1491 if (AllocateDestinationString
)
1493 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1494 UniDest
->MaximumLength
= (USHORT
)Length
;
1496 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1498 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1500 return STATUS_BUFFER_OVERFLOW
;
1503 /* Do the conversion */
1504 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1510 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1512 /* Conversion failed, free dest string and return status code */
1513 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1514 UniDest
->Buffer
= NULL
;
1518 return STATUS_SUCCESS
;
1525 * TRUE if the names are equal, FALSE if not
1528 * The comparison is case insensitive.
1532 RtlEqualComputerName(
1533 IN PUNICODE_STRING ComputerName1
,
1534 IN PUNICODE_STRING ComputerName2
)
1536 OEM_STRING OemString1
;
1537 OEM_STRING OemString2
;
1538 BOOLEAN Result
= FALSE
;
1540 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1544 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1548 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1549 RtlFreeOemString(&OemString2
);
1552 RtlFreeOemString(&OemString1
);
1562 * TRUE if the names are equal, FALSE if not
1565 * The comparison is case insensitive.
1569 RtlEqualDomainName (
1570 IN PUNICODE_STRING DomainName1
,
1571 IN PUNICODE_STRING DomainName2
)
1573 return RtlEqualComputerName(DomainName1
, DomainName2
);
1579 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1581 * Convert a string representation of a GUID into a GUID.
1584 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1585 * guid [O] Destination for the converted GUID
1588 * Success: STATUS_SUCCESS. guid contains the converted value.
1589 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1592 * See RtlStringFromGUID.
1597 IN UNICODE_STRING
*str
,
1601 const WCHAR
*lpszCLSID
= str
->Buffer
;
1602 BYTE
* lpOut
= (BYTE
*)guid
;
1604 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1606 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1607 * to memory: DWORD... WORD WORD BYTES............
1614 if (*lpszCLSID
!= '{')
1615 return STATUS_INVALID_PARAMETER
;
1622 if (*lpszCLSID
!= '-')
1623 return STATUS_INVALID_PARAMETER
;
1627 if (*lpszCLSID
!= '}')
1628 return STATUS_INVALID_PARAMETER
;
1634 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1637 /* Read two hex digits as a byte value */
1638 if (ch
>= '0' && ch
<= '9')
1640 else if (ch
>= 'a' && ch
<= 'f')
1642 else if (ch
>= 'A' && ch
<= 'F')
1645 return STATUS_INVALID_PARAMETER
;
1647 if (ch2
>= '0' && ch2
<= '9')
1649 else if (ch2
>= 'a' && ch2
<= 'f')
1650 ch2
= ch2
- 'a' + 10;
1651 else if (ch2
>= 'A' && ch2
<= 'F')
1652 ch2
= ch2
- 'A' + 10;
1654 return STATUS_INVALID_PARAMETER
;
1656 byte
= ch
<< 4 | ch2
;
1660 #ifndef WORDS_BIGENDIAN
1661 /* For Big Endian machines, we store the data such that the
1662 * dword/word members can be read as DWORDS and WORDS correctly. */
1695 lpszCLSID
++; /* Skip 2nd character of byte */
1704 return STATUS_SUCCESS
;
1712 RtlEraseUnicodeString(
1713 IN PUNICODE_STRING String
)
1715 if (String
->Buffer
&& String
->MaximumLength
)
1717 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1727 RtlHashUnicodeString(
1728 IN CONST UNICODE_STRING
*String
,
1729 IN BOOLEAN CaseInSensitive
,
1730 IN ULONG HashAlgorithm
,
1731 OUT PULONG HashValue
)
1733 if (String
!= NULL
&& HashValue
!= NULL
)
1735 switch (HashAlgorithm
)
1737 case HASH_STRING_ALGORITHM_DEFAULT
:
1738 case HASH_STRING_ALGORITHM_X65599
:
1743 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1745 if (CaseInSensitive
)
1747 for (c
= String
->Buffer
; c
!= end
; c
++)
1749 /* only uppercase characters if they are 'a' ... 'z'! */
1750 *HashValue
= ((65599 * (*HashValue
)) +
1751 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1752 (*c
) - L
'a' + L
'A' : (*c
)));
1757 for (c
= String
->Buffer
; c
!= end
; c
++)
1759 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1763 return STATUS_SUCCESS
;
1768 return STATUS_INVALID_PARAMETER
;
1775 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1776 * Does a partial copy if the dest buffer is too small
1780 RtlUnicodeStringToCountedOemString(
1781 IN OUT POEM_STRING OemDest
,
1782 IN PCUNICODE_STRING UniSource
,
1783 IN BOOLEAN AllocateDestinationString
)
1791 /* Calculate size of the string */
1792 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1794 /* If it's 0 then zero out dest string and return */
1797 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1798 return STATUS_SUCCESS
;
1801 /* Check if length is a sane value */
1802 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1804 /* Store it in dest string */
1805 OemDest
->Length
= (USHORT
)Length
;
1807 /* If we're asked to alloc the string - do so */
1808 if (AllocateDestinationString
)
1810 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1811 OemDest
->MaximumLength
= (USHORT
)Length
;
1812 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1814 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1816 return STATUS_BUFFER_OVERFLOW
;
1819 /* Do the conversion */
1820 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1826 /* Check for unmapped character */
1827 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1828 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1830 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1832 /* Conversion failed, free dest string and return status code */
1833 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1834 OemDest
->Buffer
= NULL
;
1846 RtlLargeIntegerToChar(
1847 IN PLARGE_INTEGER Value
,
1850 IN OUT PCHAR String
)
1852 ULONGLONG Val
= Value
->QuadPart
;
1858 if (Base
== 0) Base
= 10;
1860 if ((Base
!= 2) && (Base
!= 8) && (Base
!= 10) && (Base
!= 16))
1862 return STATUS_INVALID_PARAMETER
;
1871 Digit
= (CHAR
)(Val
% Base
);
1877 *Pos
= 'A' + Digit
- 10;
1881 Len
= &Buffer
[64] - Pos
;
1884 return STATUS_BUFFER_OVERFLOW
;
1886 /* If possible, add the 0 termination */
1890 /* Copy the string to the target using SEH */
1891 return RtlpSafeCopyMemory(String
, Pos
, Len
);
1898 * dest is never '\0' terminated because it may be equal to src, and src
1899 * might not be '\0' terminated. dest->Length is only set upon success.
1903 RtlUpcaseUnicodeString(
1904 IN OUT PUNICODE_STRING UniDest
,
1905 IN PCUNICODE_STRING UniSource
,
1906 IN BOOLEAN AllocateDestinationString
)
1912 if (AllocateDestinationString
)
1914 UniDest
->MaximumLength
= UniSource
->Length
;
1915 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1916 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1918 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1920 return STATUS_BUFFER_OVERFLOW
;
1923 j
= UniSource
->Length
/ sizeof(WCHAR
);
1925 for (i
= 0; i
< j
; i
++)
1927 UniDest
->Buffer
[i
] = RtlpUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1930 UniDest
->Length
= UniSource
->Length
;
1931 return STATUS_SUCCESS
;
1938 * This function always writes a terminating '\0'.
1939 * It performs a partial copy if ansi is too small.
1943 RtlUpcaseUnicodeStringToAnsiString(
1944 IN OUT PANSI_STRING AnsiDest
,
1945 IN PCUNICODE_STRING UniSource
,
1946 IN BOOLEAN AllocateDestinationString
)
1953 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1954 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1956 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1958 if (AllocateDestinationString
)
1960 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1961 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1962 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1964 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1966 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1969 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1975 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1977 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1978 AnsiDest
->Buffer
= NULL
;
1982 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1990 * This function always writes a terminating '\0'.
1991 * It performs a partial copy if ansi is too small.
1995 RtlUpcaseUnicodeStringToCountedOemString(
1996 IN OUT POEM_STRING OemDest
,
1997 IN PCUNICODE_STRING UniSource
,
1998 IN BOOLEAN AllocateDestinationString
)
2005 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
2009 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
2012 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
2014 OemDest
->Length
= (USHORT
)Length
;
2016 if (AllocateDestinationString
)
2018 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
2019 OemDest
->MaximumLength
= (USHORT
)Length
;
2020 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
2022 else if (OemDest
->Length
> OemDest
->MaximumLength
)
2024 return STATUS_BUFFER_OVERFLOW
;
2027 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2033 /* Check for unmapped characters */
2034 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2035 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2037 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2039 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2040 OemDest
->Buffer
= NULL
;
2050 * OEM string is always nullterminated
2051 * It performs a partial copy if oem is too small.
2055 RtlUpcaseUnicodeStringToOemString (
2056 IN OUT POEM_STRING OemDest
,
2057 IN PCUNICODE_STRING UniSource
,
2058 IN BOOLEAN AllocateDestinationString
)
2065 Length
= RtlUnicodeStringToOemSize(UniSource
);
2066 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
2068 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
2070 if (AllocateDestinationString
)
2072 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
2073 OemDest
->MaximumLength
= (USHORT
)Length
;
2074 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
2076 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
2078 return STATUS_BUFFER_OVERFLOW
;
2081 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2087 /* Check for unmapped characters */
2088 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2089 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2091 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2093 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2094 OemDest
->Buffer
= NULL
;
2098 OemDest
->Buffer
[Index
] = ANSI_NULL
;
2106 * Bytes calculated including nullterm
2110 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
2114 /* Convert the Mb String to Unicode Size */
2115 RtlMultiByteToUnicodeSize(&Size
,
2119 /* Return the size + null-char */
2120 return (Size
+ sizeof(WCHAR
));
2128 RtlStringFromGUID (IN REFGUID Guid
,
2129 OUT PUNICODE_STRING GuidString
)
2131 /* Setup the string */
2132 GuidString
->Length
= 38 * sizeof(WCHAR
);
2133 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
2134 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
2136 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
2138 /* Now format the GUID */
2139 swprintf(GuidString
->Buffer
,
2140 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2152 return STATUS_SUCCESS
;
2159 * Bytes calculated including nullterm
2163 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
2168 ASSERT(!(UnicodeString
->Length
& 1));
2170 /* Convert the Unicode String to Mb Size */
2171 RtlUnicodeToMultiByteSize(&Size
,
2172 UnicodeString
->Buffer
,
2173 UnicodeString
->Length
);
2175 /* Return the size + null-char */
2176 return (Size
+ sizeof(CHAR
));
2184 RtlCompareUnicodeString(
2185 IN PCUNICODE_STRING s1
,
2186 IN PCUNICODE_STRING s2
,
2187 IN BOOLEAN CaseInsensitive
)
2193 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2197 if (CaseInsensitive
)
2199 while (!ret
&& len
--) ret
= RtlpUpcaseUnicodeChar(*p1
++) - RtlpUpcaseUnicodeChar(*p2
++);
2203 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2206 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2217 IN OUT PSTRING DestinationString
,
2218 IN
const STRING
*SourceString OPTIONAL
)
2223 /* Check if there was no source given */
2226 /* Simply return an empty string */
2227 DestinationString
->Length
= 0;
2231 /* Choose the smallest length */
2232 SourceLength
= min(DestinationString
->MaximumLength
,
2233 SourceString
->Length
);
2236 DestinationString
->Length
= (USHORT
)SourceLength
;
2238 /* Save the pointers to each buffer */
2239 p1
= DestinationString
->Buffer
;
2240 p2
= SourceString
->Buffer
;
2242 /* Loop the buffer */
2243 while (SourceLength
)
2245 /* Copy the character and move on */
2257 RtlCopyUnicodeString(
2258 IN OUT PUNICODE_STRING DestinationString
,
2259 IN PCUNICODE_STRING SourceString
)
2263 if(SourceString
== NULL
)
2265 DestinationString
->Length
= 0;
2269 SourceLength
= min(DestinationString
->MaximumLength
,
2270 SourceString
->Length
);
2271 DestinationString
->Length
= (USHORT
)SourceLength
;
2273 RtlCopyMemory(DestinationString
->Buffer
,
2274 SourceString
->Buffer
,
2277 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2279 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2288 * Creates a nullterminated UNICODE_STRING
2292 RtlCreateUnicodeString(
2293 IN OUT PUNICODE_STRING UniDest
,
2299 Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2300 if (Size
> MAXUSHORT
) return FALSE
;
2302 UniDest
->Buffer
= RtlpAllocateStringMemory((ULONG
)Size
, TAG_USTR
);
2304 if (UniDest
->Buffer
== NULL
) return FALSE
;
2306 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
2307 UniDest
->MaximumLength
= (USHORT
)Size
;
2308 UniDest
->Length
= (USHORT
)Size
- sizeof (WCHAR
);
2318 RtlCreateUnicodeStringFromAsciiz(
2319 OUT PUNICODE_STRING Destination
,
2322 ANSI_STRING AnsiString
;
2325 RtlInitAnsiString(&AnsiString
, Source
);
2327 Status
= RtlAnsiStringToUnicodeString(Destination
,
2331 return NT_SUCCESS(Status
);
2338 * Dest is never '\0' terminated because it may be equal to src, and src
2339 * might not be '\0' terminated.
2340 * Dest->Length is only set upon success.
2344 RtlDowncaseUnicodeString(
2345 IN OUT PUNICODE_STRING UniDest
,
2346 IN PCUNICODE_STRING UniSource
,
2347 IN BOOLEAN AllocateDestinationString
)
2353 if (AllocateDestinationString
)
2355 UniDest
->MaximumLength
= UniSource
->Length
;
2356 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2357 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2359 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2361 return STATUS_BUFFER_OVERFLOW
;
2364 UniDest
->Length
= UniSource
->Length
;
2365 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2367 for (i
= 0 ; i
< StopGap
; i
++)
2369 if (UniSource
->Buffer
[i
] < L
'A')
2371 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2373 else if (UniSource
->Buffer
[i
] <= L
'Z')
2375 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2379 UniDest
->Buffer
[i
] = RtlpDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2383 return STATUS_SUCCESS
;
2390 * if src is NULL dest is unchanged.
2391 * dest is '\0' terminated when the MaximumLength allowes it.
2392 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2396 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2404 UNICODE_STRING UnicodeSource
;
2406 RtlInitUnicodeString(&UnicodeSource
, Source
);
2407 Length
= UnicodeSource
.Length
;
2409 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2411 return STATUS_BUFFER_TOO_SMALL
;
2414 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2415 RtlMoveMemory(DestBuffer
, Source
, Length
);
2416 Destination
->Length
+= Length
;
2418 /* append terminating '\0' if enough space */
2419 if(Destination
->MaximumLength
> Destination
->Length
)
2421 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2425 return STATUS_SUCCESS
;
2432 * if src is NULL dest is unchanged.
2433 * dest is never '\0' terminated.
2437 RtlAppendAsciizToString(
2438 IN OUT PSTRING Destination
,
2445 Size
= strlen(Source
);
2447 if (Destination
->Length
+ Size
> Destination
->MaximumLength
)
2449 return STATUS_BUFFER_TOO_SMALL
;
2452 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Size
);
2453 Destination
->Length
+= (USHORT
)Size
;
2456 return STATUS_SUCCESS
;
2464 RtlUpperString(PSTRING DestinationString
,
2465 const STRING
*SourceString
)
2470 Length
= min(SourceString
->Length
,
2471 DestinationString
->MaximumLength
);
2473 Src
= SourceString
->Buffer
;
2474 Dest
= DestinationString
->Buffer
;
2475 DestinationString
->Length
= Length
;
2479 *Dest
++ = RtlUpperChar(*Src
++);
2488 * See RtlpDuplicateUnicodeString
2492 RtlDuplicateUnicodeString(
2494 IN PCUNICODE_STRING SourceString
,
2495 OUT PUNICODE_STRING DestinationString
)
2499 if (SourceString
== NULL
|| DestinationString
== NULL
||
2500 SourceString
->Length
> SourceString
->MaximumLength
||
2501 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2502 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4)
2504 return STATUS_INVALID_PARAMETER
;
2508 if ((SourceString
->Length
== 0) &&
2509 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2510 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2512 DestinationString
->Length
= 0;
2513 DestinationString
->MaximumLength
= 0;
2514 DestinationString
->Buffer
= NULL
;
2518 UINT DestMaxLength
= SourceString
->Length
;
2520 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2521 DestMaxLength
+= sizeof(UNICODE_NULL
);
2523 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2525 if (DestinationString
->Buffer
== NULL
)
2526 return STATUS_NO_MEMORY
;
2528 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2529 DestinationString
->Length
= SourceString
->Length
;
2530 DestinationString
->MaximumLength
= DestMaxLength
;
2532 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2533 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2536 return STATUS_SUCCESS
;
2544 RtlValidateUnicodeString(IN ULONG Flags
,
2545 IN PCUNICODE_STRING UnicodeString
)
2547 /* currently no flags are supported! */
2551 ((UnicodeString
== NULL
) ||
2552 ((UnicodeString
->Length
!= 0) &&
2553 (UnicodeString
->Buffer
!= NULL
) &&
2554 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2555 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2556 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2558 /* a NULL pointer as a unicode string is considered to be a valid unicode
2560 return STATUS_SUCCESS
;
2564 return STATUS_INVALID_PARAMETER
;
2573 RtlpEnsureBufferSize(
2575 IN OUT PRTL_BUFFER Buffer
,
2576 IN SIZE_T RequiredSize
)
2580 /* Parameter checks */
2581 if (Flags
& ~RTL_SKIP_BUFFER_COPY
)
2582 return STATUS_INVALID_PARAMETER
;
2584 return STATUS_INVALID_PARAMETER
;
2587 * We don't need to grow the buffer if its size
2588 * is already larger than the required size.
2590 if (Buffer
->Size
>= RequiredSize
)
2591 return STATUS_SUCCESS
;
2594 * When we are using the static buffer as our buffer, we don't need
2595 * to grow it if its size is already larger than the required size.
2596 * In this case, just keep it but update the current buffer size to
2597 * the one requested.
2598 * (But NEVER EVER modify the size of the static buffer!!)
2599 * Otherwise, we'll need to create a new buffer and use this one instead.
2601 if ( (Buffer
->Buffer
== Buffer
->StaticBuffer
) &&
2602 (Buffer
->StaticSize
>= RequiredSize
) )
2604 Buffer
->Size
= RequiredSize
;
2605 return STATUS_SUCCESS
;
2608 /* The buffer we are using is not large enough, try to create a bigger one */
2609 NewBuffer
= RtlpAllocateStringMemory(RequiredSize
, TAG_USTR
);
2610 if (NewBuffer
== NULL
)
2611 return STATUS_NO_MEMORY
;
2613 /* Copy the original content if needed */
2614 if (!(Flags
& RTL_SKIP_BUFFER_COPY
))
2616 RtlMoveMemory(NewBuffer
, Buffer
->Buffer
, Buffer
->Size
);
2619 /* Free the original buffer only if it's not the static buffer */
2620 if (Buffer
->Buffer
!= Buffer
->StaticBuffer
)
2622 RtlpFreeStringMemory(Buffer
->Buffer
, TAG_USTR
);
2625 /* Update the members */
2626 Buffer
->Buffer
= NewBuffer
;
2627 Buffer
->Size
= RequiredSize
;
2630 return STATUS_SUCCESS
;
2635 RtlpIsCharInUnicodeString(
2637 IN PCUNICODE_STRING MatchString
,
2638 IN BOOLEAN CaseInSensitive
)
2642 if (CaseInSensitive
)
2643 Char
= RtlpUpcaseUnicodeChar(Char
);
2645 for (i
= 0; i
< MatchString
->Length
/ sizeof(WCHAR
); i
++)
2647 WCHAR OtherChar
= MatchString
->Buffer
[i
];
2648 if (CaseInSensitive
)
2649 OtherChar
= RtlpUpcaseUnicodeChar(OtherChar
);
2651 if (Char
== OtherChar
)
2663 RtlFindCharInUnicodeString(
2665 IN PCUNICODE_STRING SearchString
,
2666 IN PCUNICODE_STRING MatchString
,
2667 OUT PUSHORT Position
)
2670 const BOOLEAN WantToFind
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
) == 0;
2671 const BOOLEAN CaseInSensitive
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
) != 0;
2674 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2675 Flags
, SearchString
, MatchString
, Position
);
2677 /* Parameter checks */
2678 if (Position
== NULL
)
2679 return STATUS_INVALID_PARAMETER
;
2683 if (Flags
& ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
|
2684 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
|
2685 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
))
2686 return STATUS_INVALID_PARAMETER
;
2689 Length
= SearchString
->Length
/ sizeof(WCHAR
);
2690 if (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
)
2692 for (i
= Length
- 1; (SHORT
)i
>= 0; i
--)
2694 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2695 if (Found
== WantToFind
)
2697 *Position
= i
* sizeof(WCHAR
);
2698 return STATUS_SUCCESS
;
2704 for (i
= 0; i
< Length
; i
++)
2706 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2707 if (Found
== WantToFind
)
2709 *Position
= (i
+ 1) * sizeof(WCHAR
);
2710 return STATUS_SUCCESS
;
2715 return STATUS_NOT_FOUND
;
2722 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2723 * Convert is to an uppercase oem string and check for unmapped characters.
2724 * Then convert the oem string back to an unicode string.
2728 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
, PUNICODE_STRING DnsHostName
, BOOLEAN AllocateComputerNameString
)
2732 ULONG ComputerNameLength
;
2733 ULONG ComputerNameOemNLength
;
2734 OEM_STRING ComputerNameOem
;
2735 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2737 Status
= STATUS_INVALID_COMPUTER_NAME
;
2738 ComputerNameLength
= DnsHostName
->Length
;
2740 /* find the first dot in the dns host name */
2741 for (Length
= 0; Length
< DnsHostName
->Length
/ sizeof(WCHAR
); Length
++)
2743 if (DnsHostName
->Buffer
[Length
] == L
'.')
2745 /* dot found, so set the length for the oem translation */
2746 ComputerNameLength
= Length
* sizeof(WCHAR
);
2751 /* the computername must have one character */
2752 if (ComputerNameLength
> 0)
2754 ComputerNameOemNLength
= 0;
2755 /* convert to oem string and use uppercase letters */
2756 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2757 MAX_COMPUTERNAME_LENGTH
,
2758 &ComputerNameOemNLength
,
2759 DnsHostName
->Buffer
,
2760 ComputerNameLength
);
2762 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2763 have MAX_COMPUTERNAME_LENGTH characters */
2764 if ((Status
== STATUS_SUCCESS
) ||
2765 (Status
== STATUS_BUFFER_OVERFLOW
))
2767 /* set the termination for the oem string */
2768 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2769 /* set status for the case the next function failed */
2770 Status
= STATUS_INVALID_COMPUTER_NAME
;
2771 /* fillup the oem string structure with the converted computername
2772 and check it for unmapped characters */
2773 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2774 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2775 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2777 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
))
2779 /* no unmapped character so convert it back to an unicode string */
2780 Status
= RtlOemStringToUnicodeString(ComputerName
,
2782 AllocateComputerNameString
);