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
= 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
)
325 *value
= bMinus
? -RunningTotal
: RunningTotal
;
326 return STATUS_SUCCESS
;
329 RunningTotal
= RunningTotal
* base
+ digit
;
333 *value
= bMinus
? -RunningTotal
: RunningTotal
;
334 return STATUS_SUCCESS
;
345 IN BOOLEAN CaseInsensitive
)
351 len
= min(s1
->Length
, s2
->Length
);
357 while (!ret
&& len
--)
358 ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
362 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
365 if (!ret
) ret
= s1
->Length
- s2
->Length
;
374 * TRUE if strings are equal.
381 IN BOOLEAN CaseInsensitive
)
383 if (s1
->Length
!= s2
->Length
) return FALSE
;
384 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
391 * TRUE if strings are equal.
395 RtlEqualUnicodeString(
396 IN CONST UNICODE_STRING
*s1
,
397 IN CONST UNICODE_STRING
*s2
,
398 IN BOOLEAN CaseInsensitive
)
400 if (s1
->Length
!= s2
->Length
) return FALSE
;
401 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
409 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
413 if (AnsiString
->Buffer
)
415 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
416 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
425 RtlFreeOemString(IN POEM_STRING OemString
)
429 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
437 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
441 if (UnicodeString
->Buffer
)
443 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
444 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
453 * Check the OEM string to match the Unicode string.
455 * Functions which convert Unicode strings to OEM strings will set a
456 * DefaultChar from the OEM codepage when the characters are unknown.
457 * So check it against the Unicode string and return false when the
458 * Unicode string does not contain a TransDefaultChar.
462 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
463 IN POEM_STRING OemString
)
467 if (NlsMbOemCodePageTag
== FALSE
)
469 /* single-byte code page */
470 /* Go through all characters of a string */
471 while (i
< OemString
->Length
)
473 /* Check if it got translated into a default char,
474 * but source char wasn't a default char equivalent
476 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
477 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
479 /* Yes, it means unmappable characters were found */
483 /* Move to the next char */
487 /* All chars were translated successfuly */
492 /* multibyte code page */
504 RtlIsValidOemCharacter(IN PWCHAR Char
)
514 * If source is NULL the length of source is assumed to be 0.
518 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
519 IN PCSZ SourceString
)
525 DestSize
= strlen(SourceString
);
526 DestinationString
->Length
= (USHORT
)DestSize
;
527 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(CHAR
);
531 DestinationString
->Length
= 0;
532 DestinationString
->MaximumLength
= 0;
535 DestinationString
->Buffer
= (PCHAR
)SourceString
;
540 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
541 IN PCSZ SourceString
)
547 DestSize
= strlen(SourceString
);
548 if (DestSize
>= 0xFFFF) return STATUS_NAME_TOO_LONG
;
549 DestinationString
->Length
= (USHORT
)DestSize
;
550 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(CHAR
);
554 DestinationString
->Length
= 0;
555 DestinationString
->MaximumLength
= 0;
558 DestinationString
->Buffer
= (PCHAR
)SourceString
;
559 return STATUS_SUCCESS
;
566 * If source is NULL the length of source is assumed to be 0.
571 IN OUT PSTRING DestinationString
,
572 IN PCSZ SourceString
)
574 RtlInitAnsiString(DestinationString
, SourceString
);
581 * If source is NULL the length of source is assumed to be 0.
585 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString
,
586 IN PCWSTR SourceString
)
592 DestSize
= wcslen(SourceString
) * sizeof(WCHAR
);
593 DestinationString
->Length
= (USHORT
)DestSize
;
594 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(WCHAR
);
598 DestinationString
->Length
= 0;
599 DestinationString
->MaximumLength
= 0;
602 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
610 RtlInitUnicodeStringEx(OUT PUNICODE_STRING DestinationString
,
611 IN PCWSTR SourceString
)
617 DestSize
= wcslen(SourceString
) * sizeof(WCHAR
);
618 if (DestSize
>= 0xFFFC) return STATUS_NAME_TOO_LONG
;
619 DestinationString
->Length
= (USHORT
)DestSize
;
620 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(WCHAR
);
624 DestinationString
->Length
= 0;
625 DestinationString
->MaximumLength
= 0;
628 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
629 return STATUS_SUCCESS
;
636 * Writes at most length characters to the string str.
637 * Str is nullterminated when length allowes it.
638 * When str fits exactly in length characters the nullterm is ommitted.
640 NTSTATUS NTAPI
RtlIntegerToChar(
641 ULONG value
, /* [I] Value to be converted */
642 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
643 ULONG length
, /* [I] Length of the str buffer in bytes */
644 PCHAR str
) /* [O] Destination for the converted value */
655 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
657 return STATUS_INVALID_PARAMETER
;
666 digit
= value
% base
;
667 value
= value
/ base
;
675 *pos
= 'A' + digit
- 10;
680 len
= &buffer
[32] - pos
;
684 return STATUS_BUFFER_OVERFLOW
;
686 else if (str
== NULL
)
688 return STATUS_ACCESS_VIOLATION
;
690 else if (len
== length
)
692 memcpy(str
, pos
, len
);
696 memcpy(str
, pos
, len
+ 1);
699 return STATUS_SUCCESS
;
709 IN ULONG Base OPTIONAL
,
710 IN ULONG Length OPTIONAL
,
711 IN OUT LPWSTR String
)
722 if (Radix
== 0) Radix
= 10;
724 if ((Radix
!= 2) && (Radix
!= 8) &&
725 (Radix
!= 10) && (Radix
!= 16))
727 return STATUS_INVALID_PARAMETER
;
732 while (v
|| tp
== temp
)
737 if (i
< 10) *tp
= i
+ L
'0';
738 else *tp
= i
+ L
'a' - 10;
743 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
745 return STATUS_BUFFER_TOO_SMALL
;
750 while (tp
> temp
) *sp
++ = *--tp
;
754 return STATUS_SUCCESS
;
762 RtlIntegerToUnicodeString(
764 IN ULONG Base OPTIONAL
,
765 IN OUT PUNICODE_STRING String
)
767 ANSI_STRING AnsiString
;
771 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
772 if (NT_SUCCESS(Status
))
774 AnsiString
.Buffer
= Buffer
;
775 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
776 AnsiString
.MaximumLength
= sizeof(Buffer
);
778 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
789 RtlInt64ToUnicodeString (
791 IN ULONG Base OPTIONAL
,
792 IN OUT PUNICODE_STRING String
)
794 LARGE_INTEGER LargeInt
;
795 ANSI_STRING AnsiString
;
799 LargeInt
.QuadPart
= Value
;
801 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
802 if (NT_SUCCESS(Status
))
804 AnsiString
.Buffer
= Buffer
;
805 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
806 AnsiString
.MaximumLength
= sizeof(Buffer
);
808 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
818 * TRUE if String2 contains String1 as a prefix.
823 PANSI_STRING String1
,
824 PANSI_STRING String2
,
825 BOOLEAN CaseInsensitive
)
831 if (String2
->Length
< String1
->Length
) return FALSE
;
833 Length
= String1
->Length
;
834 pc1
= String1
->Buffer
;
835 pc2
= String2
->Buffer
;
843 if (RtlUpperChar (*pc1
++) != RtlUpperChar (*pc2
++))
851 if (*pc1
++ != *pc2
++)
866 * TRUE if String2 contains String1 as a prefix.
870 RtlPrefixUnicodeString(
871 PCUNICODE_STRING String1
,
872 PCUNICODE_STRING String2
,
873 BOOLEAN CaseInsensitive
)
879 if (String2
->Length
< String1
->Length
)
882 Length
= String1
->Length
/ 2;
883 pc1
= String1
->Buffer
;
884 pc2
= String2
->Buffer
;
892 if (RtlUpcaseUnicodeChar(*pc1
++) !=
893 RtlUpcaseUnicodeChar(*pc2
++))
901 if( *pc1
++ != *pc2
++ )
916 RtlUnicodeStringToInteger(
917 const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
918 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
919 ULONG
*value
) /* [O] Destination for the converted value */
921 LPWSTR lpwstr
= str
->Buffer
;
922 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
925 ULONG RunningTotal
= 0;
928 while (CharsRemaining
>= 1 && *lpwstr
<= ' ')
934 if (CharsRemaining
>= 1)
941 else if (*lpwstr
== '-')
953 if (CharsRemaining
>= 2 && lpwstr
[0] == '0')
955 if (lpwstr
[1] == 'b')
961 else if (lpwstr
[1] == 'o')
967 else if (lpwstr
[1] == 'x')
975 else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16)
977 return STATUS_INVALID_PARAMETER
;
982 return STATUS_ACCESS_VIOLATION
;
985 while (CharsRemaining
>= 1)
987 wchCurrent
= *lpwstr
;
989 if (wchCurrent
>= '0' && wchCurrent
<= '9')
991 digit
= wchCurrent
- '0';
993 else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z')
995 digit
= wchCurrent
- 'A' + 10;
997 else if (wchCurrent
>= 'a' && wchCurrent
<= 'z')
999 digit
= wchCurrent
- 'a' + 10;
1006 if (digit
< 0 || digit
>= base
)
1008 *value
= bMinus
? -RunningTotal
: RunningTotal
;
1009 return STATUS_SUCCESS
;
1012 RunningTotal
= RunningTotal
* base
+ digit
;
1017 *value
= bMinus
? -RunningTotal
: RunningTotal
;
1018 return STATUS_SUCCESS
;
1025 * Bytes necessary for the conversion including nullterm.
1029 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
1033 /* Convert the Unicode String to Mb Size */
1034 RtlUnicodeToMultiByteSize(&Size
,
1035 UnicodeString
->Buffer
,
1036 UnicodeString
->Length
);
1038 /* Return the size + the null char */
1039 return (Size
+ sizeof(CHAR
));
1046 * This function always writes a terminating '\0'.
1047 * It performs a partial copy if ansi is too small.
1051 RtlUnicodeStringToAnsiString(
1052 IN OUT PANSI_STRING AnsiDest
,
1053 IN PCUNICODE_STRING UniSource
,
1054 IN BOOLEAN AllocateDestinationString
)
1056 NTSTATUS Status
= STATUS_SUCCESS
;
1057 NTSTATUS RealStatus
;
1063 ASSERT(!(UniSource
->Length
& 1));
1065 if (NlsMbCodePageTag
== FALSE
)
1067 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
1071 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
1074 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1076 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1078 if (AllocateDestinationString
)
1080 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1081 AnsiDest
->MaximumLength
= Length
;
1083 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1085 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1087 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1089 Status
= STATUS_BUFFER_OVERFLOW
;
1090 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1093 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1099 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1101 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1105 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1113 * This function always writes a terminating '\0'.
1114 * Does NOT perform a partial copy if unicode is too small!
1118 RtlOemStringToUnicodeString(
1119 IN OUT PUNICODE_STRING UniDest
,
1120 IN PCOEM_STRING OemSource
,
1121 IN BOOLEAN AllocateDestinationString
)
1129 Length
= RtlOemStringToUnicodeSize(OemSource
);
1131 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1133 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1135 if (AllocateDestinationString
)
1137 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1138 UniDest
->MaximumLength
= Length
;
1140 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1142 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1144 return STATUS_BUFFER_OVERFLOW
;
1147 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1153 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1155 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1156 UniDest
->Buffer
= NULL
;
1160 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1168 * This function always '\0' terminates the string returned.
1172 RtlUnicodeStringToOemString(
1173 IN OUT POEM_STRING OemDest
,
1174 IN PCUNICODE_STRING UniSource
,
1175 IN BOOLEAN AllocateDestinationString
)
1183 Length
= RtlUnicodeStringToOemSize(UniSource
);
1185 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1187 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1189 if (AllocateDestinationString
)
1191 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1192 OemDest
->MaximumLength
= Length
;
1194 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1196 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1198 return STATUS_BUFFER_OVERFLOW
;
1201 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1207 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1209 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1210 OemDest
->Buffer
= NULL
;
1214 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1218 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1224 * The length of the string if all tests were passed, 0 otherwise.
1228 RtlIsTextUnicode( PVOID buf
, INT len
, INT
*pf
)
1230 static const WCHAR std_control_chars
[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1231 static const WCHAR byterev_control_chars
[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1232 const WCHAR
*s
= buf
;
1234 unsigned int flags
= MAXULONG
, out_flags
= 0;
1236 if (len
< sizeof(WCHAR
))
1238 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1248 * Apply various tests to the text string. According to the
1249 * docs, each test "passed" sets the corresponding flag in
1250 * the output flags. But some of the tests are mutually
1251 * exclusive, so I don't see how you could pass all tests ...
1254 /* Check for an odd length ... pass if even. */
1255 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1257 if (((char *)buf
)[len
- 1] == 0)
1258 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1260 len
/= sizeof(WCHAR
);
1262 /* Windows only checks the first 256 characters */
1263 if (len
> 256) len
= 256;
1265 /* Check for the special byte order unicode marks. */
1266 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1267 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1269 /* apply some statistical analysis */
1270 if (flags
& IS_TEXT_UNICODE_STATISTICS
)
1274 /* FIXME: checks only for ASCII characters in the unicode stream */
1275 for (i
= 0; i
< len
; i
++)
1277 if (s
[i
] <= 255) stats
++;
1280 if (stats
> len
/ 2)
1281 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1284 /* Check for unicode NULL chars */
1285 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1287 for (i
= 0; i
< len
; i
++)
1289 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1291 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1297 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1299 for (i
= 0; i
< len
; i
++)
1301 if (strchrW(std_control_chars
, s
[i
]))
1303 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1309 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1311 for (i
= 0; i
< len
; i
++)
1313 if (strchrW(byterev_control_chars
, s
[i
]))
1315 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1327 /* check for flags that indicate it's definitely not valid Unicode */
1328 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1330 /* now check for invalid ASCII, and assume Unicode if so */
1331 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1333 /* now check for Unicode flags */
1334 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1345 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1346 * A partial copy is NOT performed if the dest buffer is too small!
1350 RtlOemStringToCountedUnicodeString(
1351 IN OUT PUNICODE_STRING UniDest
,
1352 IN PCOEM_STRING OemSource
,
1353 IN BOOLEAN AllocateDestinationString
)
1361 /* Calculate size of the string */
1362 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1364 /* If it's 0 then zero out dest string and return */
1367 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1368 return STATUS_SUCCESS
;
1371 /* Check if length is a sane value */
1372 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1374 /* Store it in dest string */
1375 UniDest
->Length
= (USHORT
)Length
;
1377 /* If we're asked to alloc the string - do so */
1378 if (AllocateDestinationString
)
1380 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1381 UniDest
->MaximumLength
= Length
;
1383 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1385 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1387 return STATUS_BUFFER_OVERFLOW
;
1390 /* Do the conversion */
1391 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1397 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1399 /* Conversion failed, free dest string and return status code */
1400 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1401 UniDest
->Buffer
= NULL
;
1405 return STATUS_SUCCESS
;
1412 * TRUE if the names are equal, FALSE if not
1415 * The comparison is case insensitive.
1419 RtlEqualComputerName(
1420 IN PUNICODE_STRING ComputerName1
,
1421 IN PUNICODE_STRING ComputerName2
)
1423 OEM_STRING OemString1
;
1424 OEM_STRING OemString2
;
1425 BOOLEAN Result
= FALSE
;
1427 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1431 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1435 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1436 RtlFreeOemString(&OemString2
);
1439 RtlFreeOemString(&OemString1
);
1449 * TRUE if the names are equal, FALSE if not
1452 * The comparison is case insensitive.
1456 RtlEqualDomainName (
1457 IN PUNICODE_STRING DomainName1
,
1458 IN PUNICODE_STRING DomainName2
1461 return RtlEqualComputerName(DomainName1
, DomainName2
);
1467 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1469 * Convert a string representation of a GUID into a GUID.
1472 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1473 * guid [O] Destination for the converted GUID
1476 * Success: STATUS_SUCCESS. guid contains the converted value.
1477 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1480 * See RtlStringFromGUID.
1485 IN UNICODE_STRING
*str
,
1490 const WCHAR
*lpszCLSID
= str
->Buffer
;
1491 BYTE
* lpOut
= (BYTE
*)guid
;
1493 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1495 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1496 * to memory: DWORD... WORD WORD BYTES............
1503 if (*lpszCLSID
!= '{')
1504 return STATUS_INVALID_PARAMETER
;
1511 if (*lpszCLSID
!= '-')
1512 return STATUS_INVALID_PARAMETER
;
1516 if (*lpszCLSID
!= '}')
1517 return STATUS_INVALID_PARAMETER
;
1523 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1526 /* Read two hex digits as a byte value */
1527 if (ch
>= '0' && ch
<= '9')
1529 else if (ch
>= 'a' && ch
<= 'f')
1531 else if (ch
>= 'A' && ch
<= 'F')
1534 return STATUS_INVALID_PARAMETER
;
1536 if (ch2
>= '0' && ch2
<= '9')
1538 else if (ch2
>= 'a' && ch2
<= 'f')
1539 ch2
= ch2
- 'a' + 10;
1540 else if (ch2
>= 'A' && ch2
<= 'F')
1541 ch2
= ch2
- 'A' + 10;
1543 return STATUS_INVALID_PARAMETER
;
1545 byte
= ch
<< 4 | ch2
;
1549 #ifndef WORDS_BIGENDIAN
1550 /* For Big Endian machines, we store the data such that the
1551 * dword/word members can be read as DWORDS and WORDS correctly. */
1584 lpszCLSID
++; /* Skip 2nd character of byte */
1593 return STATUS_SUCCESS
;
1601 RtlEraseUnicodeString(
1602 IN PUNICODE_STRING String
)
1604 if (String
->Buffer
&& String
->MaximumLength
)
1606 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1616 RtlHashUnicodeString(
1617 IN CONST UNICODE_STRING
*String
,
1618 IN BOOLEAN CaseInSensitive
,
1619 IN ULONG HashAlgorithm
,
1620 OUT PULONG HashValue
)
1622 if (String
!= NULL
&& HashValue
!= NULL
)
1624 switch (HashAlgorithm
)
1626 case HASH_STRING_ALGORITHM_DEFAULT
:
1627 case HASH_STRING_ALGORITHM_X65599
:
1632 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1634 if (CaseInSensitive
)
1636 for (c
= String
->Buffer
; c
!= end
; c
++)
1638 /* only uppercase characters if they are 'a' ... 'z'! */
1639 *HashValue
= ((65599 * (*HashValue
)) +
1640 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1641 (*c
) - L
'a' + L
'A' : (*c
)));
1646 for (c
= String
->Buffer
; c
!= end
; c
++)
1648 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1652 return STATUS_SUCCESS
;
1657 return STATUS_INVALID_PARAMETER
;
1664 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1665 * Does a partial copy if the dest buffer is too small
1669 RtlUnicodeStringToCountedOemString(
1670 IN OUT POEM_STRING OemDest
,
1671 IN PUNICODE_STRING UniSource
,
1672 IN BOOLEAN AllocateDestinationString
)
1680 /* Calculate size of the string */
1681 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1683 /* If it's 0 then zero out dest string and return */
1686 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1687 return STATUS_SUCCESS
;
1690 /* Check if length is a sane value */
1691 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1693 /* Store it in dest string */
1694 OemDest
->Length
= (USHORT
)Length
;
1696 /* If we're asked to alloc the string - do so */
1697 if (AllocateDestinationString
)
1699 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1700 OemDest
->MaximumLength
= Length
;
1701 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1703 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1705 return STATUS_BUFFER_OVERFLOW
;
1708 /* Do the conversion */
1709 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1715 /* Check for unmapped character */
1716 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1717 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1719 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1721 /* Conversion failed, free dest string and return status code */
1722 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1723 OemDest
->Buffer
= NULL
;
1735 RtlLargeIntegerToChar(
1736 IN PLARGE_INTEGER Value
,
1739 IN OUT PCHAR String
)
1741 ULONGLONG Val
= Value
->QuadPart
;
1742 NTSTATUS Status
= STATUS_SUCCESS
;
1748 if (Base
== 0) Base
= 10;
1750 if ((Base
!= 2) && (Base
!= 8) &&
1751 (Base
!= 10) && (Base
!= 16))
1753 return STATUS_INVALID_PARAMETER
;
1768 *Pos
= 'A' + Digit
- 10;
1772 Len
= &Buffer
[64] - Pos
;
1775 return STATUS_BUFFER_OVERFLOW
;
1777 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1781 return STATUS_ACCESS_VIOLATION
;
1792 RtlCopyMemory(String
, Pos
, Len
);
1794 RtlCopyMemory(String
, Pos
, Len
+ 1);
1798 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1800 /* Get the error code */
1801 Status
= _SEH2_GetExceptionCode();
1813 * dest is never '\0' terminated because it may be equal to src, and src
1814 * might not be '\0' terminated. dest->Length is only set upon success.
1818 RtlUpcaseUnicodeString(
1819 IN OUT PUNICODE_STRING UniDest
,
1820 IN PCUNICODE_STRING UniSource
,
1821 IN BOOLEAN AllocateDestinationString
)
1827 if (AllocateDestinationString
== TRUE
)
1829 UniDest
->MaximumLength
= UniSource
->Length
;
1830 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1831 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1833 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1835 return STATUS_BUFFER_OVERFLOW
;
1838 j
= UniSource
->Length
/ sizeof(WCHAR
);
1840 for (i
= 0; i
< j
; i
++)
1842 UniDest
->Buffer
[i
] = RtlUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1845 UniDest
->Length
= UniSource
->Length
;
1846 return STATUS_SUCCESS
;
1853 * This function always writes a terminating '\0'.
1854 * It performs a partial copy if ansi is too small.
1858 RtlUpcaseUnicodeStringToAnsiString(
1859 IN OUT PANSI_STRING AnsiDest
,
1860 IN PUNICODE_STRING UniSource
,
1861 IN BOOLEAN AllocateDestinationString
)
1868 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1869 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1871 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1873 if (AllocateDestinationString
)
1875 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1876 AnsiDest
->MaximumLength
= Length
;
1877 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1879 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1881 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1884 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1890 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1892 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1893 AnsiDest
->Buffer
= NULL
;
1897 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1905 * This function always writes a terminating '\0'.
1906 * It performs a partial copy if ansi is too small.
1910 RtlUpcaseUnicodeStringToCountedOemString(
1911 IN OUT POEM_STRING OemDest
,
1912 IN PCUNICODE_STRING UniSource
,
1913 IN BOOLEAN AllocateDestinationString
)
1920 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1924 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1927 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1929 OemDest
->Length
= (USHORT
)Length
;
1931 if (AllocateDestinationString
)
1933 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1934 OemDest
->MaximumLength
= Length
;
1935 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1937 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1939 return STATUS_BUFFER_OVERFLOW
;
1942 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1948 /* Check for unmapped characters */
1949 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1950 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1952 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1954 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1955 OemDest
->Buffer
= NULL
;
1965 * Oem string is allways nullterminated
1966 * It performs a partial copy if oem is too small.
1970 RtlUpcaseUnicodeStringToOemString (
1971 IN OUT POEM_STRING OemDest
,
1972 IN PCUNICODE_STRING UniSource
,
1973 IN BOOLEAN AllocateDestinationString
)
1980 Length
= RtlUnicodeStringToOemSize(UniSource
);
1981 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1983 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1985 if (AllocateDestinationString
)
1987 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1988 OemDest
->MaximumLength
= Length
;
1989 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1991 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1993 return STATUS_BUFFER_OVERFLOW
;
1996 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
2002 /* Check for unmapped characters */
2003 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
2004 Status
= STATUS_UNMAPPABLE_CHARACTER
;
2006 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2008 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
2009 OemDest
->Buffer
= NULL
;
2013 OemDest
->Buffer
[Index
] = ANSI_NULL
;
2021 * Bytes calculated including nullterm
2025 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
2029 /* Convert the Mb String to Unicode Size */
2030 RtlMultiByteToUnicodeSize(&Size
,
2034 /* Return the size + null-char */
2035 return (Size
+ sizeof(WCHAR
));
2043 RtlStringFromGUID (IN REFGUID Guid
,
2044 OUT PUNICODE_STRING GuidString
)
2046 /* Setup the string */
2047 GuidString
->Length
= 38 * sizeof(WCHAR
);
2048 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
2049 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
2051 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
2053 /* Now format the GUID */
2054 swprintf(GuidString
->Buffer
,
2055 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2067 return STATUS_SUCCESS
;
2074 * Bytes calculated including nullterm
2078 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
2083 ASSERT(!(UnicodeString
->Length
& 1));
2085 /* Convert the Unicode String to Mb Size */
2086 RtlUnicodeToMultiByteSize(&Size
,
2087 UnicodeString
->Buffer
,
2088 UnicodeString
->Length
);
2090 /* Return the size + null-char */
2091 return (Size
+ sizeof(CHAR
));
2099 RtlCompareUnicodeString(
2100 IN PCUNICODE_STRING s1
,
2101 IN PCUNICODE_STRING s2
,
2102 IN BOOLEAN CaseInsensitive
)
2108 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2112 if (CaseInsensitive
)
2114 while (!ret
&& len
--) ret
= RtlUpcaseUnicodeChar(*p1
++) - RtlUpcaseUnicodeChar(*p2
++);
2118 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2121 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2132 IN OUT PSTRING DestinationString
,
2133 IN PSTRING SourceString OPTIONAL
)
2138 /* Check if there was no source given */
2141 /* Simply return an empty string */
2142 DestinationString
->Length
= 0;
2146 /* Choose the smallest length */
2147 SourceLength
= min(DestinationString
->MaximumLength
,
2148 SourceString
->Length
);
2151 DestinationString
->Length
= (USHORT
)SourceLength
;
2153 /* Save the pointers to each buffer */
2154 p1
= DestinationString
->Buffer
;
2155 p2
= SourceString
->Buffer
;
2157 /* Loop the buffer */
2158 while (SourceLength
)
2160 /* Copy the character and move on */
2172 RtlCopyUnicodeString(
2173 IN OUT PUNICODE_STRING DestinationString
,
2174 IN PCUNICODE_STRING SourceString
)
2178 if(SourceString
== NULL
)
2180 DestinationString
->Length
= 0;
2184 SourceLength
= min(DestinationString
->MaximumLength
,
2185 SourceString
->Length
);
2186 DestinationString
->Length
= (USHORT
)SourceLength
;
2188 RtlCopyMemory(DestinationString
->Buffer
,
2189 SourceString
->Buffer
,
2192 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2194 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2203 * Creates a nullterminated UNICODE_STRING
2207 RtlCreateUnicodeString(
2208 IN OUT PUNICODE_STRING UniDest
,
2214 Length
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2215 if (Length
> 0xFFFE) return FALSE
;
2217 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
2219 if (UniDest
->Buffer
== NULL
) return FALSE
;
2221 RtlCopyMemory(UniDest
->Buffer
, Source
, Length
);
2222 UniDest
->MaximumLength
= (USHORT
)Length
;
2223 UniDest
->Length
= Length
- sizeof (WCHAR
);
2233 RtlCreateUnicodeStringFromAsciiz(
2234 OUT PUNICODE_STRING Destination
,
2237 ANSI_STRING AnsiString
;
2240 RtlInitAnsiString(&AnsiString
, Source
);
2242 Status
= RtlAnsiStringToUnicodeString(Destination
,
2246 return NT_SUCCESS(Status
);
2253 * Dest is never '\0' terminated because it may be equal to src, and src
2254 * might not be '\0' terminated.
2255 * Dest->Length is only set upon success.
2259 RtlDowncaseUnicodeString(
2260 IN OUT PUNICODE_STRING UniDest
,
2261 IN PCUNICODE_STRING UniSource
,
2262 IN BOOLEAN AllocateDestinationString
)
2268 if (AllocateDestinationString
)
2270 UniDest
->MaximumLength
= UniSource
->Length
;
2271 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2272 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2274 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2276 return STATUS_BUFFER_OVERFLOW
;
2279 UniDest
->Length
= UniSource
->Length
;
2280 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2282 for (i
= 0 ; i
< StopGap
; i
++)
2284 if (UniSource
->Buffer
[i
] < L
'A')
2286 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2288 else if (UniSource
->Buffer
[i
] <= L
'Z')
2290 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2294 UniDest
->Buffer
[i
] = RtlDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2298 return STATUS_SUCCESS
;
2305 * if src is NULL dest is unchanged.
2306 * dest is '\0' terminated when the MaximumLength allowes it.
2307 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2311 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2319 UNICODE_STRING UnicodeSource
;
2321 RtlInitUnicodeString(&UnicodeSource
, Source
);
2322 Length
= UnicodeSource
.Length
;
2324 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2326 return STATUS_BUFFER_TOO_SMALL
;
2329 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2330 RtlMoveMemory(DestBuffer
, Source
, Length
);
2331 Destination
->Length
+= Length
;
2333 /* append terminating '\0' if enough space */
2334 if(Destination
->MaximumLength
> Destination
->Length
)
2336 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2340 return STATUS_SUCCESS
;
2347 * if src is NULL dest is unchanged.
2348 * dest is never '\0' terminated.
2352 RtlAppendAsciizToString(
2353 IN OUT PSTRING Destination
,
2360 Length
= (USHORT
)strlen(Source
);
2362 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2364 return STATUS_BUFFER_TOO_SMALL
;
2367 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Length
);
2368 Destination
->Length
+= Length
;
2371 return STATUS_SUCCESS
;
2379 RtlUpperString(PSTRING DestinationString
,
2380 PSTRING SourceString
)
2385 Length
= min(SourceString
->Length
,
2386 DestinationString
->MaximumLength
);
2388 Src
= SourceString
->Buffer
;
2389 Dest
= DestinationString
->Buffer
;
2390 DestinationString
->Length
= Length
;
2394 *Dest
++ = RtlUpperChar(*Src
++);
2403 * See RtlpDuplicateUnicodeString
2407 RtlDuplicateUnicodeString(
2409 IN PCUNICODE_STRING SourceString
,
2410 OUT PUNICODE_STRING DestinationString
)
2414 if (SourceString
== NULL
|| DestinationString
== NULL
||
2415 SourceString
->Length
> SourceString
->MaximumLength
||
2416 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2417 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4)
2419 return STATUS_INVALID_PARAMETER
;
2423 if ((SourceString
->Length
== 0) &&
2424 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2425 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2427 DestinationString
->Length
= 0;
2428 DestinationString
->MaximumLength
= 0;
2429 DestinationString
->Buffer
= NULL
;
2433 UINT DestMaxLength
= SourceString
->Length
;
2435 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2436 DestMaxLength
+= sizeof(UNICODE_NULL
);
2438 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2440 if (DestinationString
->Buffer
== NULL
)
2441 return STATUS_NO_MEMORY
;
2443 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2444 DestinationString
->Length
= SourceString
->Length
;
2445 DestinationString
->MaximumLength
= DestMaxLength
;
2447 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2448 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2451 return STATUS_SUCCESS
;
2459 RtlValidateUnicodeString(IN ULONG Flags
,
2460 IN PCUNICODE_STRING UnicodeString
)
2462 /* currently no flags are supported! */
2466 ((UnicodeString
== NULL
) ||
2467 ((UnicodeString
->Length
!= 0) &&
2468 (UnicodeString
->Buffer
!= NULL
) &&
2469 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2470 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2471 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2473 /* a NULL pointer as a unicode string is considered to be a valid unicode
2475 return STATUS_SUCCESS
;
2479 return STATUS_INVALID_PARAMETER
;
2488 RtlpEnsureBufferSize(ULONG Unknown1
, ULONG Unknown2
, ULONG Unknown3
)
2490 DPRINT1("RtlpEnsureBufferSize: stub\n");
2491 return STATUS_NOT_IMPLEMENTED
;
2499 RtlFindCharInUnicodeString(
2501 IN PUNICODE_STRING SearchString
,
2502 IN PCUNICODE_STRING MatchString
,
2503 OUT PUSHORT Position
)
2506 unsigned int search_idx
;
2512 for (main_idx
= 0; main_idx
< SearchString
->Length
/ sizeof(WCHAR
); main_idx
++)
2514 for (search_idx
= 0; search_idx
< MatchString
->Length
/ sizeof(WCHAR
); search_idx
++)
2516 if (SearchString
->Buffer
[main_idx
] == MatchString
->Buffer
[search_idx
])
2518 *Position
= (main_idx
+ 1) * sizeof(WCHAR
);
2519 return STATUS_SUCCESS
;
2525 return STATUS_NOT_FOUND
;
2530 for (main_idx
= SearchString
->Length
/ sizeof(WCHAR
) - 1; main_idx
>= 0; main_idx
--)
2532 for (search_idx
= 0; search_idx
< MatchString
->Length
/ sizeof(WCHAR
); search_idx
++)
2534 if (SearchString
->Buffer
[main_idx
] == MatchString
->Buffer
[search_idx
])
2536 *Position
= main_idx
* sizeof(WCHAR
);
2537 return STATUS_SUCCESS
;
2543 return STATUS_NOT_FOUND
;
2548 for (main_idx
= 0; main_idx
< SearchString
->Length
/ sizeof(WCHAR
); main_idx
++)
2552 while (search_idx
< MatchString
->Length
/ sizeof(WCHAR
) &&
2553 SearchString
->Buffer
[main_idx
] != MatchString
->Buffer
[search_idx
])
2558 if (search_idx
>= MatchString
->Length
/ sizeof(WCHAR
))
2560 *Position
= (main_idx
+ 1) * sizeof(WCHAR
);
2561 return STATUS_SUCCESS
;
2566 return STATUS_NOT_FOUND
;
2571 for (main_idx
= SearchString
->Length
/ sizeof(WCHAR
) - 1; main_idx
>= 0; main_idx
--)
2575 while (search_idx
< MatchString
->Length
/ sizeof(WCHAR
) &&
2576 SearchString
->Buffer
[main_idx
] != MatchString
->Buffer
[search_idx
])
2581 if (search_idx
>= MatchString
->Length
/ sizeof(WCHAR
))
2583 *Position
= main_idx
* sizeof(WCHAR
);
2584 return STATUS_SUCCESS
;
2589 return STATUS_NOT_FOUND
;
2593 return STATUS_NOT_FOUND
;
2600 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2601 * Convert is to an uppercase oem string and check for unmapped characters.
2602 * Then convert the oem string back to an unicode string.
2606 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
, PUNICODE_STRING DnsHostName
, BOOLEAN AllocateComputerNameString
)
2610 ULONG ComputerNameLength
;
2611 ULONG ComputerNameOemNLength
;
2612 OEM_STRING ComputerNameOem
;
2613 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2615 Status
= STATUS_INVALID_COMPUTER_NAME
;
2616 ComputerNameLength
= DnsHostName
->Length
;
2618 /* find the first dot in the dns host name */
2619 for (Length
= 0; Length
< DnsHostName
->Length
/ sizeof(WCHAR
); Length
++)
2621 if (DnsHostName
->Buffer
[Length
] == L
'.')
2623 /* dot found, so set the length for the oem translation */
2624 ComputerNameLength
= Length
* sizeof(WCHAR
);
2629 /* the computername must have one character */
2630 if (ComputerNameLength
> 0)
2632 ComputerNameOemNLength
= 0;
2633 /* convert to oem string and use uppercase letters */
2634 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2635 MAX_COMPUTERNAME_LENGTH
,
2636 &ComputerNameOemNLength
,
2637 DnsHostName
->Buffer
,
2638 ComputerNameLength
);
2640 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2641 have MAX_COMPUTERNAME_LENGTH characters */
2642 if ((Status
== STATUS_SUCCESS
) ||
2643 (Status
== STATUS_BUFFER_OVERFLOW
))
2645 /* set the termination for the oem string */
2646 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2647 /* set status for the case the next function failed */
2648 Status
= STATUS_INVALID_COMPUTER_NAME
;
2649 /* fillup the oem string structure with the converted computername
2650 and check it for unmapped characters */
2651 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2652 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2653 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2655 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
) == TRUE
)
2657 /* no unmapped character so convert it back to an unicode string */
2658 Status
= RtlOemStringToUnicodeString(ComputerName
,
2660 AllocateComputerNameString
);