Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2028 lines
41 KiB

/*++
Copyright (c) 1995-2001 Microsoft Corporation
Module Name:
string.c
Abstract:
Domain Name System (DNS) Library
DNS string routines.
Author:
Jim Gilroy (jamesg) October 1995
Revision History:
jamesg Jan 1997 UTF-8, Unicode conversions
--*/
#include "local.h"
PSTR
Dns_CreateStringCopy(
IN PCHAR pchString,
IN DWORD cchString
)
/*++
Routine Description:
Create copy of string.
Arguments:
pchString -- ptr to string to copy
cchString -- length of string, if unknown; if NOT given, then pchString
MUST be NULL terminated
Return Value:
Ptr to string copy, if successful
NULL on failure.
--*/
{
LPSTR pstringNew;
DNSDBG( TRACE, ( "Dns_CreateStringCopy()\n" ));
if ( !pchString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
// determine string length, if not given
if ( !cchString )
{
cchString = strlen( pchString );
}
// allocate memory
pstringNew = (LPSTR) ALLOCATE_HEAP( cchString+1 );
if ( !pstringNew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
// copy and NULL terminate
RtlCopyMemory(
pstringNew,
pchString,
cchString );
pstringNew[cchString] = 0;
return( pstringNew );
}
DWORD
Dns_GetBufferLengthForStringCopy(
IN PCHAR pchString,
IN DWORD cchString,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Determing length required for copy of string.
Arguments:
pchString -- ptr to string to get buffer length for
cchString -- length of string, if known;
- if CharSetIn is unicode, then this is length in wide characters
- if NOT given, then pchString MUST be NULL terminated
CharSetIn -- incoming character set
CharSetOut -- result character set
Return Value:
Buffer length (bytes) required for string, includes space for terminating NULL.
Zero on invalid\unconvertible string. GetLastError() set to ERROR_INVALID_DATA.
--*/
{
INT length;
DNSDBG( TRACE, ( "Dns_GetBufferLengthForStringCopy()\n" ));
if ( !pchString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( 0 );
}
//
// incoming Unicode
//
if ( CharSetIn == DnsCharSetUnicode )
{
if ( !cchString )
{
cchString = (WORD) wcslen( (PWCHAR)pchString );
}
// unicode to unicode
if ( CharSetOut == DnsCharSetUnicode )
{
return( (cchString+1) * 2 );
}
// unicode to UTF8
//
// use private unicode\utf8 conversion functions
// - superior to public ones (faster, more robust)
// - Win95 does not support CP_UTF8
//
// for unicode-UTF8 there's no invalid string possible
else if ( CharSetOut == DnsCharSetUtf8 )
{
#if 0
length = WideCharToMultiByte(
CP_UTF8,
0, // no flags
(PWCHAR) pchString,
(INT) cchString,
NULL,
0, // call determines required buffer length
NULL,
NULL );
#endif
length = Dns_UnicodeToUtf8(
(PWCHAR) pchString,
(INT) cchString,
NULL,
0
);
ASSERT( length != 0 || cchString == 0 );
return( length + 1 );
}
// unicode to ANSI
// - some chars will NOT convert
else if ( CharSetOut == DnsCharSetAnsi )
{
length = WideCharToMultiByte(
CP_ACP,
0, // no flags
(PWCHAR) pchString,
(INT) cchString,
NULL,
0, // call determines required buffer length
NULL,
NULL
);
if ( length == 0 && cchString != 0 )
{
goto Failed;
}
return( length + 1 );
}
// bad CharSetOut drops to Failed
}
//
// incoming UTF8
//
else if ( CharSetIn == DnsCharSetUtf8 )
{
if ( !cchString )
{
cchString = strlen( pchString );
}
// UTF8 to UTF8
if ( CharSetOut == DnsCharSetUtf8 )
{
return( cchString + 1 );
}
// UTF8 to unicode
//
// use private unicode\utf8 conversion functions
// - superior to public ones (faster, more robust)
// - Win95 does not support CP_UTF8
//
// for UTF8 string can be invalid, catch and return error
else if ( CharSetOut == DnsCharSetUnicode )
{
#if 0
length = MultiByteToWideChar(
CP_UTF8,
0, // no flags
pchString,
(INT) cchString,
NULL,
0 // call determines required buffer length
);
#endif
length = Dns_Utf8ToUnicode(
pchString,
(INT) cchString,
NULL,
0
);
if ( length == 0 && cchString != 0 )
{
ASSERT( GetLastError() == ERROR_INVALID_DATA );
return( 0 );
}
return( (length+1)*2 );
}
// UTF8 to ANSI
// - note, result length here is actually buffer length
else if ( CharSetOut == DnsCharSetAnsi )
{
return Dns_Utf8ToAnsi(
pchString,
cchString,
NULL,
0 );
}
// bad CharSetOut drops to Failed
}
//
// incoming ANSI
//
else if ( CharSetIn == DnsCharSetAnsi )
{
if ( !cchString )
{
cchString = strlen( pchString );
}
// ANSI to ANSI
if ( CharSetOut == DnsCharSetAnsi )
{
return( cchString + 1 );
}
// ANSI to unicode
// - should always succeed
else if ( CharSetOut == DnsCharSetUnicode )
{
length = MultiByteToWideChar(
CP_ACP,
0, // no flags
pchString,
(INT) cchString,
NULL,
0 // call determines required buffer length
);
if ( length == 0 && cchString )
{
ASSERT( FALSE );
ASSERT( GetLastError() == ERROR_INVALID_DATA );
goto Failed;
}
return( (length+1) * 2 );
}
// ANSI to UTF8
// - note, result length here is actually buffer length
else if ( CharSetOut == DnsCharSetUtf8 )
{
return Dns_AnsiToUtf8(
pchString,
cchString,
NULL,
0 );
}
// bad CharSetOut drops to Failed
}
// all unhandled cases are failures
Failed:
DNSDBG( ANY, (
"ERROR: Dns_GetBufferLengthForStringCopy() failed!\n"
"\tpchString = %p (%*s)\n"
"\tcchString = %d\n"
"\tCharSetIn = %d\n"
"\tCharSetOut = %d\n",
pchString,
cchString, pchString,
cchString,
CharSetIn,
CharSetOut ));
SetLastError( ERROR_INVALID_DATA );
return( 0 );
}
DWORD
Dns_StringCopy(
OUT PBYTE pBuffer,
IN OUT PDWORD pdwBufLength,
IN PCHAR pchString,
IN DWORD cchString,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Create copy of DNS string.
Arguments:
pBuffer -- buffer to copy to
pdwBufLength -- ptr to length of buffer in bytes;
if NULL, buffer MUST have adequate length
if exists, then copy only completed if *pdwBufLength is adequate
to hold converted result
pchString -- ptr to string to copy
cchString -- length of string, if known;
- if CharSetIn is unicode, then this is length in wide characters
- if NOT given, then pchString MUST be NULL terminated
CharSetIn -- incoming character set
CharSetOut -- result character set
Return Value:
Count of bytes written to buffer (includes terminating NULL).
Zero on error. GetLastError() for status.
--*/
{
INT length;
DWORD bufLength;
DNSDBG( TRACE, ( "Dns_StringCopy()\n" ));
DNSDBG( STRING, (
"Dns_StringCopy()\n"
"\tpBuffer = %p\n"
"\tpdwBufLen = %p\n"
"\tbuf length = %d\n"
"\tpchString = %p\n"
"\tcchString = %d\n"
"\tCharSetIn = %d\n"
"\tCharSetOut = %d\n",
pBuffer,
pdwBufLength,
pdwBufLength ? *pdwBufLength : 0,
pchString,
cchString,
CharSetIn,
CharSetOut ));
if ( !pchString )
{
DNS_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
return( 0 );
}
//
// find string length
// do this here so don't do it twice if must calculate required buffer length
//
if ( cchString == 0 )
{
if ( CharSetIn == DnsCharSetUnicode )
{
cchString = (WORD) wcslen( (PWCHAR)pchString );
}
else
{
cchString = strlen( pchString );
}
}
//
// verify adequate buffer length
//
// DCR_PERF: ideally make direct copy to buffer and fail if
// over length, rather than effectively having to convert
// twice
//
if ( pdwBufLength )
{
bufLength = Dns_GetBufferLengthForStringCopy(
pchString,
cchString,
CharSetIn,
CharSetOut );
if ( bufLength == 0 )
{
SetLastError( ERROR_INVALID_DATA );
*pdwBufLength = 0;
return( 0 );
}
if ( bufLength > *pdwBufLength )
{
SetLastError( ERROR_MORE_DATA );
*pdwBufLength = bufLength;
return( 0 );
}
*pdwBufLength = bufLength;
}
//
// incoming unicode string
//
if ( CharSetIn == DnsCharSetUnicode )
{
// unicode to unicode straight copy
// - correct for length in wide characters
if ( CharSetOut == DnsCharSetUnicode )
{
((PWORD)pBuffer)[ cchString ] = 0;
cchString *= 2;
RtlCopyMemory(
pBuffer,
pchString,
cchString );
return( cchString+2 );
}
// unicode => UTF8
//
// use private unicode\utf8 conversion functions
// - superior to public ones (faster, more robust)
// - Win95 does not support CP_UTF8
//
// for unicode-UTF8 there's no invalid string possible
else if ( CharSetOut == DnsCharSetUtf8 )
{
#if 0
length = WideCharToMultiByte(
CP_UTF8,
0, // no flags
(PWCHAR) pchString,
(INT) cchString,
pBuffer,
MAXWORD, // assuming adequate length
NULL,
NULL );
#endif
length = Dns_UnicodeToUtf8(
(LPWSTR) pchString,
cchString,
pBuffer,
MAXWORD // assuming adequate length
);
ASSERT( length != 0 || cchString == 0 );
pBuffer[ length ] = 0;
return( length + 1 );
}
// unicode => ANSI
// - this conversion can fail
else if ( CharSetOut == DnsCharSetAnsi )
{
length = WideCharToMultiByte(
CP_ACP,
0, // no flags
(PWCHAR) pchString,
(INT) cchString,
pBuffer,
MAXWORD, // assuming adequate length
NULL,
NULL );
if ( length == 0 && cchString != 0 )
{
goto Failed;
}
pBuffer[ length ] = 0;
return( length + 1 );
}
// bad CharSetOut drops to Failed
}
//
// incoming UTF8
//
if ( CharSetIn == DnsCharSetUtf8 )
{
// UTF8 to UTF8 straight copy
if ( CharSetOut == DnsCharSetUtf8 )
{
memcpy(
pBuffer,
pchString,
cchString );
pBuffer[cchString] = 0;
return( cchString + 1 );
}
// UTF8 to unicode conversion
//
// use private unicode\utf8 conversion functions
// - superior to public ones (faster, more robust)
// - Win95 does not support CP_UTF8
//
// UTF8 strings can be invalid, and since sending in "infinite"
// buffer, this is only possible error
else if ( CharSetOut == DnsCharSetUnicode )
{
#if 0
length = MultiByteToWideChar(
CP_UTF8,
0, // no flags
(PCHAR) pchString,
(INT) cchString,
(PWCHAR) pBuffer,
MAXWORD // assuming adequate length
);
#endif
length = Dns_Utf8ToUnicode(
pchString,
cchString,
(LPWSTR) pBuffer,
MAXWORD
);
if ( length == 0 && cchString != 0 )
{
ASSERT( GetLastError() == ERROR_INVALID_DATA );
goto Failed;
}
((PWORD)pBuffer)[length] = 0;
return( (length+1) * 2 );
}
// UTF8 to ANSI
// - note, result length here is actually buffer length
else if ( CharSetOut == DnsCharSetAnsi )
{
length = Dns_Utf8ToAnsi(
pchString,
cchString,
pBuffer,
MAXWORD );
if ( length == 0 )
{
goto Failed;
}
return( length );
}
// bad CharSetOut drops to Failed
}
//
// incoming ANSI
//
if ( CharSetIn == DnsCharSetAnsi )
{
// ANSI to ANSI straight copy
if ( CharSetOut == DnsCharSetAnsi )
{
memcpy(
pBuffer,
pchString,
cchString );
pBuffer[cchString] = 0;
return( cchString + 1 );
}
// ANSI to unicode conversion
// - ANSI to unicode should not fail
else if ( CharSetOut == DnsCharSetUnicode )
{
length = MultiByteToWideChar(
CP_ACP,
0, // no flags
(PCHAR) pchString,
(INT) cchString,
(PWCHAR) pBuffer,
MAXWORD // assuming adequate length
);
if ( length == 0 && cchString )
{
ASSERT( FALSE );
ASSERT( GetLastError() == ERROR_INVALID_DATA );
goto Failed;
}
((PWORD)pBuffer)[length] = 0;
return( (length+1) * 2 );
}
// ANSI to UTF8
// - note, result length here is actually buffer length
else if ( CharSetOut == DnsCharSetUtf8 )
{
length = Dns_AnsiToUtf8(
pchString,
cchString,
pBuffer,
MAXWORD );
if ( length == 0 )
{
goto Failed;
}
return( length );
}
// bad CharSetOut drops to Failed
}
// all unhandled cases are failures
Failed:
DNSDBG( ANY, (
"ERROR: Dns_StringCopy() failed!\n"
"\tpBuffer = %p\n"
"\tpdwBufLen = %p\n"
"\tbuf length = %d\n"
"\tpchString = %p (%*s)\n"
"\tcchString = %d\n"
"\tCharSetIn = %d\n"
"\tCharSetOut = %d\n",
pBuffer,
pdwBufLength,
pdwBufLength ? *pdwBufLength : 0,
pchString,
cchString, pchString,
cchString,
CharSetIn,
CharSetOut ));
SetLastError( ERROR_INVALID_DATA );
return( 0 );
}
PVOID
Dns_StringCopyAllocate(
IN PCHAR pchString,
IN DWORD cchString,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Create copy of DNS string
Arguments:
pchString -- ptr to string to copy
cchString -- length of string, if known;
- if CharSetIn, then this is length in wide characters
- if NOT given, then pchString MUST be NULL terminated
CharSetIn -- flag indicates incoming string is unicode
CharSetOut -- flag indicates copy will be in unicode format
Return Value:
Ptr to string copy, if successful
NULL on failure.
--*/
{
PCHAR pnew;
DWORD length;
DNSDBG( TRACE, ( "Dns_StringCopyAllocate()\n" ));
DNSDBG( STRING, (
"Dns_StringCopyAllocate( %.*s )\n"
"\tpchString = %p\n"
"\tcchString = %d\n"
"\tUnicodeIn = %d\n"
"\tUnicodeOut = %d\n",
cchString,
pchString,
pchString,
cchString,
CharSetIn,
CharSetOut ));
if ( !pchString )
{
// For parity with other string routines, do not treat NULL argument
// as an event worth of assert.
// DNS_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
//
// determine incoming string length
// do this explicitly to avoid doing string length operations twice
//
if ( !cchString )
{
if ( CharSetIn == DnsCharSetUnicode )
{
cchString = (WORD) wcslen( (PWCHAR)pchString );
}
else
{
cchString = strlen( pchString );
}
}
//
// determine required buffer length and allocate
//
length = Dns_GetBufferLengthForStringCopy(
pchString,
cchString,
CharSetIn,
CharSetOut );
if ( length == 0 )
{
ASSERT( CharSetIn && CharSetOut && GetLastError() == ERROR_INVALID_DATA );
SetLastError( ERROR_INVALID_DATA );
return( NULL );
}
pnew = (PVOID) ALLOCATE_HEAP( length );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
//
// copy \ convert string
// - can fail if conversion not valid
// (ex. bogus UTF8 string, or attempting
// conversion from ANSI to UTF8)
//
if ( ! Dns_StringCopy(
pnew,
NULL,
pchString,
cchString,
CharSetIn,
CharSetOut ) )
{
FREE_HEAP( pnew );
return( NULL );
}
return( pnew );
}
//
// Simple create string copy utilities.
//
PSTR
Dns_CreateStringCopy_A(
IN PCSTR pszString
)
/*++
Routine Description:
Create copy of string.
Simple wrapper to handle
- sizing
- memory allocation
- copy of string
Arguments:
pszString -- ptr to string to copy
Return Value:
Ptr to string copy, if successful
NULL on failure.
--*/
{
PSTR pnew;
DWORD length;
DNSDBG( TRACE, ( "Dns_CreateStringCopy_A( %s )\n", pszString ));
if ( !pszString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
// determine string length, if not given
length = strlen( pszString ) + 1;
// allocate memory
pnew = (LPSTR) ALLOCATE_HEAP( length );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
// copy and NULL terminate
RtlCopyMemory(
pnew,
pszString,
length );
return( pnew );
}
PWSTR
Dns_CreateStringCopy_W(
IN PCWSTR pwsString
)
{
PWSTR pnew;
DWORD length;
DNSDBG( TRACE, ( "Dns_CreateStringCopy_W( %S )\n", pwsString ));
if ( !pwsString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
// allocate memory
length = (wcslen( pwsString ) + 1) * sizeof(WCHAR);
pnew = (PWSTR) ALLOCATE_HEAP( length );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
// copy and NULL terminate
RtlCopyMemory(
pnew,
pwsString,
length );
return( pnew );
}
PWSTR
Dns_CreateConcatenatedString_W(
IN PCWSTR * pStringArray
)
/*++
Routine Description:
Create concatenated string.
Arguments:
pStringArray -- array of string pointers to concat
NULL pointer terminates array
Return Value:
Ptr to concantenated string copy, if successful
NULL on failure.
--*/
{
PWSTR pnew;
PCWSTR pwstr;
DWORD length;
DWORD iter;
DNSDBG( TRACE, ( "Dns_CreateConcatenatedString_W()\n" ));
if ( !pStringArray )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
//
// loop determining required length
//
length = 1;
iter = 0;
while ( pwstr = pStringArray[iter++] )
{
length += wcslen( pwstr );
}
//
// allocate
//
pnew = (PWSTR) ALLOCATE_HEAP( length*sizeof(WCHAR) );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return NULL;
}
//
// write concatented string
//
pnew[0] = 0;
iter = 0;
while ( pwstr = pStringArray[iter++] )
{
wcscat( pnew, pwstr );
}
DNSDBG( TRACE, ( "Concatented string = %S\n", pnew ));
return pnew;
}
//
// MULTI_SZ routines
//
DWORD
MultiSz_Size_A(
IN PCSTR pmszString
)
/*++
Routine Description:
Determine length (size) of MULTI_SZ string.
Arguments:
pmszString -- ptr to string to size
Return Value:
Size of MULTI_SZ string (in bytes).
Includes terminating double NULL.
--*/
{
PSTR pnext;
DWORD lengthTotal = 0;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_Size_A( %s )\n", pmszString ));
//
// loop until read at end of strings
//
// when we reach the end, we'll be pointing at the second
// zero in the double null terminator; strlen() will return
// zero, and we'll add that to our count as 1 and exit
//
pnext = (PSTR) pmszString;
while ( pnext )
{
length = strlen( pnext ) + 1;
lengthTotal += length;
if ( length == 1 )
{
break;
}
pnext += length;
}
return lengthTotal;
}
PSTR
MultiSz_NextString_A(
IN PCSTR pmszString
)
/*++
Routine Description:
Find next string in MULTI_SZ string
Arguments:
pmszString -- ptr to multi string
Return Value:
Next string in MULTI_SZ string.
NULL if no strings left.
--*/
{
PSTR pnext;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_NextString_A( %s )\n", pmszString ));
//
// find next string in multi-string
// - find length of current string
// - hop over it (inc. null)
// - if pointing at terminating double-null return
// NULL to signal end
//
pnext = (PSTR) pmszString;
if ( !pnext )
{
return NULL;
}
length = strlen( pnext );
if ( length == 0 )
{
DNSDBG( ANY, (
"ERROR: MultiSz_Next(%p) called on terminator!\n",
pmszString ));
return NULL;
}
pnext += length + 1;
if ( *pnext == 0 )
{
return NULL;
}
return pnext;
}
PSTR
MultiSz_Copy_A(
IN PCSTR pmszString
)
/*++
Routine Description:
Create copy of MULTI_SZ string.
Simple wrapper to handle
- sizing
- memory allocation
- copy of string
Arguments:
pmszString -- ptr to string to copy
Return Value:
Ptr to string copy, if successful
NULL on failure.
--*/
{
PSTR pnew;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_Copy_A( %s )\n", pmszString ));
if ( !pmszString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
// determine string length, if not given
length = MultiSz_Size_A( pmszString );
// allocate memory
pnew = (LPSTR) ALLOCATE_HEAP( length );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
// copy and NULL terminate
RtlCopyMemory(
pnew,
pmszString,
length );
return( pnew );
}
BOOL
MultiSz_Equal_A(
IN PCSTR pmszString1,
IN PCSTR pmszString2
)
/*++
Routine Description:
Compare two MULTI_SZ strings.
Arguments:
pmszString1 -- ptr to string
pmszString2 -- ptr to string
Return Value:
TRUE -- if strings equal
FALSE -- if strings different
--*/
{
DWORD length1;
DWORD length2;
DNSDBG( TRACE, (
"MultiSz_Equal_A( %s, %s )\n",
pmszString1,
pmszString2
));
//
// non-existence cases
//
if ( !pmszString1 )
{
return !pmszString2;
}
if ( !pmszString2 )
{
return !pmszString1;
}
//
// length check
//
length1 = MultiSz_Size_A( pmszString1 );
length2 = MultiSz_Size_A( pmszString2 );
if ( length1 != length2 )
{
return FALSE;
}
//
// memory check
//
return RtlEqualMemory(
pmszString1,
pmszString2,
length1 );
}
//
// MULTI_SZ routines -- in wide char
//
DWORD
MultiSz_Size_W(
IN PCWSTR pmszString
)
/*++
Routine Description:
Determine size of MULTI_SZ string.
Arguments:
pmszString -- ptr to string to size
Return Value:
Size of MULTI_SZ string (in bytes).
Includes terminating double NULL.
--*/
{
PWSTR pnext;
DWORD lengthTotal = 0;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_Size_W( %S )\n", pmszString ));
//
// loop until read at end of strings
//
// when we reach the end, we'll be pointing at the second
// zero in the double null terminator; strlen() will return
// zero, and we'll add that to our count as 1 and exit
//
pnext = (PWSTR) pmszString;
while ( pnext )
{
length = wcslen( pnext ) + 1;
lengthTotal += length;
if ( length == 1 )
{
break;
}
pnext += length;
}
return lengthTotal * sizeof(WCHAR);
}
PWSTR
MultiSz_NextString_W(
IN PCWSTR pmszString
)
/*++
Routine Description:
Find next string in MULTI_SZ string
Arguments:
pmszString -- ptr to multi string
Return Value:
Next string in MULTI_SZ string.
NULL if no strings left.
--*/
{
PWSTR pnext;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_NextString_W( %S )\n", pmszString ));
//
// find next string in multi-string
// - find length of current string
// - hop over it (inc. null)
// - if pointing at terminating double-null return
// NULL to signal end
//
pnext = (PWSTR) pmszString;
if ( !pnext )
{
return NULL;
}
length = wcslen( pnext );
if ( length == 0 )
{
DNSDBG( ANY, (
"ERROR: MultiSz_Next(%p) called on terminator!\n",
pmszString ));
return NULL;
}
pnext += length + 1;
if ( *pnext == 0 )
{
return NULL;
}
return pnext;
}
PWSTR
MultiSz_Copy_W(
IN PCWSTR pmszString
)
/*++
Routine Description:
Create copy of MULTI_SZ string.
Simple wrapper to handle
- sizing
- memory allocation
- copy of string
Arguments:
pmszString -- ptr to string to copy
Return Value:
Ptr to string copy, if successful
NULL on failure.
--*/
{
PWSTR pnew;
DWORD length;
DNSDBG( TRACE, ( "MultiSz_Copy_W( %S )\n", pmszString ));
if ( !pmszString )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( NULL );
}
// determine string length, if not given
length = MultiSz_Size_W( pmszString );
// allocate memory
pnew = (PWSTR) ALLOCATE_HEAP( length );
if ( !pnew )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
// copy and NULL terminate
RtlCopyMemory(
pnew,
pmszString,
length );
return( pnew );
}
BOOL
MultiSz_Equal_W(
IN PCWSTR pmszString1,
IN PCWSTR pmszString2
)
/*++
Routine Description:
Compare two MULTI_SZ strings.
Arguments:
pmszString1 -- ptr to string
pmszString2 -- ptr to string
Return Value:
TRUE -- if strings equal
FALSE -- if strings different
--*/
{
DWORD length1;
DWORD length2;
DNSDBG( TRACE, (
"MultiSz_Equal_W( %s, %s )\n",
pmszString1,
pmszString2
));
//
// non-existence cases
//
if ( !pmszString1 )
{
return !pmszString2;
}
if ( !pmszString2 )
{
return !pmszString1;
}
//
// length check
//
length1 = MultiSz_Size_W( pmszString1 );
length2 = MultiSz_Size_W( pmszString2 );
if ( length1 != length2 )
{
return FALSE;
}
//
// memory check
//
return RtlEqualMemory(
pmszString1,
pmszString2,
length1 );
}
BOOL
MultiSz_ContainsName_W(
IN PCWSTR pmszString,
IN PCWSTR pString
)
/*++
Routine Description:
Check if MULTISZ string contains a string.
Arguments:
pmszString -- multisz string
pString -- string to check
Return Value:
TRUE if string is in multisz.
FALSE otherwise.
--*/
{
PCWSTR pstr = pmszString;
//
// check each string
//
while ( pstr )
{
if ( Dns_NameCompare_W(
pstr,
pString ) )
{
return TRUE;
}
pstr = MultiSz_NextString_W( pstr );
}
return FALSE;
}
//
// Random
//
INT
wcsicmp_ThatWorks(
IN PWSTR pString1,
IN PWSTR pString2
)
/*++
Routine Description:
A version of wcsicmp that actually works.
This is just a wrapped on CompareStringW, to hide all the detail
and give an interface identical to wcsicmp().
It uses US English to standardize the comparison.
Arguments:
pString1 -- first string; must be NULL terminated
pString2 -- first second; must be NULL terminated
Return Value:
-1 -- if string 1 less than string 2
0 -- strings are equal
1 -- if string 1 greater than string 2
--*/
{
INT result;
//
// compare
// - case conversion done in default DNS locale -- US English
// this locale correctly matches most non-locale sensitive
// upper-lower characters
//
result = CompareStringW(
DNS_DEFAULT_LOCALE,
NORM_IGNORECASE,
pString1,
(-1), // NULL terminated
pString2,
(-1) // NULL terminated
);
if ( result == CSTR_EQUAL )
{
result = 0;
}
else if ( result == CSTR_LESS_THAN )
{
result = -1;
}
else // greater than or error
{
result = 1;
}
return( result );
}
LPWSTR
Dns_GetResourceString(
IN DWORD dwStringId,
IN OUT LPWSTR pwszBuffer,
IN DWORD cbBuffer
)
/*++
Routine Description:
Loads a string (defined in dnsmsg.mc) from current module
Arguments:
dwStringId -- The ID of the string to be fetched
Return Value:
DCR: kill off eyal function
DEVNOTE: don't understand the value of this return
-- it's essentially a BOOL, we already know what the ptr is
it's the buffer passed in
-- ptr to next byte is useful in continuous write situation
(ugly and useless in others)
-- better would just be the same return as LoadString, so we
both get the success\failure indication and also know
how many bytes forward we must push our buffer ptr if
we want to write more
Error: NULL
Success: a pointer to the loaded string
--*/
{
LPWSTR pStr = NULL;
DWORD status;
HANDLE hMod;
DNSDBG( TRACE, (
"Dns_GetStringResource()\n" ));
// Get module handle-- No need to close handle, it is just a ptr w/o increment on ref count.
hMod = GetModuleHandle( NULL );
if ( !hMod )
{
ASSERT( hMod );
return NULL;
}
status = LoadStringW(
hMod,
dwStringId,
pwszBuffer,
cbBuffer );
if ( status != 0 )
{
pStr = pwszBuffer;
}
ELSE
{
// LoadString returns # of bytes loaded, convert to error.
status = GetLastError();
DNSDBG( TRACE, (
"Error <%lu>: Failed to load string %d\n",
status, dwStringId ));
ASSERT ( FALSE );
}
DNSDBG( TRACE, (
"Exit <0x%p> Dns_GetStringResource\n",
pStr ));
return pStr;
}
DWORD
String_ReplaceCharW(
IN OUT PWSTR pString,
IN WCHAR TargetChar,
IN WCHAR ReplaceChar
)
/*++
Routine Description:
Replace a characater in the string with another character.
Arguments:
pString -- string
TargetChar -- character to replace
ReplaceChar -- character that replaces TargetChar
Return Value:
Count of replacements.
--*/
{
PWCHAR pch;
WCHAR ch;
DWORD countReplace= 0;
//
// loop matching and replacing TargetChar
//
pch = pString - 1;
while ( ch = *++pch )
{
if ( ch == TargetChar )
{
*pch = ReplaceChar;
countReplace++;
}
}
return countReplace;
}
DWORD
String_ReplaceCharA(
IN OUT PSTR pString,
IN CHAR TargetChar,
IN CHAR ReplaceChar
)
/*++
Routine Description:
Replace a characater in the string with another character.
Arguments:
pString -- string
TargetChar -- character to replace
ReplaceChar -- character that replaces TargetChar
Return Value:
Count of replacements.
--*/
{
PCHAR pch;
CHAR ch;
DWORD countReplace= 0;
//
// loop matching and replacing TargetChar
//
pch = pString - 1;
while ( ch = *++pch )
{
if ( ch == TargetChar )
{
*pch = ReplaceChar;
countReplace++;
}
}
return countReplace;
}
DWORD
Dns_TokenizeStringA(
IN OUT PSTR pBuffer,
OUT PCHAR * Argv,
IN DWORD MaxArgs
)
/*++
Routine Description:
Tokenize buffer Argv/Argc form.
Arguments:
pBuffer -- string buffer to tokenize
Argv -- argv array
MaxArgs -- max size of Argv array
Return Value:
Response code corresponding to status, if found.
Zero otherwise.
--*/
{
DWORD count = 0;
PCHAR pstring = pBuffer;
//
// tokenize string
// - note that after the first call strtok
// takes NULL ptr to continue tokening same string
//
while ( count < MaxArgs )
{
PCHAR pch;
pch = strtok( pstring, " \t\r\n" );
if ( !pch )
{
break;
}
Argv[ count++ ] = pch;
pstring = NULL;
}
return count;
}
DWORD
Dns_TokenizeStringW(
IN OUT PWSTR pBuffer,
OUT PWCHAR * Argv,
IN DWORD MaxArgs
)
/*++
Routine Description:
Tokenize buffer Argv/Argc form.
Arguments:
pBuffer -- string buffer to tokenize
Argv -- argv array
MaxArgs -- max size of Argv array
Return Value:
Response code corresponding to status, if found.
Zero otherwise.
--*/
{
DWORD count = 0;
PWCHAR pstring = pBuffer;
//
// tokenize string
// - note that after the first call strtok
// takes NULL ptr to continue tokening same string
//
while ( count < MaxArgs )
{
PWCHAR pch;
pch = wcstok( pstring, L" \t\r\n" );
if ( !pch )
{
break;
}
Argv[ count++ ] = pch;
pstring = NULL;
}
return count;
}
PSTR *
Argv_CopyEx(
IN DWORD Argc,
IN PCHAR * Argv,
IN DNS_CHARSET CharSetIn,
IN DNS_CHARSET CharSetOut
)
/*++
Routine Description:
Convert reate ANSI argv from unicode argv.
Arguments:
Argc -- argc
Argv -- argv array
CharSetIn -- char set of existing Argv
CharSetOut -- char set of desired argv copy
Return Value:
Ptr to argv. User can cast appropriately.
--*/
{
PCHAR * argvCopy;
//
// allocate Argv
//
argvCopy = (PCHAR *) ALLOCATE_HEAP( (Argc+1) * sizeof(PCHAR) );
if ( !argvCopy )
{
return NULL;
}
//
// tokenize string
// - note that after the first call strtok
// takes NULL ptr to continue tokening same string
//
argvCopy[ Argc ] = NULL;
while ( Argc-- )
{
argvCopy[ Argc ] = Dns_StringCopyAllocate(
Argv[ Argc ],
0, // null terminated
CharSetIn,
CharSetOut
);
}
return argvCopy;
}
VOID
Argv_Free(
IN OUT PSTR * Argv
)
/*++
Routine Description:
Free allocated Argv.
Arguments:
Argv -- argv array
Return Value:
None
--*/
{
DWORD i = 0;
PCHAR parg;
// free Argv strings
while ( parg = Argv[i++] )
{
FREE_HEAP( parg );
}
// free Argv itself
FREE_HEAP( parg );
}
//
// End string.c
//