windows-nt/Source/XPSP1/NT/inetsrv/query/web/ixsso/ixsinfo.cxx
2020-09-26 16:20:57 +08:00

762 lines
21 KiB
C++

//+---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation, 1997 - 2000.
//
// File: ixsinfo.cxx
//
// Contents: Query SSO query information methods
//
// History: 30 Jan 1997 Alanw Created
//
//----------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
#include "ssodebug.hxx"
#include "ixsso.hxx"
#include "ixsinfo.hxx"
#include <cgiesc.hxx>
#include <string.hxx>
#include <tgrow.hxx>
//-----------------------------------------------------------------------------
// CixssoQuery Methods
//-----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Function: AddURLTerm - public inline
//
// Synopsis: Add a term to a URL QueryString
//
// Arguments: [vString] - virtual string in which the result is accumulated
// [pwszTerm] - tag name, assumed to not need encoding
// [pwszValue] - value part
// [ulCodepage] - code page for URL encoding
//
// History: 19 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
inline void AddURLTerm(
CVirtualString & vString,
WCHAR * pwszTerm,
WCHAR * pwszValue,
ULONG ulCodepage)
{
if (vString.StrLen() > 0)
vString.CharCat( L'&' );
vString.StrCat(pwszTerm);
URLEscapeW( pwszValue, vString, ulCodepage, TRUE );
}
//+---------------------------------------------------------------------------
//
// Member: CixssoQuery::QueryToURL - public
//
// Synopsis: Produce a URL QueryString from the state of the query object
//
// Arguments: [pbstrQueryString] - The URL-encoded query string is
// returned here
//
// History: 19 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CixssoQuery::QueryToURL(BSTR * pbstrQueryString)
{
_err.Reset();
SCODE sc = S_OK;
CVirtualString vString( 512 );
*pbstrQueryString = 0;
TRY {
if (_pwszCatalog)
{
AddURLTerm( vString, L"ct=", _pwszCatalog, _ulCodepage );
}
if (_pwszDialect)
{
AddURLTerm( vString, L"di=", _pwszDialect, _ulCodepage );
}
if (_pwszSort)
{
AddURLTerm( vString, L"so=", _pwszSort, _ulCodepage );
}
if (_pwszGroup)
{
AddURLTerm( vString, L"gr=", _pwszGroup, _ulCodepage );
}
if (_pwszRestriction)
{
AddURLTerm( vString, L"qu=", _pwszRestriction, _ulCodepage );
}
if (_maxResults)
{
WCHAR awchBuf[20];
wsprintf(awchBuf, L"%d", _maxResults);
AddURLTerm( vString, L"mh=", awchBuf, _ulCodepage );
}
if (_cFirstRows)
{
WCHAR awchBuf[20];
wsprintf(awchBuf, L"%d", _cFirstRows);
AddURLTerm( vString, L"fr=", awchBuf, _ulCodepage );
}
if (_StartHit.Get())
{
XGrowable<WCHAR> awchBuf;
FormatLongVector( _StartHit.Get(), awchBuf );
AddURLTerm( vString, L"sh=", awchBuf.Get(), _ulCodepage );
}
if (_fAllowEnumeration)
{
AddURLTerm( vString, L"ae=", L"1", _ulCodepage );
}
// OptimizeFor defaults to Hitcount
if (_dwOptimizeFlags != eOptHitCount)
{
WCHAR awchBuf[4];
unsigned i = 0;
if (_dwOptimizeFlags & eOptPerformance)
awchBuf[i++] = L'x';
if (_dwOptimizeFlags & eOptRecall)
awchBuf[i++] = L'r';
if ( !(_dwOptimizeFlags & eOptHitCount) )
awchBuf[i++] = L'h';
awchBuf[i] = L'\0';
AddURLTerm( vString, L"op=", awchBuf, _ulCodepage );
}
//
// The URL encoded string is assembled. Copy it into a BSTR for return.
//
BSTR bstr = SysAllocStringLen( vString.GetPointer(), vString.StrLen() );
if (0 == bstr)
THROW(CException( E_OUTOFMEMORY ) );
*pbstrQueryString = bstr;
}
CATCH (CException, e)
{
sc = GetOleError( e );
}
END_CATCH
if (FAILED(sc))
{
SetError( sc, OLESTR("QueryToURL") );
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CixssoQuery::SetQueryFromURL - public
//
// Synopsis: Parse a URL QueryString and update object state accordingly.
//
// Arguments: [bstrQueryString] - The input URL-encoded query string
//
// History: 20 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CixssoQuery::SetQueryFromURL(BSTR bstrQueryString)
{
_err.Reset();
SCODE sc = S_OK;
TRY {
CQueryInfo Info;
ixssoDebugOut(( DEB_ITRACE, "QUERY_STRING = %ws\n", bstrQueryString ));
//
// Parse the string, which has the following format:
//
//
// tag1=Value1&tag2=value2&tag3=value+%7c+0&foo&bar
//
unsigned cchBuffer = SysStringLen(bstrQueryString);
WCHAR * pwszToken = (WCHAR *)bstrQueryString;
while ( pwszToken && (L'\0' != *pwszToken) )
{
//
// Find the value on the right hand side of the equal sign.
//
WCHAR *pwszTag = pwszToken;
WCHAR *pwszValue = wcschr( pwszTag, L'=' );
if ( 0 != pwszValue )
{
unsigned cchTag = CiPtrToUint( pwszValue - pwszTag );
pwszValue++;
//
// Point to the next Tag.
//
pwszToken = wcschr( pwszToken, L'&' );
ULONG cchValue;
if ( 0 != pwszToken )
{
if ( pwszToken < pwszValue )
{
//
// We have a construction like foo&bar=value. Set
// the tag with a null value and go on to the next
// tag=value pair.
//
cchValue = 0;
}
else
cchValue = CiPtrToUlong( pwszToken - pwszValue );
pwszToken++;
}
else
{
cchValue = CiPtrToUlong( (WCHAR *)&bstrQueryString[cchBuffer] - pwszValue );
}
if ( 0 == cchValue )
{
ixssoDebugOut(( DEB_ITRACE,
"SetQueryFromURL - setting %.*ws=NULL\n",
cchTag, pwszTag ));
XPtrST<WCHAR> xpValue( 0 );
Info.SetQueryParameter( pwszTag, xpValue );
}
else
{
XGrowable<BYTE> achBuf( cchValue );
for ( unsigned i=0; i<cchValue; i++ )
{
Win4Assert( pwszValue[i] < 0x100 );
achBuf[i] = (BYTE) pwszValue[i];
}
XPtrST<WCHAR> xpwchValue( new WCHAR[cchValue+1] );
DecodeURLEscapes( achBuf.Get(),
cchValue,
xpwchValue.GetPointer(),
_ulCodepage );
ixssoDebugOut(( DEB_ITRACE,
"SetQueryFromURL - setting %.*ws=%ws\n",
cchTag, pwszTag,
xpwchValue.GetPointer() ));
Info.SetQueryParameter( pwszTag, xpwchValue );
}
}
else if ( 0 != pwszToken )
{
//
// There was no tag=value pair found; a lonely '&' was
// found. Skip it and proceed to the next '&'.
//
pwszToken = wcschr( pwszToken+1, L'&' );
}
}
Info.MakeFinalQueryString();
if (Info.GetQuery())
{
delete _pwszRestriction;
_pwszRestriction = Info.AcquireQuery();
}
if (Info.GetCatalog())
{
delete _pwszCatalog;
_pwszCatalog = Info.AcquireCatalog();
}
if ( Info.GetDialect() )
{
delete _pwszDialect;
_pwszDialect = Info.AcquireDialect();
}
if (Info.GetSort())
{
delete _pwszSort;
_pwszSort = Info.AcquireSort();
}
if (Info.GetGroup())
{
delete _pwszGroup;
_pwszGroup = Info.AcquireGroup();
}
if (Info.GetMaxHits())
{
_maxResults = Info.GetMaxHits();
}
if (Info.GetFirstRows())
{
_cFirstRows = Info.GetFirstRows();
}
if (Info.GetStartHit().Count())
{
unsigned cHits = Info.GetStartHit().Count();
SCODE sc;
SAFEARRAY* psa;
XSafeArray xsa;
psa = SafeArrayCreateVector(VT_I4, 1, cHits);
if( ! psa )
THROW(CException( E_OUTOFMEMORY ));
xsa.Set(psa);
for (unsigned i=1; i<=cHits; i++)
{
long rgIx[1];
LONG lVal = Info.GetStartHit().Get(i-1);
rgIx[0] = (long)i;
sc = SafeArrayPutElement( xsa.Get(), rgIx, &lVal );
if ( FAILED( sc ) )
THROW( CException( sc ) );
}
_StartHit.Destroy();
_StartHit.Set( xsa.Acquire() );
}
if (Info.WasAllowEnumSet())
{
_fAllowEnumeration = Info.GetAllowEnum();
}
if (eOptHitCount != Info.GetOptimizeFor())
{
_dwOptimizeFlags = Info.GetOptimizeFor();
}
}
CATCH( CIxssoException, e )
{
sc = e.GetErrorCode();
Win4Assert( !SUCCEEDED(sc) );
SetError( sc, OLESTR("SetqueryFromURL"), eIxssoError );
}
AND_CATCH( CException, e )
{
sc = GetOleError( e );
SetError( sc, OLESTR("SetQueryFromURL") );
}
END_CATCH
return sc;
}
//-----------------------------------------------------------------------------
// CQueryInfo Methods
//-----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Function: EncodeTagString - inline
//
// Synopsis: Encode a one or two character tag into a DWORD value
//
// Arguments: [pwszTag] - a pointer to the tag
// [dwCodedTag] - the coded value which is returned
// [iParam] - the numeric value for the tag
//
// Notes: Tags consisting of one alpha character, two alpha characters
// or one alpha followed by a numeric character are recognized
// and converted into a DWORD (whose value just happens to be
// the same as a one or two character character constant for the
// alpha characters in the tag). If the third form is recognized,
// the iParam parameter gets the value of the numeric character,
// otherwise iParam is zero.
//
// dwCodedTag will be zero if pwszTag is not one of the allowed
// forms.
//
// History: 19 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
inline void EncodeTagString( WCHAR const * pwszTag,
DWORD & dwCodedTag,
USHORT & iParam )
{
dwCodedTag = 0;
iParam = 0;
if (0 == pwszTag || L'\0' == *pwszTag)
return;
if (isalpha(*pwszTag))
{
dwCodedTag = towupper(*pwszTag) & 0xFF;
if (isalpha(pwszTag[1]))
{
dwCodedTag <<= 8;
dwCodedTag |= (towupper(pwszTag[1]) & 0xFF);
}
else if (isdigit(pwszTag[1]))
iParam = pwszTag[1] - L'0';
else if (L'=' == pwszTag[1] ||
L'&' == pwszTag[1] ||
L'\0' == pwszTag[1])
return;
else
{
dwCodedTag = 0;
return;
}
if ( L'=' != pwszTag[2] &&
L'&' != pwszTag[2] &&
L'\0' != pwszTag[2])
dwCodedTag = 0;
}
return;
}
//+---------------------------------------------------------------------------
//
// Member: CQueryInfo::SetQueryParameter - public
//
// Synopsis: Process a QueryString parameter
//
// Arguments: [pwszTag] - the tag name for the parameter
// [pwszValue] - the value for the parameter
//
// History: 19 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
void CQueryInfo::SetQueryParameter( WCHAR const * pwszTag,
XPtrST<WCHAR> & pwszValue )
{
DWORD dwParamCode;
USHORT iParam;
EncodeTagString( pwszTag, dwParamCode, iParam );
if (0 == dwParamCode)
return;
for (unsigned i=0; i<cQueryTagTable; i++)
if (dwParamCode == aQueryTagTable[i].dwTagName)
break;
if (i == cQueryTagTable)
return;
i = aQueryTagTable[i].qtQueryTagType;
switch (i)
{
case qtQueryFullText:
AddToParam( _xpQuery, pwszValue );
break;
case qtMaxHits:
{
LONG cNum = 0;
if (0 != pwszValue.GetPointer())
cNum = _wtoi( pwszValue.GetPointer() );
if (cNum > 0)
{
_maxHits = cNum;
}
else
{
ixssoDebugOut(( DEB_TRACE,
"CIxsQueryInfo::SetQueryParameter - invalid numeric %ws\n",
pwszValue.GetPointer() ));
}
}
break;
case qtFirstRows:
{
LONG cNum = 0;
if (0 != pwszValue.GetPointer())
cNum = _wtoi( pwszValue.GetPointer() );
if (cNum > 0)
{
_cFirstRows = cNum;
}
else
{
ixssoDebugOut(( DEB_TRACE,
"CIxsQueryInfo::SetQueryParameter - invalid numeric %ws\n",
pwszValue.GetPointer() ));
}
}
break;
case qtStartHit:
ParseNumberVectorString( pwszValue.GetPointer(), GetStartHit() );
break;
case qtCatalog:
AddToParam( _xpCatalog, pwszValue );
break;
case qtDialect:
AddToParam( _xpDialect, pwszValue );
break;
case qtSort:
AddToParam( _xpSort, pwszValue );
break;
case qtSortDown:
if (pwszValue.GetPointer())
AddToParam( _xpSort, pwszValue, L",", L"[d]" );
break;
#if IXSSO_CATEGORIZE == 1
case qtGroup:
AddToParam( _xpGroup, pwszValue );
break;
case qtGroupDown:
if (pwszValue.GetPointer())
AddToParam( _xpGroup, pwszValue, L",", L"[d]" );
break;
#endif // IXSSO_CATEGORIZE == 1
case qtAllowEnumeration:
_fAllowEnumeration = 0 != pwszValue.GetPointer() &&
iswdigit(*pwszValue.GetPointer()) &&
*pwszValue.GetPointer() != L'0';
_fSetAllowEnumeration = 1;
break;
case qtOptimizeFor:
{
WCHAR * pwszVal = pwszValue.GetPointer();
while (pwszVal && *pwszVal)
{
WCHAR chKey = towupper(*pwszVal);
if (chKey == L'X')
{
_dwOptimizeFor &= ~eOptRecall;
_dwOptimizeFor |= eOptPerformance;
}
else if (chKey == L'R')
{
_dwOptimizeFor &= ~eOptPerformance;
_dwOptimizeFor |= eOptRecall;
}
else if (chKey == L'H')
{
_dwOptimizeFor &= ~eOptHitCount;
}
// else if (chKey == L'P')
// _dwOptimizeFor |= eOptPrecision;
pwszVal++;
}
break;
}
case qtColumn:
Win4Assert( iParam >= 0 && iParam < 10 );
SetBuiltupQueryTerm( _aQueryCol, iParam, pwszValue );
break;
case qtOperator:
Win4Assert( iParam >= 0 && iParam < 10 );
SetBuiltupQueryTerm( _aQueryOp, iParam, pwszValue );
break;
case qtQuery:
Win4Assert( iParam >= 0 && iParam < 10 );
SetBuiltupQueryTerm( _aQueryVal, iParam, pwszValue );
break;
default:
ixssoDebugOut(( DEB_WARN, "SetQueryFromURL - reserved tag %.2ws\n", pwszTag ));
THROW( CIxssoException(MSG_IXSSO_INVALID_QUERYSTRING_TAG, 0) );
break;
}
return;
}
//+---------------------------------------------------------------------------
//
// Member: CQueryInfo::AddToParam - private
//
// Synopsis: Append a string to a parameter
//
// Arguments: [xpString] - A smart pointer to the string to be appended to
// [pwszValue] - The value to be added to xpString
// [pwszPre] - the separator for multiple values in xpString.
// Defaults to ','.
// [pwszPost] - unconditionally appended to pwszValue
//
// History: 19 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
void CQueryInfo::AddToParam( XPtrST<WCHAR> & xpString,
XPtrST<WCHAR> & pwszValue,
WCHAR const * pwszPre,
WCHAR const * pwszPost )
{
unsigned cch = 0;
if (0 == xpString.GetPointer())
{
if (0 == pwszPost)
{
xpString.Set( pwszValue.Acquire() );
}
else
{
if (pwszValue.GetPointer())
cch = wcslen(pwszValue.GetPointer());
xpString.Set( new WCHAR[cch + wcslen(pwszPost) + 1] );
if (cch)
wcsncpy(xpString.GetPointer(), pwszValue.GetPointer(), cch);
wcscpy(xpString.GetPointer() + cch, pwszPost);
}
return;
}
cch = wcslen(xpString.GetPointer());
cch += pwszPre ? wcslen(pwszPre) : wcslen(L",");
if (pwszValue.GetPointer())
cch += wcslen( pwszValue.GetPointer() );
if (pwszPost)
cch += wcslen( pwszPost );
XPtrST<WCHAR> xpDest( new WCHAR[cch+1] );
wcscpy(xpDest.GetPointer(), xpString.GetPointer());
wcscat(xpDest.GetPointer(), pwszPre ? pwszPre : L",");
if (pwszValue.GetPointer())
wcscat(xpDest.GetPointer(), pwszValue.GetPointer());
if (pwszPost)
wcscat(xpDest.GetPointer(), pwszPost);
xpString.Free();
xpString.Set( xpDest.Acquire() );
}
//+---------------------------------------------------------------------------
//
// Member: CQueryInfo::SetBuiltupQueryTerm - private
//
// Synopsis: Add an individual partial query term to an array of terms.
//
// Arguments: [apString] - A dynamic array of string pointers
// [iTerm] - The index of the term to be added
// [pwszValue] - The value to be added to apString
//
// Notes: If the array entry for the term is already set, it is
// overwritten.
//
// History: 21 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
void CQueryInfo::SetBuiltupQueryTerm( CDynArray<WCHAR> & apString,
unsigned iTerm,
XPtrST<WCHAR> & pwszValue )
{
Win4Assert( iTerm < 10 );
delete apString.Acquire(iTerm);
apString.Add( pwszValue.GetPointer(), iTerm );
pwszValue.Acquire();
}
//+---------------------------------------------------------------------------
//
// Member: CQueryInfo::MakeFinalQueryString - public
//
// Synopsis: Combine the built-up query terms into the complete query
// restriction.
//
// Arguments: - NONE -
//
// History: 20 Mar 1997 Alanw Created
//
//----------------------------------------------------------------------------
void CQueryInfo::MakeFinalQueryString( )
{
//
// Add query terms to any pre-existing full query string
//
for (unsigned i = 0; i < 10; i++)
{
// Ignore the term if the qn= part was not set.
if ( _aQueryVal[i] != 0 )
{
XPtrST<WCHAR> xpStr(0);
AddToParam( _xpQuery, xpStr, IMPLIED_QUERY_TERM_OPERATOR, L" ( ");
if ( _aQueryCol[i] != 0 )
{
xpStr.Set( _aQueryCol.Acquire(i) );
AddToParam( _xpQuery, xpStr, L"", L" ");
xpStr.Free();
}
if ( _aQueryOp[i] != 0 )
{
xpStr.Set( _aQueryOp.Acquire(i) );
AddToParam( _xpQuery, xpStr, L"", L" ");
xpStr.Free();
}
if ( _aQueryVal[i] != 0 )
{
xpStr.Set( _aQueryVal.Acquire(i) );
AddToParam( _xpQuery, xpStr, L"", L" ");
xpStr.Free();
}
AddToParam( _xpQuery, xpStr, L")");
}
}
}