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
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
|
|
//
|
|
|
|
|
|
|