//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-2000. // // File: idq.cxx // // Contents: Parser for an IDQ file // // History: 96/Jan/3 DwightKr Created // //---------------------------------------------------------------------------- #include #pragma hdrstop // // These hash values MUST be unique. They have been calculated to be // unique via the ISAPI_IDQHash function below. // // If the spelling of a IDQ variable name is changed, or a new variable // is added to the list, this table must be re-generated using the // code supplied below. // static const ULONG ISAPI_CIBOOLVECTORPREFIX_HASH = 0x1174d5c; static const ULONG ISAPI_CIBOOLVECTORSEPARATOR_HASH = 0x8ba6b1d; static const ULONG ISAPI_CIBOOLVECTORSUFFIX_HASH = 0x1174df4; static const ULONG ISAPI_CICATALOG_HASH = 0x89c6; static const ULONG ISAPI_CICOLUMNS_HASH = 0x8bb4; static const ULONG ISAPI_CICURRENCYVECTORPREFIX_HASH = 0x119add60; static const ULONG ISAPI_CICURRENCYVECTORSEPARATOR_HASH = 0x8cd6eb21; static const ULONG ISAPI_CICURRENCYVECTORSUFFIX_HASH = 0x119addf8; static const ULONG ISAPI_CICURRENTPAGENUMBER_HASH = 0x233792f; static const ULONG ISAPI_CICURRENTRECORDNUMBER_HASH = 0x8ce0671; static const ULONG ISAPI_CIDATEVECTORPREFIX_HASH = 0x114fd5c; static const ULONG ISAPI_CIDATEVECTORSEPARATOR_HASH = 0x8a7eb1d; static const ULONG ISAPI_CIDATEVECTORSUFFIX_HASH = 0x114fdf4; static const ULONG ISAPI_CIFORCEUSECI_HASH = 0x46337; static const ULONG ISAPI_CIDEFERTRIMMING_HASH = 0x8a26e6f8; static const ULONG ISAPI_CIDIALECT_HASH = 0x8a07; static const ULONG ISAPI_CIFLAGS_HASH = 0x228c; static const ULONG ISAPI_CILOCALE_HASH = 0x4631; static const ULONG ISAPI_CIMATCHEDRECORDCOUNT_HASH = 0x4639280; static const ULONG ISAPI_CIMAXRECORDSINRESULTSET_HASH = 0x2349b581; static const ULONG ISAPI_CIMAXRECORDSPERPAGE_HASH = 0x2349baa; static const ULONG ISAPI_CIFIRSTROWSINRESULTSET_HASH = 0x118dc580; static const ULONG ISAPI_CINUMBERVECTORPREFIX_HASH = 0x476ad5e; static const ULONG ISAPI_CINUMBERVECTORSEPARATOR_HASH = 0x23b56b1f; static const ULONG ISAPI_CINUMBERVECTORSUFFIX_HASH = 0x476adf6; static const ULONG ISAPI_CIRESTRICTION_HASH = 0x8ed8d; static const ULONG ISAPI_CISCOPE_HASH = 0x2350; static const ULONG ISAPI_CISORT_HASH = 0x11c2; static const ULONG ISAPI_CISTRINGVECTORPREFIX_HASH = 0x4845d5e; static const ULONG ISAPI_CISTRINGVECTORSEPARATOR_HASH = 0x2422eb1f; static const ULONG ISAPI_CISTRINGVECTORSUFFIX_HASH = 0x4845df6; static const ULONG ISAPI_CITEMPLATE_HASH = 0x11d3b; static const ULONG ISAPI_CICANONICALOUTPUT_HASH = 0x8a0c9f; static const ULONG ISAPI_CIDONTTIMEOUT_HASH = 0x8c55f; #if 0 // // Use the following routine to verify the above hash values are perfect. // //+--------------------------------------------------------------------------- // // Function: main - program entry point; used to verify perfect hash // //---------------------------------------------------------------------------- int __cdecl main( int argc, char ** argv ) { ULONG aHash[100]; Win4Assert( 100 > cISAPI_CiParams ); for (unsigned i=0; i xMapView; TRY { xMapView.Set( new CFileMapView( _wcsIDQFileName ) ); xMapView->Init(); } CATCH( CException, e ) { if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == e.GetErrorCode() ) { THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) ); } else { RETHROW(); } } END_CATCH CFileBuffer idqFile( xMapView.GetReference(), _codePage ); // // Save the last write time of this file. // SCODE sc = GetLastWriteTime( _wcsIDQFileName, _ftIDQLastWriteTime ); if ( FAILED( sc ) ) THROW( CException( sc ) ); // // Process a line at a time, look for either the [Names] or the [Query] // section and process lines within those sections. // BOOL fQuerySection = FALSE; BOOL fNamesSection = FALSE; int iLine = 0; // Start counting at line #1 for( ;; ) { iLine++; XGrowable xLine; ULONG cwcChar = idqFile.fgetsw( xLine ); if ( 0 == cwcChar ) { break; } WCHAR *pwcLine = xLine.Get(); // // Skip ahead until we find a [Query] section // if ( L'[' == *pwcLine ) { if (_wcsnicmp(pwcLine+1, L"Query]", 6) == 0 ) { fQuerySection = TRUE; continue; } else if (_wcsnicmp(pwcLine+1, L"Names]", 6) == 0 ) { fNamesSection = TRUE; continue; } else { fQuerySection = fNamesSection = FALSE; continue; } } else if ( L'#' == *pwcLine ) { continue; } if ( fQuerySection ) { CQueryScanner scanner( pwcLine, FALSE ); ParseOneLine( scanner, iLine ); } else if (fNamesSection) { XPtr propentry; CQueryScanner scanner( pwcLine, FALSE ); CPropertyList::ParseOneLine(scanner, iLine, propentry); if (propentry.GetPointer()) { _xList->AddEntry( propentry.GetPointer(), iLine ); propentry.Acquire(); } } } // // Verify that the minimum set of parameters are specified. // // // We must have all of the following: // // - a restriction // - a scope // - a template (HTX) file // - output columns // if ( 0 == _wcsRestriction ) { // Report an error ciGibDebugOut(( DEB_IERROR, "Restriction not found in IDQ file\n" )); THROW( CIDQException(MSG_CI_IDQ_MISSING_RESTRICTION, 0) ); } else if ( 0 == _wcsScope ) { // Report an error ciGibDebugOut(( DEB_IERROR, "Scope not found in IDQ file\n" )); THROW( CIDQException(MSG_CI_IDQ_MISSING_SCOPE, 0) ); } else if ( 0 == _wcsHTXFileName && !IsCanonicalOutput() ) { // Report an error ciGibDebugOut(( DEB_IERROR, "HTX filename not found in IDQ file\n" )); THROW( CIDQException(MSG_CI_IDQ_MISSING_TEMPLATEFILE, 0) ); } else if ( 0 == _wcsColumns ) { // Report an error ciGibDebugOut(( DEB_IERROR, "Output columns not found in IDQ file\n" )); THROW( CIDQException(MSG_CI_IDQ_MISSING_OUTPUTCOLUMNS, 0) ); } // // If no catalog was specified, use the default catalog in the registry // if ( 0 == _wcsCatalog ) { ciGibDebugOut(( DEB_ITRACE, "Using default catalog\n" )); WCHAR awcTmp[ MAX_PATH ]; ULONG cwcRequired = TheIDQRegParams.GetISDefaultCatalog( awcTmp, MAX_PATH ); if ( cwcRequired > MAX_PATH ) THROW( CException(STATUS_INVALID_PARAMETER) ); cwcRequired++; // make room for termination _wcsCatalog = new WCHAR[ cwcRequired ]; RtlCopyMemory( _wcsCatalog, awcTmp, cwcRequired * sizeof WCHAR ); } } //+--------------------------------------------------------------------------- // // Member: CIDQFile::ParseOneLine, private // // Synopsis: Parses one line of the IDQ file // // Arguments: [scan] -- scanner initialized with the current line // [iLine] -- current line number // // History: 96/Jan/03 DwightKr created // //---------------------------------------------------------------------------- void CIDQFile::ParseOneLine( CQueryScanner & scan, unsigned iLine ) { // // Is this a comment line (does it start with #) or an empty line? // if ( scan.LookAhead() == PROP_REGEX_TOKEN || scan.LookAhead() == EOS_TOKEN ) { return; } if ( scan.LookAhead() != TEXT_TOKEN ) // Better be a word { // Report an error THROW( CIDQException( MSG_CI_IDQ_EXPECTING_NAME, iLine ) ); } XPtrST wcsAttribute( scan.AcqWord() ); if( wcsAttribute.GetPointer() == 0 ) // Better find a word { THROW( CIDQException( MSG_CI_IDQ_EXPECTING_TYPE, iLine ) ); } scan.Accept(); if ( scan.LookAhead() != EQUAL_TOKEN ) { // Report an error THROW( CIDQException( MSG_CI_IDQ_EXPECTING_EQUAL, iLine ) ); } scan.Accept(); // // Convert the string to upper-case and HASH it. Lookup the hashed value. // Note that this code assumes the HASH IS PERFECT. Whenever a IDQ // variable is renamed or added, this assumption may no-longer be true. // Check it out with the above program. // // This code essentially replaces 25 wcsicmp functions; or an average // of 12.5 wscicmp calls per line in the IDQ file. // Win4Assert( ISAPI_CICOLUMNS_HASH == ISAPI_IDQHash(ISAPI_CI_COLUMNS) ); Win4Assert( ISAPI_CIFLAGS_HASH == ISAPI_IDQHash(ISAPI_CI_FLAGS) ); Win4Assert( ISAPI_CIMAXRECORDSINRESULTSET_HASH == ISAPI_IDQHash(ISAPI_CI_MAX_RECORDS_IN_RESULTSET) ); Win4Assert( ISAPI_CIMAXRECORDSPERPAGE_HASH == ISAPI_IDQHash(ISAPI_CI_MAX_RECORDS_PER_PAGE) ); Win4Assert( ISAPI_CIFIRSTROWSINRESULTSET_HASH == ISAPI_IDQHash(ISAPI_CI_FIRST_ROWS_IN_RESULTSET) ); Win4Assert( ISAPI_CIRESTRICTION_HASH == ISAPI_IDQHash(ISAPI_CI_RESTRICTION) ); Win4Assert( ISAPI_CIDIALECT_HASH == ISAPI_IDQHash(ISAPI_CI_DIALECT) ); Win4Assert( ISAPI_CISCOPE_HASH == ISAPI_IDQHash(ISAPI_CI_SCOPE) ); Win4Assert( ISAPI_CISORT_HASH == ISAPI_IDQHash(ISAPI_CI_SORT) ); Win4Assert( ISAPI_CITEMPLATE_HASH == ISAPI_IDQHash(ISAPI_CI_TEMPLATE) ); Win4Assert( ISAPI_CICATALOG_HASH == ISAPI_IDQHash(ISAPI_CI_CATALOG) ); Win4Assert( ISAPI_CILOCALE_HASH == ISAPI_IDQHash(ISAPI_CI_LOCALE) ); Win4Assert( ISAPI_CIBOOLVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_PREFIX) ); Win4Assert( ISAPI_CIBOOLVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_SEPARATOR) ); Win4Assert( ISAPI_CIBOOLVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_SUFFIX) ); Win4Assert( ISAPI_CICURRENCYVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_PREFIX) ); Win4Assert( ISAPI_CICURRENCYVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_SEPARATOR) ); Win4Assert( ISAPI_CICURRENCYVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_SUFFIX) ); Win4Assert( ISAPI_CIDATEVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_PREFIX) ); Win4Assert( ISAPI_CIDATEVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_SEPARATOR) ); Win4Assert( ISAPI_CIDATEVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_SUFFIX) ); Win4Assert( ISAPI_CINUMBERVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_PREFIX) ); Win4Assert( ISAPI_CINUMBERVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_SEPARATOR) ); Win4Assert( ISAPI_CINUMBERVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_SUFFIX) ); Win4Assert( ISAPI_CISTRINGVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_PREFIX) ); Win4Assert( ISAPI_CISTRINGVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_SEPARATOR) ); Win4Assert( ISAPI_CISTRINGVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_SUFFIX) ); Win4Assert( ISAPI_CIFORCEUSECI_HASH == ISAPI_IDQHash(ISAPI_CI_FORCE_USE_CI) ); Win4Assert( ISAPI_CIDEFERTRIMMING_HASH == ISAPI_IDQHash(ISAPI_CI_DEFER_NONINDEXED_TRIMMING ) ); Win4Assert( ISAPI_CICANONICALOUTPUT_HASH == ISAPI_IDQHash(ISAPI_CI_CANONICAL_OUTPUT ) ); Win4Assert( ISAPI_CIDONTTIMEOUT_HASH == ISAPI_IDQHash(ISAPI_CI_DONT_TIMEOUT ) ); _wcsupr( wcsAttribute.GetPointer() ); ULONG ulHash = ISAPI_IDQHash( wcsAttribute.GetPointer() ); switch ( ulHash ) { case ISAPI_CICOLUMNS_HASH: GetStringValue( scan, iLine, &_wcsColumns ); break; case ISAPI_CIFLAGS_HASH: GetStringValue( scan, iLine, &_wcsCiFlags ); break; case ISAPI_CIMAXRECORDSINRESULTSET_HASH: GetStringValue( scan, iLine, &_wcsMaxRecordsInResultSet ); break; case ISAPI_CIMAXRECORDSPERPAGE_HASH: GetStringValue( scan, iLine, &_wcsMaxRecordsPerPage ); break; case ISAPI_CIFIRSTROWSINRESULTSET_HASH: GetStringValue( scan, iLine, &_wcsFirstRowsInResultSet ); break; case ISAPI_CIRESTRICTION_HASH: GetStringValue( scan, iLine, &_wcsRestriction ); break; case ISAPI_CIDIALECT_HASH: GetStringValue( scan, iLine, &_wcsDialect ); break; case ISAPI_CISCOPE_HASH: GetStringValue( scan, iLine, &_wcsScope, FALSE ); break; case ISAPI_CISORT_HASH: GetStringValue( scan, iLine, &_wcsSort ); break; case ISAPI_CITEMPLATE_HASH: GetStringValue( scan, iLine, &_wcsHTXFileName ); break; case ISAPI_CICATALOG_HASH: GetStringValue( scan, iLine, &_wcsCatalog ); break; case ISAPI_CIBOOLVECTORPREFIX_HASH: GetStringValue( scan, iLine, &_wcsBoolVectorPrefix ); break; case ISAPI_CIBOOLVECTORSEPARATOR_HASH: GetStringValue( scan, iLine, &_wcsBoolVectorSeparator ); break; case ISAPI_CIBOOLVECTORSUFFIX_HASH: GetStringValue( scan, iLine, &_wcsBoolVectorSuffix ); break; case ISAPI_CICURRENCYVECTORPREFIX_HASH: GetStringValue( scan, iLine, &_wcsCurrencyVectorPrefix ); break; case ISAPI_CICURRENCYVECTORSEPARATOR_HASH: GetStringValue( scan, iLine, &_wcsCurrencyVectorSeparator ); break; case ISAPI_CICURRENCYVECTORSUFFIX_HASH: GetStringValue( scan, iLine, &_wcsCurrencyVectorSuffix ); break; case ISAPI_CIDATEVECTORPREFIX_HASH: GetStringValue( scan, iLine, &_wcsDateVectorPrefix ); break; case ISAPI_CIDATEVECTORSEPARATOR_HASH: GetStringValue( scan, iLine, &_wcsDateVectorSeparator ); break; case ISAPI_CIDATEVECTORSUFFIX_HASH: GetStringValue( scan, iLine, &_wcsDateVectorSuffix ); break; case ISAPI_CINUMBERVECTORPREFIX_HASH: GetStringValue( scan, iLine, &_wcsNumberVectorPrefix ); break; case ISAPI_CINUMBERVECTORSEPARATOR_HASH: GetStringValue( scan, iLine, &_wcsNumberVectorSeparator ); break; case ISAPI_CINUMBERVECTORSUFFIX_HASH: GetStringValue( scan, iLine, &_wcsNumberVectorSuffix ); break; case ISAPI_CISTRINGVECTORPREFIX_HASH: GetStringValue( scan, iLine, &_wcsStringVectorPrefix ); break; case ISAPI_CISTRINGVECTORSEPARATOR_HASH: GetStringValue( scan, iLine, &_wcsStringVectorSeparator ); break; case ISAPI_CISTRINGVECTORSUFFIX_HASH: GetStringValue( scan, iLine, &_wcsStringVectorSuffix ); break; case ISAPI_CIFORCEUSECI_HASH: GetStringValue( scan, iLine, &_wcsForceUseCi ); break; case ISAPI_CIDEFERTRIMMING_HASH: GetStringValue( scan, iLine, &_wcsDeferTrimming ); break; case ISAPI_CILOCALE_HASH: GetStringValue( scan, iLine, &_wcsLocale ); break; case ISAPI_CICANONICALOUTPUT_HASH: GetStringValue( scan, iLine, &_wcsCanonicalOutput ); break; case ISAPI_CIDONTTIMEOUT_HASH: GetStringValue( scan, iLine, &_wcsDontTimeout ); break; default: // // We've found a keyword/attribute that we don't support. // Don't report an error. This will allow this version of the // parser to work with newer .IDQ file versions with new parameters. // ciGibDebugOut(( DEB_ERROR, "Invalid string in hash table for %ws; hash = 0x%x\n", wcsAttribute.GetPointer(), ulHash )); break; } } //+--------------------------------------------------------------------------- // // Member: CIDQFile::ParseColumns, public // // Synopsis: Parses the columns attribute // // Arguments: [wcsColumns] -- string to convert // [variableSet] -- list of replaceable parameters // [varColumns] -- Column variables returned here // // Returns: CDbColumns* - counted array of column IDs // // History: 96/Jan/03 DwightKr created // 96/Feb/23 DwightKr Add check for duplicate value // 96/Mar/12 DwightKr Made public // 96/May/23 AlanW Detect duplicate column names // //---------------------------------------------------------------------------- CDbColumns * CIDQFile::ParseColumns( WCHAR const * wcsColumns, CVariableSet & variableSet, CDynArray & awcsColumns ) { return ::ParseStringColumns( wcsColumns, _xList.GetPointer(), GetUserDefaultLCID(), &variableSet, &awcsColumns ); } //+--------------------------------------------------------------------------- // // Member: CIDQFile::ParseFlags, private // // Synopsis: Parses the flags attribute // // Arguments: [wcsCiFlags] -- flags // // History: 96/Jan/03 DwightKr created // 96/Apr/12 DwightKr mad a replaceable parameter // //---------------------------------------------------------------------------- ULONG CIDQFile::ParseFlags( WCHAR const * wcsCiFlags ) { if ( 0 == wcsCiFlags ) { return QUERY_DEEP; } ULONG ulFlags; if ( _wcsicmp(wcsCiFlags, L"SHALLOW") == 0 ) { ulFlags = QUERY_SHALLOW; } else if ( _wcsicmp(wcsCiFlags, L"DEEP") == 0 ) { ulFlags = QUERY_DEEP; } else { THROW( CIDQException(MSG_CI_IDQ_EXPECTING_SHALLOWDEEP, 0) ); } return ulFlags; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::IsCanonicalOutput // // Synopsis: Tests if canonical output is enabled. // // Returns: TRUE if canonical output is needed; FALSE o/w // // History: 6-14-96 srikants Created // // Notes: Assumed here that it is not a replaceable parameter. // //---------------------------------------------------------------------------- BOOL CIDQFile::IsCanonicalOutput() const { if ( 0 == _wcsCanonicalOutput ) return FALSE; return _wcsicmp(_wcsCanonicalOutput, L"TRUE") == 0; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::IsDontTimeout // // Synopsis: Specifies if the don't timeout parameter is true // // History: 9-13-96 srikants Created // //---------------------------------------------------------------------------- BOOL CIDQFile::IsDontTimeout() const { if ( 0 == _wcsDontTimeout ) return FALSE; return _wcsicmp(_wcsDontTimeout, L"TRUE") == 0; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::GetStringValue - private // // Synopsis: Gets the string value on the currenct line // // Arguments: [scan] -- scanner initialized with the current line // [iLine] -- current line number // [pwcsStringValue] -- value to put string into // [fParseQuotes] -- if TRUE, remove first and trailing quotes // // History: 96/Jan/03 DwightKr created // 96/Feb/23 DwightKr Add check for duplicate value // //---------------------------------------------------------------------------- void CIDQFile::GetStringValue( CQueryScanner & scan, unsigned iLine, WCHAR ** pwcsStringValue, BOOL fParseQuotes ) { if ( 0 != *pwcsStringValue ) { ciGibDebugOut(( DEB_IWARN, "Duplicate CiXX=value in IDQ file on line #%d\n", iLine )); THROW( CIDQException(MSG_CI_IDQ_DUPLICATE_ENTRY, iLine) ); } *pwcsStringValue = scan.AcqLine( fParseQuotes ); if ( IsAReplaceableParameter( *pwcsStringValue ) != eIsSimpleString ) { _cReplaceableParameters++; } } //+--------------------------------------------------------------------------- // // Member: CIDQFile::IsCachedDataValid - public // // Synopsis: Determines if the IDQ file is still vaid, or has it // changed since it was last read. // // History: 96/Jan/03 DwightKr created // //---------------------------------------------------------------------------- BOOL CIDQFile::IsCachedDataValid() { FILETIME ft; SCODE sc = GetLastWriteTime( _wcsIDQFileName, ft ); // this usually fails because the file no longer exists if ( FAILED( sc ) ) return FALSE; return ( (_ftIDQLastWriteTime.dwLowDateTime == ft.dwLowDateTime) && (_ftIDQLastWriteTime.dwHighDateTime == ft.dwHighDateTime) ); } //+--------------------------------------------------------------------------- // // Function: GetLastWriteTime // // Purpose: Gets the last change time of the file specified // // Arguments: [wcsFileName] - name of file to get last write time of // [filetime] - where the filetime is returned // // Returns: SCODE result // // History: 96/Jan/23 DwightKr Created // 96/Mar/13 DwightKr Changed to use GetFileAttributesEx() // //---------------------------------------------------------------------------- SCODE GetLastWriteTime( WCHAR const * wcsFileName, FILETIME & filetime ) { Win4Assert( 0 != wcsFileName ); // CImpersonateRemoteAccess imprsnat; // imprsnat.ImpersonateIf( wcsFileName ); WIN32_FIND_DATA ffData; if ( !GetFileAttributesEx( wcsFileName, GetFileExInfoStandard, &ffData ) ) { ULONG error = GetLastError(); ciGibDebugOut(( DEB_IERROR, "Unable to GetFileAttributesEx(%ws) GetLastError=0x%x\n", wcsFileName, error )); return HRESULT_FROM_WIN32( error ); } filetime = ffData.ftLastWriteTime; return S_OK; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::ParseForceUseCI - public // // Synopsis: Gets the TRUE/FALSE value for CiForceUseCI // // Arguments: [wcsForceUseCi] -- string to parse // // History: 96/Mar/03 DwightKr created // //---------------------------------------------------------------------------- BOOL CIDQFile::ParseForceUseCI( WCHAR const * wcsForceUseCi ) { if ( 0 == wcsForceUseCi ) { return FALSE; } BOOL fForceUseCi; if ( _wcsicmp( wcsForceUseCi, L"FALSE" ) == 0 ) { fForceUseCi = FALSE; } else if ( _wcsicmp( wcsForceUseCi, L"TRUE" ) == 0 ) { fForceUseCi = TRUE; } else { THROW( CIDQException(MSG_CI_IDQ_EXPECTING_TRUEFALSE, 0) ); } return fForceUseCi; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::ParseDeferTrimming - public // // Synopsis: Gets the TRUE/FALSE value for CiDeferNonIndexedTrimming // // Arguments: [wcsDeferTrimming] -- string to parse // // History: 96/Mar/03 DwightKr created // //---------------------------------------------------------------------------- BOOL CIDQFile::ParseDeferTrimming( WCHAR const * wcsDeferTrimming ) { if ( 0 == wcsDeferTrimming ) { return FALSE; } BOOL fDeferTrimming; if ( _wcsicmp( wcsDeferTrimming, L"FALSE" ) == 0 ) { fDeferTrimming = FALSE; } else if ( _wcsicmp( wcsDeferTrimming, L"TRUE" ) == 0 ) { fDeferTrimming = TRUE; } else { THROW( CIDQException(MSG_CI_IDQ_EXPECTING_TRUEFALSE, 0) ); } return fDeferTrimming; } //+--------------------------------------------------------------------------- // // Member: CIDQFile::GetVectorFormatting, public // // Synopsis: Sets up the vector formatting for output // // Arguments: [outputFormat] -- the output format object to setup // // History: 96/Feb/26 DwightKr created // //---------------------------------------------------------------------------- void CIDQFile::GetVectorFormatting( COutputFormat & outputFormat ) { outputFormat.SetBoolVectorFormat( _wcsBoolVectorPrefix, _wcsBoolVectorSeparator, _wcsBoolVectorSuffix ); outputFormat.SetCurrencyVectorFormat( _wcsCurrencyVectorPrefix, _wcsCurrencyVectorSeparator, _wcsCurrencyVectorSuffix ); outputFormat.SetDateVectorFormat( _wcsDateVectorPrefix, _wcsDateVectorSeparator, _wcsDateVectorSuffix ); outputFormat.SetNumberVectorFormat( _wcsNumberVectorPrefix, _wcsNumberVectorSeparator, _wcsNumberVectorSuffix ); outputFormat.SetStringVectorFormat( _wcsStringVectorPrefix, _wcsStringVectorSeparator, _wcsStringVectorSuffix ); } //+--------------------------------------------------------------------------- // // Member: CIDQFileList::Find - public // // Synopsis: Finds a matching parsed IDQ file in list, or builds a new // one if a match can not be found. // // Arguments: [wcsFileName] -- full path to IDQ file // [codePage] -- code page of parsed IDQ file // // History: 96/Mar/27 DwightKr Created. // //---------------------------------------------------------------------------- CIDQFile * CIDQFileList::Find( WCHAR const * wcsFileName, UINT codePage, CSecurityIdentity const & securityIdentity ) { // // Refcount everything in the list so that we can examine the list // outside of the lock. // ULONG cItems; XArray aIDQFile; // ========================================== { CLock lock( _mutex ); cItems = _aIDQFile.Count(); // Save count of items to examine aIDQFile.Init( cItems ); for (unsigned i=0; iLokAddRef(); } } // ========================================== // Can't throw while the .idq files are addref'ed -- remember the // error and throw it after the .idq files are released. // IsCachedDataValid() throws! SCODE sc = S_OK; CIDQFile * pIDQFile = 0; TRY { // // Now walk though the list looking for a match; outside of the lock. // for (unsigned i=0; iGetIDQFileName(), wcsFileName) == 0) && (aIDQFile[i]->GetCodePage() == codePage) && (aIDQFile[i]->IsCachedDataValid() ) ) { pIDQFile = aIDQFile[i]; ciGibDebugOut(( DEB_ITRACE, "A cached version of IDQ file %ws was found\n", wcsFileName )); break; } } } CATCH( CException, e ) { sc = e.GetErrorCode(); } END_CATCH // // If pIDQFile is non-0, we've found a match. Decrement the ref-count // for all items which did not match. // for (unsigned i=0; iRelease(); } } if ( S_OK != sc ) { Win4Assert( 0 == pIDQFile ); THROW( CException( sc ) ); } // // We may have matched, but still not have access to this file. First, make // a quick check for an exact match on security token, and then try harder // by opening the file. // if ( 0 != pIDQFile ) { if ( !pIDQFile->CheckSecurity( securityIdentity ) ) { HANDLE h = CreateFile( wcsFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ); // // Don't try to determine here if security caused the problem. // Just let the standard exception handling below in file parsing // deal with the error. // if ( INVALID_HANDLE_VALUE == h ) { pIDQFile->Release(); pIDQFile = 0; } else { CloseHandle( h ); // // Update the security token of the cached Idq file, // to optimize away the CreateFile check in two cases: // 1. When the file is first parsed with admin // privileges, and all subsequent queries are with // anonymous privileges. // 2. When the security token changes over time // pIDQFile->SetSecurityToken( securityIdentity ); } } } // // If we didn't find a match, then open and parse a new IDQ file, and // add it to the list of parsed IDQ files // if ( 0 == pIDQFile ) { ciGibDebugOut(( DEB_ITRACE, "Adding IDQ file %ws to cache\n", wcsFileName )); pIDQFile = new CIDQFile(wcsFileName, codePage, securityIdentity); XPtr xIDQFile( pIDQFile ); pIDQFile->ParseFile(); { // ========================================== CLock lock( _mutex ); _aIDQFile.Add( pIDQFile, _aIDQFile.Count() ); pIDQFile->LokAddRef(); // ========================================== } xIDQFile.Acquire(); } return pIDQFile; } //+--------------------------------------------------------------------------- // // Member: CIDQFileList::~CIDQFileList - public destructor // // History: 96/Mar/27 DwightKr Created. // //---------------------------------------------------------------------------- CIDQFileList::~CIDQFileList() { for (unsigned i=0; i<_aIDQFile.Count(); i++) { ciGibDebugOut(( DEB_ITRACE, "Deleting IDQ cache entry %ws\n", _aIDQFile[i]->GetIDQFileName() )); delete _aIDQFile[i]; } } //+--------------------------------------------------------------------------- // // Member: CIDQFileList::Release - public // // Synopsis: Releases the IDQ file by decrementing its refcount. // // Arguments: [idqFile] -- pointer to the IDQ file object // // History: 96/Mar/27 DwightKr Created. // //---------------------------------------------------------------------------- void CIDQFileList::Release( CIDQFile & idqFile ) { idqFile.Release(); } //+--------------------------------------------------------------------------- // // Member: CIDQFileList::DeleteZombies - public // // Synopsis: Removes IDQ files that are zombies; i.e. out of date // // History: 96/Mar/28 DwightKr Created. // //---------------------------------------------------------------------------- void CIDQFileList::DeleteZombies() { // ========================================== CLock lock( _mutex ); unsigned i=0; while ( i<_aIDQFile.Count() ) { if ( _aIDQFile[i]->LokGetRefCount() == 0 && !_aIDQFile[i]->IsCachedDataValid() ) { CIDQFile * pIDQFile = _aIDQFile[i]; _aIDQFile.Remove(i); ciGibDebugOut(( DEB_ITRACE, "Deleting zombie IDQ cache entry %ws, %d entries cached\n", pIDQFile->GetIDQFileName(), _aIDQFile.Count() )); delete pIDQFile; } else { ciGibDebugOut(( DEB_ITRACE, "IDQ cache entry %ws was not deleted, refCount=%d\n", _aIDQFile[i]->GetIDQFileName(), _aIDQFile[i]->LokGetRefCount() )); i++; } } // ========================================== }