//+--------------------------------------------------------------------------- // // 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 #include #include //----------------------------------------------------------------------------- // 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 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 xpValue( 0 ); Info.SetQueryParameter( pwszTag, xpValue ); } else { XGrowable achBuf( cchValue ); for ( unsigned i=0; i 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 & pwszValue ) { DWORD dwParamCode; USHORT iParam; EncodeTagString( pwszTag, dwParamCode, iParam ); if (0 == dwParamCode) return; for (unsigned i=0; i 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 & xpString, XPtrST & 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 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 & apString, unsigned iTerm, XPtrST & 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 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")"); } } }