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
;
26 extern USHORT NlsOemDefaultChar
;
27 extern USHORT NlsUnicodeDefaultChar
;
29 /* FUNCTIONS *****************************************************************/
36 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR
*AnsiChar
)
40 WCHAR UnicodeChar
= L
' ';
46 Size
= (NlsLeadByteInfo
[**AnsiChar
] == 0) ? 1 : 2;
50 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
54 Status
= RtlMultiByteToUnicodeN(&UnicodeChar
,
60 if (!NT_SUCCESS(Status
))
73 * This function always writes a terminating '\0'.
74 * If the dest buffer is too small a partial copy is NOT performed!
78 RtlAnsiStringToUnicodeString(
79 IN OUT PUNICODE_STRING UniDest
,
80 IN PANSI_STRING AnsiSource
,
81 IN BOOLEAN AllocateDestinationString
)
89 if (NlsMbCodePageTag
== FALSE
)
91 Length
= AnsiSource
->Length
* 2 + sizeof(WCHAR
);
95 Length
= RtlxAnsiStringToUnicodeSize(AnsiSource
);
97 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
98 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
100 if (AllocateDestinationString
)
102 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
103 UniDest
->MaximumLength
= Length
;
104 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
106 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
108 return STATUS_BUFFER_OVERFLOW
;
111 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
112 ASSERT(!(UniDest
->MaximumLength
& 1) && UniDest
->Length
<= UniDest
->MaximumLength
);
114 Status
= RtlMultiByteToUnicodeN(UniDest
->Buffer
,
120 if (!NT_SUCCESS(Status
))
122 if (AllocateDestinationString
)
124 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
125 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
)
148 /* Convert from Mb String to Unicode Size */
149 RtlMultiByteToUnicodeSize(&Size
,
153 /* Return the size plus the null-char */
154 return(Size
+ sizeof(WCHAR
));
161 * If src->length is zero dest is unchanged.
162 * Dest is never nullterminated.
166 RtlAppendStringToString(IN PSTRING Destination
,
169 USHORT SourceLength
= Source
->Length
;
173 if (Destination
->Length
+ SourceLength
> Destination
->MaximumLength
)
175 return STATUS_BUFFER_TOO_SMALL
;
178 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
],
182 Destination
->Length
+= SourceLength
;
185 return STATUS_SUCCESS
;
192 * If src->length is zero dest is unchanged.
193 * Dest is nullterminated when the MaximumLength allowes it.
194 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
198 RtlAppendUnicodeStringToString(
199 IN OUT PUNICODE_STRING Destination
,
200 IN PCUNICODE_STRING Source
)
202 USHORT SourceLength
= Source
->Length
;
203 PWCHAR Buffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
207 if ((SourceLength
+ Destination
->Length
) > Destination
->MaximumLength
)
209 return STATUS_BUFFER_TOO_SMALL
;
212 RtlMoveMemory(Buffer
, Source
->Buffer
, SourceLength
);
213 Destination
->Length
+= SourceLength
;
215 /* append terminating '\0' if enough space */
216 if (Destination
->MaximumLength
> Destination
->Length
)
218 Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
222 return STATUS_SUCCESS
;
225 /**************************************************************************
226 * RtlCharToInteger (NTDLL.@)
228 * Converts a character string into its integer equivalent.
231 * Success: STATUS_SUCCESS. value contains the converted number
232 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
233 * STATUS_ACCESS_VIOLATION, if value is NULL.
236 * For base 0 it uses 10 as base and the string should be in the format
237 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
238 * For other bases the string should be in the format
239 * "{whitespace} [+|-] {digits}".
240 * No check is made for value overflow, only the lower 32 bits are assigned.
241 * If str is NULL it crashes, as the native function does.
244 * This function does not read garbage behind '\0' as the native version does.
249 PCSZ str
, /* [I] '\0' terminated single-byte string containing a number */
250 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
251 PULONG value
) /* [O] Destination for the converted value */
255 ULONG RunningTotal
= 0;
258 while (*str
!= '\0' && *str
<= ' ') {
264 } else if (*str
== '-') {
275 } else if (str
[1] == 'o') {
278 } else if (str
[1] == 'x') {
283 } else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16) {
284 return STATUS_INVALID_PARAMETER
;
288 return STATUS_ACCESS_VIOLATION
;
291 while (*str
!= '\0') {
293 if (chCurrent
>= '0' && chCurrent
<= '9') {
294 digit
= chCurrent
- '0';
295 } else if (chCurrent
>= 'A' && chCurrent
<= 'Z') {
296 digit
= chCurrent
- 'A' + 10;
297 } else if (chCurrent
>= 'a' && chCurrent
<= 'z') {
298 digit
= chCurrent
- 'a' + 10;
302 if (digit
< 0 || digit
>= (int)base
) {
303 *value
= bMinus
? -RunningTotal
: RunningTotal
;
304 return STATUS_SUCCESS
;
307 RunningTotal
= RunningTotal
* base
+ digit
;
311 *value
= bMinus
? -RunningTotal
: RunningTotal
;
312 return STATUS_SUCCESS
;
323 IN BOOLEAN CaseInsensitive
)
329 len
= min(s1
->Length
, s2
->Length
);
335 while (!ret
&& len
--) ret
= RtlUpperChar(*p1
++) - RtlUpperChar(*p2
++);
339 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
341 if (!ret
) ret
= s1
->Length
- s2
->Length
;
349 * TRUE if strings are equal.
356 IN BOOLEAN CaseInsensitive
)
358 if (s1
->Length
!= s2
->Length
) return FALSE
;
359 return !RtlCompareString(s1
, s2
, CaseInsensitive
);
366 * TRUE if strings are equal.
370 RtlEqualUnicodeString(
371 IN CONST UNICODE_STRING
*s1
,
372 IN CONST UNICODE_STRING
*s2
,
373 IN BOOLEAN CaseInsensitive
)
375 if (s1
->Length
!= s2
->Length
) return FALSE
;
376 return !RtlCompareUnicodeString(s1
, s2
, CaseInsensitive
);
384 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
388 if (AnsiString
->Buffer
)
390 RtlpFreeStringMemory(AnsiString
->Buffer
, TAG_ASTR
);
391 RtlZeroMemory(AnsiString
, sizeof(ANSI_STRING
));
400 RtlFreeOemString(IN POEM_STRING OemString
)
404 if (OemString
->Buffer
) RtlpFreeStringMemory(OemString
->Buffer
, TAG_OSTR
);
412 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
416 if (UnicodeString
->Buffer
)
418 RtlpFreeStringMemory(UnicodeString
->Buffer
, TAG_USTR
);
419 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
428 * Check the OEM string to match the Unicode string.
430 * Functions which convert Unicode strings to OEM strings will set a
431 * DefaultChar from the OEM codepage when the characters are unknown.
432 * So check it against the Unicode string and return false when the
433 * Unicode string does not contain a TransDefaultChar.
437 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString
,
438 IN POEM_STRING OemString
)
442 if (NlsMbOemCodePageTag
== FALSE
)
444 /* single-byte code page */
445 /* Go through all characters of a string */
446 while (i
< OemString
->Length
)
448 /* Check if it got translated into a default char,
449 * but source char wasn't a default char equivalent
451 if ((OemString
->Buffer
[i
] == NlsOemDefaultChar
) &&
452 (UnicodeString
->Buffer
[i
] != NlsUnicodeDefaultChar
))
454 /* Yes, it means unmappable characters were found */
458 /* Move to the next char */
462 /* All chars were translated successfuly */
467 /* multibyte code page */
479 RtlIsValidOemCharacter(IN PWCHAR Char
)
489 * If source is NULL the length of source is assumed to be 0.
493 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
494 IN PCSZ SourceString
)
500 DestSize
= strlen(SourceString
);
501 DestinationString
->Length
= (USHORT
)DestSize
;
502 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(CHAR
);
506 DestinationString
->Length
= 0;
507 DestinationString
->MaximumLength
= 0;
510 DestinationString
->Buffer
= (PCHAR
)SourceString
;
515 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString
,
516 IN PCSZ SourceString
)
522 DestSize
= strlen(SourceString
);
523 if (DestSize
>= 0xFFFF) return STATUS_NAME_TOO_LONG
;
524 DestinationString
->Length
= (USHORT
)DestSize
;
525 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(CHAR
);
529 DestinationString
->Length
= 0;
530 DestinationString
->MaximumLength
= 0;
533 DestinationString
->Buffer
= (PCHAR
)SourceString
;
534 return STATUS_SUCCESS
;
541 * If source is NULL the length of source is assumed to be 0.
546 IN OUT PSTRING DestinationString
,
547 IN PCSZ SourceString
)
549 RtlInitAnsiString(DestinationString
, SourceString
);
556 * If source is NULL the length of source is assumed to be 0.
560 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString
,
561 IN PCWSTR SourceString
)
567 DestSize
= wcslen(SourceString
) * sizeof(WCHAR
);
568 DestinationString
->Length
= (USHORT
)DestSize
;
569 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(WCHAR
);
573 DestinationString
->Length
= 0;
574 DestinationString
->MaximumLength
= 0;
577 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
585 RtlInitUnicodeStringEx(OUT PUNICODE_STRING DestinationString
,
586 IN PCWSTR SourceString
)
592 DestSize
= wcslen(SourceString
) * sizeof(WCHAR
);
593 if (DestSize
>= 0xFFFC) return STATUS_NAME_TOO_LONG
;
594 DestinationString
->Length
= (USHORT
)DestSize
;
595 DestinationString
->MaximumLength
= (USHORT
)DestSize
+ sizeof(WCHAR
);
599 DestinationString
->Length
= 0;
600 DestinationString
->MaximumLength
= 0;
603 DestinationString
->Buffer
= (PWCHAR
)SourceString
;
604 return STATUS_SUCCESS
;
611 * Writes at most length characters to the string str.
612 * Str is nullterminated when length allowes it.
613 * When str fits exactly in length characters the nullterm is ommitted.
615 NTSTATUS NTAPI
RtlIntegerToChar(
616 ULONG value
, /* [I] Value to be converted */
617 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
618 ULONG length
, /* [I] Length of the str buffer in bytes */
619 PCHAR str
) /* [O] Destination for the converted value */
628 } else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16) {
629 return STATUS_INVALID_PARAMETER
;
637 digit
= value
% base
;
638 value
= value
/ base
;
642 *pos
= 'A' + digit
- 10;
644 } while (value
!= 0L);
646 len
= &buffer
[32] - pos
;
648 return STATUS_BUFFER_OVERFLOW
;
649 } else if (str
== NULL
) {
650 return STATUS_ACCESS_VIOLATION
;
651 } else if (len
== length
) {
652 memcpy(str
, pos
, len
);
654 memcpy(str
, pos
, len
+ 1);
656 return STATUS_SUCCESS
;
666 IN ULONG Base OPTIONAL
,
667 IN ULONG Length OPTIONAL
,
682 if ((Radix
!= 2) && (Radix
!= 8) &&
683 (Radix
!= 10) && (Radix
!= 16))
685 return STATUS_INVALID_PARAMETER
;
689 while (v
|| tp
== temp
)
700 if ((ULONG
)((ULONG_PTR
)tp
- (ULONG_PTR
)temp
) >= Length
)
702 return STATUS_BUFFER_TOO_SMALL
;
710 return STATUS_SUCCESS
;
718 RtlIntegerToUnicodeString(
720 IN ULONG Base OPTIONAL
,
721 IN OUT PUNICODE_STRING String
)
723 ANSI_STRING AnsiString
;
727 Status
= RtlIntegerToChar(Value
, Base
, sizeof(Buffer
), Buffer
);
728 if (NT_SUCCESS(Status
))
730 AnsiString
.Buffer
= Buffer
;
731 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
732 AnsiString
.MaximumLength
= sizeof(Buffer
);
734 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
745 RtlInt64ToUnicodeString (
747 IN ULONG Base OPTIONAL
,
748 IN OUT PUNICODE_STRING String
)
750 LARGE_INTEGER LargeInt
;
751 ANSI_STRING AnsiString
;
755 LargeInt
.QuadPart
= Value
;
757 Status
= RtlLargeIntegerToChar(&LargeInt
, Base
, sizeof(Buffer
), Buffer
);
758 if (NT_SUCCESS(Status
))
760 AnsiString
.Buffer
= Buffer
;
761 AnsiString
.Length
= (USHORT
)strlen(Buffer
);
762 AnsiString
.MaximumLength
= sizeof(Buffer
);
764 Status
= RtlAnsiStringToUnicodeString(String
, &AnsiString
, FALSE
);
774 * TRUE if String2 contains String1 as a prefix.
779 PANSI_STRING String1
,
780 PANSI_STRING String2
,
781 BOOLEAN CaseInsensitive
)
787 if (String2
->Length
< String1
->Length
)
790 Length
= String1
->Length
;
791 pc1
= String1
->Buffer
;
792 pc2
= String2
->Buffer
;
800 if (RtlUpperChar (*pc1
++) != RtlUpperChar (*pc2
++))
808 if (*pc1
++ != *pc2
++)
821 * TRUE if String2 contains String1 as a prefix.
825 RtlPrefixUnicodeString(
826 PCUNICODE_STRING String1
,
827 PCUNICODE_STRING String2
,
828 BOOLEAN CaseInsensitive
)
834 if (String2
->Length
< String1
->Length
)
837 Length
= String1
->Length
/ 2;
838 pc1
= String1
->Buffer
;
839 pc2
= String2
->Buffer
;
847 if (RtlUpcaseUnicodeChar (*pc1
++)
848 != RtlUpcaseUnicodeChar (*pc2
++))
856 if( *pc1
++ != *pc2
++ )
869 RtlUnicodeStringToInteger(const UNICODE_STRING
*str
, /* [I] Unicode string to be converted */
870 ULONG base
, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
871 ULONG
*value
) /* [O] Destination for the converted value */
873 LPWSTR lpwstr
= str
->Buffer
;
874 USHORT CharsRemaining
= str
->Length
/ sizeof(WCHAR
);
877 ULONG RunningTotal
= 0;
880 while (CharsRemaining
>= 1 && *lpwstr
<= ' ') {
885 if (CharsRemaining
>= 1) {
886 if (*lpwstr
== '+') {
889 } else if (*lpwstr
== '-') {
898 if (CharsRemaining
>= 2 && lpwstr
[0] == '0') {
899 if (lpwstr
[1] == 'b') {
903 } else if (lpwstr
[1] == 'o') {
907 } else if (lpwstr
[1] == 'x') {
913 } else if (base
!= 2 && base
!= 8 && base
!= 10 && base
!= 16) {
914 return STATUS_INVALID_PARAMETER
;
918 return STATUS_ACCESS_VIOLATION
;
921 while (CharsRemaining
>= 1) {
922 wchCurrent
= *lpwstr
;
923 if (wchCurrent
>= '0' && wchCurrent
<= '9') {
924 digit
= wchCurrent
- '0';
925 } else if (wchCurrent
>= 'A' && wchCurrent
<= 'Z') {
926 digit
= wchCurrent
- 'A' + 10;
927 } else if (wchCurrent
>= 'a' && wchCurrent
<= 'z') {
928 digit
= wchCurrent
- 'a' + 10;
932 if (digit
< 0 || digit
>= base
) {
933 *value
= bMinus
? -RunningTotal
: RunningTotal
;
934 return STATUS_SUCCESS
;
937 RunningTotal
= RunningTotal
* base
+ digit
;
942 *value
= bMinus
? -RunningTotal
: RunningTotal
;
943 return STATUS_SUCCESS
;
950 * Bytes necessary for the conversion including nullterm.
954 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString
)
958 /* Convert the Unicode String to Mb Size */
959 RtlUnicodeToMultiByteSize(&Size
,
960 UnicodeString
->Buffer
,
961 UnicodeString
->Length
);
963 /* Return the size + the null char */
964 return (Size
+ sizeof(CHAR
));
971 * This function always writes a terminating '\0'.
972 * It performs a partial copy if ansi is too small.
976 RtlUnicodeStringToAnsiString(
977 IN OUT PANSI_STRING AnsiDest
,
978 IN PCUNICODE_STRING UniSource
,
979 IN BOOLEAN AllocateDestinationString
)
981 NTSTATUS Status
= STATUS_SUCCESS
;
988 ASSERT(!(UniSource
->Length
& 1));
990 if (NlsMbCodePageTag
== FALSE
)
992 Length
= (UniSource
->Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
996 Length
= RtlxUnicodeStringToAnsiSize(UniSource
);
998 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1000 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1002 if (AllocateDestinationString
)
1004 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1005 AnsiDest
->MaximumLength
= Length
;
1006 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1008 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1010 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1012 Status
= STATUS_BUFFER_OVERFLOW
;
1013 AnsiDest
->Length
= AnsiDest
->MaximumLength
- 1;
1016 RealStatus
= RtlUnicodeToMultiByteN(AnsiDest
->Buffer
,
1022 if (!NT_SUCCESS(RealStatus
) && AllocateDestinationString
)
1024 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1028 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1036 * This function always writes a terminating '\0'.
1037 * Does NOT perform a partial copy if unicode is too small!
1041 RtlOemStringToUnicodeString(
1042 IN OUT PUNICODE_STRING UniDest
,
1043 IN PCOEM_STRING OemSource
,
1044 IN BOOLEAN AllocateDestinationString
)
1052 Length
= RtlOemStringToUnicodeSize(OemSource
);
1053 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1055 UniDest
->Length
= (USHORT
)Length
- sizeof(WCHAR
);
1057 if (AllocateDestinationString
)
1059 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1060 UniDest
->MaximumLength
= Length
;
1061 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1063 else if (UniDest
->Length
>= UniDest
->MaximumLength
)
1065 return STATUS_BUFFER_OVERFLOW
;
1068 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1074 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1076 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1077 UniDest
->Buffer
= NULL
;
1081 UniDest
->Buffer
[Index
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1089 * This function always '\0' terminates the string returned.
1093 RtlUnicodeStringToOemString(
1094 IN OUT POEM_STRING OemDest
,
1095 IN PCUNICODE_STRING UniSource
,
1096 IN BOOLEAN AllocateDestinationString
)
1104 Length
= RtlUnicodeStringToOemSize(UniSource
);
1105 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1107 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1109 if (AllocateDestinationString
)
1111 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1112 OemDest
->MaximumLength
= Length
;
1113 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1115 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1117 return STATUS_BUFFER_OVERFLOW
;
1120 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1126 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1128 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1129 OemDest
->Buffer
= NULL
;
1133 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1137 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1143 * The length of the string if all tests were passed, 0 otherwise.
1147 RtlIsTextUnicode( PVOID buf
, INT len
, INT
*pf
)
1149 static const WCHAR std_control_chars
[] = {'\r','\n','\t',' ',0x3000,0};
1150 static const WCHAR byterev_control_chars
[] = {0x0d00,0x0a00,0x0900,0x2000,0};
1151 const WCHAR
*s
= buf
;
1153 unsigned int flags
= MAXULONG
, out_flags
= 0;
1155 if (len
< sizeof(WCHAR
))
1157 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1164 * Apply various tests to the text string. According to the
1165 * docs, each test "passed" sets the corresponding flag in
1166 * the output flags. But some of the tests are mutually
1167 * exclusive, so I don't see how you could pass all tests ...
1170 /* Check for an odd length ... pass if even. */
1171 if (len
& 1) out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1173 if (((char *)buf
)[len
- 1] == 0)
1174 len
--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1176 len
/= sizeof(WCHAR
);
1177 /* Windows only checks the first 256 characters */
1178 if (len
> 256) len
= 256;
1180 /* Check for the special byte order unicode marks. */
1181 if (*s
== 0xFEFF) out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1182 if (*s
== 0xFFFE) out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1184 /* apply some statistical analysis */
1185 if (flags
& IS_TEXT_UNICODE_STATISTICS
)
1188 /* FIXME: checks only for ASCII characters in the unicode stream */
1189 for (i
= 0; i
< len
; i
++)
1191 if (s
[i
] <= 255) stats
++;
1193 if (stats
> len
/ 2)
1194 out_flags
|= IS_TEXT_UNICODE_STATISTICS
;
1197 /* Check for unicode NULL chars */
1198 if (flags
& IS_TEXT_UNICODE_NULL_BYTES
)
1200 for (i
= 0; i
< len
; i
++)
1202 if (!(s
[i
] & 0xff) || !(s
[i
] >> 8))
1204 out_flags
|= IS_TEXT_UNICODE_NULL_BYTES
;
1210 if (flags
& IS_TEXT_UNICODE_CONTROLS
)
1212 for (i
= 0; i
< len
; i
++)
1214 if (strchrW(std_control_chars
, s
[i
]))
1216 out_flags
|= IS_TEXT_UNICODE_CONTROLS
;
1222 if (flags
& IS_TEXT_UNICODE_REVERSE_CONTROLS
)
1224 for (i
= 0; i
< len
; i
++)
1226 if (strchrW(byterev_control_chars
, s
[i
]))
1228 out_flags
|= IS_TEXT_UNICODE_REVERSE_CONTROLS
;
1239 /* check for flags that indicate it's definitely not valid Unicode */
1240 if (out_flags
& (IS_TEXT_UNICODE_REVERSE_MASK
| IS_TEXT_UNICODE_NOT_UNICODE_MASK
)) return FALSE
;
1241 /* now check for invalid ASCII, and assume Unicode if so */
1242 if (out_flags
& IS_TEXT_UNICODE_NOT_ASCII_MASK
) return TRUE
;
1243 /* now check for Unicode flags */
1244 if (out_flags
& IS_TEXT_UNICODE_UNICODE_MASK
) return TRUE
;
1254 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1255 * A partial copy is NOT performed if the dest buffer is too small!
1259 RtlOemStringToCountedUnicodeString(
1260 IN OUT PUNICODE_STRING UniDest
,
1261 IN PCOEM_STRING OemSource
,
1262 IN BOOLEAN AllocateDestinationString
)
1270 /* Calculate size of the string */
1271 Length
= RtlOemStringToCountedUnicodeSize(OemSource
);
1273 /* If it's 0 then zero out dest string and return */
1276 RtlZeroMemory(UniDest
, sizeof(UNICODE_STRING
));
1277 return STATUS_SUCCESS
;
1280 /* Check if length is a sane value */
1281 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1283 /* Store it in dest string */
1284 UniDest
->Length
= (USHORT
)Length
;
1286 /* If we're asked to alloc the string - do so */
1287 if (AllocateDestinationString
)
1289 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
1290 UniDest
->MaximumLength
= Length
;
1291 if (!UniDest
->Buffer
) return STATUS_NO_MEMORY
;
1293 else if (UniDest
->Length
> UniDest
->MaximumLength
)
1295 return STATUS_BUFFER_OVERFLOW
;
1298 /* Do the conversion */
1299 Status
= RtlOemToUnicodeN(UniDest
->Buffer
,
1305 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1307 /* Conversion failed, free dest string and return status code */
1308 RtlpFreeStringMemory(UniDest
->Buffer
, TAG_USTR
);
1309 UniDest
->Buffer
= NULL
;
1313 return STATUS_SUCCESS
;
1320 * TRUE if the names are equal, FALSE if not
1323 * The comparison is case insensitive.
1327 RtlEqualComputerName(
1328 IN PUNICODE_STRING ComputerName1
,
1329 IN PUNICODE_STRING ComputerName2
)
1331 OEM_STRING OemString1
;
1332 OEM_STRING OemString2
;
1333 BOOLEAN Result
= FALSE
;
1335 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1
,
1339 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2
,
1343 Result
= RtlEqualString(&OemString1
, &OemString2
, FALSE
);
1344 RtlFreeOemString(&OemString2
);
1346 RtlFreeOemString(&OemString1
);
1356 * TRUE if the names are equal, FALSE if not
1359 * The comparison is case insensitive.
1363 RtlEqualDomainName (
1364 IN PUNICODE_STRING DomainName1
,
1365 IN PUNICODE_STRING DomainName2
1368 return RtlEqualComputerName(DomainName1
, DomainName2
);
1374 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1376 * Convert a string representation of a GUID into a GUID.
1379 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1380 * guid [O] Destination for the converted GUID
1383 * Success: STATUS_SUCCESS. guid contains the converted value.
1384 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1387 * See RtlStringFromGUID.
1392 IN UNICODE_STRING
*str
,
1397 const WCHAR
*lpszCLSID
= str
->Buffer
;
1398 BYTE
* lpOut
= (BYTE
*)guid
;
1400 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1402 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1403 * to memory: DWORD... WORD WORD BYTES............
1410 if (*lpszCLSID
!= '{')
1411 return STATUS_INVALID_PARAMETER
;
1418 if (*lpszCLSID
!= '-')
1419 return STATUS_INVALID_PARAMETER
;
1423 if (*lpszCLSID
!= '}')
1424 return STATUS_INVALID_PARAMETER
;
1429 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1432 /* Read two hex digits as a byte value */
1433 if (ch
>= '0' && ch
<= '9')
1435 else if (ch
>= 'a' && ch
<= 'f')
1437 else if (ch
>= 'A' && ch
<= 'F')
1440 return STATUS_INVALID_PARAMETER
;
1442 if (ch2
>= '0' && ch2
<= '9')
1444 else if (ch2
>= 'a' && ch2
<= 'f')
1445 ch2
= ch2
- 'a' + 10;
1446 else if (ch2
>= 'A' && ch2
<= 'F')
1447 ch2
= ch2
- 'A' + 10;
1449 return STATUS_INVALID_PARAMETER
;
1451 byte
= ch
<< 4 | ch2
;
1455 #ifndef WORDS_BIGENDIAN
1456 /* For Big Endian machines, we store the data such that the
1457 * dword/word members can be read as DWORDS and WORDS correctly. */
1489 lpszCLSID
++; /* Skip 2nd character of byte */
1497 return STATUS_SUCCESS
;
1505 RtlEraseUnicodeString(
1506 IN PUNICODE_STRING String
)
1508 if (String
->Buffer
&& String
->MaximumLength
)
1510 RtlZeroMemory(String
->Buffer
, String
->MaximumLength
);
1520 RtlHashUnicodeString(
1521 IN CONST UNICODE_STRING
*String
,
1522 IN BOOLEAN CaseInSensitive
,
1523 IN ULONG HashAlgorithm
,
1524 OUT PULONG HashValue
)
1526 if (String
!= NULL
&& HashValue
!= NULL
)
1528 switch (HashAlgorithm
)
1530 case HASH_STRING_ALGORITHM_DEFAULT
:
1531 case HASH_STRING_ALGORITHM_X65599
:
1536 end
= String
->Buffer
+ (String
->Length
/ sizeof(WCHAR
));
1538 if (CaseInSensitive
)
1540 for (c
= String
->Buffer
;
1544 /* only uppercase characters if they are 'a' ... 'z'! */
1545 *HashValue
= ((65599 * (*HashValue
)) +
1546 (ULONG
)(((*c
) >= L
'a' && (*c
) <= L
'z') ?
1547 (*c
) - L
'a' + L
'A' : (*c
)));
1552 for (c
= String
->Buffer
;
1556 *HashValue
= ((65599 * (*HashValue
)) + (ULONG
)(*c
));
1559 return STATUS_SUCCESS
;
1564 return STATUS_INVALID_PARAMETER
;
1571 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1572 * Does a partial copy if the dest buffer is too small
1576 RtlUnicodeStringToCountedOemString(
1577 IN OUT POEM_STRING OemDest
,
1578 IN PUNICODE_STRING UniSource
,
1579 IN BOOLEAN AllocateDestinationString
)
1587 /* Calculate size of the string */
1588 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1590 /* If it's 0 then zero out dest string and return */
1593 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1594 return STATUS_SUCCESS
;
1597 /* Check if length is a sane value */
1598 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1600 /* Store it in dest string */
1601 OemDest
->Length
= (USHORT
)Length
;
1603 /* If we're asked to alloc the string - do so */
1604 if (AllocateDestinationString
)
1606 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1607 OemDest
->MaximumLength
= Length
;
1608 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1610 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1612 return STATUS_BUFFER_OVERFLOW
;
1615 /* Do the conversion */
1616 Status
= RtlUnicodeToOemN(OemDest
->Buffer
,
1622 /* Check for unmapped character */
1623 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1624 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1626 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1628 /* Conversion failed, free dest string and return status code */
1629 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1630 OemDest
->Buffer
= NULL
;
1642 RtlLargeIntegerToChar(
1643 IN PLARGE_INTEGER Value
,
1646 IN OUT PCHAR String
)
1648 ULONGLONG Val
= Value
->QuadPart
;
1649 NTSTATUS Status
= STATUS_SUCCESS
;
1655 if (Base
== 0) Base
= 10;
1657 if ((Base
!= 2) && (Base
!= 8) &&
1658 (Base
!= 10) && (Base
!= 16))
1660 return STATUS_INVALID_PARAMETER
;
1674 *Pos
= 'A' + Digit
- 10;
1678 Len
= &Buffer
[64] - Pos
;
1681 return STATUS_BUFFER_OVERFLOW
;
1683 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1686 return STATUS_ACCESS_VIOLATION
;
1695 RtlCopyMemory(String
, Pos
, Len
);
1697 RtlCopyMemory(String
, Pos
, Len
+ 1);
1700 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1702 /* Get the error code */
1703 Status
= _SEH2_GetExceptionCode();
1715 * dest is never '\0' terminated because it may be equal to src, and src
1716 * might not be '\0' terminated. dest->Length is only set upon success.
1720 RtlUpcaseUnicodeString(
1721 IN OUT PUNICODE_STRING UniDest
,
1722 IN PCUNICODE_STRING UniSource
,
1723 IN BOOLEAN AllocateDestinationString
)
1729 if (AllocateDestinationString
== TRUE
)
1731 UniDest
->MaximumLength
= UniSource
->Length
;
1732 UniDest
->Buffer
= RtlpAllocateStringMemory(UniDest
->MaximumLength
, TAG_USTR
);
1733 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
1735 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1737 return STATUS_BUFFER_OVERFLOW
;
1740 j
= UniSource
->Length
/ sizeof(WCHAR
);
1742 for (i
= 0; i
< j
; i
++)
1744 UniDest
->Buffer
[i
] = RtlUpcaseUnicodeChar(UniSource
->Buffer
[i
]);
1747 UniDest
->Length
= UniSource
->Length
;
1748 return STATUS_SUCCESS
;
1755 * This function always writes a terminating '\0'.
1756 * It performs a partial copy if ansi is too small.
1760 RtlUpcaseUnicodeStringToAnsiString(
1761 IN OUT PANSI_STRING AnsiDest
,
1762 IN PUNICODE_STRING UniSource
,
1763 IN BOOLEAN AllocateDestinationString
)
1771 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1772 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1774 AnsiDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1776 if (AllocateDestinationString
)
1778 AnsiDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_ASTR
);
1779 AnsiDest
->MaximumLength
= Length
;
1780 if (!AnsiDest
->Buffer
) return STATUS_NO_MEMORY
;
1782 else if (AnsiDest
->Length
>= AnsiDest
->MaximumLength
)
1784 if (!AnsiDest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1787 Status
= RtlUpcaseUnicodeToMultiByteN(AnsiDest
->Buffer
,
1793 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1795 RtlpFreeStringMemory(AnsiDest
->Buffer
, TAG_ASTR
);
1796 AnsiDest
->Buffer
= NULL
;
1800 AnsiDest
->Buffer
[Index
] = ANSI_NULL
;
1808 * This function always writes a terminating '\0'.
1809 * It performs a partial copy if ansi is too small.
1813 RtlUpcaseUnicodeStringToCountedOemString(
1814 IN OUT POEM_STRING OemDest
,
1815 IN PCUNICODE_STRING UniSource
,
1816 IN BOOLEAN AllocateDestinationString
)
1824 Length
= RtlUnicodeStringToCountedOemSize(UniSource
);
1828 RtlZeroMemory(OemDest
, sizeof(OEM_STRING
));
1831 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1833 OemDest
->Length
= (USHORT
)Length
;
1835 if (AllocateDestinationString
)
1837 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1838 OemDest
->MaximumLength
= Length
;
1839 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1841 else if (OemDest
->Length
> OemDest
->MaximumLength
)
1843 return STATUS_BUFFER_OVERFLOW
;
1846 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1852 /* Check for unmapped characters */
1853 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1854 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1856 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1858 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1859 OemDest
->Buffer
= NULL
;
1869 * Oem string is allways nullterminated
1870 * It performs a partial copy if oem is too small.
1874 RtlUpcaseUnicodeStringToOemString (
1875 IN OUT POEM_STRING OemDest
,
1876 IN PCUNICODE_STRING UniSource
,
1877 IN BOOLEAN AllocateDestinationString
)
1885 Length
= RtlUnicodeStringToOemSize(UniSource
);
1886 if (Length
> MAXUSHORT
) return STATUS_INVALID_PARAMETER_2
;
1888 OemDest
->Length
= (USHORT
)Length
- sizeof(CHAR
);
1890 if (AllocateDestinationString
)
1892 OemDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_OSTR
);
1893 OemDest
->MaximumLength
= Length
;
1894 if (!OemDest
->Buffer
) return STATUS_NO_MEMORY
;
1896 else if (OemDest
->Length
>= OemDest
->MaximumLength
)
1898 return STATUS_BUFFER_OVERFLOW
;
1901 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1907 /* Check for unmapped characters */
1908 if (NT_SUCCESS(Status
) && !RtlpDidUnicodeToOemWork(UniSource
, OemDest
))
1909 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1911 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1913 RtlpFreeStringMemory(OemDest
->Buffer
, TAG_OSTR
);
1914 OemDest
->Buffer
= NULL
;
1918 OemDest
->Buffer
[Index
] = ANSI_NULL
;
1926 * Bytes calculated including nullterm
1930 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString
)
1934 /* Convert the Mb String to Unicode Size */
1935 RtlMultiByteToUnicodeSize(&Size
,
1939 /* Return the size + null-char */
1940 return (Size
+ sizeof(WCHAR
));
1948 RtlStringFromGUID (IN REFGUID Guid
,
1949 OUT PUNICODE_STRING GuidString
)
1951 /* Setup the string */
1952 GuidString
->Length
= 38 * sizeof(WCHAR
);
1953 GuidString
->MaximumLength
= GuidString
->Length
+ sizeof(UNICODE_NULL
);
1954 GuidString
->Buffer
= RtlpAllocateStringMemory(GuidString
->MaximumLength
,
1956 if (!GuidString
->Buffer
) return STATUS_NO_MEMORY
;
1958 /* Now format the GUID */
1959 swprintf(GuidString
->Buffer
,
1960 L
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1972 return STATUS_SUCCESS
;
1979 * Bytes calculated including nullterm
1983 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString
)
1989 ASSERT(!(UnicodeString
->Length
& 1));
1991 /* Convert the Unicode String to Mb Size */
1992 RtlUnicodeToMultiByteSize(&Size
,
1993 UnicodeString
->Buffer
,
1994 UnicodeString
->Length
);
1996 /* Return the size + null-char */
1997 return (Size
+ sizeof(CHAR
));
2005 RtlCompareUnicodeString(
2006 IN PCUNICODE_STRING s1
,
2007 IN PCUNICODE_STRING s2
,
2008 IN BOOLEAN CaseInsensitive
)
2014 len
= min(s1
->Length
, s2
->Length
) / sizeof(WCHAR
);
2018 if (CaseInsensitive
)
2020 while (!ret
&& len
--) ret
= RtlUpcaseUnicodeChar(*p1
++) - RtlUpcaseUnicodeChar(*p2
++);
2024 while (!ret
&& len
--) ret
= *p1
++ - *p2
++;
2026 if (!ret
) ret
= s1
->Length
- s2
->Length
;
2036 IN OUT PSTRING DestinationString
,
2037 IN PSTRING SourceString OPTIONAL
)
2042 /* Check if there was no source given */
2045 /* Simply return an empty string */
2046 DestinationString
->Length
= 0;
2050 /* Choose the smallest length */
2051 SourceLength
= min(DestinationString
->MaximumLength
,
2052 SourceString
->Length
);
2055 DestinationString
->Length
= (USHORT
)SourceLength
;
2057 /* Save the pointers to each buffer */
2058 p1
= DestinationString
->Buffer
;
2059 p2
= SourceString
->Buffer
;
2061 /* Loop the buffer */
2062 while (SourceLength
)
2064 /* Copy the character and move on */
2076 RtlCopyUnicodeString(
2077 IN OUT PUNICODE_STRING DestinationString
,
2078 IN PCUNICODE_STRING SourceString
)
2082 if(SourceString
== NULL
)
2084 DestinationString
->Length
= 0;
2088 SourceLength
= min(DestinationString
->MaximumLength
,
2089 SourceString
->Length
);
2090 DestinationString
->Length
= (USHORT
)SourceLength
;
2092 RtlCopyMemory(DestinationString
->Buffer
,
2093 SourceString
->Buffer
,
2096 if (DestinationString
->Length
< DestinationString
->MaximumLength
)
2098 DestinationString
->Buffer
[SourceLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2107 * Creates a nullterminated UNICODE_STRING
2111 RtlCreateUnicodeString(
2112 IN OUT PUNICODE_STRING UniDest
,
2119 Length
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
2120 if (Length
> 0xFFFE) return FALSE
;
2122 UniDest
->Buffer
= RtlpAllocateStringMemory(Length
, TAG_USTR
);
2124 if (UniDest
->Buffer
== NULL
) return FALSE
;
2126 RtlCopyMemory(UniDest
->Buffer
, Source
, Length
);
2127 UniDest
->MaximumLength
= (USHORT
)Length
;
2128 UniDest
->Length
= Length
- sizeof (WCHAR
);
2138 RtlCreateUnicodeStringFromAsciiz(
2139 OUT PUNICODE_STRING Destination
,
2142 ANSI_STRING AnsiString
;
2145 RtlInitAnsiString(&AnsiString
, Source
);
2147 Status
= RtlAnsiStringToUnicodeString(Destination
,
2151 return NT_SUCCESS(Status
);
2158 * Dest is never '\0' terminated because it may be equal to src, and src
2159 * might not be '\0' terminated.
2160 * Dest->Length is only set upon success.
2164 RtlDowncaseUnicodeString(
2165 IN OUT PUNICODE_STRING UniDest
,
2166 IN PCUNICODE_STRING UniSource
,
2167 IN BOOLEAN AllocateDestinationString
)
2174 if (AllocateDestinationString
)
2176 UniDest
->MaximumLength
= UniSource
->Length
;
2177 UniDest
->Buffer
= RtlpAllocateStringMemory(UniSource
->Length
, TAG_USTR
);
2178 if (UniDest
->Buffer
== NULL
) return STATUS_NO_MEMORY
;
2180 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2182 return STATUS_BUFFER_OVERFLOW
;
2185 UniDest
->Length
= UniSource
->Length
;
2186 StopGap
= UniSource
->Length
/ sizeof(WCHAR
);
2188 for (i
= 0 ; i
< StopGap
; i
++)
2190 if (UniSource
->Buffer
[i
] < L
'A')
2192 UniDest
->Buffer
[i
] = UniSource
->Buffer
[i
];
2194 else if (UniSource
->Buffer
[i
] <= L
'Z')
2196 UniDest
->Buffer
[i
] = (UniSource
->Buffer
[i
] + (L
'a' - L
'A'));
2200 UniDest
->Buffer
[i
] = RtlDowncaseUnicodeChar(UniSource
->Buffer
[i
]);
2204 return STATUS_SUCCESS
;
2211 * if src is NULL dest is unchanged.
2212 * dest is '\0' terminated when the MaximumLength allowes it.
2213 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2217 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2225 UNICODE_STRING UnicodeSource
;
2227 RtlInitUnicodeString(&UnicodeSource
, Source
);
2228 Length
= UnicodeSource
.Length
;
2230 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2232 return STATUS_BUFFER_TOO_SMALL
;
2235 DestBuffer
= &Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)];
2236 RtlMoveMemory(DestBuffer
, Source
, Length
);
2237 Destination
->Length
+= Length
;
2239 /* append terminating '\0' if enough space */
2240 if(Destination
->MaximumLength
> Destination
->Length
)
2242 DestBuffer
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2246 return STATUS_SUCCESS
;
2253 * if src is NULL dest is unchanged.
2254 * dest is never '\0' terminated.
2258 RtlAppendAsciizToString(
2259 IN OUT PSTRING Destination
,
2266 Length
= (USHORT
)strlen(Source
);
2268 if (Destination
->Length
+ Length
> Destination
->MaximumLength
)
2270 return STATUS_BUFFER_TOO_SMALL
;
2273 RtlMoveMemory(&Destination
->Buffer
[Destination
->Length
], Source
, Length
);
2274 Destination
->Length
+= Length
;
2277 return STATUS_SUCCESS
;
2285 RtlUpperString(PSTRING DestinationString
,
2286 PSTRING SourceString
)
2291 Length
= min(SourceString
->Length
,
2292 DestinationString
->MaximumLength
);
2294 Src
= SourceString
->Buffer
;
2295 Dest
= DestinationString
->Buffer
;
2296 DestinationString
->Length
= Length
;
2299 *Dest
++ = RtlUpperChar(*Src
++);
2308 * See RtlpDuplicateUnicodeString
2312 RtlDuplicateUnicodeString(
2314 IN PCUNICODE_STRING SourceString
,
2315 OUT PUNICODE_STRING DestinationString
)
2319 if (SourceString
== NULL
|| DestinationString
== NULL
||
2320 SourceString
->Length
> SourceString
->MaximumLength
||
2321 (SourceString
->Length
== 0 && SourceString
->MaximumLength
> 0 && SourceString
->Buffer
== NULL
) ||
2322 Flags
== RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
|| Flags
>= 4) {
2323 return STATUS_INVALID_PARAMETER
;
2327 if ((SourceString
->Length
== 0) &&
2328 (Flags
!= (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
|
2329 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
)))
2331 DestinationString
->Length
= 0;
2332 DestinationString
->MaximumLength
= 0;
2333 DestinationString
->Buffer
= NULL
;
2337 UINT DestMaxLength
= SourceString
->Length
;
2339 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2340 DestMaxLength
+= sizeof(UNICODE_NULL
);
2342 DestinationString
->Buffer
= RtlpAllocateStringMemory(DestMaxLength
, TAG_USTR
);
2343 if (DestinationString
->Buffer
== NULL
)
2344 return STATUS_NO_MEMORY
;
2346 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2347 DestinationString
->Length
= SourceString
->Length
;
2348 DestinationString
->MaximumLength
= DestMaxLength
;
2350 if (Flags
& RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
)
2351 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2354 return STATUS_SUCCESS
;
2361 RtlValidateUnicodeString(IN ULONG Flags
,
2362 IN PCUNICODE_STRING UnicodeString
)
2364 /* currently no flags are supported! */
2368 ((UnicodeString
== NULL
) ||
2369 ((UnicodeString
->Length
!= 0) &&
2370 (UnicodeString
->Buffer
!= NULL
) &&
2371 ((UnicodeString
->Length
% sizeof(WCHAR
)) == 0) &&
2372 ((UnicodeString
->MaximumLength
% sizeof(WCHAR
)) == 0) &&
2373 (UnicodeString
->MaximumLength
>= UnicodeString
->Length
))))
2375 /* a NULL pointer as a unicode string is considered to be a valid unicode
2377 return STATUS_SUCCESS
;
2381 return STATUS_INVALID_PARAMETER
;
2389 RtlpEnsureBufferSize(ULONG Unknown1
, ULONG Unknown2
, ULONG Unknown3
)
2391 DPRINT1("RtlpEnsureBufferSize: stub\n");
2392 return STATUS_NOT_IMPLEMENTED
;
2400 RtlFindCharInUnicodeString(IN ULONG Flags
,
2401 IN PUNICODE_STRING SearchString
,
2402 IN PCUNICODE_STRING MatchString
,
2403 OUT PUSHORT Position
)
2406 unsigned int search_idx
;
2412 for (main_idx
= 0; main_idx
< SearchString
->Length
/ sizeof(WCHAR
); main_idx
++)
2414 for (search_idx
= 0; search_idx
< MatchString
->Length
/ sizeof(WCHAR
); search_idx
++)
2416 if (SearchString
->Buffer
[main_idx
] == MatchString
->Buffer
[search_idx
])
2418 *Position
= (main_idx
+ 1) * sizeof(WCHAR
);
2419 return STATUS_SUCCESS
;
2424 return STATUS_NOT_FOUND
;
2429 for (main_idx
= SearchString
->Length
/ sizeof(WCHAR
) - 1; main_idx
>= 0; main_idx
--)
2431 for (search_idx
= 0; search_idx
< MatchString
->Length
/ sizeof(WCHAR
); search_idx
++)
2433 if (SearchString
->Buffer
[main_idx
] == MatchString
->Buffer
[search_idx
])
2435 *Position
= main_idx
* sizeof(WCHAR
);
2436 return STATUS_SUCCESS
;
2441 return STATUS_NOT_FOUND
;
2446 for (main_idx
= 0; main_idx
< SearchString
->Length
/ sizeof(WCHAR
); main_idx
++)
2449 while (search_idx
< MatchString
->Length
/ sizeof(WCHAR
) &&
2450 SearchString
->Buffer
[main_idx
] != MatchString
->Buffer
[search_idx
])
2454 if (search_idx
>= MatchString
->Length
/ sizeof(WCHAR
))
2456 *Position
= (main_idx
+ 1) * sizeof(WCHAR
);
2457 return STATUS_SUCCESS
;
2461 return STATUS_NOT_FOUND
;
2466 for (main_idx
= SearchString
->Length
/ sizeof(WCHAR
) - 1; main_idx
>= 0; main_idx
--)
2469 while (search_idx
< MatchString
->Length
/ sizeof(WCHAR
) &&
2470 SearchString
->Buffer
[main_idx
] != MatchString
->Buffer
[search_idx
])
2474 if (search_idx
>= MatchString
->Length
/ sizeof(WCHAR
))
2476 *Position
= main_idx
* sizeof(WCHAR
);
2477 return STATUS_SUCCESS
;
2481 return STATUS_NOT_FOUND
;
2485 return STATUS_NOT_FOUND
;
2492 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2493 * Convert is to an uppercase oem string and check for unmapped characters.
2494 * Then convert the oem string back to an unicode string.
2498 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName
,PUNICODE_STRING DnsHostName
,BOOLEAN AllocateComputerNameString
)
2502 ULONG ComputerNameLength
;
2503 ULONG ComputerNameOemNLength
;
2504 OEM_STRING ComputerNameOem
;
2505 CHAR ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
+ 1];
2507 Status
= STATUS_INVALID_COMPUTER_NAME
;
2508 ComputerNameLength
= DnsHostName
->Length
;
2510 /* find the first dot in the dns host name */
2511 for (Length
= 0;Length
< DnsHostName
->Length
/sizeof(WCHAR
);Length
++)
2513 if (DnsHostName
->Buffer
[Length
] == L
'.')
2515 /* dot found, so set the length for the oem translation */
2516 ComputerNameLength
= Length
*sizeof(WCHAR
);
2521 /* the computername must have one character */
2522 if (ComputerNameLength
> 0)
2524 ComputerNameOemNLength
= 0;
2525 /* convert to oem string and use uppercase letters */
2526 Status
= RtlUpcaseUnicodeToOemN(ComputerNameOemN
,
2527 MAX_COMPUTERNAME_LENGTH
,
2528 &ComputerNameOemNLength
,
2529 DnsHostName
->Buffer
,
2530 ComputerNameLength
);
2531 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2532 have MAX_COMPUTERNAME_LENGTH characters */
2533 if ((Status
== STATUS_SUCCESS
) ||
2534 (Status
== STATUS_BUFFER_OVERFLOW
))
2536 /* set the termination for the oem string */
2537 ComputerNameOemN
[MAX_COMPUTERNAME_LENGTH
] = 0;
2538 /* set status for the case the next function failed */
2539 Status
= STATUS_INVALID_COMPUTER_NAME
;
2540 /* fillup the oem string structure with the converted computername
2541 and check it for unmapped characters */
2542 ComputerNameOem
.Buffer
= ComputerNameOemN
;
2543 ComputerNameOem
.Length
= (USHORT
)ComputerNameOemNLength
;
2544 ComputerNameOem
.MaximumLength
= (USHORT
)(MAX_COMPUTERNAME_LENGTH
+ 1);
2545 if (RtlpDidUnicodeToOemWork(DnsHostName
, &ComputerNameOem
) == TRUE
)
2547 /* no unmapped character so convert it back to an unicode string */
2548 Status
= RtlOemStringToUnicodeString(ComputerName
,
2550 AllocateComputerNameString
);