windows-nt/Source/XPSP1/NT/inetsrv/query/qutil/querylib/string.cxx
2020-09-26 16:20:57 +08:00

462 lines
15 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1998.
//
// File: string.cxx
//
// Contents: Yet another string class and support functions
//
// History: 96/Jan/3 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <locale.h>
//+---------------------------------------------------------------------------
//
// Member: CVirtualString::CVirtualString - public constructor
//
// Synopsis: Initializes the string by virtually allocating a buffer.
//
// History: 96/Jan/03 DwightKr Created.
//
//----------------------------------------------------------------------------
CVirtualString::CVirtualString( unsigned cwcBuffer )
: _wcsString(0),
_wcsEnd(0),
_cwcBuffer(cwcBuffer),
_pwcLastCommitted(0)
{
_wcsString = new WCHAR[ _cwcBuffer ];
_pwcLastCommitted = _wcsString + _cwcBuffer - 1;
_wcsEnd = _wcsString;
*_wcsEnd = 0;
} //CVirtualString
//+---------------------------------------------------------------------------
//
// Member: CVirtualString::~CVirtualString - public destructor
//
// Synopsis: Releases virtual memory assocated with this buffer
//
// History: 96/Jan/03 DwightKr Created.
//
//----------------------------------------------------------------------------
CVirtualString::~CVirtualString()
{
delete [] _wcsString;
} //~CVirtualString
//+---------------------------------------------------------------------------
//
// Member: CVirtualString::GrowBuffer, private
//
// Synopsis: Commits or re-allocates the string as needed
//
// Arguments: [cwcValue] - # of WCHARs by which to grow the buffer
//
// History: 96/Mar/25 dlee Created from DwightKr's StrCat
//
//----------------------------------------------------------------------------
void CVirtualString::GrowBuffer( ULONG cwcValue )
{
unsigned cwcNewString = cwcValue + 1;
unsigned cwcOldString = CiPtrToUint( _wcsEnd - _wcsString );
unsigned cwcRemaining = CiPtrToUint( _cwcBuffer - cwcOldString );
Win4Assert( _cwcBuffer >= cwcOldString );
if ( cwcRemaining < cwcNewString )
{
DWORD cwcOldBuffer = _cwcBuffer;
DWORD cwcNewBuffer = _cwcBuffer;
do
{
cwcNewBuffer *= 2;
cwcRemaining = cwcNewBuffer - cwcOldString;
}
while ( cwcRemaining < cwcNewString );
XArray<WCHAR> xTemp( cwcNewBuffer );
RtlCopyMemory( xTemp.GetPointer(),
_wcsString,
_cwcBuffer * sizeof WCHAR );
delete [] _wcsString;
_wcsString = xTemp.Acquire();
_cwcBuffer = cwcNewBuffer;
_wcsEnd = _wcsString + cwcOldString;
_pwcLastCommitted = _wcsString + _cwcBuffer - 1;
}
} //GrowBuffer
// if TRUE, the character doesn't need to be URL escaped
static const BYTE g_afNoEscape[128] =
{
FALSE, // 00 (NUL)
FALSE, // 01 (SOH)
FALSE, // 02 (STX)
FALSE, // 03 (ETX)
FALSE, // 04 (EOT)
FALSE, // 05 (ENQ)
FALSE, // 06 (ACK)
FALSE, // 07 (BEL)
FALSE, // 08 (BS)
FALSE, // 09 (HT)
FALSE, // 0A (LF)
FALSE, // 0B (VT)
FALSE, // 0C (FF)
FALSE, // 0D (CR)
FALSE, // 0E (SI)
FALSE, // 0F (SO)
FALSE, // 10 (DLE)
FALSE, // 11 (DC1)
FALSE, // 12 (DC2)
FALSE, // 13 (DC3)
FALSE, // 14 (DC4)
FALSE, // 15 (NAK)
FALSE, // 16 (SYN)
FALSE, // 17 (ETB)
FALSE, // 18 (CAN)
FALSE, // 19 (EM)
FALSE, // 1A (SUB)
FALSE, // 1B (ESC)
FALSE, // 1C (FS)
FALSE, // 1D (GS)
FALSE, // 1E (RS)
FALSE, // 1F (US)
FALSE, // 20 SPACE
FALSE, // 21 !
FALSE, // 22 "
FALSE, // 23 #
FALSE, // 24 $
FALSE, // 25 %
FALSE, // 26 &
FALSE, // 27 '
FALSE, // 28 (
FALSE, // 29 )
FALSE, // 2A *
FALSE, // 2B +
FALSE, // 2C ,
FALSE, // 2D -
TRUE, // 2E .
TRUE, // 2F /
TRUE, // 30 0
TRUE, // 31 1
TRUE, // 32 2
TRUE, // 33 3
TRUE, // 34 4
TRUE, // 35 5
TRUE, // 36 6
TRUE, // 37 7
TRUE, // 38 8
TRUE, // 39 9
TRUE, // 3A :
FALSE, // 3B ;
FALSE, // 3C <
TRUE, // 3D =
FALSE, // 3E >
FALSE, // 3F ?
FALSE, // 40 @
TRUE, // 41 A
TRUE, // 42 B
TRUE, // 43 C
TRUE, // 44 D
TRUE, // 45 E
TRUE, // 46 F
TRUE, // 47 G
TRUE, // 48 H
TRUE, // 49 I
TRUE, // 4A J
TRUE, // 4B K
TRUE, // 4C L
TRUE, // 4D M
TRUE, // 4E N
TRUE, // 4F O
TRUE, // 50 P
TRUE, // 51 Q
TRUE, // 52 R
TRUE, // 53 S
TRUE, // 54 T
TRUE, // 55 U
TRUE, // 56 V
TRUE, // 57 W
TRUE, // 58 X
TRUE, // 59 Y
TRUE, // 5A Z
FALSE, // 5B [
FALSE, // 5C \
FALSE, // 5D ]
FALSE, // 5E ^
FALSE, // 5F _
FALSE, // 60 `
TRUE, // 61 a
TRUE, // 62 b
TRUE, // 63 c
TRUE, // 64 d
TRUE, // 65 e
TRUE, // 66 f
TRUE, // 67 g
TRUE, // 68 h
TRUE, // 69 i
TRUE, // 6A j
TRUE, // 6B k
TRUE, // 6C l
TRUE, // 6D m
TRUE, // 6E n
TRUE, // 6F o
TRUE, // 70 p
TRUE, // 71 q
TRUE, // 72 r
TRUE, // 73 s
TRUE, // 74 t
TRUE, // 75 u
TRUE, // 76 v
TRUE, // 77 w
TRUE, // 78 x
TRUE, // 79 y
TRUE, // 7A z
FALSE, // 7B {
FALSE, // 7C |
FALSE, // 7D }
FALSE, // 7E ~
FALSE, // 7F (DEL)
};
static const unsigned cNoEscape = sizeof g_afNoEscape / sizeof g_afNoEscape[0];
//+---------------------------------------------------------------------------
//
// Function: IsNoUrlEscape
//
// Synopsis: Determines if a character doesn't need URL escaping.
//
// Arguments: [c] -- Character to test, T must be unsigned.
//
// Returns: TRUE if b doesn't need URL escaping.
//
// History: 98/Apr/22 dlee Created.
//
//----------------------------------------------------------------------------
template<class T> inline BOOL IsNoUrlEscape( T c )
{
if ( c < cNoEscape )
return g_afNoEscape[ c ];
return FALSE;
} //IsNoUrlEscape
//+---------------------------------------------------------------------------
//
// Function: URLEscapeW
//
// Synopsis: Appends an escaped version of a string to a virtual string.
//
// History: 96/Apr/03 dlee Created from DwightKr's code
// 96/May/21 DwightKr Escape spaces
// 97/Nov/19 AlanW Allow %ummmm escape codes
//
//----------------------------------------------------------------------------
void URLEscapeW( WCHAR const * wcsString,
CVirtualString & StrResult,
ULONG ulCodepage,
BOOL fConvertSpaceToPlus )
{
BOOL fTryConvertMB = TRUE;
//
// All spaces are converted to plus signs (+), percents are doubled,
// Non alphanumeric characters are represented by their
// hexadecimal ASCII equivalents.
//
Win4Assert( wcsString != 0 );
while ( *wcsString != 0 )
{
//
// Spaces can be treated differently on either size of the ?.
// Spaces before the ? (the URI) needs to have spaces escaped;
// those AFTER the ? can be EITHER escaped, or changed to a +.
// Use either '+' or the % escape depending upon fConverSpaceToPlus
//
if ( IsNoUrlEscape( *wcsString ) )
{
StrResult.CharCat( *wcsString );
}
else if ( L' ' == *wcsString )
{
if ( fConvertSpaceToPlus )
StrResult.CharCat( L'+' );
else
StrResult.StrCat( L"%20", 3 );
}
else if ( L'%' == *wcsString )
{
StrResult.StrCat( L"%%", 2 );
}
else if ( *wcsString < 0x80 )
{
StrResult.CharCat( L'%' );
unsigned hiNibble = ((*wcsString) & 0xf0) >> 4;
unsigned loNibble = (*wcsString) & 0x0f;
StrResult.CharCat( hiNibble > 9 ? (hiNibble-10 + L'A') : (hiNibble + L'0') );
StrResult.CharCat( loNibble > 9 ? (loNibble-10 + L'A') : (loNibble + L'0') );
}
else
{
Win4Assert( *wcsString >= 0x80 );
//
// We encountered a character outside the ASCII range.
// Try counverting the Unicode string to multi-byte. If the
// conversion succeeds, continue by converting to 8 bit characters.
// Otherwise, convert this and any other Unicode characters to the
// %ummmm escape.
//
if ( fTryConvertMB )
{
ULONG cchString = wcslen(wcsString);
XArray<BYTE> pszString( cchString*2 );
BOOL fUsedDefaultChar = FALSE;
DWORD cbConvert;
ULONG cbString = pszString.Count();
do
{
cbConvert = WideCharToMultiByte( ulCodepage,
#if (WINVER >= 0x0500)
WC_NO_BEST_FIT_CHARS |
#endif // (WINVER >= 0x0500)
WC_COMPOSITECHECK |
WC_DEFAULTCHAR,
wcsString,
cchString,
(CHAR *) pszString.Get(),
cbString,
0,
&fUsedDefaultChar );
if ( 0 == cbConvert )
{
Win4Assert( cbString > 0 );
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
cbString += cbString;
delete pszString.Acquire();
pszString.Init(cbString);
}
else if ( GetLastError() == ERROR_INVALID_PARAMETER )
{
// Presumably unknown code page.
fUsedDefaultChar = TRUE;
break;
}
else
{
THROW( CException() );
}
}
} while ( 0 == cbConvert );
if ( ! fUsedDefaultChar )
{
URLEscapeMToW(pszString.Get(), cbConvert, StrResult, fConvertSpaceToPlus );
return;
}
fTryConvertMB = FALSE;
}
// Convert to an escaped Unicode character
StrResult.StrCat( L"%u", 2 );
USHORT wch = *wcsString;
unsigned iNibble = (wch & 0xf000) >> 12;
StrResult.CharCat( iNibble > 9 ? (iNibble-10 + L'A') : (iNibble + L'0') );
iNibble = (wch & 0x0f00) >> 8;
StrResult.CharCat( iNibble > 9 ? (iNibble-10 + L'A') : (iNibble + L'0') );
iNibble = (wch & 0x00f0) >> 4;
StrResult.CharCat( iNibble > 9 ? (iNibble-10 + L'A') : (iNibble + L'0') );
iNibble = wch & 0x000f;
StrResult.CharCat( iNibble > 9 ? (iNibble-10 + L'A') : (iNibble + L'0') );
}
wcsString++;
}
} //URLEscapeW
//+---------------------------------------------------------------------------
//
// Function: URLEscapeMToW
//
// Synopsis: Appends an escaped version of a string to a virtual string.
// The string is 'pseudo-UniCode'. A multi-byte input string
// is converted to a UniCode URL, which is implicitly ASCII.
//
// History: 96/Apr/03 dlee Created from DwightKr's code
// 96/May/21 DwightKr Escape spaces
// 96-Sep-17 KyleP Modified URLEscapeW
//
//----------------------------------------------------------------------------
void URLEscapeMToW( BYTE const * psz,
unsigned cc,
CVirtualString & StrResult,
BOOL fConvertSpaceToPlus )
{
//
// All spaces are converted to plus signs (+), percents are doubled,
// Non alphanumeric characters are represented by their
// hexadecimal ASCII equivalents.
//
Win4Assert( psz != 0 );
for( unsigned i = 0; i < cc; i++ )
{
//
// Spaces can be treated differently on either size of the ?.
// Spaces before the ? (the URI) needs to have spaces escaped;
// those AFTER the ? can be EITHER escaped, or changed to a +.
// Use either '+' or the % escape depending upon fConverSpaceToPlus
//
if ( IsNoUrlEscape( psz[i] ) )
{
StrResult.CharCat( (WCHAR)psz[i] );
}
else if ( L' ' == psz[i] )
{
if ( fConvertSpaceToPlus )
StrResult.CharCat( L'+' );
else
StrResult.StrCat( L"%20", 3 );
}
else if ( L'%' == psz[i] )
{
StrResult.StrCat( L"%%", 2 );
}
else
{
StrResult.CharCat( L'%' );
unsigned hiNibble = ((psz[i]) & 0xf0) >> 4;
unsigned loNibble = (psz[i]) & 0x0f;
StrResult.CharCat( hiNibble > 9 ? (hiNibble-10 + L'A') : (hiNibble + L'0') );
StrResult.CharCat( loNibble > 9 ? (loNibble-10 + L'A') : (loNibble + L'0') );
}
}
} //URLEscapeMToW