2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Unicode Conversion Routines
5 * FILE: lib/rtl/unicode.c
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
11 /* INCLUDES *****************************************************************/
18 #include <wine/unicode.h>
20 /* GLOBALS *******************************************************************/
22 extern BOOLEAN NlsMbCodePageTag
;
23 extern BOOLEAN NlsMbOemCodePageTag
;
24 extern PUSHORT NlsLeadByteInfo
;
25 extern USHORT NlsOemDefaultChar
;
26 extern USHORT NlsUnicodeDefaultChar
;
29 /* FUNCTIONS *****************************************************************/
36 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR
*AnsiChar
)
40 WCHAR UnicodeChar
= L
' ';
45 Size
= (NlsLeadByteInfo
[**AnsiChar
] == 0) ? 1 : 2;
49 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
53 Status
= RtlMultiByteToUnicodeN(&UnicodeChar
,
59 if (!NT_SUCCESS(Status
))
72 * This function always writes a terminating '\0'.
73 * If the dest buffer is too small a partial copy is NOT performed!
77 RtlAnsiStringToUnicodeString(
78 IN OUT PUNICODE_STRING UniDest
,
79 IN PANSI_STRING AnsiSource
,
80 IN BOOLEAN AllocateDestinationString
)
88 if (NlsMbCodePageTag
== FALSE
)
90 Length
= AnsiSource
->Length
* 2 + sizeof(WCHAR
);
94 Length
= RtlxAnsiStringToUnicodeSize(AnsiSource
);
96 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
97 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
99 if (AllocateDestinationString
)
101 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
102 UniDest
->MaximumLength
= (USHORT
)Length
;
103 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
105 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
107 return STATUS_BUFFER_OVERFLOW
;
110 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
111 ASSERT(!(UniDest
->MaximumLength
& 1) && UniDest
->Length
<= UniDest
->MaximumLength
);
113 Status
= RtlMultiByteToUnicodeN(UniDest
->Buffer
,
119 if (!NT_SUCCESS(Status
))
121 if (AllocateDestinationString
)
123 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
124 UniDest
->Buffer
= NULL
;
130 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
138 * The calculated size in bytes including nullterm.
142 RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString
)
147 /* Convert from Mb String to Unicode Size */
148 RtlMultiByteToUnicodeSize(&Size
,
152 /* Return the size plus the null-char */
153 return(Size
+ sizeof(WCHAR
));
160 * If src->length is zero dest is unchanged.
161 * Dest is never nullterminated.
165 RtlAppendStringToString(IN PSTRING Destination
,
168 USHORT SourceLength
= Source
->Length
;
172 if (Destination
->Length
+ SourceLength
> Destination
->MaximumLength
)
174 return STATUS_BUFFER_TOO_SMALL
;
177 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
],
181 Destination
->Length
+= SourceLength
;
184 return STATUS_SUCCESS
;
191 * If src->length is zero dest is unchanged.
192 * Dest is nullterminated when the MaximumLength allowes it.
193 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
197 RtlAppendUnicodeStringToString(
198 IN OUT PUNICODE_STRING Destination
,
199 IN PCUNICODE_STRING Source
)
201 USHORT SourceLength
= Source
->Length
;
202 PWCHAR Buffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
206 if ((SourceLength
+ Destination
->Length
) > Destination
->MaximumLength
)
208 return STATUS_BUFFER_TOO_SMALL
;
211 RtlMoveMemory(Buffer
, Source
->Buffer
, SourceLength
);
212 Destination
->Length
+= SourceLength
;
214 /* append terminating '\0' if enough space */
215 if (Destination
->MaximumLength
> Destination
->Length
)
217 Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
221 return STATUS_SUCCESS
;
224 /**************************************************************************
225 * RtlCharToInteger (NTDLL.@)
227 * Converts a character string into its integer equivalent.
230 * Success: STATUS_SUCCESS. value contains the converted number
231 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
232 * STATUS_ACCESS_VIOLATION, if value is NULL.
235 * For base 0 it uses 10 as base and the string should be in the format
236 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
237 * For other bases the string should be in the format
238 * "{whitespace} [+|-] {digits}".
239 * No check is made for value overflow, only the lower 32 bits are assigned.
240 * If str is NULL it crashes, as the native function does.
243 * This function does not read garbage behind '\0' as the native version does.
248 PCSZ str
, /* [I] '\0' terminated single-byte string containing a number */
249 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
250 PULONG value
) /* [O] Destination for the converted value */
254 ULONG RunningTotal
= 0;
257 /* skip leading whitespaces */
258 while (*str
!= '\0' && *str
<= ' ') str
++;
265 else if (*str
== '-')
271 /* base = 0 means autobase */
283 else if (str
[1] == 'o')
288 else if (str
[1] == 'x')
295 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
297 return STATUS_INVALID_PARAMETER
;
300 if (value
== NULL
) return STATUS_ACCESS_VIOLATION
;
306 if (chCurrent
>= '0' && chCurrent
<= '9')
308 digit
= chCurrent
- '0';
310 else if (chCurrent
>= 'A' && chCurrent
<= 'Z')
312 digit
= chCurrent
- 'A' + 10;
314 else if (chCurrent
>= 'a' && chCurrent
<= 'z')
316 digit
= chCurrent
- 'a' + 10;
323 if (digit
< 0 || digit
>= (int)base
) break;
325 RunningTotal
= RunningTotal
* base
+ digit
;
329 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
330 return STATUS_SUCCESS
;
341 IN BOOLEAN CaseInsensitive
)
347 len
= min(s1
->Length
, s2
->Length
);
353 while (!ret
&& len
--)
354 ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
358 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
361 if (!ret
) ret
= s1
->Length
- s2
->Length
;
370 * TRUE if strings are equal.
377 IN BOOLEAN CaseInsensitive
)
379 if (s1
->Length
!= s2
->Length
) return FALSE
;
380 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
387 * TRUE if strings are equal.
391 RtlEqualUnicodeString(
392 IN CONST UNICODE_STRING
*s1
,
393 IN CONST UNICODE_STRING
*s2
,
394 IN BOOLEAN CaseInsensitive
)
396 if (s1
->Length
!= s2
->Length
) return FALSE
;
397 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
405 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
409 if (AnsiString
->Buffer
)
411 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
412 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
421 RtlFreeOemString(IN POEM_STRING OemString
)
425 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
433 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
437 if (UnicodeString
->Buffer
)
439 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
440 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
449 * Check the OEM string to match the Unicode string.
451 * Functions which convert Unicode strings to OEM strings will set a
452 * DefaultChar from the OEM codepage when the characters are unknown.
453 * So check it against the Unicode string and return false when the
454 * Unicode string does not contain a TransDefaultChar.
458 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
459 IN POEM_STRING OemString
)
463 if (NlsMbOemCodePageTag
== FALSE
)
465 /* single-byte code page */
466 /* Go through all characters of a string */
467 while (i
< OemString
->Length
)
469 /* Check if it got translated into a default char,
470 * but source char wasn't a default char equivalent
472 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
473 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
475 /* Yes, it means unmappable characters were found */
479 /* Move to the next char */
483 /* All chars were translated successfuly */
488 /* multibyte code page */
500 RtlIsValidOemCharacter(IN PWCHAR Char
)
510 * If source is NULL the length of source is assumed to be 0.
514 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
515 IN PCSZ SourceString
)
521 Size
= strlen(SourceString
);
522 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) Size
= MAXUSHORT
- sizeof(CHAR
);
523 DestinationString
->Length
= (USHORT
)Size
;
524 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
528 DestinationString
->Length
= 0;
529 DestinationString
->MaximumLength
= 0;
532 DestinationString
->Buffer
= (PCHAR
)SourceString
;
537 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
538 IN PCSZ SourceString
)
544 Size
= strlen(SourceString
);
545 if (Size
> (MAXUSHORT
- sizeof(CHAR
))) return STATUS_NAME_TOO_LONG
;
546 DestinationString
->Length
= (USHORT
)Size
;
547 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(CHAR
);
551 DestinationString
->Length
= 0;
552 DestinationString
->MaximumLength
= 0;
555 DestinationString
->Buffer
= (PCHAR
)SourceString
;
556 return STATUS_SUCCESS
;
563 * If source is NULL the length of source is assumed to be 0.
568 IN OUT PSTRING DestinationString
,
569 IN PCSZ SourceString
)
571 RtlInitAnsiString(DestinationString
, SourceString
);
578 * If source is NULL the length of source is assumed to be 0.
582 RtlInitUnicodeString(
583 IN OUT PUNICODE_STRING DestinationString
,
584 IN PCWSTR SourceString
)
587 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(WCHAR
); // an even number
591 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
592 if (Size
> MaxSize
) Size
= MaxSize
;
593 DestinationString
->Length
= (USHORT
)Size
;
594 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(WCHAR
);
598 DestinationString
->Length
= 0;
599 DestinationString
->MaximumLength
= 0;
602 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
610 RtlInitUnicodeStringEx(
611 OUT PUNICODE_STRING DestinationString
,
612 IN PCWSTR SourceString
)
615 CONST SIZE_T MaxSize
= (MAXUSHORT
& ~1) - sizeof(WCHAR
); // an even number
619 Size
= wcslen(SourceString
) * sizeof(WCHAR
);
620 if (Size
> MaxSize
) return STATUS_NAME_TOO_LONG
;
621 DestinationString
->Length
= (USHORT
)Size
;
622 DestinationString
->MaximumLength
= (USHORT
)Size
+ sizeof(WCHAR
);
626 DestinationString
->Length
= 0;
627 DestinationString
->MaximumLength
= 0;
630 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
631 return STATUS_SUCCESS
;
638 * Writes at most length characters to the string str.
639 * Str is nullterminated when length allowes it.
640 * When str fits exactly in length characters the nullterm is ommitted.
642 NTSTATUS NTAPI
RtlIntegerToChar(
643 ULONG value
, /* [I] Value to be converted */
644 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
645 ULONG length
, /* [I] Length of the str buffer in bytes */
646 PCHAR str
) /* [O] Destination for the converted value */
657 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
659 return STATUS_INVALID_PARAMETER
;
668 digit
= (CHAR
)(value
% base
);
669 value
= value
/ base
;
677 *pos
= 'A' + digit
- 10;
682 len
= &buffer
[32] - pos
;
686 return STATUS_BUFFER_OVERFLOW
;
688 else if (str
== NULL
)
690 return STATUS_ACCESS_VIOLATION
;
692 else if (len
== length
)
694 memcpy(str
, pos
, len
);
698 memcpy(str
, pos
, len
+ 1);
701 return STATUS_SUCCESS
;
711 IN ULONG Base OPTIONAL
,
712 IN ULONG Length OPTIONAL
,
713 IN OUT LPWSTR String
)
724 if (Radix
== 0) Radix
= 10;
726 if ((Radix
!= 2) && (Radix
!= 8) &&
727 (Radix
!= 10) && (Radix
!= 16))
729 return STATUS_INVALID_PARAMETER
;
734 while (v
|| tp
== temp
)
739 if (i
< 10) *tp
= (WCHAR
)(i
+ L
'0');
740 else *tp
= (WCHAR
)(i
+ L
'a' - 10);
745 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
747 return STATUS_BUFFER_TOO_SMALL
;
752 while (tp
> temp
) *sp
++ = *--tp
;
756 return STATUS_SUCCESS
;
764 RtlIntegerToUnicodeString(
766 IN ULONG Base OPTIONAL
,
767 IN OUT PUNICODE_STRING String
)
769 ANSI_STRING AnsiString
;
773 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
774 if (NT_SUCCESS(Status
))
776 AnsiString
.Buffer
= Buffer
;
777 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
778 AnsiString
.MaximumLength
= sizeof(Buffer
);
780 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
791 RtlInt64ToUnicodeString (
793 IN ULONG Base OPTIONAL
,
794 IN OUT PUNICODE_STRING String
)
796 LARGE_INTEGER LargeInt
;
797 ANSI_STRING AnsiString
;
801 LargeInt
.QuadPart
= Value
;
803 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
804 if (NT_SUCCESS(Status
))
806 AnsiString
.Buffer
= Buffer
;
807 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
808 AnsiString
.MaximumLength
= sizeof(Buffer
);
810 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
820 * TRUE if String2 contains String1 as a prefix.
825 PANSI_STRING String1
,
826 PANSI_STRING String2
,
827 BOOLEAN CaseInsensitive
)
833 if (String2
->Length
< String1
->Length
) return FALSE
;
835 Length
= String1
->Length
;
836 pc1
= String1
->Buffer
;
837 pc2
= String2
->Buffer
;
845 if (RtlUpperChar (*pc1
++) != RtlUpperChar (*pc2
++))
853 if (*pc1
++ != *pc2
++)
868 * TRUE if String2 contains String1 as a prefix.
872 RtlPrefixUnicodeString(
873 PCUNICODE_STRING String1
,
874 PCUNICODE_STRING String2
,
875 BOOLEAN CaseInsensitive
)
881 if (String2
->Length
< String1
->Length
)
884 Length
= String1
->Length
/ 2;
885 pc1
= String1
->Buffer
;
886 pc2
= String2
->Buffer
;
894 if (RtlUpcaseUnicodeChar(*pc1
++) !=
895 RtlUpcaseUnicodeChar(*pc2
++))
903 if( *pc1
++ != *pc2
++ )
918 RtlUnicodeStringToInteger(
919 const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
920 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
921 ULONG
*value
) /* [O] Destination for the converted value */
923 LPWSTR lpwstr
= str
->Buffer
;
924 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
927 ULONG RunningTotal
= 0;
930 while (CharsRemaining
>= 1 && *lpwstr
<= ' ')
936 if (CharsRemaining
>= 1)
943 else if (*lpwstr
== '-')
955 if (CharsRemaining
>= 2 && lpwstr
[0] == '0')
957 if (lpwstr
[1] == 'b')
963 else if (lpwstr
[1] == 'o')
969 else if (lpwstr
[1] == 'x')
977 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
979 return STATUS_INVALID_PARAMETER
;
984 return STATUS_ACCESS_VIOLATION
;
987 while (CharsRemaining
>= 1)
989 wchCurrent
= *lpwstr
;
991 if (wchCurrent
>= '0' && wchCurrent
<= '9')
993 digit
= wchCurrent
- '0';
995 else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z')
997 digit
= wchCurrent
- 'A' + 10;
999 else if (wchCurrent
>= 'a' && wchCurrent
<= 'z')
1001 digit
= wchCurrent
- 'a' + 10;
1008 if (digit
< 0 || (ULONG
)digit
>= base
) break;
1010 RunningTotal
= RunningTotal
* base
+ digit
;
1015 *value
= bMinus
? (0 - RunningTotal
) : RunningTotal
;
1016 return STATUS_SUCCESS
;
1023 * Bytes necessary for the conversion including nullterm.
1027 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
1031 /* Convert the Unicode String to Mb Size */
1032 RtlUnicodeToMultiByteSize(&Size
,
1033 UnicodeString
->Buffer
,
1034 UnicodeString
->Length
);
1036 /* Return the size + the null char */
1037 return (Size
+ sizeof(CHAR
));
1044 * This function always writes a terminating '\0'.
1045 * It performs a partial copy if ansi is too small.
1049 RtlUnicodeStringToAnsiString(
1050 IN OUT PANSI_STRING AnsiDest
,
1051 IN PCUNICODE_STRING UniSource
,
1052 IN BOOLEAN AllocateDestinationString
)
1054 NTSTATUS Status
= STATUS_SUCCESS
;
1055 NTSTATUS RealStatus
;
1061 ASSERT(!(UniSource
->Length
& 1));
1063 if (NlsMbCodePageTag
== FALSE
)
1065 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
1069 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
1072 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1074 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1076 if (AllocateDestinationString
)
1078 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1079 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1081 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1083 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1085 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1087 Status
= STATUS_BUFFER_OVERFLOW
;
1088 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1091 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1097 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1099 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1103 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1111 * This function always writes a terminating '\0'.
1112 * Does NOT perform a partial copy if unicode is too small!
1116 RtlOemStringToUnicodeString(
1117 IN OUT PUNICODE_STRING UniDest
,
1118 IN PCOEM_STRING OemSource
,
1119 IN BOOLEAN AllocateDestinationString
)
1127 Length
= RtlOemStringToUnicodeSize(OemSource
);
1129 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1131 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1133 if (AllocateDestinationString
)
1135 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1136 UniDest
->MaximumLength
= (USHORT
)Length
;
1138 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1140 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1142 return STATUS_BUFFER_OVERFLOW
;
1145 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1151 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1153 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1154 UniDest
->Buffer
= NULL
;
1158 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1166 * This function always '\0' terminates the string returned.
1170 RtlUnicodeStringToOemString(
1171 IN OUT POEM_STRING OemDest
,
1172 IN PCUNICODE_STRING UniSource
,
1173 IN BOOLEAN AllocateDestinationString
)
1181 Length
= RtlUnicodeStringToOemSize(UniSource
);
1183 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1185 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1187 if (AllocateDestinationString
)
1189 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1190 OemDest
->MaximumLength
= (USHORT
)Length
;
1192 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1194 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1196 return STATUS_BUFFER_OVERFLOW
;
1199 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1205 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1207 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1208 OemDest
->Buffer
= NULL
;
1212 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1216 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1222 * The length of the string if all tests were passed, 0 otherwise.
1226 RtlIsTextUnicode( PVOID buf
, INT len
, INT
*pf
)
1228 static const WCHAR std_control_chars
[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1229 static const WCHAR byterev_control_chars
[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1230 const WCHAR
*s
= buf
;
1232 unsigned int flags
= MAXULONG
, out_flags
= 0;
1234 if (len
< sizeof(WCHAR
))
1236 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1246 * Apply various tests to the text string. According to the
1247 * docs, each test "passed" sets the corresponding flag in
1248 * the output flags. But some of the tests are mutually
1249 * exclusive, so I don't see how you could pass all tests ...
1252 /* Check for an odd length ... pass if even. */
1253 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1255 if (((char *)buf
)[len
- 1] == 0)
1256 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1258 len
/= sizeof(WCHAR
);
1260 /* Windows only checks the first 256 characters */
1261 if (len
> 256) len
= 256;
1263 /* Check for the special byte order unicode marks. */
1264 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1265 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1267 /* apply some statistical analysis */
1268 if (flags
& IS_TEXT_UNICODE_STATISTICS
)
1272 /* FIXME: checks only for ASCII characters in the unicode stream */
1273 for (i
= 0; i
< len
; i
++)
1275 if (s
[i
] <= 255) stats
++;
1278 if (stats
> len
/ 2)
1279 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1282 /* Check for unicode NULL chars */
1283 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1285 for (i
= 0; i
< len
; i
++)
1287 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1289 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1295 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1297 for (i
= 0; i
< len
; i
++)
1299 if (strchrW(std_control_chars
, s
[i
]))
1301 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1307 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1309 for (i
= 0; i
< len
; i
++)
1311 if (strchrW(byterev_control_chars
, s
[i
]))
1313 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1325 /* check for flags that indicate it's definitely not valid Unicode */
1326 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1328 /* now check for invalid ASCII, and assume Unicode if so */
1329 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1331 /* now check for Unicode flags */
1332 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1343 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1344 * A partial copy is NOT performed if the dest buffer is too small!
1348 RtlOemStringToCountedUnicodeString(
1349 IN OUT PUNICODE_STRING UniDest
,
1350 IN PCOEM_STRING OemSource
,
1351 IN BOOLEAN AllocateDestinationString
)
1359 /* Calculate size of the string */
1360 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1362 /* If it's 0 then zero out dest string and return */
1365 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1366 return STATUS_SUCCESS
;
1369 /* Check if length is a sane value */
1370 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1372 /* Store it in dest string */
1373 UniDest
->Length
= (USHORT
)Length
;
1375 /* If we're asked to alloc the string - do so */
1376 if (AllocateDestinationString
)
1378 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1379 UniDest
->MaximumLength
= (USHORT
)Length
;
1381 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1383 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1385 return STATUS_BUFFER_OVERFLOW
;
1388 /* Do the conversion */
1389 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1395 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1397 /* Conversion failed, free dest string and return status code */
1398 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1399 UniDest
->Buffer
= NULL
;
1403 return STATUS_SUCCESS
;
1410 * TRUE if the names are equal, FALSE if not
1413 * The comparison is case insensitive.
1417 RtlEqualComputerName(
1418 IN PUNICODE_STRING ComputerName1
,
1419 IN PUNICODE_STRING ComputerName2
)
1421 OEM_STRING OemString1
;
1422 OEM_STRING OemString2
;
1423 BOOLEAN Result
= FALSE
;
1425 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1429 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1433 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1434 RtlFreeOemString(&OemString2
);
1437 RtlFreeOemString(&OemString1
);
1447 * TRUE if the names are equal, FALSE if not
1450 * The comparison is case insensitive.
1454 RtlEqualDomainName (
1455 IN PUNICODE_STRING DomainName1
,
1456 IN PUNICODE_STRING DomainName2
)
1458 return RtlEqualComputerName(DomainName1
, DomainName2
);
1464 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1466 * Convert a string representation of a GUID into a GUID.
1469 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1470 * guid [O] Destination for the converted GUID
1473 * Success: STATUS_SUCCESS. guid contains the converted value.
1474 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1477 * See RtlStringFromGUID.
1482 IN UNICODE_STRING
*str
,
1486 const WCHAR
*lpszCLSID
= str
->Buffer
;
1487 BYTE
* lpOut
= (BYTE
*)guid
;
1489 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1491 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1492 * to memory: DWORD... WORD WORD BYTES............
1499 if (*lpszCLSID
!= '{')
1500 return STATUS_INVALID_PARAMETER
;
1507 if (*lpszCLSID
!= '-')
1508 return STATUS_INVALID_PARAMETER
;
1512 if (*lpszCLSID
!= '}')
1513 return STATUS_INVALID_PARAMETER
;
1519 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1522 /* Read two hex digits as a byte value */
1523 if (ch
>= '0' && ch
<= '9')
1525 else if (ch
>= 'a' && ch
<= 'f')
1527 else if (ch
>= 'A' && ch
<= 'F')
1530 return STATUS_INVALID_PARAMETER
;
1532 if (ch2
>= '0' && ch2
<= '9')
1534 else if (ch2
>= 'a' && ch2
<= 'f')
1535 ch2
= ch2
- 'a' + 10;
1536 else if (ch2
>= 'A' && ch2
<= 'F')
1537 ch2
= ch2
- 'A' + 10;
1539 return STATUS_INVALID_PARAMETER
;
1541 byte
= ch
<< 4 | ch2
;
1545 #ifndef WORDS_BIGENDIAN
1546 /* For Big Endian machines, we store the data such that the
1547 * dword/word members can be read as DWORDS and WORDS correctly. */
1580 lpszCLSID
++; /* Skip 2nd character of byte */
1589 return STATUS_SUCCESS
;
1597 RtlEraseUnicodeString(
1598 IN PUNICODE_STRING String
)
1600 if (String
->Buffer
&& String
->MaximumLength
)
1602 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1612 RtlHashUnicodeString(
1613 IN CONST UNICODE_STRING
*String
,
1614 IN BOOLEAN CaseInSensitive
,
1615 IN ULONG HashAlgorithm
,
1616 OUT PULONG HashValue
)
1618 if (String
!= NULL
&& HashValue
!= NULL
)
1620 switch (HashAlgorithm
)
1622 case HASH_STRING_ALGORITHM_DEFAULT
:
1623 case HASH_STRING_ALGORITHM_X65599
:
1628 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1630 if (CaseInSensitive
)
1632 for (c
= String
->Buffer
; c
!= end
; c
++)
1634 /* only uppercase characters if they are 'a' ... 'z'! */
1635 *HashValue
= ((65599 * (*HashValue
)) +
1636 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1637 (*c
) - L
'a' + L
'A' : (*c
)));
1642 for (c
= String
->Buffer
; c
!= end
; c
++)
1644 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1648 return STATUS_SUCCESS
;
1653 return STATUS_INVALID_PARAMETER
;
1660 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1661 * Does a partial copy if the dest buffer is too small
1665 RtlUnicodeStringToCountedOemString(
1666 IN OUT POEM_STRING OemDest
,
1667 IN PUNICODE_STRING UniSource
,
1668 IN BOOLEAN AllocateDestinationString
)
1676 /* Calculate size of the string */
1677 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1679 /* If it's 0 then zero out dest string and return */
1682 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1683 return STATUS_SUCCESS
;
1686 /* Check if length is a sane value */
1687 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1689 /* Store it in dest string */
1690 OemDest
->Length
= (USHORT
)Length
;
1692 /* If we're asked to alloc the string - do so */
1693 if (AllocateDestinationString
)
1695 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1696 OemDest
->MaximumLength
= (USHORT
)Length
;
1697 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1699 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1701 return STATUS_BUFFER_OVERFLOW
;
1704 /* Do the conversion */
1705 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1711 /* Check for unmapped character */
1712 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1713 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1715 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1717 /* Conversion failed, free dest string and return status code */
1718 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1719 OemDest
->Buffer
= NULL
;
1731 RtlLargeIntegerToChar(
1732 IN PLARGE_INTEGER Value
,
1735 IN OUT PCHAR String
)
1737 ULONGLONG Val
= Value
->QuadPart
;
1738 NTSTATUS Status
= STATUS_SUCCESS
;
1744 if (Base
== 0) Base
= 10;
1746 if ((Base
!= 2) && (Base
!= 8) && (Base
!= 10) && (Base
!= 16))
1748 return STATUS_INVALID_PARAMETER
;
1757 Digit
= (CHAR
)(Val
% Base
);
1763 *Pos
= 'A' + Digit
- 10;
1767 Len
= &Buffer
[64] - Pos
;
1770 return STATUS_BUFFER_OVERFLOW
;
1772 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1776 return STATUS_ACCESS_VIOLATION
;
1787 RtlCopyMemory(String
, Pos
, Len
);
1789 RtlCopyMemory(String
, Pos
, Len
+ 1);
1793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1795 /* Get the error code */
1796 Status
= _SEH2_GetExceptionCode();
1808 * dest is never '\0' terminated because it may be equal to src, and src
1809 * might not be '\0' terminated. dest->Length is only set upon success.
1813 RtlUpcaseUnicodeString(
1814 IN OUT PUNICODE_STRING UniDest
,
1815 IN PCUNICODE_STRING UniSource
,
1816 IN BOOLEAN AllocateDestinationString
)
1822 if (AllocateDestinationString
== TRUE
)
1824 UniDest
->MaximumLength
= UniSource
->Length
;
1825 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1826 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1828 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1830 return STATUS_BUFFER_OVERFLOW
;
1833 j
= UniSource
->Length
/ sizeof(WCHAR
);
1835 for (i
= 0; i
< j
; i
++)
1837 UniDest
->Buffer
[i
] = RtlUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1840 UniDest
->Length
= UniSource
->Length
;
1841 return STATUS_SUCCESS
;
1848 * This function always writes a terminating '\0'.
1849 * It performs a partial copy if ansi is too small.
1853 RtlUpcaseUnicodeStringToAnsiString(
1854 IN OUT PANSI_STRING AnsiDest
,
1855 IN PUNICODE_STRING UniSource
,
1856 IN BOOLEAN AllocateDestinationString
)
1863 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1864 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1866 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1868 if (AllocateDestinationString
)
1870 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1871 AnsiDest
->MaximumLength
= (USHORT
)Length
;
1872 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1874 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1876 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1879 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1885 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1887 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1888 AnsiDest
->Buffer
= NULL
;
1892 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1900 * This function always writes a terminating '\0'.
1901 * It performs a partial copy if ansi is too small.
1905 RtlUpcaseUnicodeStringToCountedOemString(
1906 IN OUT POEM_STRING OemDest
,
1907 IN PCUNICODE_STRING UniSource
,
1908 IN BOOLEAN AllocateDestinationString
)
1915 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1919 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1922 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1924 OemDest
->Length
= (USHORT
)Length
;
1926 if (AllocateDestinationString
)
1928 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1929 OemDest
->MaximumLength
= (USHORT
)Length
;
1930 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1932 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1934 return STATUS_BUFFER_OVERFLOW
;
1937 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1943 /* Check for unmapped characters */
1944 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1945 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1947 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1949 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1950 OemDest
->Buffer
= NULL
;
1960 * Oem string is allways nullterminated
1961 * It performs a partial copy if oem is too small.
1965 RtlUpcaseUnicodeStringToOemString (
1966 IN OUT POEM_STRING OemDest
,
1967 IN PCUNICODE_STRING UniSource
,
1968 IN BOOLEAN AllocateDestinationString
)
1975 Length
= RtlUnicodeStringToOemSize(UniSource
);
1976 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1978 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1980 if (AllocateDestinationString
)
1982 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1983 OemDest
->MaximumLength
= (USHORT
)Length
;
1984 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1986 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1988 return STATUS_BUFFER_OVERFLOW
;
1991 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1997 /* Check for unmapped characters */
1998 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1999 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2001 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2003 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2004 OemDest
->Buffer
= NULL
;
2008 OemDest
->Buffer
[Index
] = ANSI_NULL
;
2016 * Bytes calculated including nullterm
2020 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
2024 /* Convert the Mb String to Unicode Size */
2025 RtlMultiByteToUnicodeSize(&Size
,
2029 /* Return the size + null-char */
2030 return (Size
+ sizeof(WCHAR
));
2038 RtlStringFromGUID (IN REFGUID Guid
,
2039 OUT PUNICODE_STRING GuidString
)
2041 /* Setup the string */
2042 GuidString
->Length
= 38 * sizeof(WCHAR
);
2043 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
2044 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
2046 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
2048 /* Now format the GUID */
2049 swprintf(GuidString
->Buffer
,
2050 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2062 return STATUS_SUCCESS
;
2069 * Bytes calculated including nullterm
2073 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
2078 ASSERT(!(UnicodeString
->Length
& 1));
2080 /* Convert the Unicode String to Mb Size */
2081 RtlUnicodeToMultiByteSize(&Size
,
2082 UnicodeString
->Buffer
,
2083 UnicodeString
->Length
);
2085 /* Return the size + null-char */
2086 return (Size
+ sizeof(CHAR
));
2094 RtlCompareUnicodeString(
2095 IN PCUNICODE_STRING s1
,
2096 IN PCUNICODE_STRING s2
,
2097 IN BOOLEAN CaseInsensitive
)
2103 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2107 if (CaseInsensitive
)
2109 while (!ret
&& len
--) ret
= RtlUpcaseUnicodeChar(*p1
++) - RtlUpcaseUnicodeChar(*p2
++);
2113 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2116 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2127 IN OUT PSTRING DestinationString
,
2128 IN PSTRING SourceString OPTIONAL
)
2133 /* Check if there was no source given */
2136 /* Simply return an empty string */
2137 DestinationString
->Length
= 0;
2141 /* Choose the smallest length */
2142 SourceLength
= min(DestinationString
->MaximumLength
,
2143 SourceString
->Length
);
2146 DestinationString
->Length
= (USHORT
)SourceLength
;
2148 /* Save the pointers to each buffer */
2149 p1
= DestinationString
->Buffer
;
2150 p2
= SourceString
->Buffer
;
2152 /* Loop the buffer */
2153 while (SourceLength
)
2155 /* Copy the character and move on */
2167 RtlCopyUnicodeString(
2168 IN OUT PUNICODE_STRING DestinationString
,
2169 IN PCUNICODE_STRING SourceString
)
2173 if(SourceString
== NULL
)
2175 DestinationString
->Length
= 0;
2179 SourceLength
= min(DestinationString
->MaximumLength
,
2180 SourceString
->Length
);
2181 DestinationString
->Length
= (USHORT
)SourceLength
;
2183 RtlCopyMemory(DestinationString
->Buffer
,
2184 SourceString
->Buffer
,
2187 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2189 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2198 * Creates a nullterminated UNICODE_STRING
2202 RtlCreateUnicodeString(
2203 IN OUT PUNICODE_STRING UniDest
,
2209 Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2210 if (Size
> MAXUSHORT
) return FALSE
;
2212 UniDest
->Buffer
= RtlpAllocateStringMemory((ULONG
)Size
, TAG_USTR
);
2214 if (UniDest
->Buffer
== NULL
) return FALSE
;
2216 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
2217 UniDest
->MaximumLength
= (USHORT
)Size
;
2218 UniDest
->Length
= (USHORT
)Size
- sizeof (WCHAR
);
2228 RtlCreateUnicodeStringFromAsciiz(
2229 OUT PUNICODE_STRING Destination
,
2232 ANSI_STRING AnsiString
;
2235 RtlInitAnsiString(&AnsiString
, Source
);
2237 Status
= RtlAnsiStringToUnicodeString(Destination
,
2241 return NT_SUCCESS(Status
);
2248 * Dest is never '\0' terminated because it may be equal to src, and src
2249 * might not be '\0' terminated.
2250 * Dest->Length is only set upon success.
2254 RtlDowncaseUnicodeString(
2255 IN OUT PUNICODE_STRING UniDest
,
2256 IN PCUNICODE_STRING UniSource
,
2257 IN BOOLEAN AllocateDestinationString
)
2263 if (AllocateDestinationString
)
2265 UniDest
->MaximumLength
= UniSource
->Length
;
2266 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2267 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2269 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2271 return STATUS_BUFFER_OVERFLOW
;
2274 UniDest
->Length
= UniSource
->Length
;
2275 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2277 for (i
= 0 ; i
< StopGap
; i
++)
2279 if (UniSource
->Buffer
[i
] < L
'A')
2281 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2283 else if (UniSource
->Buffer
[i
] <= L
'Z')
2285 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2289 UniDest
->Buffer
[i
] = RtlDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2293 return STATUS_SUCCESS
;
2300 * if src is NULL dest is unchanged.
2301 * dest is '\0' terminated when the MaximumLength allowes it.
2302 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2306 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2314 UNICODE_STRING UnicodeSource
;
2316 RtlInitUnicodeString(&UnicodeSource
, Source
);
2317 Length
= UnicodeSource
.Length
;
2319 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2321 return STATUS_BUFFER_TOO_SMALL
;
2324 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2325 RtlMoveMemory(DestBuffer
, Source
, Length
);
2326 Destination
->Length
+= Length
;
2328 /* append terminating '\0' if enough space */
2329 if(Destination
->MaximumLength
> Destination
->Length
)
2331 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2335 return STATUS_SUCCESS
;
2342 * if src is NULL dest is unchanged.
2343 * dest is never '\0' terminated.
2347 RtlAppendAsciizToString(
2348 IN OUT PSTRING Destination
,
2355 Size
= strlen(Source
);
2357 if (Destination
->Length
+ Size
> Destination
->MaximumLength
)
2359 return STATUS_BUFFER_TOO_SMALL
;
2362 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Size
);
2363 Destination
->Length
+= (USHORT
)Size
;
2366 return STATUS_SUCCESS
;
2374 RtlUpperString(PSTRING DestinationString
,
2375 PSTRING SourceString
)
2380 Length
= min(SourceString
->Length
,
2381 DestinationString
->MaximumLength
);
2383 Src
= SourceString
->Buffer
;
2384 Dest
= DestinationString
->Buffer
;
2385 DestinationString
->Length
= Length
;
2389 *Dest
++ = RtlUpperChar(*Src
++);
2398 * See RtlpDuplicateUnicodeString
2402 RtlDuplicateUnicodeString(
2404 IN PCUNICODE_STRING SourceString
,
2405 OUT PUNICODE_STRING DestinationString
)
2409 if (SourceString
== NULL
|| DestinationString
== NULL
||
2410 SourceString
->Length
> SourceString
->MaximumLength
||
2411 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2412 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4)
2414 return STATUS_INVALID_PARAMETER
;
2418 if ((SourceString
->Length
== 0) &&
2419 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2420 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2422 DestinationString
->Length
= 0;
2423 DestinationString
->MaximumLength
= 0;
2424 DestinationString
->Buffer
= NULL
;
2428 UINT DestMaxLength
= SourceString
->Length
;
2430 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2431 DestMaxLength
+= sizeof(UNICODE_NULL
);
2433 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2435 if (DestinationString
->Buffer
== NULL
)
2436 return STATUS_NO_MEMORY
;
2438 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2439 DestinationString
->Length
= SourceString
->Length
;
2440 DestinationString
->MaximumLength
= DestMaxLength
;
2442 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2443 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2446 return STATUS_SUCCESS
;
2454 RtlValidateUnicodeString(IN ULONG Flags
,
2455 IN PCUNICODE_STRING UnicodeString
)
2457 /* currently no flags are supported! */
2461 ((UnicodeString
== NULL
) ||
2462 ((UnicodeString
->Length
!= 0) &&
2463 (UnicodeString
->Buffer
!= NULL
) &&
2464 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2465 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2466 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2468 /* a NULL pointer as a unicode string is considered to be a valid unicode
2470 return STATUS_SUCCESS
;
2474 return STATUS_INVALID_PARAMETER
;
2483 RtlpEnsureBufferSize(ULONG Unknown1
, ULONG Unknown2
, ULONG Unknown3
)
2485 DPRINT1("RtlpEnsureBufferSize: stub\n");
2486 return STATUS_NOT_IMPLEMENTED
;
2491 RtlpIsCharInUnicodeString(
2493 IN PCUNICODE_STRING MatchString
,
2494 IN BOOLEAN CaseInSensitive
)
2498 if (CaseInSensitive
)
2499 Char
= RtlUpcaseUnicodeChar(Char
);
2501 for (i
= 0; i
< MatchString
->Length
/ sizeof(WCHAR
); i
++)
2503 WCHAR OtherChar
= MatchString
->Buffer
[i
];
2504 if (CaseInSensitive
)
2505 OtherChar
= RtlUpcaseUnicodeChar(OtherChar
);
2507 if (Char
== OtherChar
)
2519 RtlFindCharInUnicodeString(
2521 IN PCUNICODE_STRING SearchString
,
2522 IN PCUNICODE_STRING MatchString
,
2523 OUT PUSHORT Position
)
2526 const BOOLEAN WantToFind
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
) == 0;
2527 const BOOLEAN CaseInSensitive
= (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
) != 0;
2531 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2532 Flags
, SearchString
, MatchString
, Position
);
2534 /* Parameter checks */
2535 if (Position
== NULL
)
2536 return STATUS_INVALID_PARAMETER
;
2540 if (Flags
& ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
|
2541 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET
|
2542 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE
))
2543 return STATUS_INVALID_PARAMETER
;
2546 Length
= SearchString
->Length
/ sizeof(WCHAR
);
2547 if (Flags
& RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
)
2549 for (i
= Length
- 1; i
>= 0; i
--)
2551 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2552 if (Found
== WantToFind
)
2554 *Position
= i
* sizeof(WCHAR
);
2555 return STATUS_SUCCESS
;
2561 for (i
= 0; i
< Length
; i
++)
2563 Found
= RtlpIsCharInUnicodeString(SearchString
->Buffer
[i
], MatchString
, CaseInSensitive
);
2564 if (Found
== WantToFind
)
2566 *Position
= (i
+ 1) * sizeof(WCHAR
);
2567 return STATUS_SUCCESS
;
2572 return STATUS_NOT_FOUND
;
2579 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2580 * Convert is to an uppercase oem string and check for unmapped characters.
2581 * Then convert the oem string back to an unicode string.
2585 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
, PUNICODE_STRING DnsHostName
, BOOLEAN AllocateComputerNameString
)
2589 ULONG ComputerNameLength
;
2590 ULONG ComputerNameOemNLength
;
2591 OEM_STRING ComputerNameOem
;
2592 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2594 Status
= STATUS_INVALID_COMPUTER_NAME
;
2595 ComputerNameLength
= DnsHostName
->Length
;
2597 /* find the first dot in the dns host name */
2598 for (Length
= 0; Length
< DnsHostName
->Length
/ sizeof(WCHAR
); Length
++)
2600 if (DnsHostName
->Buffer
[Length
] == L
'.')
2602 /* dot found, so set the length for the oem translation */
2603 ComputerNameLength
= Length
* sizeof(WCHAR
);
2608 /* the computername must have one character */
2609 if (ComputerNameLength
> 0)
2611 ComputerNameOemNLength
= 0;
2612 /* convert to oem string and use uppercase letters */
2613 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2614 MAX_COMPUTERNAME_LENGTH
,
2615 &ComputerNameOemNLength
,
2616 DnsHostName
->Buffer
,
2617 ComputerNameLength
);
2619 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2620 have MAX_COMPUTERNAME_LENGTH characters */
2621 if ((Status
== STATUS_SUCCESS
) ||
2622 (Status
== STATUS_BUFFER_OVERFLOW
))
2624 /* set the termination for the oem string */
2625 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2626 /* set status for the case the next function failed */
2627 Status
= STATUS_INVALID_COMPUTER_NAME
;
2628 /* fillup the oem string structure with the converted computername
2629 and check it for unmapped characters */
2630 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2631 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2632 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2634 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
) == TRUE
)
2636 /* no unmapped character so convert it back to an unicode string */
2637 Status
= RtlOemStringToUnicodeString(ComputerName
,
2639 AllocateComputerNameString
);