//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include //+--------------------------------------------------------------------------- // // 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 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 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 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