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
;
32 /* FUNCTIONS *****************************************************************/
36 RtlMultiAppendUnicodeStringBuffer(IN PVOID Unknown
,
41 return STATUS_NOT_IMPLEMENTED
;
49 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR
*AnsiChar
)
53 WCHAR UnicodeChar
= L
' ';
58 Size
= (NlsLeadByteInfo
[**AnsiChar
] == 0) ? 1 : 2;
62 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
66 Status
= RtlMultiByteToUnicodeN(&UnicodeChar
,
72 if (!NT_SUCCESS(Status
))
85 * This function always writes a terminating '\0'.
86 * If the dest buffer is too small a partial copy is NOT performed!
90 RtlAnsiStringToUnicodeString(
91 IN OUT PUNICODE_STRING UniDest
,
92 IN PANSI_STRING AnsiSource
,
93 IN BOOLEAN AllocateDestinationString
)
101 if (NlsMbCodePageTag
== FALSE
)
103 Length
= AnsiSource
->Length
* 2 + sizeof(WCHAR
);
107 Length
= RtlxAnsiStringToUnicodeSize(AnsiSource
);
109 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
110 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
112 if (AllocateDestinationString
)
114 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
115 UniDest
->MaximumLength
= (USHORT
)Length
;
116 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
118 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
120 return STATUS_BUFFER_OVERFLOW
;
123 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
124 ASSERT(!(UniDest
->MaximumLength
& 1) && UniDest
->Length
<= UniDest
->MaximumLength
);
126 Status
= RtlMultiByteToUnicodeN(UniDest
->Buffer
,
132 if (!NT_SUCCESS(Status
))
134 if (AllocateDestinationString
)
136 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
137 UniDest
->Buffer
= NULL
;
143 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
151 * The calculated size in bytes including nullterm.
155 RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString
)
160 /* Convert from Mb String to Unicode Size */
161 RtlMultiByteToUnicodeSize(&Size
,
165 /* Return the size plus the null-char */
166 return(Size
+ sizeof(WCHAR
));
173 * If src->length is zero dest is unchanged.
174 * Dest is never nullterminated.
178 RtlAppendStringToString(IN PSTRING Destination
,
179 IN
const STRING
*Source
)
181 USHORT SourceLength
= Source
->Length
;
185 if (Destination
->Length
+ SourceLength
> Destination
->MaximumLength
)
187 return STATUS_BUFFER_TOO_SMALL
;
190 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
],
194 Destination
->Length
+= SourceLength
;
197 return STATUS_SUCCESS
;
204 * If src->length is zero dest is unchanged.
205 * Dest is nullterminated when the MaximumLength allowes it.
206 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
210 RtlAppendUnicodeStringToString(
211 IN OUT PUNICODE_STRING Destination
,
212 IN PCUNICODE_STRING Source
)
214 USHORT SourceLength
= Source
->Length
;
215 PWCHAR Buffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
219 if ((SourceLength
+ Destination
->Length
) > Destination
->MaximumLength
)
221 return STATUS_BUFFER_TOO_SMALL
;
224 RtlMoveMemory(Buffer
, Source
->Buffer
, SourceLength
);
225 Destination
->Length
+= SourceLength
;
227 /* append terminating '\0' if enough space */
228 if (Destination
->MaximumLength
> Destination
->Length
)
230 Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
234 return STATUS_SUCCESS
;
237 /**************************************************************************
238 * RtlCharToInteger (NTDLL.@)
240 * Converts a character string into its integer equivalent.
243 * Success: STATUS_SUCCESS. value contains the converted number
244 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
245 * STATUS_ACCESS_VIOLATION, if value is NULL.
248 * For base 0 it uses 10 as base and the string should be in the format
249 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
250 * For other bases the string should be in the format
251 * "{whitespace} [+|-] {digits}".
252 * No check is made for value overflow, only the lower 32 bits are assigned.
253 * If str is NULL it crashes, as the native function does.
256 * This function does not read garbage behind '\0' as the native version does.
261 PCSZ str
, /* [I] '\0' terminated single-byte string containing a number */
262 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
263 PULONG value
) /* [O] Destination for the converted value */
267 ULONG RunningTotal
= 0;
270 /* skip leading whitespaces */
271 while (*str
!= '\0' && *str
<= ' ') str
++;
278 else if (*str
== '-')
284 /* base = 0 means autobase */
296 else if (str
[1] == 'o')
301 else if (str
[1] == 'x')
308 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
310 return STATUS_INVALID_PARAMETER
;
313 if (value
== NULL
) return STATUS_ACCESS_VIOLATION
;
319 if (chCurrent
>= '0' && chCurrent
<= '9')
321 digit
= chCurrent
- '0';
323 else if (chCurrent
>= 'A' && chCurrent
<= 'Z')
325 digit
= chCurrent
- 'A' + 10;
327 else if (chCurrent
>= 'a' && chCurrent
<= 'z')
329 digit
= chCurrent
- 'a' + 10;
336 if (digit
< 0 || digit
>= (int)base
) break;
338 RunningTotal
= RunningTotal
* base
+ digit
;
342 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
343 return STATUS_SUCCESS
;
354 IN BOOLEAN CaseInsensitive
)
360 len
= min(s1
->Length
, s2
->Length
);
366 while (!ret
&& len
--)
367 ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
371 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
374 if (!ret
) ret
= s1
->Length
- s2
->Length
;
383 * TRUE if strings are equal.
390 IN BOOLEAN CaseInsensitive
)
392 if (s1
->Length
!= s2
->Length
) return FALSE
;
393 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
400 * TRUE if strings are equal.
404 RtlEqualUnicodeString(
405 IN CONST UNICODE_STRING
*s1
,
406 IN CONST UNICODE_STRING
*s2
,
407 IN BOOLEAN CaseInsensitive
)
409 if (s1
->Length
!= s2
->Length
) return FALSE
;
410 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
418 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
422 if (AnsiString
->Buffer
)
424 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
425 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
434 RtlFreeOemString(IN POEM_STRING OemString
)
438 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
446 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
450 if (UnicodeString
->Buffer
)
452 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
453 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
462 * Check the OEM string to match the Unicode string.
464 * Functions which convert Unicode strings to OEM strings will set a
465 * DefaultChar from the OEM codepage when the characters are unknown.
466 * So check it against the Unicode string and return false when the
467 * Unicode string does not contain a TransDefaultChar.
471 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
472 IN POEM_STRING OemString
)
476 if (NlsMbOemCodePageTag
== FALSE
)
478 /* single-byte code page */
479 /* Go through all characters of a string */
480 while (i
< OemString
->Length
)
482 /* Check if it got translated into a default char,
483 * but source char wasn't a default char equivalent
485 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
486 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
488 /* Yes, it means unmappable characters were found */
492 /* Move to the next char */
496 /* All chars were translated successfuly */
501 /* multibyte code page */
513 RtlIsValidOemCharacter(IN PWCHAR Char
)
519 /* If multi-byte code page present */
520 if (NlsMbOemCodePageTag
)
524 OemChar
= NlsUnicodeToOemTable
[*Char
];
526 /* If character has Lead Byte */
527 if (NlsOemLeadByteInfo
[HIBYTE(OemChar
)])
528 Offset
= NlsOemLeadByteInfo
[HIBYTE(OemChar
)];
530 Index
= LOBYTE(OemChar
) + Offset
;
534 Index
= NlsUnicodeToOemTable
[*Char
];
537 /* Receive Unicode character from the table */
538 UnicodeChar
= RtlUpcaseUnicodeChar(NlsOemToUnicodeTable
[Index
]);
540 /* Receive OEM character from the table */
541 OemChar
= NlsUnicodeToOemTable
[UnicodeChar
];
543 /* Not valid character, failed */
544 if (OemChar
== NlsOemDefaultChar
)
556 * If source is NULL the length of source is assumed to be 0.
560 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
561 IN PCSZ SourceString
)
567 Size
= strlen(SourceString
);
568 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) Size
= MAXUSHORT
- sizeof(CHAR
);
569 DestinationString
->Length
= (USHORT
)Size
;
570 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
574 DestinationString
->Length
= 0;
575 DestinationString
->MaximumLength
= 0;
578 DestinationString
->Buffer
= (PCHAR
)SourceString
;
583 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
584 IN PCSZ SourceString
)
590 Size
= strlen(SourceString
);
591 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) return STATUS_NAME_TOO_LONG
;
592 DestinationString
->Length
= (USHORT
)Size
;
593 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
597 DestinationString
->Length
= 0;
598 DestinationString
->MaximumLength
= 0;
601 DestinationString
->Buffer
= (PCHAR
)SourceString
;
602 return STATUS_SUCCESS
;
609 * If source is NULL the length of source is assumed to be 0.
614 IN OUT PSTRING DestinationString
,
615 IN PCSZ SourceString
)
617 RtlInitAnsiString(DestinationString
, SourceString
);
624 * If source is NULL the length of source is assumed to be 0.
628 RtlInitUnicodeString(
629 IN OUT PUNICODE_STRING DestinationString
,
630 IN PCWSTR SourceString
)
633 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(UNICODE_NULL
); // an even number
637 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
638 __analysis_assume(Size
<= MaxSize
);
642 DestinationString
->Length
= (USHORT
)Size
;
643 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(UNICODE_NULL
);
647 DestinationString
->Length
= 0;
648 DestinationString
->MaximumLength
= 0;
651 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
659 RtlInitUnicodeStringEx(
660 OUT PUNICODE_STRING DestinationString
,
661 IN PCWSTR SourceString
)
664 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(WCHAR
); // an even number
668 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
669 if (Size
> MaxSize
) return STATUS_NAME_TOO_LONG
;
670 DestinationString
->Length
= (USHORT
)Size
;
671 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(WCHAR
);
675 DestinationString
->Length
= 0;
676 DestinationString
->MaximumLength
= 0;
679 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
680 return STATUS_SUCCESS
;
687 * Writes at most length characters to the string str.
688 * Str is nullterminated when length allowes it.
689 * When str fits exactly in length characters the nullterm is ommitted.
691 NTSTATUS NTAPI
RtlIntegerToChar(
692 ULONG value
, /* [I] Value to be converted */
693 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
694 ULONG length
, /* [I] Length of the str buffer in bytes */
695 PCHAR str
) /* [O] Destination for the converted value */
706 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
708 return STATUS_INVALID_PARAMETER
;
717 digit
= (CHAR
)(value
% base
);
718 value
= value
/ base
;
726 *pos
= 'A' + digit
- 10;
731 len
= &buffer
[32] - pos
;
735 return STATUS_BUFFER_OVERFLOW
;
737 else if (str
== NULL
)
739 return STATUS_ACCESS_VIOLATION
;
741 else if (len
== length
)
743 memcpy(str
, pos
, len
);
747 memcpy(str
, pos
, len
+ 1);
750 return STATUS_SUCCESS
;
760 IN ULONG Base OPTIONAL
,
761 IN ULONG Length OPTIONAL
,
762 IN OUT LPWSTR String
)
773 if (Radix
== 0) Radix
= 10;
775 if ((Radix
!= 2) && (Radix
!= 8) &&
776 (Radix
!= 10) && (Radix
!= 16))
778 return STATUS_INVALID_PARAMETER
;
783 while (v
|| tp
== temp
)
788 if (i
< 10) *tp
= (WCHAR
)(i
+ L
'0');
789 else *tp
= (WCHAR
)(i
+ L
'a' - 10);
794 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
796 return STATUS_BUFFER_TOO_SMALL
;
801 while (tp
> temp
) *sp
++ = *--tp
;
805 return STATUS_SUCCESS
;
813 RtlIntegerToUnicodeString(
815 IN ULONG Base OPTIONAL
,
816 IN OUT PUNICODE_STRING String
)
818 ANSI_STRING AnsiString
;
822 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
823 if (NT_SUCCESS(Status
))
825 AnsiString
.Buffer
= Buffer
;
826 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
827 AnsiString
.MaximumLength
= sizeof(Buffer
);
829 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
840 RtlInt64ToUnicodeString (
842 IN ULONG Base OPTIONAL
,
843 IN OUT PUNICODE_STRING String
)
845 LARGE_INTEGER LargeInt
;
846 ANSI_STRING AnsiString
;
850 LargeInt
.QuadPart
= Value
;
852 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
853 if (NT_SUCCESS(Status
))
855 AnsiString
.Buffer
= Buffer
;
856 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
857 AnsiString
.MaximumLength
= sizeof(Buffer
);
859 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
869 * TRUE if String2 contains String1 as a prefix.
874 const STRING
*String1
,
875 const STRING
*String2
,
876 BOOLEAN CaseInsensitive
)
882 if (String2
->Length
< String1
->Length
)
885 NumChars
= String1
->Length
;
886 pc1
= String1
->Buffer
;
887 pc2
= String2
->Buffer
;
895 if (RtlUpperChar(*pc1
++) != RtlUpperChar(*pc2
++))
903 if (*pc1
++ != *pc2
++)
918 * TRUE if String2 contains String1 as a prefix.
922 RtlPrefixUnicodeString(
923 PCUNICODE_STRING String1
,
924 PCUNICODE_STRING String2
,
925 BOOLEAN CaseInsensitive
)
931 if (String2
->Length
< String1
->Length
)
934 NumChars
= String1
->Length
/ sizeof(WCHAR
);
935 pc1
= String1
->Buffer
;
936 pc2
= String2
->Buffer
;
944 if (RtlUpcaseUnicodeChar(*pc1
++) !=
945 RtlUpcaseUnicodeChar(*pc2
++))
953 if (*pc1
++ != *pc2
++)
969 RtlUnicodeStringToInteger(
970 const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
971 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
972 ULONG
*value
) /* [O] Destination for the converted value */
974 LPWSTR lpwstr
= str
->Buffer
;
975 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
978 ULONG RunningTotal
= 0;
981 while (CharsRemaining
>= 1 && *lpwstr
<= ' ')
987 if (CharsRemaining
>= 1)
994 else if (*lpwstr
== '-')
1006 if (CharsRemaining
>= 2 && lpwstr
[0] == '0')
1008 if (lpwstr
[1] == 'b')
1011 CharsRemaining
-= 2;
1014 else if (lpwstr
[1] == 'o')
1017 CharsRemaining
-= 2;
1020 else if (lpwstr
[1] == 'x')
1023 CharsRemaining
-= 2;
1028 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
1030 return STATUS_INVALID_PARAMETER
;
1035 return STATUS_ACCESS_VIOLATION
;
1038 while (CharsRemaining
>= 1)
1040 wchCurrent
= *lpwstr
;
1042 if (wchCurrent
>= '0' && wchCurrent
<= '9')
1044 digit
= wchCurrent
- '0';
1046 else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z')
1048 digit
= wchCurrent
- 'A' + 10;
1050 else if (wchCurrent
>= 'a' && wchCurrent
<= 'z')
1052 digit
= wchCurrent
- 'a' + 10;
1059 if (digit
< 0 || (ULONG
)digit
>= base
) break;
1061 RunningTotal
= RunningTotal
* base
+ digit
;
1066 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
1067 return STATUS_SUCCESS
;
1074 * Bytes necessary for the conversion including nullterm.
1078 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
1082 /* Convert the Unicode String to Mb Size */
1083 RtlUnicodeToMultiByteSize(&Size
,
1084 UnicodeString
->Buffer
,
1085 UnicodeString
->Length
);
1087 /* Return the size + the null char */
1088 return (Size
+ sizeof(CHAR
));
1095 * This function always writes a terminating '\0'.
1096 * It performs a partial copy if ansi is too small.
1100 RtlUnicodeStringToAnsiString(
1101 IN OUT PANSI_STRING AnsiDest
,
1102 IN PCUNICODE_STRING UniSource
,
1103 IN BOOLEAN AllocateDestinationString
)
1105 NTSTATUS Status
= STATUS_SUCCESS
;
1106 NTSTATUS RealStatus
;
1112 ASSERT(!(UniSource
->Length
& 1));
1114 if (NlsMbCodePageTag
== FALSE
)
1116 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
1120 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
1123 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1125 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1127 if (AllocateDestinationString
)
1129 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1130 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1132 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1134 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1136 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1138 Status
= STATUS_BUFFER_OVERFLOW
;
1139 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1142 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1148 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1150 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1154 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1162 * This function always writes a terminating '\0'.
1163 * Does NOT perform a partial copy if unicode is too small!
1167 RtlOemStringToUnicodeString(
1168 IN OUT PUNICODE_STRING UniDest
,
1169 IN PCOEM_STRING OemSource
,
1170 IN BOOLEAN AllocateDestinationString
)
1178 Length
= RtlOemStringToUnicodeSize(OemSource
);
1180 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1182 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1184 if (AllocateDestinationString
)
1186 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1187 UniDest
->MaximumLength
= (USHORT
)Length
;
1189 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1191 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1193 return STATUS_BUFFER_OVERFLOW
;
1196 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1202 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1204 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1205 UniDest
->Buffer
= NULL
;
1209 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1217 * This function always '\0' terminates the string returned.
1221 RtlUnicodeStringToOemString(
1222 IN OUT POEM_STRING OemDest
,
1223 IN PCUNICODE_STRING UniSource
,
1224 IN BOOLEAN AllocateDestinationString
)
1232 Length
= RtlUnicodeStringToOemSize(UniSource
);
1234 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1236 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1238 if (AllocateDestinationString
)
1240 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1241 OemDest
->MaximumLength
= (USHORT
)Length
;
1243 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1245 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1247 return STATUS_BUFFER_OVERFLOW
;
1250 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1256 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1258 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1259 OemDest
->Buffer
= NULL
;
1263 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1267 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1273 * The length of the string if all tests were passed, 0 otherwise.
1277 RtlIsTextUnicode(CONST VOID
* buf
, INT len
, INT
* pf
)
1279 static const WCHAR std_control_chars
[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1280 static const WCHAR byterev_control_chars
[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1281 const WCHAR
*s
= buf
;
1283 unsigned int flags
= MAXULONG
, out_flags
= 0;
1284 UCHAR last_lo_byte
= 0;
1285 UCHAR last_hi_byte
= 0;
1286 ULONG hi_byte_diff
= 0;
1287 ULONG lo_byte_diff
= 0;
1289 ULONG lead_byte
= 0;
1291 if (len
< sizeof(WCHAR
))
1293 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1303 * Apply various tests to the text string. According to the
1304 * docs, each test "passed" sets the corresponding flag in
1305 * the output flags. But some of the tests are mutually
1306 * exclusive, so I don't see how you could pass all tests ...
1309 /* Check for an odd length ... pass if even. */
1310 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1312 if (((char *)buf
)[len
- 1] == 0)
1313 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1315 len
/= sizeof(WCHAR
);
1317 /* Windows only checks the first 256 characters */
1318 if (len
> 256) len
= 256;
1320 /* Check for the special byte order unicode marks. */
1321 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1322 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1324 for (i
= 0; i
< len
; i
++)
1326 UCHAR lo_byte
= LOBYTE(s
[i
]);
1327 UCHAR hi_byte
= HIBYTE(s
[i
]);
1329 lo_byte_diff
+= max(lo_byte
, last_lo_byte
) - min(lo_byte
, last_lo_byte
);
1330 hi_byte_diff
+= max(hi_byte
, last_hi_byte
) - min(hi_byte
, last_hi_byte
);
1332 last_lo_byte
= lo_byte
;
1333 last_hi_byte
= hi_byte
;
1337 case 0xFFFE: /* Reverse BOM */
1339 case 0x0A0D: /* ASCII CRLF (packed into one word) */
1340 case 0xFFFF: /* Unicode 0xFFFF */
1341 out_flags
|= IS_TEXT_UNICODE_ILLEGAL_CHARS
;
1346 if (NlsMbCodePageTag
)
1348 for (i
= 0; i
< len
; i
++)
1350 if (NlsLeadByteInfo
[s
[i
]])
1359 weight
= (len
/ 2) - 1;
1361 if (lead_byte
< (weight
/ 3))
1363 else if (lead_byte
< ((weight
* 2) / 3))
1368 if (*pf
&& (*pf
& IS_TEXT_UNICODE_DBCS_LEADBYTE
))
1369 out_flags
|= IS_TEXT_UNICODE_DBCS_LEADBYTE
;
1373 if (lo_byte_diff
< 127 && !hi_byte_diff
)
1375 out_flags
|= IS_TEXT_UNICODE_ASCII16
;
1378 if (hi_byte_diff
&& !lo_byte_diff
)
1380 out_flags
|= IS_TEXT_UNICODE_REVERSE_ASCII16
;
1383 if ((weight
* lo_byte_diff
) < hi_byte_diff
)
1385 out_flags
|= IS_TEXT_UNICODE_REVERSE_STATISTICS
;
1388 /* apply some statistical analysis */
1389 if ((flags
& IS_TEXT_UNICODE_STATISTICS
) &&
1390 ((weight
* hi_byte_diff
) < lo_byte_diff
))
1392 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1395 /* Check for unicode NULL chars */
1396 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1398 for (i
= 0; i
< len
; i
++)
1400 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1402 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1408 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1410 for (i
= 0; i
< len
; i
++)
1412 if (strchrW(std_control_chars
, s
[i
]))
1414 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1420 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1422 for (i
= 0; i
< len
; i
++)
1424 if (strchrW(byterev_control_chars
, s
[i
]))
1426 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1438 /* check for flags that indicate it's definitely not valid Unicode */
1439 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1441 /* now check for invalid ASCII, and assume Unicode if so */
1442 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1444 /* now check for Unicode flags */
1445 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1456 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1457 * A partial copy is NOT performed if the dest buffer is too small!
1461 RtlOemStringToCountedUnicodeString(
1462 IN OUT PUNICODE_STRING UniDest
,
1463 IN PCOEM_STRING OemSource
,
1464 IN BOOLEAN AllocateDestinationString
)
1472 /* Calculate size of the string */
1473 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1475 /* If it's 0 then zero out dest string and return */
1478 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1479 return STATUS_SUCCESS
;
1482 /* Check if length is a sane value */
1483 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1485 /* Store it in dest string */
1486 UniDest
->Length
= (USHORT
)Length
;
1488 /* If we're asked to alloc the string - do so */
1489 if (AllocateDestinationString
)
1491 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1492 UniDest
->MaximumLength
= (USHORT
)Length
;
1494 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1496 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1498 return STATUS_BUFFER_OVERFLOW
;
1501 /* Do the conversion */
1502 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1508 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1510 /* Conversion failed, free dest string and return status code */
1511 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1512 UniDest
->Buffer
= NULL
;
1516 return STATUS_SUCCESS
;
1523 * TRUE if the names are equal, FALSE if not
1526 * The comparison is case insensitive.
1530 RtlEqualComputerName(
1531 IN PUNICODE_STRING ComputerName1
,
1532 IN PUNICODE_STRING ComputerName2
)
1534 OEM_STRING OemString1
;
1535 OEM_STRING OemString2
;
1536 BOOLEAN Result
= FALSE
;
1538 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1542 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1546 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1547 RtlFreeOemString(&OemString2
);
1550 RtlFreeOemString(&OemString1
);
1560 * TRUE if the names are equal, FALSE if not
1563 * The comparison is case insensitive.
1567 RtlEqualDomainName (
1568 IN PUNICODE_STRING DomainName1
,
1569 IN PUNICODE_STRING DomainName2
)
1571 return RtlEqualComputerName(DomainName1
, DomainName2
);
1577 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1579 * Convert a string representation of a GUID into a GUID.
1582 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1583 * guid [O] Destination for the converted GUID
1586 * Success: STATUS_SUCCESS. guid contains the converted value.
1587 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1590 * See RtlStringFromGUID.
1595 IN UNICODE_STRING
*str
,
1599 const WCHAR
*lpszCLSID
= str
->Buffer
;
1600 BYTE
* lpOut
= (BYTE
*)guid
;
1602 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1604 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1605 * to memory: DWORD... WORD WORD BYTES............
1612 if (*lpszCLSID
!= '{')
1613 return STATUS_INVALID_PARAMETER
;
1620 if (*lpszCLSID
!= '-')
1621 return STATUS_INVALID_PARAMETER
;
1625 if (*lpszCLSID
!= '}')
1626 return STATUS_INVALID_PARAMETER
;
1632 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1635 /* Read two hex digits as a byte value */
1636 if (ch
>= '0' && ch
<= '9')
1638 else if (ch
>= 'a' && ch
<= 'f')
1640 else if (ch
>= 'A' && ch
<= 'F')
1643 return STATUS_INVALID_PARAMETER
;
1645 if (ch2
>= '0' && ch2
<= '9')
1647 else if (ch2
>= 'a' && ch2
<= 'f')
1648 ch2
= ch2
- 'a' + 10;
1649 else if (ch2
>= 'A' && ch2
<= 'F')
1650 ch2
= ch2
- 'A' + 10;
1652 return STATUS_INVALID_PARAMETER
;
1654 byte
= ch
<< 4 | ch2
;
1658 #ifndef WORDS_BIGENDIAN
1659 /* For Big Endian machines, we store the data such that the
1660 * dword/word members can be read as DWORDS and WORDS correctly. */
1693 lpszCLSID
++; /* Skip 2nd character of byte */
1702 return STATUS_SUCCESS
;
1710 RtlEraseUnicodeString(
1711 IN PUNICODE_STRING String
)
1713 if (String
->Buffer
&& String
->MaximumLength
)
1715 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1725 RtlHashUnicodeString(
1726 IN CONST UNICODE_STRING
*String
,
1727 IN BOOLEAN CaseInSensitive
,
1728 IN ULONG HashAlgorithm
,
1729 OUT PULONG HashValue
)
1731 if (String
!= NULL
&& HashValue
!= NULL
)
1733 switch (HashAlgorithm
)
1735 case HASH_STRING_ALGORITHM_DEFAULT
:
1736 case HASH_STRING_ALGORITHM_X65599
:
1741 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1743 if (CaseInSensitive
)
1745 for (c
= String
->Buffer
; c
!= end
; c
++)
1747 /* only uppercase characters if they are 'a' ... 'z'! */
1748 *HashValue
= ((65599 * (*HashValue
)) +
1749 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1750 (*c
) - L
'a' + L
'A' : (*c
)));
1755 for (c
= String
->Buffer
; c
!= end
; c
++)
1757 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1761 return STATUS_SUCCESS
;
1766 return STATUS_INVALID_PARAMETER
;
1773 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1774 * Does a partial copy if the dest buffer is too small
1778 RtlUnicodeStringToCountedOemString(
1779 IN OUT POEM_STRING OemDest
,
1780 IN PUNICODE_STRING UniSource
,
1781 IN BOOLEAN AllocateDestinationString
)
1789 /* Calculate size of the string */
1790 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1792 /* If it's 0 then zero out dest string and return */
1795 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1796 return STATUS_SUCCESS
;
1799 /* Check if length is a sane value */
1800 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1802 /* Store it in dest string */
1803 OemDest
->Length
= (USHORT
)Length
;
1805 /* If we're asked to alloc the string - do so */
1806 if (AllocateDestinationString
)
1808 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1809 OemDest
->MaximumLength
= (USHORT
)Length
;
1810 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1812 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1814 return STATUS_BUFFER_OVERFLOW
;
1817 /* Do the conversion */
1818 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1824 /* Check for unmapped character */
1825 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1826 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1828 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1830 /* Conversion failed, free dest string and return status code */
1831 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1832 OemDest
->Buffer
= NULL
;
1844 RtlLargeIntegerToChar(
1845 IN PLARGE_INTEGER Value
,
1848 IN OUT PCHAR String
)
1850 ULONGLONG Val
= Value
->QuadPart
;
1856 if (Base
== 0) Base
= 10;
1858 if ((Base
!= 2) && (Base
!= 8) && (Base
!= 10) && (Base
!= 16))
1860 return STATUS_INVALID_PARAMETER
;
1869 Digit
= (CHAR
)(Val
% Base
);
1875 *Pos
= 'A' + Digit
- 10;
1879 Len
= &Buffer
[64] - Pos
;
1882 return STATUS_BUFFER_OVERFLOW
;
1884 /* If possible, add the 0 termination */
1888 /* Copy the string to the target using SEH */
1889 return RtlpSafeCopyMemory(String
, Pos
, Len
);
1896 * dest is never '\0' terminated because it may be equal to src, and src
1897 * might not be '\0' terminated. dest->Length is only set upon success.
1901 RtlUpcaseUnicodeString(
1902 IN OUT PUNICODE_STRING UniDest
,
1903 IN PCUNICODE_STRING UniSource
,
1904 IN BOOLEAN AllocateDestinationString
)
1910 if (AllocateDestinationString
)
1912 UniDest
->MaximumLength
= UniSource
->Length
;
1913 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1914 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1916 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1918 return STATUS_BUFFER_OVERFLOW
;
1921 j
= UniSource
->Length
/ sizeof(WCHAR
);
1923 for (i
= 0; i
< j
; i
++)
1925 UniDest
->Buffer
[i
] = RtlUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1928 UniDest
->Length
= UniSource
->Length
;
1929 return STATUS_SUCCESS
;
1936 * This function always writes a terminating '\0'.
1937 * It performs a partial copy if ansi is too small.
1941 RtlUpcaseUnicodeStringToAnsiString(
1942 IN OUT PANSI_STRING AnsiDest
,
1943 IN PUNICODE_STRING UniSource
,
1944 IN BOOLEAN AllocateDestinationString
)
1951 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1952 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1954 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1956 if (AllocateDestinationString
)
1958 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1959 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1960 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1962 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1964 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1967 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1973 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1975 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1976 AnsiDest
->Buffer
= NULL
;
1980 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1988 * This function always writes a terminating '\0'.
1989 * It performs a partial copy if ansi is too small.
1993 RtlUpcaseUnicodeStringToCountedOemString(
1994 IN OUT POEM_STRING OemDest
,
1995 IN PCUNICODE_STRING UniSource
,
1996 IN BOOLEAN AllocateDestinationString
)
2003 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
2007 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
2010 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
2012 OemDest
->Length
= (USHORT
)Length
;
2014 if (AllocateDestinationString
)
2016 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
2017 OemDest
->MaximumLength
= (USHORT
)Length
;
2018 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
2020 else if (OemDest
->Length
> OemDest
->MaximumLength
)
2022 return STATUS_BUFFER_OVERFLOW
;
2025 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2031 /* Check for unmapped characters */
2032 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2033 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2035 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2037 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2038 OemDest
->Buffer
= NULL
;
2048 * OEM string is always nullterminated
2049 * It performs a partial copy if oem is too small.
2053 RtlUpcaseUnicodeStringToOemString (
2054 IN OUT POEM_STRING OemDest
,
2055 IN PCUNICODE_STRING UniSource
,
2056 IN BOOLEAN AllocateDestinationString
)
2063 Length
= RtlUnicodeStringToOemSize(UniSource
);
2064 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
2066 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
2068 if (AllocateDestinationString
)
2070 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
2071 OemDest
->MaximumLength
= (USHORT
)Length
;
2072 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
2074 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
2076 return STATUS_BUFFER_OVERFLOW
;
2079 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2085 /* Check for unmapped characters */
2086 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2087 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2089 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2091 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2092 OemDest
->Buffer
= NULL
;
2096 OemDest
->Buffer
[Index
] = ANSI_NULL
;
2104 * Bytes calculated including nullterm
2108 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
2112 /* Convert the Mb String to Unicode Size */
2113 RtlMultiByteToUnicodeSize(&Size
,
2117 /* Return the size + null-char */
2118 return (Size
+ sizeof(WCHAR
));
2126 RtlStringFromGUID (IN REFGUID Guid
,
2127 OUT PUNICODE_STRING GuidString
)
2129 /* Setup the string */
2130 GuidString
->Length
= 38 * sizeof(WCHAR
);
2131 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
2132 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
2134 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
2136 /* Now format the GUID */
2137 swprintf(GuidString
->Buffer
,
2138 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2150 return STATUS_SUCCESS
;
2157 * Bytes calculated including nullterm
2161 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
2166 ASSERT(!(UnicodeString
->Length
& 1));
2168 /* Convert the Unicode String to Mb Size */
2169 RtlUnicodeToMultiByteSize(&Size
,
2170 UnicodeString
->Buffer
,
2171 UnicodeString
->Length
);
2173 /* Return the size + null-char */
2174 return (Size
+ sizeof(CHAR
));
2182 RtlCompareUnicodeString(
2183 IN PCUNICODE_STRING s1
,
2184 IN PCUNICODE_STRING s2
,
2185 IN BOOLEAN CaseInsensitive
)
2191 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2195 if (CaseInsensitive
)
2197 while (!ret
&& len
--) ret
= RtlUpcaseUnicodeChar(*p1
++) - RtlUpcaseUnicodeChar(*p2
++);
2201 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2204 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2215 IN OUT PSTRING DestinationString
,
2216 IN
const STRING
*SourceString OPTIONAL
)
2221 /* Check if there was no source given */
2224 /* Simply return an empty string */
2225 DestinationString
->Length
= 0;
2229 /* Choose the smallest length */
2230 SourceLength
= min(DestinationString
->MaximumLength
,
2231 SourceString
->Length
);
2234 DestinationString
->Length
= (USHORT
)SourceLength
;
2236 /* Save the pointers to each buffer */
2237 p1
= DestinationString
->Buffer
;
2238 p2
= SourceString
->Buffer
;
2240 /* Loop the buffer */
2241 while (SourceLength
)
2243 /* Copy the character and move on */
2255 RtlCopyUnicodeString(
2256 IN OUT PUNICODE_STRING DestinationString
,
2257 IN PCUNICODE_STRING SourceString
)
2261 if(SourceString
== NULL
)
2263 DestinationString
->Length
= 0;
2267 SourceLength
= min(DestinationString
->MaximumLength
,
2268 SourceString
->Length
);
2269 DestinationString
->Length
= (USHORT
)SourceLength
;
2271 RtlCopyMemory(DestinationString
->Buffer
,
2272 SourceString
->Buffer
,
2275 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2277 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2286 * Creates a nullterminated UNICODE_STRING
2290 RtlCreateUnicodeString(
2291 IN OUT PUNICODE_STRING UniDest
,
2297 Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2298 if (Size
> MAXUSHORT
) return FALSE
;
2300 UniDest
->Buffer
= RtlpAllocateStringMemory((ULONG
)Size
, TAG_USTR
);
2302 if (UniDest
->Buffer
== NULL
) return FALSE
;
2304 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
2305 UniDest
->MaximumLength
= (USHORT
)Size
;
2306 UniDest
->Length
= (USHORT
)Size
- sizeof (WCHAR
);
2316 RtlCreateUnicodeStringFromAsciiz(
2317 OUT PUNICODE_STRING Destination
,
2320 ANSI_STRING AnsiString
;
2323 RtlInitAnsiString(&AnsiString
, Source
);
2325 Status
= RtlAnsiStringToUnicodeString(Destination
,
2329 return NT_SUCCESS(Status
);
2336 * Dest is never '\0' terminated because it may be equal to src, and src
2337 * might not be '\0' terminated.
2338 * Dest->Length is only set upon success.
2342 RtlDowncaseUnicodeString(
2343 IN OUT PUNICODE_STRING UniDest
,
2344 IN PCUNICODE_STRING UniSource
,
2345 IN BOOLEAN AllocateDestinationString
)
2351 if (AllocateDestinationString
)
2353 UniDest
->MaximumLength
= UniSource
->Length
;
2354 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2355 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2357 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2359 return STATUS_BUFFER_OVERFLOW
;
2362 UniDest
->Length
= UniSource
->Length
;
2363 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2365 for (i
= 0 ; i
< StopGap
; i
++)
2367 if (UniSource
->Buffer
[i
] < L
'A')
2369 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2371 else if (UniSource
->Buffer
[i
] <= L
'Z')
2373 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2377 UniDest
->Buffer
[i
] = RtlDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2381 return STATUS_SUCCESS
;
2388 * if src is NULL dest is unchanged.
2389 * dest is '\0' terminated when the MaximumLength allowes it.
2390 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2394 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2402 UNICODE_STRING UnicodeSource
;
2404 RtlInitUnicodeString(&UnicodeSource
, Source
);
2405 Length
= UnicodeSource
.Length
;
2407 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2409 return STATUS_BUFFER_TOO_SMALL
;
2412 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2413 RtlMoveMemory(DestBuffer
, Source
, Length
);
2414 Destination
->Length
+= Length
;
2416 /* append terminating '\0' if enough space */
2417 if(Destination
->MaximumLength
> Destination
->Length
)
2419 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2423 return STATUS_SUCCESS
;
2430 * if src is NULL dest is unchanged.
2431 * dest is never '\0' terminated.
2435 RtlAppendAsciizToString(
2436 IN OUT PSTRING Destination
,
2443 Size
= strlen(Source
);
2445 if (Destination
->Length
+ Size
> Destination
->MaximumLength
)
2447 return STATUS_BUFFER_TOO_SMALL
;
2450 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Size
);
2451 Destination
->Length
+= (USHORT
)Size
;
2454 return STATUS_SUCCESS
;
2462 RtlUpperString(PSTRING DestinationString
,
2463 const STRING
*SourceString
)
2468 Length
= min(SourceString
->Length
,
2469 DestinationString
->MaximumLength
);
2471 Src
= SourceString
->Buffer
;
2472 Dest
= DestinationString
->Buffer
;
2473 DestinationString
->Length
= Length
;
2477 *Dest
++ = RtlUpperChar(*Src
++);
2486 * See RtlpDuplicateUnicodeString
2490 RtlDuplicateUnicodeString(
2492 IN PCUNICODE_STRING SourceString
,
2493 OUT PUNICODE_STRING DestinationString
)
2497 if (SourceString
== NULL
|| DestinationString
== NULL
||
2498 SourceString
->Length
> SourceString
->MaximumLength
||
2499 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2500 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4)
2502 return STATUS_INVALID_PARAMETER
;
2506 if ((SourceString
->Length
== 0) &&
2507 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2508 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2510 DestinationString
->Length
= 0;
2511 DestinationString
->MaximumLength
= 0;
2512 DestinationString
->Buffer
= NULL
;
2516 UINT DestMaxLength
= SourceString
->Length
;
2518 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2519 DestMaxLength
+= sizeof(UNICODE_NULL
);
2521 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2523 if (DestinationString
->Buffer
== NULL
)
2524 return STATUS_NO_MEMORY
;
2526 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2527 DestinationString
->Length
= SourceString
->Length
;
2528 DestinationString
->MaximumLength
= DestMaxLength
;
2530 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2531 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2534 return STATUS_SUCCESS
;
2542 RtlValidateUnicodeString(IN ULONG Flags
,
2543 IN PCUNICODE_STRING UnicodeString
)
2545 /* currently no flags are supported! */
2549 ((UnicodeString
== NULL
) ||
2550 ((UnicodeString
->Length
!= 0) &&
2551 (UnicodeString
->Buffer
!= NULL
) &&
2552 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2553 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2554 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2556 /* a NULL pointer as a unicode string is considered to be a valid unicode
2558 return STATUS_SUCCESS
;
2562 return STATUS_INVALID_PARAMETER
;
2571 RtlpEnsureBufferSize(ULONG Unknown1
, ULONG Unknown2
, ULONG Unknown3
)
2573 DPRINT1("RtlpEnsureBufferSize: stub\n");
2574 return STATUS_NOT_IMPLEMENTED
;
2579 RtlpIsCharInUnicodeString(
2581 IN PCUNICODE_STRING MatchString
,
2582 IN BOOLEAN CaseInSensitive
)
2586 if (CaseInSensitive
)
2587 Char
= RtlUpcaseUnicodeChar(Char
);
2589 for (i
= 0; i
< MatchString
->Length
/ sizeof(WCHAR
); i
++)
2591 WCHAR OtherChar
= MatchString
->Buffer
[i
];
2592 if (CaseInSensitive
)
2593 OtherChar
= RtlUpcaseUnicodeChar(OtherChar
);
2595 if (Char
== OtherChar
)
2607 RtlFindCharInUnicodeString(
2609 IN PCUNICODE_STRING SearchString
,
2610 IN PCUNICODE_STRING MatchString
,
2611 OUT PUSHORT Position
)
2614 const BOOLEAN WantToFind
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
) == 0;
2615 const BOOLEAN CaseInSensitive
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
) != 0;
2618 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2619 Flags
, SearchString
, MatchString
, Position
);
2621 /* Parameter checks */
2622 if (Position
== NULL
)
2623 return STATUS_INVALID_PARAMETER
;
2627 if (Flags
& ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
|
2628 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
|
2629 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
))
2630 return STATUS_INVALID_PARAMETER
;
2633 Length
= SearchString
->Length
/ sizeof(WCHAR
);
2634 if (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
)
2636 for (i
= Length
- 1; (SHORT
)i
>= 0; i
--)
2638 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2639 if (Found
== WantToFind
)
2641 *Position
= i
* sizeof(WCHAR
);
2642 return STATUS_SUCCESS
;
2648 for (i
= 0; i
< Length
; i
++)
2650 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2651 if (Found
== WantToFind
)
2653 *Position
= (i
+ 1) * sizeof(WCHAR
);
2654 return STATUS_SUCCESS
;
2659 return STATUS_NOT_FOUND
;
2666 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2667 * Convert is to an uppercase oem string and check for unmapped characters.
2668 * Then convert the oem string back to an unicode string.
2672 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
, PUNICODE_STRING DnsHostName
, BOOLEAN AllocateComputerNameString
)
2676 ULONG ComputerNameLength
;
2677 ULONG ComputerNameOemNLength
;
2678 OEM_STRING ComputerNameOem
;
2679 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2681 Status
= STATUS_INVALID_COMPUTER_NAME
;
2682 ComputerNameLength
= DnsHostName
->Length
;
2684 /* find the first dot in the dns host name */
2685 for (Length
= 0; Length
< DnsHostName
->Length
/ sizeof(WCHAR
); Length
++)
2687 if (DnsHostName
->Buffer
[Length
] == L
'.')
2689 /* dot found, so set the length for the oem translation */
2690 ComputerNameLength
= Length
* sizeof(WCHAR
);
2695 /* the computername must have one character */
2696 if (ComputerNameLength
> 0)
2698 ComputerNameOemNLength
= 0;
2699 /* convert to oem string and use uppercase letters */
2700 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2701 MAX_COMPUTERNAME_LENGTH
,
2702 &ComputerNameOemNLength
,
2703 DnsHostName
->Buffer
,
2704 ComputerNameLength
);
2706 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2707 have MAX_COMPUTERNAME_LENGTH characters */
2708 if ((Status
== STATUS_SUCCESS
) ||
2709 (Status
== STATUS_BUFFER_OVERFLOW
))
2711 /* set the termination for the oem string */
2712 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2713 /* set status for the case the next function failed */
2714 Status
= STATUS_INVALID_COMPUTER_NAME
;
2715 /* fillup the oem string structure with the converted computername
2716 and check it for unmapped characters */
2717 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2718 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2719 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2721 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
))
2723 /* no unmapped character so convert it back to an unicode string */
2724 Status
= RtlOemStringToUnicodeString(ComputerName
,
2726 AllocateComputerNameString
);