4 * Copyright (C) 1996-1998 Marcus Meissner
5 * Copyright (C) 2000 Alexandre Julliard
6 * Copyright (C) 2003 Thomas Mertes
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <ddk/ntddk.h>
27 #include <ntdll/rtl.h>
29 #include <ntos/minmax.h>
35 /* GLOBALS *******************************************************************/
37 #define TAG_USTR TAG('U', 'S', 'T', 'R')
38 #define TAG_ASTR TAG('A', 'S', 'T', 'R')
39 #define TAG_OSTR TAG('O', 'S', 'T', 'R')
42 extern BOOLEAN NlsMbCodePageTag
;
43 extern BOOLEAN NlsMbOemCodePageTag
;
45 /* FUNCTIONS *****************************************************************/
50 RtlAnsiCharToUnicodeChar (IN CHAR AnsiChar
)
58 Size
= (NlsLeadByteInfo
[AnsiChar
] == 0) ? 1 : 2;
61 RtlMultiByteToUnicodeN (&UnicodeChar
,
75 * The calculated size in bytes including nullterm.
79 RtlAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString
)
83 RtlMultiByteToUnicodeSize(&Size
,
96 * If src->length is zero dest is unchanged.
97 * Dest is never nullterminated.
101 RtlAppendStringToString(IN OUT PSTRING Destination
,
106 if (Source
->Length
== 0)
107 return(STATUS_SUCCESS
);
109 if (Destination
->Length
+ Source
->Length
>= Destination
->MaximumLength
)
110 return(STATUS_BUFFER_TOO_SMALL
);
112 Ptr
= Destination
->Buffer
+ Destination
->Length
;
116 Ptr
+= Source
->Length
;
119 Destination
->Length
+= Source
->Length
;
121 return(STATUS_SUCCESS
);
130 * If src->length is zero dest is unchanged.
131 * Dest is nullterminated when the MaximumLength allowes it.
132 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
136 RtlAppendUnicodeStringToString(
137 IN OUT PUNICODE_STRING Destination
,
138 IN PUNICODE_STRING Source
)
141 if ((Source
->Length
+ Destination
->Length
) > Destination
->MaximumLength
)
142 return STATUS_BUFFER_TOO_SMALL
;
144 memcpy((char*)Destination
->Buffer
+ Destination
->Length
, Source
->Buffer
, Source
->Length
);
145 Destination
->Length
+= Source
->Length
;
146 /* append terminating '\0' if enough space */
147 if( Destination
->MaximumLength
> Destination
->Length
)
148 Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)] = 0;
150 return STATUS_SUCCESS
;
175 if ((*String
== 'x') && isxdigit (String
[1]))
183 if (!isxdigit (*String
))
184 return STATUS_INVALID_PARAMETER
;
186 while (isxdigit (*String
) &&
187 (Val
= isdigit (*String
) ? * String
- '0' : (islower (*String
)
188 ? toupper (*String
) : *String
) - 'A' + 10) < Base
)
190 *Value
= *Value
* Base
+ Val
;
194 return STATUS_SUCCESS
;
207 IN BOOLEAN CaseInsensitive
)
213 if (String1
&& String2
)
215 len1
= String1
->Length
;
216 len2
= String2
->Length
;
217 s1
= String1
->Buffer
;
218 s2
= String2
->Buffer
;
226 c1
= len1
-- ? RtlUpperChar (*s1
++) : 0;
227 c2
= len2
-- ? RtlUpperChar (*s2
++) : 0;
228 if (!c1
|| !c2
|| c1
!= c2
)
236 c1
= len1
-- ? *s1
++ : 0;
237 c2
= len2
-- ? *s2
++ : 0;
238 if (!c1
|| !c2
|| c1
!= c2
)
253 * TRUE if strings are equal.
260 IN BOOLEAN CaseInsensitive
)
266 if (String1
->Length
!= String2
->Length
)
269 p1
= String1
->Buffer
;
270 p2
= String2
->Buffer
;
271 for (i
= 0; i
< String1
->Length
; i
++)
273 if (CaseInsensitive
== TRUE
)
275 c1
= RtlUpperChar (*p1
);
276 c2
= RtlUpperChar (*p2
);
299 * TRUE if strings are equal.
303 RtlEqualUnicodeString(
304 IN PUNICODE_STRING String1
,
305 IN PUNICODE_STRING String2
,
306 IN BOOLEAN CaseInsensitive
)
312 if (String1
->Length
!= String2
->Length
)
315 pw1
= String1
->Buffer
;
316 pw2
= String2
->Buffer
;
318 for (i
= 0; i
< String1
->Length
/ sizeof(WCHAR
); i
++)
320 if (CaseInsensitive
== TRUE
)
322 wc1
= RtlUpcaseUnicodeChar (*pw1
);
323 wc2
= RtlUpcaseUnicodeChar (*pw2
);
347 RtlFreeAnsiString(IN PANSI_STRING AnsiString
)
349 if (AnsiString
->Buffer
== NULL
)
352 ExFreePool(AnsiString
->Buffer
);
354 AnsiString
->Buffer
= NULL
;
355 AnsiString
->Length
= 0;
356 AnsiString
->MaximumLength
= 0;
365 RtlFreeOemString(IN POEM_STRING OemString
)
367 if (OemString
->Buffer
== NULL
)
370 ExFreePool(OemString
->Buffer
);
372 OemString
->Buffer
= NULL
;
373 OemString
->Length
= 0;
374 OemString
->MaximumLength
= 0;
383 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
385 if (UnicodeString
->Buffer
== NULL
)
388 ExFreePool(UnicodeString
->Buffer
);
390 UnicodeString
->Buffer
= NULL
;
391 UnicodeString
->Length
= 0;
392 UnicodeString
->MaximumLength
= 0;
400 * If source is NULL the length of source is assumed to be 0.
404 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString
,
405 IN PCSZ SourceString
)
409 if (SourceString
== NULL
)
411 DestinationString
->Length
= 0;
412 DestinationString
->MaximumLength
= 0;
416 DestSize
= strlen ((const char *)SourceString
);
417 DestinationString
->Length
= DestSize
;
418 DestinationString
->MaximumLength
= DestSize
+ sizeof(CHAR
);
420 DestinationString
->Buffer
= (PCHAR
)SourceString
;
429 * If source is NULL the length of source is assumed to be 0.
434 IN OUT PSTRING DestinationString
,
435 IN PCSZ SourceString
)
439 if (SourceString
== NULL
)
441 DestinationString
->Length
= 0;
442 DestinationString
->MaximumLength
= 0;
446 DestSize
= strlen((const char *)SourceString
);
447 DestinationString
->Length
= DestSize
;
448 DestinationString
->MaximumLength
= DestSize
+ sizeof(CHAR
);
450 DestinationString
->Buffer
= (PCHAR
)SourceString
;
458 * If source is NULL the length of source is assumed to be 0.
462 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString
,
463 IN PCWSTR SourceString
)
467 DPRINT("RtlInitUnicodeString(DestinationString %x, SourceString %x)\n",
471 if (SourceString
== NULL
)
473 DestinationString
->Length
= 0;
474 DestinationString
->MaximumLength
= 0;
478 DestSize
= wcslen((PWSTR
)SourceString
) * sizeof(WCHAR
);
479 DestinationString
->Length
= DestSize
;
480 DestinationString
->MaximumLength
= DestSize
+ sizeof(WCHAR
);
482 DestinationString
->Buffer
= (PWSTR
)SourceString
;
491 * Writes at most length characters to the string str.
492 * Str is nullterminated when length allowes it.
493 * When str fits exactly in length characters the nullterm is ommitted.
514 if ((Radix
!= 2) && (Radix
!= 8) &&
515 (Radix
!= 10) && (Radix
!= 16))
516 return STATUS_INVALID_PARAMETER
;
519 while (v
|| tp
== temp
)
530 if (tp
- temp
>= Length
)
531 return STATUS_BUFFER_TOO_SMALL
;
538 return STATUS_SUCCESS
;
548 RtlIntegerToUnicodeString(
550 IN ULONG Base
, /* optional */
551 IN OUT PUNICODE_STRING String
)
553 ANSI_STRING AnsiString
;
557 Status
= RtlIntegerToChar (Value
,
561 if (!NT_SUCCESS(Status
))
564 AnsiString
.Buffer
= Buffer
;
565 AnsiString
.Length
= strlen (Buffer
);
566 AnsiString
.MaximumLength
= 33;
568 Status
= RtlAnsiStringToUnicodeString (String
,
580 * TRUE if String2 contains String1 as a prefix.
585 PANSI_STRING String1
,
586 PANSI_STRING String2
,
587 BOOLEAN CaseInsensitive
)
593 if (String2
->Length
< String1
->Length
)
596 Length
= String1
->Length
;
597 pc1
= String1
->Buffer
;
598 pc2
= String2
->Buffer
;
606 if (RtlUpperChar (*pc1
++) != RtlUpperChar (*pc2
++))
614 if (*pc1
++ != *pc2
++)
628 * TRUE if String2 contains String1 as a prefix.
632 RtlPrefixUnicodeString(
633 PUNICODE_STRING String1
,
634 PUNICODE_STRING String2
,
635 BOOLEAN CaseInsensitive
)
641 if (String2
->Length
< String1
->Length
)
644 Length
= String1
->Length
/ 2;
645 pc1
= String1
->Buffer
;
646 pc2
= String2
->Buffer
;
654 if (RtlUpcaseUnicodeChar (*pc1
++)
655 != RtlUpcaseUnicodeChar (*pc2
++))
663 if( *pc1
++ != *pc2
++ )
679 RtlUnicodeStringToInteger(
680 IN PUNICODE_STRING String
,
688 BOOLEAN addneg
= FALSE
;
691 Str
= String
->Buffer
;
693 for (i
= 0; i
< String
->Length
/ sizeof(WCHAR
); i
++)
700 else if (*Str
== L
'o')
705 else if (*Str
== L
'd')
710 else if (*Str
== L
'x')
715 else if (*Str
== L
'+')
719 else if (*Str
== L
'-')
724 else if ((*Str
> L
'1') && (Base
== 2))
726 return STATUS_INVALID_PARAMETER
;
728 else if (((*Str
> L
'7') || (*Str
< L
'0')) && (Base
== 8))
730 return STATUS_INVALID_PARAMETER
;
732 else if (((*Str
> L
'9') || (*Str
< L
'0')) && (Base
== 10))
734 return STATUS_INVALID_PARAMETER
;
736 else if ( ((*Str
> L
'9') || (*Str
< L
'0')) &&
737 ((towupper (*Str
) > L
'F') || (towupper (*Str
) < L
'A')) &&
740 return STATUS_INVALID_PARAMETER
;
745 Str
= String
->Buffer
+ lenmin
;
750 while (iswxdigit (*Str
) &&
751 (Val
= iswdigit (*Str
) ? *Str
- L
'0' : (iswlower (*Str
)
752 ? towupper (*Str
) : *Str
) - L
'A' + 10) < Base
)
754 *Value
= *Value
* Base
+ Val
;
761 return STATUS_SUCCESS
;
770 * Bytes necessary for the conversion including nullterm.
774 RtlUnicodeStringToOemSize(
775 IN PUNICODE_STRING UnicodeString
)
779 RtlUnicodeToMultiByteSize (&Size
,
780 UnicodeString
->Buffer
,
781 UnicodeString
->Length
);
783 return Size
+1; //NB: incl. nullterm
792 * See RtlpUnicodeStringToAnsiString
796 RtlUnicodeStringToAnsiString(
797 IN OUT PANSI_STRING AnsiDest
,
798 IN PUNICODE_STRING UniSource
,
799 IN BOOLEAN AllocateDestinationString
)
801 return RtlpUnicodeStringToAnsiString(
804 AllocateDestinationString
,
813 * This function always writes a terminating '\0'.
814 * It performs a partial copy if ansi is too small.
818 RtlpUnicodeStringToAnsiString(
819 IN OUT PANSI_STRING AnsiDest
,
820 IN PUNICODE_STRING UniSource
,
821 IN BOOLEAN AllocateDestinationString
,
822 IN POOL_TYPE PoolType
)
824 NTSTATUS Status
= STATUS_SUCCESS
;
825 ULONG Length
; //including nullterm
827 if (NlsMbCodePageTag
== TRUE
)
829 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
832 Length
= (UniSource
->Length
/ sizeof(WCHAR
)) + sizeof(CHAR
);
834 AnsiDest
->Length
= Length
- sizeof(CHAR
);
836 if (AllocateDestinationString
)
838 AnsiDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_ASTR
);
839 if (AnsiDest
->Buffer
== NULL
)
840 return STATUS_NO_MEMORY
;
842 AnsiDest
->MaximumLength
= Length
;
844 else if (AnsiDest
->MaximumLength
== 0)
846 return STATUS_BUFFER_TOO_SMALL
;
848 else if (Length
> AnsiDest
->MaximumLength
)
850 //make room for nullterm
851 AnsiDest
->Length
= AnsiDest
->MaximumLength
- sizeof(CHAR
);
854 Status
= RtlUnicodeToMultiByteN (AnsiDest
->Buffer
,
860 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
862 ExFreePool (AnsiDest
->Buffer
);
866 AnsiDest
->Buffer
[AnsiDest
->Length
] = 0;
875 * See RtlpOemStringToUnicodeString
879 RtlOemStringToUnicodeString(
880 IN OUT PUNICODE_STRING UniDest
,
881 IN POEM_STRING OemSource
,
882 IN BOOLEAN AllocateDestinationString
)
884 return RtlpOemStringToUnicodeString(
887 AllocateDestinationString
,
896 * This function always writes a terminating '\0'.
897 * Does NOT perform a partial copy if unicode is too small!
901 RtlpOemStringToUnicodeString(
902 IN OUT PUNICODE_STRING UniDest
,
903 IN POEM_STRING OemSource
,
904 IN BOOLEAN AllocateDestinationString
,
905 IN POOL_TYPE PoolType
)
908 ULONG Length
; //including nullterm
910 if (NlsMbOemCodePageTag
== TRUE
)
911 Length
= RtlOemStringToUnicodeSize(OemSource
);
913 Length
= (OemSource
->Length
* sizeof(WCHAR
)) + sizeof(WCHAR
);
916 return STATUS_INVALID_PARAMETER_2
;
918 UniDest
->Length
= (WORD
)(Length
- sizeof(WCHAR
));
920 if (AllocateDestinationString
)
922 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_USTR
);
923 if (UniDest
->Buffer
== NULL
)
924 return STATUS_NO_MEMORY
;
926 UniDest
->MaximumLength
= Length
;
928 else if (Length
> UniDest
->MaximumLength
)
930 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
931 return STATUS_BUFFER_TOO_SMALL
;
934 //FIXME: Do we need this????? -Gunnar
935 RtlZeroMemory (UniDest
->Buffer
,
938 Status
= RtlOemToUnicodeN (UniDest
->Buffer
,
944 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
946 ExFreePool (UniDest
->Buffer
);
950 UniDest
->Buffer
[UniDest
->Length
/ sizeof(WCHAR
)] = 0;
951 return STATUS_SUCCESS
;
959 * See RtlpUnicodeStringToOemString.
963 RtlUnicodeStringToOemString(
964 IN OUT POEM_STRING OemDest
,
965 IN PUNICODE_STRING UniSource
,
966 IN BOOLEAN AllocateDestinationString
)
968 return RtlpUnicodeStringToOemString(
971 AllocateDestinationString
,
981 * This function always '\0' terminates the string returned.
985 RtlpUnicodeStringToOemString(
986 IN OUT POEM_STRING OemDest
,
987 IN PUNICODE_STRING UniSource
,
988 IN BOOLEAN AllocateDestinationString
,
989 IN POOL_TYPE PoolType
)
991 NTSTATUS Status
= STATUS_SUCCESS
;
992 ULONG Length
; //including nullterm
994 if (NlsMbOemCodePageTag
== TRUE
)
995 Length
= RtlUnicodeStringToAnsiSize (UniSource
);
997 Length
= (UniSource
->Length
/ sizeof(WCHAR
)) + sizeof(CHAR
);
999 if (Length
> 0x0000FFFF)
1000 return STATUS_INVALID_PARAMETER_2
;
1002 OemDest
->Length
= (WORD
)(Length
- sizeof(CHAR
));
1004 if (AllocateDestinationString
)
1006 OemDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_OSTR
);
1007 if (OemDest
->Buffer
== NULL
)
1008 return STATUS_NO_MEMORY
;
1010 OemDest
->MaximumLength
= Length
;
1012 else if (OemDest
->MaximumLength
== 0)
1014 return STATUS_BUFFER_TOO_SMALL
;
1016 else if (Length
> OemDest
->MaximumLength
)
1018 //make room for nullterm
1019 OemDest
->Length
= OemDest
->MaximumLength
- sizeof(CHAR
);
1022 Status
= RtlUnicodeToOemN (OemDest
->Buffer
,
1028 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1030 ExFreePool(OemDest
->Buffer
);
1034 OemDest
->Buffer
[OemDest
->Length
] = 0;
1040 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1047 * The length of the string if all tests were passed, 0 otherwise.
1050 RtlIsTextUnicode (PVOID Buffer
,
1055 ULONG in_flags
= (ULONG
)-1;
1056 ULONG out_flags
= 0;
1065 * Apply various tests to the text string. According to the
1066 * docs, each test "passed" sets the corresponding flag in
1067 * the output flags. But some of the tests are mutually
1068 * exclusive, so I don't see how you could pass all tests ...
1071 /* Check for an odd length ... pass if even. */
1073 out_flags
|= IS_TEXT_UNICODE_ODD_LENGTH
;
1075 /* Check for the BOM (byte order mark). */
1077 out_flags
|= IS_TEXT_UNICODE_SIGNATURE
;
1080 /* Check for the reverse BOM (byte order mark). */
1082 out_flags
|= IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
1085 /* FIXME: Add more tests */
1088 * Check whether the string passed all of the tests.
1090 in_flags
&= ITU_IMPLEMENTED_TESTS
;
1091 if ((out_flags
& in_flags
) != in_flags
)
1106 * See RtlpOemStringToCountedUnicodeString
1110 RtlOemStringToCountedUnicodeString(
1111 IN OUT PUNICODE_STRING UniDest
,
1112 IN POEM_STRING OemSource
,
1113 IN BOOLEAN AllocateDestinationString
)
1115 return RtlpOemStringToCountedUnicodeString(
1118 AllocateDestinationString
,
1128 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1129 * A partial copy is NOT performed if the dest buffer is too small!
1133 RtlpOemStringToCountedUnicodeString(
1134 IN OUT PUNICODE_STRING UniDest
,
1135 IN POEM_STRING OemSource
,
1136 IN BOOLEAN AllocateDestinationString
,
1137 IN POOL_TYPE PoolType
)
1140 ULONG Length
; //excluding nullterm
1142 if (NlsMbCodePageTag
== TRUE
)
1143 Length
= RtlOemStringToUnicodeSize(OemSource
) - sizeof(WCHAR
);
1145 Length
= OemSource
->Length
* sizeof(WCHAR
);
1148 return STATUS_INVALID_PARAMETER_2
;
1150 if (AllocateDestinationString
== TRUE
)
1152 UniDest
->Buffer
= ExAllocatePoolWithTag (PoolType
, Length
, TAG_USTR
);
1153 if (UniDest
->Buffer
== NULL
)
1154 return STATUS_NO_MEMORY
;
1156 UniDest
->MaximumLength
= Length
;
1158 else if (Length
> UniDest
->MaximumLength
)
1160 return STATUS_BUFFER_TOO_SMALL
;
1163 UniDest
->Length
= Length
;
1165 Status
= RtlOemToUnicodeN (UniDest
->Buffer
,
1171 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1173 ExFreePool (UniDest
->Buffer
);
1181 //FIXME: sjekk returnverdi og returtype. Wine koflikter mht. returtype for EqualString og EqualComputer---
1186 * 0 if the names are equal, non-zero otherwise.
1189 * The comparison is case insensitive.
1193 RtlEqualComputerName(
1194 IN PUNICODE_STRING ComputerName1
,
1195 IN PUNICODE_STRING ComputerName2
)
1197 OEM_STRING OemString1
;
1198 OEM_STRING OemString2
;
1199 BOOLEAN Result
= FALSE
;
1201 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString1
, ComputerName1
, TRUE
)))
1203 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString2
, ComputerName2
, TRUE
)))
1205 Result
= RtlEqualString( &OemString1
, &OemString2
, FALSE
);
1206 RtlFreeOemString( &OemString2
);
1208 RtlFreeOemString( &OemString1
);
1214 //FIXME: sjekk returnverdi og returtype. Wine koflikter mht. returtype for EqualString og EqualComputer---
1219 * 0 if the names are equal, non-zero otherwise.
1222 * The comparison is case insensitive.
1226 RtlEqualDomainName (
1227 IN PUNICODE_STRING DomainName1
,
1228 IN PUNICODE_STRING DomainName2
1231 return RtlEqualComputerName(DomainName1
, DomainName2
);
1241 RtlEqualDomainName (
1242 IN PUNICODE_STRING DomainName1,
1243 IN PUNICODE_STRING DomainName2
1246 OEM_STRING OemString1;
1247 OEM_STRING OemString2;
1250 RtlUpcaseUnicodeStringToOemString (&OemString1,
1253 RtlUpcaseUnicodeStringToOemString (&OemString2,
1257 Result = RtlEqualString (&OemString1,
1261 RtlFreeOemString (&OemString1);
1262 RtlFreeOemString (&OemString2);
1272 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1274 * Convert a string representation of a GUID into a GUID.
1277 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1278 * guid [O] Destination for the converted GUID
1281 * Success: STATUS_SUCCESS. guid contains the converted value.
1282 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1285 * See RtlStringFromGUID.
1290 IN UNICODE_STRING
*str
,
1295 const WCHAR
*lpszCLSID
= str
->Buffer
;
1296 BYTE
* lpOut
= (BYTE
*)guid
;
1298 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1300 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1301 * to memory: DWORD... WORD WORD BYTES............
1308 if (*lpszCLSID
!= '{')
1309 return STATUS_INVALID_PARAMETER
;
1316 if (*lpszCLSID
!= '-')
1317 return STATUS_INVALID_PARAMETER
;
1321 if (*lpszCLSID
!= '}')
1322 return STATUS_INVALID_PARAMETER
;
1327 WCHAR ch
= *lpszCLSID
, ch2
= lpszCLSID
[1];
1330 /* Read two hex digits as a byte value */
1331 if (ch
>= '0' && ch
<= '9')
1333 else if (ch
>= 'a' && ch
<= 'f')
1335 else if (ch
>= 'A' && ch
<= 'F')
1338 return STATUS_INVALID_PARAMETER
;
1340 if (ch2
>= '0' && ch2
<= '9')
1342 else if (ch2
>= 'a' && ch2
<= 'f')
1343 ch2
= ch2
- 'a' + 10;
1344 else if (ch2
>= 'A' && ch2
<= 'F')
1345 ch2
= ch2
- 'A' + 10;
1347 return STATUS_INVALID_PARAMETER
;
1349 byte
= ch
<< 4 | ch2
;
1353 #ifndef WORDS_BIGENDIAN
1354 /* For Big Endian machines, we store the data such that the
1355 * dword/word members can be read as DWORDS and WORDS correctly. */
1387 lpszCLSID
++; /* Skip 2nd character of byte */
1395 return STATUS_SUCCESS
;
1403 RtlInt64ToUnicodeString (IN ULONGLONG Value
,
1405 OUT PUNICODE_STRING String
)
1407 return STATUS_NOT_IMPLEMENTED
;
1416 RtlEraseUnicodeString(
1417 IN PUNICODE_STRING String
)
1419 if (String
->Buffer
== NULL
)
1422 if (String
->MaximumLength
== 0)
1425 memset (String
->Buffer
,
1427 String
->MaximumLength
);
1438 * See RtlpUnicodeStringToCountedOemString.
1442 RtlUnicodeStringToCountedOemString(
1443 IN OUT POEM_STRING OemDest
,
1444 IN PUNICODE_STRING UniSource
,
1445 IN BOOLEAN AllocateDestinationString
)
1447 return RtlpUnicodeStringToCountedOemString(
1450 AllocateDestinationString
,
1458 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1459 * Does a partial copy if the dest buffer is too small
1463 RtlpUnicodeStringToCountedOemString(
1464 IN OUT POEM_STRING OemDest
,
1465 IN PUNICODE_STRING UniSource
,
1466 IN BOOLEAN AllocateDestinationString
,
1467 IN POOL_TYPE PoolType
)
1470 ULONG Length
; //excluding nullterm
1472 if (NlsMbOemCodePageTag
== TRUE
)
1473 Length
= RtlUnicodeStringToAnsiSize(UniSource
) - sizeof(CHAR
);
1475 Length
= (UniSource
->Length
/ sizeof(WCHAR
));
1477 if (Length
> 0x0000FFFF)
1478 return STATUS_INVALID_PARAMETER_2
;
1480 OemDest
->Length
= (WORD
)(Length
);
1482 if (AllocateDestinationString
)
1484 OemDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_OSTR
);
1485 if (OemDest
->Buffer
== NULL
)
1486 return STATUS_NO_MEMORY
;
1488 OemDest
->MaximumLength
= Length
;
1490 else if (OemDest
->MaximumLength
== 0)
1492 return STATUS_BUFFER_TOO_SMALL
;
1494 else if (Length
> OemDest
->MaximumLength
)
1496 OemDest
->Length
= OemDest
->MaximumLength
;
1499 Status
= RtlUnicodeToOemN (OemDest
->Buffer
,
1505 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1507 ExFreePool(OemDest
->Buffer
);
1519 RtlLargeIntegerToChar(
1520 IN PLARGE_INTEGER Value
,
1523 IN OUT PCHAR String
)
1527 ULONGLONG v
= Value
->QuadPart
;
1536 if ((Radix
!= 2) && (Radix
!= 8) &&
1537 (Radix
!= 10) && (Radix
!= 16))
1538 return STATUS_INVALID_PARAMETER
;
1541 while (v
|| tp
== temp
)
1552 if (tp
- temp
>= Length
)
1553 return STATUS_BUFFER_TOO_SMALL
;
1560 return STATUS_SUCCESS
;
1569 * See RtlpUpcaseUnicodeString
1573 RtlUpcaseUnicodeString(
1574 IN OUT PUNICODE_STRING UniDest
,
1575 IN PCUNICODE_STRING UniSource
,
1576 IN BOOLEAN AllocateDestinationString
)
1579 return RtlpUpcaseUnicodeString(
1582 AllocateDestinationString
,
1591 * dest is never '\0' terminated because it may be equal to src, and src
1592 * might not be '\0' terminated. dest->Length is only set upon success.
1596 RtlpUpcaseUnicodeString(
1597 IN OUT PUNICODE_STRING UniDest
,
1598 IN PCUNICODE_STRING UniSource
,
1599 IN BOOLEAN AllocateDestinationString
,
1600 IN POOL_TYPE PoolType
)
1605 if (AllocateDestinationString
== TRUE
)
1607 UniDest
->MaximumLength
= UniSource
->Length
;
1608 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, UniDest
->MaximumLength
, TAG_USTR
);
1609 if (UniDest
->Buffer
== NULL
)
1610 return STATUS_NO_MEMORY
;
1612 else if (UniSource
->Length
> UniDest
->MaximumLength
)
1614 return STATUS_BUFFER_TOO_SMALL
;
1617 UniDest
->Length
= UniSource
->Length
;
1619 Src
= UniSource
->Buffer
;
1620 Dest
= UniDest
->Buffer
;
1621 for (i
= 0; i
< UniSource
->Length
/ sizeof(WCHAR
); i
++)
1623 *Dest
= RtlUpcaseUnicodeChar (*Src
);
1628 return STATUS_SUCCESS
;
1637 * See RtlpUpcaseUnicodeStringToAnsiString
1641 RtlUpcaseUnicodeStringToAnsiString(
1642 IN OUT PANSI_STRING AnsiDest
,
1643 IN PUNICODE_STRING UniSource
,
1644 IN BOOLEAN AllocateDestinationString
)
1646 return RtlpUpcaseUnicodeStringToAnsiString(
1649 AllocateDestinationString
,
1657 * This function always writes a terminating '\0'.
1658 * It performs a partial copy if ansi is too small.
1662 RtlpUpcaseUnicodeStringToAnsiString(
1663 IN OUT PANSI_STRING AnsiDest
,
1664 IN PUNICODE_STRING UniSource
,
1665 IN BOOLEAN AllocateDestinationString
,
1666 IN POOL_TYPE PoolType
)
1669 ULONG Length
; //including nullterm
1671 if (NlsMbCodePageTag
== TRUE
)
1672 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1674 Length
= (UniSource
->Length
/ sizeof(WCHAR
)) + sizeof(CHAR
);
1676 if (Length
> 0x0000FFFF)
1677 return STATUS_INVALID_PARAMETER_2
;
1679 AnsiDest
->Length
= (WORD
)(Length
- sizeof(CHAR
));
1681 if (AllocateDestinationString
)
1683 AnsiDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_ASTR
);
1684 if (AnsiDest
->Buffer
== NULL
)
1685 return STATUS_NO_MEMORY
;
1687 AnsiDest
->MaximumLength
= Length
;
1689 else if (AnsiDest
->MaximumLength
== 0)
1691 return STATUS_BUFFER_TOO_SMALL
;
1693 else if (Length
> AnsiDest
->MaximumLength
)
1695 //make room for nullterm
1696 AnsiDest
->Length
= AnsiDest
->MaximumLength
- sizeof(CHAR
);
1699 //FIXME: do we need this??????? -Gunnar
1700 RtlZeroMemory (AnsiDest
->Buffer
,
1703 Status
= RtlUpcaseUnicodeToMultiByteN (AnsiDest
->Buffer
,
1709 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1711 ExFreePool(AnsiDest
->Buffer
);
1715 AnsiDest
->Buffer
[AnsiDest
->Length
] = 0;
1725 * See RtlpUpcaseUnicodeStringToCountedOemString
1729 RtlUpcaseUnicodeStringToCountedOemString(
1730 IN OUT POEM_STRING OemDest
,
1731 IN PUNICODE_STRING UniSource
,
1732 IN BOOLEAN AllocateDestinationString
)
1734 return RtlpUpcaseUnicodeStringToCountedOemString(
1737 AllocateDestinationString
,
1747 * Same as RtlUpcaseUnicodeStringToOemString but doesn't write terminating null
1748 * It performs a partial copy if oem is too small.
1752 RtlpUpcaseUnicodeStringToCountedOemString(
1753 IN OUT POEM_STRING OemDest
,
1754 IN PUNICODE_STRING UniSource
,
1755 IN BOOLEAN AllocateDestinationString
,
1756 IN POOL_TYPE PoolType
)
1759 ULONG Length
; //excluding nullterm
1761 if (NlsMbCodePageTag
== TRUE
)
1762 Length
= RtlUnicodeStringToAnsiSize(UniSource
) - sizeof(CHAR
);
1764 Length
= UniSource
->Length
/ sizeof(WCHAR
);
1766 if (Length
> 0x0000FFFF)
1767 return(STATUS_INVALID_PARAMETER_2
);
1769 OemDest
->Length
= (WORD
)(Length
);
1771 if (AllocateDestinationString
)
1773 OemDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_OSTR
);
1774 if (OemDest
->Buffer
== NULL
)
1775 return(STATUS_NO_MEMORY
);
1777 //FIXME: Do we need this?????
1778 RtlZeroMemory (OemDest
->Buffer
, Length
);
1780 OemDest
->MaximumLength
= (WORD
)Length
;
1782 else if (OemDest
->MaximumLength
== 0)
1784 return(STATUS_BUFFER_TOO_SMALL
);
1786 else if (Length
> OemDest
->MaximumLength
)
1788 OemDest
->Length
= OemDest
->MaximumLength
;
1791 Status
= RtlUpcaseUnicodeToOemN(OemDest
->Buffer
,
1797 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1799 ExFreePool(OemDest
->Buffer
);
1810 * See RtlpUpcaseUnicodeStringToOemString
1814 RtlUpcaseUnicodeStringToOemString (
1815 IN OUT POEM_STRING OemDest
,
1816 IN PUNICODE_STRING UniSource
,
1817 IN BOOLEAN AllocateDestinationString
1820 return RtlpUpcaseUnicodeStringToOemString(
1823 AllocateDestinationString
,
1832 * Oem string is allways nullterminated
1833 * It performs a partial copy if oem is too small.
1837 RtlpUpcaseUnicodeStringToOemString (
1838 IN OUT POEM_STRING OemDest
,
1839 IN PUNICODE_STRING UniSource
,
1840 IN BOOLEAN AllocateDestinationString
,
1841 IN POOL_TYPE PoolType
1845 ULONG Length
; //including nullterm
1847 if (NlsMbOemCodePageTag
== TRUE
)
1848 Length
= RtlUnicodeStringToAnsiSize(UniSource
);
1850 Length
= (UniSource
->Length
/ sizeof(WCHAR
)) + sizeof(CHAR
);
1852 if (Length
> 0x0000FFFF)
1853 return STATUS_INVALID_PARAMETER_2
;
1855 OemDest
->Length
= (WORD
)(Length
- sizeof(CHAR
));
1857 if (AllocateDestinationString
)
1859 OemDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_OSTR
);
1860 if (OemDest
->Buffer
== NULL
)
1861 return STATUS_NO_MEMORY
;
1863 //FIXME: Do we need this????
1864 RtlZeroMemory (OemDest
->Buffer
, Length
);
1866 OemDest
->MaximumLength
= (WORD
)Length
;
1868 else if (OemDest
->MaximumLength
== 0)
1870 return STATUS_BUFFER_OVERFLOW
;
1872 else if (Length
> OemDest
->MaximumLength
)
1874 //make room for nullterm
1875 OemDest
->Length
= OemDest
->MaximumLength
- sizeof(CHAR
);
1878 Status
= RtlUpcaseUnicodeToOemN (OemDest
->Buffer
,
1884 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
1886 ExFreePool(OemDest
->Buffer
);
1890 OemDest
->Buffer
[OemDest
->Length
] = 0;
1899 * Bytes calculated including nullterm
1903 RtlOemStringToUnicodeSize(IN POEM_STRING OemString
)
1907 //this function returns size including nullterm
1908 RtlMultiByteToUnicodeSize(&Size
,
1922 RtlStringFromGUID (IN REFGUID Guid
,
1923 OUT PUNICODE_STRING GuidString
)
1925 STATIC CONST PWCHAR Hex
= L
"0123456789ABCDEF";
1932 return STATUS_INVALID_PARAMETER
;
1936 L
"{%08lX-%04X-%04X-%02X%02X-",
1942 BufferPtr
= Buffer
+ 25;
1945 for (i
= 2; i
< 8; i
++)
1947 *BufferPtr
++ = Hex
[Guid
->Data4
[i
] >> 4];
1948 *BufferPtr
++ = Hex
[Guid
->Data4
[i
] & 0xf];
1951 *BufferPtr
++ = L
'}';
1952 *BufferPtr
++ = L
'\0';
1954 return RtlCreateUnicodeString (GuidString
, Buffer
);
1962 * Bytes calculated including nullterm
1966 RtlUnicodeStringToAnsiSize(
1967 IN PUNICODE_STRING UnicodeString
)
1971 //this function return size without nullterm!
1972 RtlUnicodeToMultiByteSize (&Size
,
1973 UnicodeString
->Buffer
,
1974 UnicodeString
->Length
);
1976 return Size
+ sizeof(CHAR
); //NB: incl. nullterm
1987 RtlCompareUnicodeString(
1988 IN PUNICODE_STRING String1
,
1989 IN PUNICODE_STRING String2
,
1990 IN BOOLEAN CaseInsensitive
)
1996 if (String1
&& String2
)
1998 len1
= String1
->Length
/ sizeof(WCHAR
);
1999 len2
= String2
->Length
/ sizeof(WCHAR
);
2000 s1
= String1
->Buffer
;
2001 s2
= String2
->Buffer
;
2005 if (CaseInsensitive
)
2009 c1
= len1
-- ? RtlUpcaseUnicodeChar (*s1
++) : 0;
2010 c2
= len2
-- ? RtlUpcaseUnicodeChar (*s2
++) : 0;
2011 if (!c1
|| !c2
|| c1
!= c2
)
2019 c1
= len1
-- ? *s1
++ : 0;
2020 c2
= len2
-- ? *s2
++ : 0;
2021 if (!c1
|| !c2
|| c1
!= c2
)
2038 IN OUT PSTRING DestinationString
,
2039 IN PSTRING SourceString
)
2043 if(SourceString
== NULL
)
2045 DestinationString
->Length
= 0;
2049 copylen
= min (DestinationString
->MaximumLength
- sizeof(CHAR
),
2050 SourceString
->Length
);
2052 memcpy(DestinationString
->Buffer
, SourceString
->Buffer
, copylen
);
2053 DestinationString
->Buffer
[copylen
] = 0;
2054 DestinationString
->Length
= copylen
;
2064 RtlCopyUnicodeString(
2065 IN OUT PUNICODE_STRING DestinationString
,
2066 IN PUNICODE_STRING SourceString
)
2070 if (SourceString
== NULL
)
2072 DestinationString
->Length
= 0;
2076 copylen
= min (DestinationString
->MaximumLength
- sizeof(WCHAR
),
2077 SourceString
->Length
);
2078 memcpy(DestinationString
->Buffer
, SourceString
->Buffer
, copylen
);
2079 DestinationString
->Buffer
[copylen
/ sizeof(WCHAR
)] = 0;
2080 DestinationString
->Length
= copylen
;
2088 * See RtlpCreateUnicodeString
2092 RtlCreateUnicodeString(
2093 IN OUT PUNICODE_STRING UniDest
,
2097 DPRINT("RtlCreateUnicodeString\n");
2098 return RtlpCreateUnicodeString(UniDest
, Source
, NonPagedPool
);
2107 RtlpCreateUnicodeString(
2108 IN OUT PUNICODE_STRING UniDest
,
2110 IN POOL_TYPE PoolType
)
2114 Length
= (wcslen (Source
) + 1) * sizeof(WCHAR
);
2116 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_USTR
);
2117 if (UniDest
->Buffer
== NULL
)
2120 memmove (UniDest
->Buffer
,
2124 UniDest
->MaximumLength
= Length
;
2125 UniDest
->Length
= Length
- sizeof (WCHAR
);
2137 RtlCreateUnicodeStringFromAsciiz(
2138 OUT PUNICODE_STRING Destination
,
2141 ANSI_STRING AnsiString
;
2144 RtlInitAnsiString (&AnsiString
,
2147 Status
= RtlAnsiStringToUnicodeString (Destination
,
2151 return NT_SUCCESS(Status
);
2160 * See RtlpDowncaseUnicodeString
2163 RtlDowncaseUnicodeString(
2164 IN OUT PUNICODE_STRING UniDest
,
2165 IN PUNICODE_STRING UniSource
,
2166 IN BOOLEAN AllocateDestinationString
)
2168 return RtlpDowncaseUnicodeString(
2171 AllocateDestinationString
,
2180 * Dest is never '\0' terminated because it may be equal to src, and src
2181 * might not be '\0' terminated.
2182 * Dest->Length is only set upon success.
2186 RtlpDowncaseUnicodeString(
2187 IN OUT PUNICODE_STRING UniDest
,
2188 IN PUNICODE_STRING UniSource
,
2189 IN BOOLEAN AllocateDestinationString
,
2190 IN POOL_TYPE PoolType
)
2195 if (AllocateDestinationString
)
2197 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, UniSource
->Length
, TAG_USTR
);
2198 if (UniDest
->Buffer
== NULL
)
2199 return STATUS_NO_MEMORY
;
2201 UniDest
->MaximumLength
= UniSource
->Length
;
2203 else if (UniSource
->Length
> UniDest
->MaximumLength
)
2205 return STATUS_BUFFER_TOO_SMALL
;
2208 UniDest
->Length
= UniSource
->Length
;
2210 Src
= UniSource
->Buffer
;
2211 Dest
= UniDest
->Buffer
;
2212 for (i
=0; i
< UniSource
->Length
/ sizeof(WCHAR
); i
++)
2218 else if (*Src
<= L
'Z')
2220 *Dest
= (*Src
+ (L
'a' - L
'A'));
2224 *Dest
= RtlDowncaseUnicodeChar(*Src
);
2231 return STATUS_SUCCESS
;
2240 * if src is NULL dest is unchanged.
2241 * dest is '\0' terminated when the MaximumLength allowes it.
2242 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2245 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination
,
2250 slen
= wcslen(Source
) * sizeof(WCHAR
);
2252 if (Destination
->Length
+ slen
> Destination
->MaximumLength
)
2253 return(STATUS_BUFFER_TOO_SMALL
);
2255 memcpy((char*)Destination
->Buffer
+ Destination
->Length
, Source
, slen
);
2256 Destination
->Length
+= slen
;
2257 /* append terminating '\0' if enough space */
2258 if( Destination
->MaximumLength
> Destination
->Length
)
2259 Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)] = 0;
2261 return(STATUS_SUCCESS
);
2269 * See RtlpAnsiStringToUnicodeString
2273 RtlAnsiStringToUnicodeString(
2274 IN OUT PUNICODE_STRING UniDest
,
2275 IN PANSI_STRING AnsiSource
,
2276 IN BOOLEAN AllocateDestinationString
)
2278 return RtlpAnsiStringToUnicodeString(
2281 AllocateDestinationString
,
2291 * This function always writes a terminating '\0'.
2292 * If the dest buffer is too small a partial copy is NOT performed!
2296 RtlpAnsiStringToUnicodeString(
2297 IN OUT PUNICODE_STRING UniDest
,
2298 IN PANSI_STRING AnsiSource
,
2299 IN BOOLEAN AllocateDestinationString
,
2300 IN POOL_TYPE PoolType
)
2303 ULONG Length
; //including nullterm
2305 if (NlsMbCodePageTag
== TRUE
)
2306 Length
= RtlAnsiStringToUnicodeSize(AnsiSource
);
2308 Length
= (AnsiSource
->Length
* sizeof(WCHAR
)) + sizeof(WCHAR
);
2310 if (Length
> 0xffff)
2311 return STATUS_INVALID_PARAMETER_2
;
2313 if (AllocateDestinationString
== TRUE
)
2315 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG_USTR
);
2316 if (UniDest
->Buffer
== NULL
)
2317 return STATUS_NO_MEMORY
;
2319 UniDest
->MaximumLength
= Length
;
2321 else if (Length
> UniDest
->MaximumLength
)
2323 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
2324 return STATUS_BUFFER_TOO_SMALL
;
2327 UniDest
->Length
= Length
- sizeof(WCHAR
);
2329 //FIXME: We don't need this??? -Gunnar
2330 RtlZeroMemory (UniDest
->Buffer
,
2333 Status
= RtlMultiByteToUnicodeN (UniDest
->Buffer
,
2337 AnsiSource
->Length
);
2339 if (!NT_SUCCESS(Status
) && AllocateDestinationString
)
2341 ExFreePool(UniDest
->Buffer
);
2345 UniDest
->Buffer
[UniDest
->Length
/ sizeof(WCHAR
)] = 0;
2355 * if src is NULL dest is unchanged.
2356 * dest is never '\0' terminated.
2360 RtlAppendAsciizToString(
2361 IN OUT PSTRING Destination
,
2368 return STATUS_SUCCESS
;
2370 Length
= strlen (Source
);
2371 if (Destination
->Length
+ Length
>= Destination
->MaximumLength
)
2372 return STATUS_BUFFER_TOO_SMALL
;
2374 Ptr
= Destination
->Buffer
+ Destination
->Length
;
2381 Destination
->Length
+= Length
;
2383 return STATUS_SUCCESS
;
2391 RtlUpperString(PSTRING DestinationString
,
2392 PSTRING SourceString
)
2399 Length
= min(SourceString
->Length
,
2400 DestinationString
->MaximumLength
- 1);
2402 Src
= SourceString
->Buffer
;
2403 Dest
= DestinationString
->Buffer
;
2404 for (i
= 0; i
< Length
; i
++)
2406 *Dest
= RtlUpperChar(*Src
);
2412 DestinationString
->Length
= SourceString
->Length
;
2420 RtlxAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString
)
2422 return RtlAnsiStringToUnicodeSize(AnsiString
);
2430 RtlxOemStringToUnicodeSize(IN POEM_STRING OemString
)
2432 return RtlOemStringToUnicodeSize((PANSI_STRING
)OemString
);
2441 RtlxUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString
)
2443 return RtlUnicodeStringToAnsiSize(UnicodeString
);
2451 RtlxUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString
)
2453 return RtlUnicodeStringToOemSize(UnicodeString
);
2461 RtlDuplicateUnicodeString(
2463 IN PUNICODE_STRING SourceString
,
2464 PUNICODE_STRING DestinationString
)
2466 if (SourceString
== NULL
|| DestinationString
== NULL
)
2467 return STATUS_INVALID_PARAMETER
;
2470 if (SourceString
->Length
== 0 && AddNull
!= 3)
2472 DestinationString
->Length
= 0;
2473 DestinationString
->MaximumLength
= 0;
2474 DestinationString
->Buffer
= NULL
;
2478 unsigned int DestMaxLength
= SourceString
->Length
;
2481 DestMaxLength
+= sizeof(UNICODE_NULL
);
2483 DestinationString
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, DestMaxLength
);
2484 if (DestinationString
->Buffer
== NULL
)
2485 return STATUS_NO_MEMORY
;
2487 RtlCopyMemory(DestinationString
->Buffer
, SourceString
->Buffer
, SourceString
->Length
);
2488 DestinationString
->Length
= SourceString
->Length
;
2489 DestinationString
->MaximumLength
= DestMaxLength
;
2492 DestinationString
->Buffer
[DestinationString
->Length
/ sizeof(WCHAR
)] = 0;
2495 return STATUS_SUCCESS
;