windows-nt/Source/XPSP1/NT/inetsrv/query/web/dll/idq.cxx

1202 lines
37 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-2000.
//
// File: idq.cxx
//
// Contents: Parser for an IDQ file
//
// History: 96/Jan/3 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#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<cISAPI_CiParams; i++)
{
aHash[i] = ISAPI_IDQHash( aISAPI_CiParams[i] );
}
for (i=0; i<cISAPI_CiParams-1; i++)
{
for (unsigned j=i+1; j<cISAPI_CiParams; j++)
{
if ( aHash[i] == aHash[j] )
{
printf( "Hash collision between %ls(0x%x) and %ls(0x%x)\n",
aISAPI_CiParams[i],
aHash[i],
aISAPI_CiParams[j],
aHash[j] );
}
}
}
printf ("Hash table: Copy this as necessary into idq\\idq.cxx\n");
for (i=0; i<cISAPI_CiParams; i++)
{
printf("static const ULONG ISAPI_%ws_HASH\t= 0x%x;\n", aISAPI_CiParams[i], aHash[i] );
}
return 0;
}
#endif // 0
//+---------------------------------------------------------------------------
//
// Member: CIDQFile::CIDQFile - public constructor
//
// Synopsis: Builds a CIDQFile object, initializes values
//
// Arguments: [wcsFileName] -- full path to IDQ file
// [codePage] -- code page to translate IDQ file
//
// History: 96/Jan/03 DwightKr Created.
//
//----------------------------------------------------------------------------
CIDQFile::CIDQFile( WCHAR const * wcsFileName,
UINT codePage,
CSecurityIdentity const & securityIdentity )
: _wcsRestriction(0),
_wcsDialect(0),
_wcsScope(0),
_wcsSort(0),
_wcsColumns(0),
_wcsLocale(0),
_wcsHTXFileName(0),
_wcsMaxRecordsInResultSet(0),
_wcsMaxRecordsPerPage(0),
_wcsFirstRowsInResultSet(0),
_wcsCatalog(0),
_wcsForceUseCi(0),
_wcsDeferTrimming(0),
_wcsCanonicalOutput(0),
_wcsDontTimeout(0),
_wcsCiFlags(0),
_wcsBoolVectorPrefix(0),
_wcsBoolVectorSeparator(0),
_wcsBoolVectorSuffix(0),
_wcsCurrencyVectorPrefix(0),
_wcsCurrencyVectorSeparator(0),
_wcsCurrencyVectorSuffix(0),
_wcsDateVectorPrefix(0),
_wcsDateVectorSeparator(0),
_wcsDateVectorSuffix(0),
_wcsNumberVectorPrefix(0),
_wcsNumberVectorSeparator(0),
_wcsNumberVectorSuffix(0),
_wcsStringVectorPrefix(0),
_wcsStringVectorSeparator(0),
_wcsStringVectorSuffix(0),
_cReplaceableParameters(0),
_refCount(0),
_codePage(codePage),
_securityIdentity( securityIdentity )
{
wcscpy( _wcsIDQFileName, wcsFileName );
}
//+---------------------------------------------------------------------------
//
// Member: CIDQFile::~CIDQFile - public destructor
//
// History: 96/Jan/03 DwightKr Created.
//
//----------------------------------------------------------------------------
CIDQFile::~CIDQFile()
{
Win4Assert( _refCount == 0 );
delete _wcsRestriction;
delete _wcsDialect;
delete _wcsScope;
delete _wcsSort;
delete _wcsColumns;
delete _wcsLocale;
delete _wcsHTXFileName;
delete _wcsMaxRecordsInResultSet;
delete _wcsMaxRecordsPerPage;
delete _wcsFirstRowsInResultSet;
delete _wcsCatalog;
delete _wcsCiFlags;
delete _wcsForceUseCi;
delete _wcsDeferTrimming;
delete _wcsCanonicalOutput;
delete _wcsDontTimeout;
delete _wcsBoolVectorPrefix;
delete _wcsBoolVectorSeparator;
delete _wcsBoolVectorSuffix;
delete _wcsCurrencyVectorPrefix;
delete _wcsCurrencyVectorSeparator;
delete _wcsCurrencyVectorSuffix;
delete _wcsDateVectorPrefix;
delete _wcsDateVectorSeparator;
delete _wcsDateVectorSuffix;
delete _wcsNumberVectorPrefix;
delete _wcsNumberVectorSeparator;
delete _wcsNumberVectorSuffix;
delete _wcsStringVectorPrefix;
delete _wcsStringVectorSeparator;
delete _wcsStringVectorSuffix;
}
//+---------------------------------------------------------------------------
//
// Member: CIDQFile::ParseFile, private
//
// Synopsis: Parses the given file and sets up the necessary variables
//
// History: 96/Jan/03 DwightKr Created.
//
//----------------------------------------------------------------------------
void CIDQFile::ParseFile()
{
_xList.Set(new CLocalGlobalPropertyList( _codePage ));
// We don't support impersonation for scripts.
// It involves getting the server ip address, vpath and then using
// that for impersonation
Win4Assert( !IsNetPath( _wcsIDQFileName ) );
//
// Now parse the query parameters
//
// Open the file in a TRY block, so we can make this an IDQ error
// if the IDQ file isn't found. Otherwise the error doesn't include
// the IDQ filename.
// For scoping reasons, the CFileMapView is new'ed, not on the stack.
XPtr<CFileMapView> 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<WCHAR> 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<CPropEntry> 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<WCHAR> 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<WCHAR> & 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<CIDQFile *> aIDQFile;
// ==========================================
{
CLock lock( _mutex );
cItems = _aIDQFile.Count(); // Save count of items to examine
aIDQFile.Init( cItems );
for (unsigned i=0; i<cItems; i++)
{
aIDQFile[i] = _aIDQFile[i];
aIDQFile[i]->LokAddRef();
}
}
// ==========================================
// 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; i<cItems; i++)
{
if ( (_wcsicmp(aIDQFile[i]->GetIDQFileName(), 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; i<cItems; i++)
{
if ( pIDQFile != aIDQFile[i] )
{
aIDQFile[i]->Release();
}
}
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<CIDQFile> 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++;
}
}
// ==========================================
}