462 lines
15 KiB
C++
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
|