Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1201 lines
38 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-2000.
  5. //
  6. // File: idq.cxx
  7. //
  8. // Contents: Parser for an IDQ file
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. //
  16. // These hash values MUST be unique. They have been calculated to be
  17. // unique via the ISAPI_IDQHash function below.
  18. //
  19. // If the spelling of a IDQ variable name is changed, or a new variable
  20. // is added to the list, this table must be re-generated using the
  21. // code supplied below.
  22. //
  23. static const ULONG ISAPI_CIBOOLVECTORPREFIX_HASH = 0x1174d5c;
  24. static const ULONG ISAPI_CIBOOLVECTORSEPARATOR_HASH = 0x8ba6b1d;
  25. static const ULONG ISAPI_CIBOOLVECTORSUFFIX_HASH = 0x1174df4;
  26. static const ULONG ISAPI_CICATALOG_HASH = 0x89c6;
  27. static const ULONG ISAPI_CICOLUMNS_HASH = 0x8bb4;
  28. static const ULONG ISAPI_CICURRENCYVECTORPREFIX_HASH = 0x119add60;
  29. static const ULONG ISAPI_CICURRENCYVECTORSEPARATOR_HASH = 0x8cd6eb21;
  30. static const ULONG ISAPI_CICURRENCYVECTORSUFFIX_HASH = 0x119addf8;
  31. static const ULONG ISAPI_CICURRENTPAGENUMBER_HASH = 0x233792f;
  32. static const ULONG ISAPI_CICURRENTRECORDNUMBER_HASH = 0x8ce0671;
  33. static const ULONG ISAPI_CIDATEVECTORPREFIX_HASH = 0x114fd5c;
  34. static const ULONG ISAPI_CIDATEVECTORSEPARATOR_HASH = 0x8a7eb1d;
  35. static const ULONG ISAPI_CIDATEVECTORSUFFIX_HASH = 0x114fdf4;
  36. static const ULONG ISAPI_CIFORCEUSECI_HASH = 0x46337;
  37. static const ULONG ISAPI_CIDEFERTRIMMING_HASH = 0x8a26e6f8;
  38. static const ULONG ISAPI_CIDIALECT_HASH = 0x8a07;
  39. static const ULONG ISAPI_CIFLAGS_HASH = 0x228c;
  40. static const ULONG ISAPI_CILOCALE_HASH = 0x4631;
  41. static const ULONG ISAPI_CIMATCHEDRECORDCOUNT_HASH = 0x4639280;
  42. static const ULONG ISAPI_CIMAXRECORDSINRESULTSET_HASH = 0x2349b581;
  43. static const ULONG ISAPI_CIMAXRECORDSPERPAGE_HASH = 0x2349baa;
  44. static const ULONG ISAPI_CIFIRSTROWSINRESULTSET_HASH = 0x118dc580;
  45. static const ULONG ISAPI_CINUMBERVECTORPREFIX_HASH = 0x476ad5e;
  46. static const ULONG ISAPI_CINUMBERVECTORSEPARATOR_HASH = 0x23b56b1f;
  47. static const ULONG ISAPI_CINUMBERVECTORSUFFIX_HASH = 0x476adf6;
  48. static const ULONG ISAPI_CIRESTRICTION_HASH = 0x8ed8d;
  49. static const ULONG ISAPI_CISCOPE_HASH = 0x2350;
  50. static const ULONG ISAPI_CISORT_HASH = 0x11c2;
  51. static const ULONG ISAPI_CISTRINGVECTORPREFIX_HASH = 0x4845d5e;
  52. static const ULONG ISAPI_CISTRINGVECTORSEPARATOR_HASH = 0x2422eb1f;
  53. static const ULONG ISAPI_CISTRINGVECTORSUFFIX_HASH = 0x4845df6;
  54. static const ULONG ISAPI_CITEMPLATE_HASH = 0x11d3b;
  55. static const ULONG ISAPI_CICANONICALOUTPUT_HASH = 0x8a0c9f;
  56. static const ULONG ISAPI_CIDONTTIMEOUT_HASH = 0x8c55f;
  57. #if 0
  58. //
  59. // Use the following routine to verify the above hash values are perfect.
  60. //
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Function: main - program entry point; used to verify perfect hash
  64. //
  65. //----------------------------------------------------------------------------
  66. int __cdecl main( int argc, char ** argv )
  67. {
  68. ULONG aHash[100];
  69. Win4Assert( 100 > cISAPI_CiParams );
  70. for (unsigned i=0; i<cISAPI_CiParams; i++)
  71. {
  72. aHash[i] = ISAPI_IDQHash( aISAPI_CiParams[i] );
  73. }
  74. for (i=0; i<cISAPI_CiParams-1; i++)
  75. {
  76. for (unsigned j=i+1; j<cISAPI_CiParams; j++)
  77. {
  78. if ( aHash[i] == aHash[j] )
  79. {
  80. printf( "Hash collision between %ls(0x%x) and %ls(0x%x)\n",
  81. aISAPI_CiParams[i],
  82. aHash[i],
  83. aISAPI_CiParams[j],
  84. aHash[j] );
  85. }
  86. }
  87. }
  88. printf ("Hash table: Copy this as necessary into idq\\idq.cxx\n");
  89. for (i=0; i<cISAPI_CiParams; i++)
  90. {
  91. printf("static const ULONG ISAPI_%ws_HASH\t= 0x%x;\n", aISAPI_CiParams[i], aHash[i] );
  92. }
  93. return 0;
  94. }
  95. #endif // 0
  96. //+---------------------------------------------------------------------------
  97. //
  98. // Member: CIDQFile::CIDQFile - public constructor
  99. //
  100. // Synopsis: Builds a CIDQFile object, initializes values
  101. //
  102. // Arguments: [wcsFileName] -- full path to IDQ file
  103. // [codePage] -- code page to translate IDQ file
  104. //
  105. // History: 96/Jan/03 DwightKr Created.
  106. //
  107. //----------------------------------------------------------------------------
  108. CIDQFile::CIDQFile( WCHAR const * wcsFileName,
  109. UINT codePage,
  110. CSecurityIdentity const & securityIdentity )
  111. : _wcsRestriction(0),
  112. _wcsDialect(0),
  113. _wcsScope(0),
  114. _wcsSort(0),
  115. _wcsColumns(0),
  116. _wcsLocale(0),
  117. _wcsHTXFileName(0),
  118. _wcsMaxRecordsInResultSet(0),
  119. _wcsMaxRecordsPerPage(0),
  120. _wcsFirstRowsInResultSet(0),
  121. _wcsCatalog(0),
  122. _wcsForceUseCi(0),
  123. _wcsDeferTrimming(0),
  124. _wcsCanonicalOutput(0),
  125. _wcsDontTimeout(0),
  126. _wcsCiFlags(0),
  127. _wcsBoolVectorPrefix(0),
  128. _wcsBoolVectorSeparator(0),
  129. _wcsBoolVectorSuffix(0),
  130. _wcsCurrencyVectorPrefix(0),
  131. _wcsCurrencyVectorSeparator(0),
  132. _wcsCurrencyVectorSuffix(0),
  133. _wcsDateVectorPrefix(0),
  134. _wcsDateVectorSeparator(0),
  135. _wcsDateVectorSuffix(0),
  136. _wcsNumberVectorPrefix(0),
  137. _wcsNumberVectorSeparator(0),
  138. _wcsNumberVectorSuffix(0),
  139. _wcsStringVectorPrefix(0),
  140. _wcsStringVectorSeparator(0),
  141. _wcsStringVectorSuffix(0),
  142. _cReplaceableParameters(0),
  143. _refCount(0),
  144. _codePage(codePage),
  145. _securityIdentity( securityIdentity )
  146. {
  147. wcscpy( _wcsIDQFileName, wcsFileName );
  148. }
  149. //+---------------------------------------------------------------------------
  150. //
  151. // Member: CIDQFile::~CIDQFile - public destructor
  152. //
  153. // History: 96/Jan/03 DwightKr Created.
  154. //
  155. //----------------------------------------------------------------------------
  156. CIDQFile::~CIDQFile()
  157. {
  158. Win4Assert( _refCount == 0 );
  159. delete _wcsRestriction;
  160. delete _wcsDialect;
  161. delete _wcsScope;
  162. delete _wcsSort;
  163. delete _wcsColumns;
  164. delete _wcsLocale;
  165. delete _wcsHTXFileName;
  166. delete _wcsMaxRecordsInResultSet;
  167. delete _wcsMaxRecordsPerPage;
  168. delete _wcsFirstRowsInResultSet;
  169. delete _wcsCatalog;
  170. delete _wcsCiFlags;
  171. delete _wcsForceUseCi;
  172. delete _wcsDeferTrimming;
  173. delete _wcsCanonicalOutput;
  174. delete _wcsDontTimeout;
  175. delete _wcsBoolVectorPrefix;
  176. delete _wcsBoolVectorSeparator;
  177. delete _wcsBoolVectorSuffix;
  178. delete _wcsCurrencyVectorPrefix;
  179. delete _wcsCurrencyVectorSeparator;
  180. delete _wcsCurrencyVectorSuffix;
  181. delete _wcsDateVectorPrefix;
  182. delete _wcsDateVectorSeparator;
  183. delete _wcsDateVectorSuffix;
  184. delete _wcsNumberVectorPrefix;
  185. delete _wcsNumberVectorSeparator;
  186. delete _wcsNumberVectorSuffix;
  187. delete _wcsStringVectorPrefix;
  188. delete _wcsStringVectorSeparator;
  189. delete _wcsStringVectorSuffix;
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Member: CIDQFile::ParseFile, private
  194. //
  195. // Synopsis: Parses the given file and sets up the necessary variables
  196. //
  197. // History: 96/Jan/03 DwightKr Created.
  198. //
  199. //----------------------------------------------------------------------------
  200. void CIDQFile::ParseFile()
  201. {
  202. _xList.Set(new CLocalGlobalPropertyList( _codePage ));
  203. // We don't support impersonation for scripts.
  204. // It involves getting the server ip address, vpath and then using
  205. // that for impersonation
  206. Win4Assert( !IsNetPath( _wcsIDQFileName ) );
  207. //
  208. // Now parse the query parameters
  209. //
  210. // Open the file in a TRY block, so we can make this an IDQ error
  211. // if the IDQ file isn't found. Otherwise the error doesn't include
  212. // the IDQ filename.
  213. // For scoping reasons, the CFileMapView is new'ed, not on the stack.
  214. XPtr<CFileMapView> xMapView;
  215. TRY
  216. {
  217. xMapView.Set( new CFileMapView( _wcsIDQFileName ) );
  218. xMapView->Init();
  219. }
  220. CATCH( CException, e )
  221. {
  222. if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == e.GetErrorCode() )
  223. {
  224. THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
  225. }
  226. else
  227. {
  228. RETHROW();
  229. }
  230. }
  231. END_CATCH
  232. CFileBuffer idqFile( xMapView.GetReference(), _codePage );
  233. //
  234. // Save the last write time of this file.
  235. //
  236. SCODE sc = GetLastWriteTime( _wcsIDQFileName, _ftIDQLastWriteTime );
  237. if ( FAILED( sc ) )
  238. THROW( CException( sc ) );
  239. //
  240. // Process a line at a time, look for either the [Names] or the [Query]
  241. // section and process lines within those sections.
  242. //
  243. BOOL fQuerySection = FALSE;
  244. BOOL fNamesSection = FALSE;
  245. int iLine = 0; // Start counting at line #1
  246. for( ;; )
  247. {
  248. iLine++;
  249. XGrowable<WCHAR> xLine;
  250. ULONG cwcChar = idqFile.fgetsw( xLine );
  251. if ( 0 == cwcChar )
  252. {
  253. break;
  254. }
  255. WCHAR *pwcLine = xLine.Get();
  256. //
  257. // Skip ahead until we find a [Query] section
  258. //
  259. if ( L'[' == *pwcLine )
  260. {
  261. if (_wcsnicmp(pwcLine+1, L"Query]", 6) == 0 )
  262. {
  263. fQuerySection = TRUE;
  264. continue;
  265. }
  266. else if (_wcsnicmp(pwcLine+1, L"Names]", 6) == 0 )
  267. {
  268. fNamesSection = TRUE;
  269. continue;
  270. }
  271. else
  272. {
  273. fQuerySection = fNamesSection = FALSE;
  274. continue;
  275. }
  276. }
  277. else if ( L'#' == *pwcLine )
  278. {
  279. continue;
  280. }
  281. if ( fQuerySection )
  282. {
  283. CQueryScanner scanner( pwcLine, FALSE );
  284. ParseOneLine( scanner, iLine );
  285. }
  286. else if (fNamesSection)
  287. {
  288. XPtr<CPropEntry> propentry;
  289. CQueryScanner scanner( pwcLine, FALSE );
  290. CPropertyList::ParseOneLine(scanner, iLine, propentry);
  291. if (propentry.GetPointer())
  292. {
  293. _xList->AddEntry( propentry.GetPointer(), iLine );
  294. propentry.Acquire();
  295. }
  296. }
  297. }
  298. //
  299. // Verify that the minimum set of parameters are specified.
  300. //
  301. //
  302. // We must have all of the following:
  303. //
  304. // - a restriction
  305. // - a scope
  306. // - a template (HTX) file
  307. // - output columns
  308. //
  309. if ( 0 == _wcsRestriction )
  310. {
  311. // Report an error
  312. ciGibDebugOut(( DEB_IERROR, "Restriction not found in IDQ file\n" ));
  313. THROW( CIDQException(MSG_CI_IDQ_MISSING_RESTRICTION, 0) );
  314. }
  315. else if ( 0 == _wcsScope )
  316. {
  317. // Report an error
  318. ciGibDebugOut(( DEB_IERROR, "Scope not found in IDQ file\n" ));
  319. THROW( CIDQException(MSG_CI_IDQ_MISSING_SCOPE, 0) );
  320. }
  321. else if ( 0 == _wcsHTXFileName && !IsCanonicalOutput() )
  322. {
  323. // Report an error
  324. ciGibDebugOut(( DEB_IERROR, "HTX filename not found in IDQ file\n" ));
  325. THROW( CIDQException(MSG_CI_IDQ_MISSING_TEMPLATEFILE, 0) );
  326. }
  327. else if ( 0 == _wcsColumns )
  328. {
  329. // Report an error
  330. ciGibDebugOut(( DEB_IERROR, "Output columns not found in IDQ file\n" ));
  331. THROW( CIDQException(MSG_CI_IDQ_MISSING_OUTPUTCOLUMNS, 0) );
  332. }
  333. //
  334. // If no catalog was specified, use the default catalog in the registry
  335. //
  336. if ( 0 == _wcsCatalog )
  337. {
  338. ciGibDebugOut(( DEB_ITRACE, "Using default catalog\n" ));
  339. WCHAR awcTmp[ MAX_PATH ];
  340. ULONG cwcRequired = TheIDQRegParams.GetISDefaultCatalog( awcTmp,
  341. MAX_PATH );
  342. if ( cwcRequired > MAX_PATH )
  343. THROW( CException(STATUS_INVALID_PARAMETER) );
  344. cwcRequired++; // make room for termination
  345. _wcsCatalog = new WCHAR[ cwcRequired ];
  346. RtlCopyMemory( _wcsCatalog, awcTmp, cwcRequired * sizeof WCHAR );
  347. }
  348. }
  349. //+---------------------------------------------------------------------------
  350. //
  351. // Member: CIDQFile::ParseOneLine, private
  352. //
  353. // Synopsis: Parses one line of the IDQ file
  354. //
  355. // Arguments: [scan] -- scanner initialized with the current line
  356. // [iLine] -- current line number
  357. //
  358. // History: 96/Jan/03 DwightKr created
  359. //
  360. //----------------------------------------------------------------------------
  361. void CIDQFile::ParseOneLine( CQueryScanner & scan,
  362. unsigned iLine )
  363. {
  364. //
  365. // Is this a comment line (does it start with #) or an empty line?
  366. //
  367. if ( scan.LookAhead() == PROP_REGEX_TOKEN || scan.LookAhead() == EOS_TOKEN )
  368. {
  369. return;
  370. }
  371. if ( scan.LookAhead() != TEXT_TOKEN ) // Better be a word
  372. {
  373. // Report an error
  374. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_NAME, iLine ) );
  375. }
  376. XPtrST<WCHAR> wcsAttribute( scan.AcqWord() );
  377. if( wcsAttribute.GetPointer() == 0 ) // Better find a word
  378. {
  379. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_TYPE, iLine ) );
  380. }
  381. scan.Accept();
  382. if ( scan.LookAhead() != EQUAL_TOKEN )
  383. {
  384. // Report an error
  385. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_EQUAL, iLine ) );
  386. }
  387. scan.Accept();
  388. //
  389. // Convert the string to upper-case and HASH it. Lookup the hashed value.
  390. // Note that this code assumes the HASH IS PERFECT. Whenever a IDQ
  391. // variable is renamed or added, this assumption may no-longer be true.
  392. // Check it out with the above program.
  393. //
  394. // This code essentially replaces 25 wcsicmp functions; or an average
  395. // of 12.5 wscicmp calls per line in the IDQ file.
  396. //
  397. Win4Assert( ISAPI_CICOLUMNS_HASH == ISAPI_IDQHash(ISAPI_CI_COLUMNS) );
  398. Win4Assert( ISAPI_CIFLAGS_HASH == ISAPI_IDQHash(ISAPI_CI_FLAGS) );
  399. Win4Assert( ISAPI_CIMAXRECORDSINRESULTSET_HASH == ISAPI_IDQHash(ISAPI_CI_MAX_RECORDS_IN_RESULTSET) );
  400. Win4Assert( ISAPI_CIMAXRECORDSPERPAGE_HASH == ISAPI_IDQHash(ISAPI_CI_MAX_RECORDS_PER_PAGE) );
  401. Win4Assert( ISAPI_CIFIRSTROWSINRESULTSET_HASH == ISAPI_IDQHash(ISAPI_CI_FIRST_ROWS_IN_RESULTSET) );
  402. Win4Assert( ISAPI_CIRESTRICTION_HASH == ISAPI_IDQHash(ISAPI_CI_RESTRICTION) );
  403. Win4Assert( ISAPI_CIDIALECT_HASH == ISAPI_IDQHash(ISAPI_CI_DIALECT) );
  404. Win4Assert( ISAPI_CISCOPE_HASH == ISAPI_IDQHash(ISAPI_CI_SCOPE) );
  405. Win4Assert( ISAPI_CISORT_HASH == ISAPI_IDQHash(ISAPI_CI_SORT) );
  406. Win4Assert( ISAPI_CITEMPLATE_HASH == ISAPI_IDQHash(ISAPI_CI_TEMPLATE) );
  407. Win4Assert( ISAPI_CICATALOG_HASH == ISAPI_IDQHash(ISAPI_CI_CATALOG) );
  408. Win4Assert( ISAPI_CILOCALE_HASH == ISAPI_IDQHash(ISAPI_CI_LOCALE) );
  409. Win4Assert( ISAPI_CIBOOLVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_PREFIX) );
  410. Win4Assert( ISAPI_CIBOOLVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_SEPARATOR) );
  411. Win4Assert( ISAPI_CIBOOLVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_BOOL_VECTOR_SUFFIX) );
  412. Win4Assert( ISAPI_CICURRENCYVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_PREFIX) );
  413. Win4Assert( ISAPI_CICURRENCYVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_SEPARATOR) );
  414. Win4Assert( ISAPI_CICURRENCYVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_CURRENCY_VECTOR_SUFFIX) );
  415. Win4Assert( ISAPI_CIDATEVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_PREFIX) );
  416. Win4Assert( ISAPI_CIDATEVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_SEPARATOR) );
  417. Win4Assert( ISAPI_CIDATEVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_DATE_VECTOR_SUFFIX) );
  418. Win4Assert( ISAPI_CINUMBERVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_PREFIX) );
  419. Win4Assert( ISAPI_CINUMBERVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_SEPARATOR) );
  420. Win4Assert( ISAPI_CINUMBERVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_NUMBER_VECTOR_SUFFIX) );
  421. Win4Assert( ISAPI_CISTRINGVECTORPREFIX_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_PREFIX) );
  422. Win4Assert( ISAPI_CISTRINGVECTORSEPARATOR_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_SEPARATOR) );
  423. Win4Assert( ISAPI_CISTRINGVECTORSUFFIX_HASH == ISAPI_IDQHash(ISAPI_CI_STRING_VECTOR_SUFFIX) );
  424. Win4Assert( ISAPI_CIFORCEUSECI_HASH == ISAPI_IDQHash(ISAPI_CI_FORCE_USE_CI) );
  425. Win4Assert( ISAPI_CIDEFERTRIMMING_HASH == ISAPI_IDQHash(ISAPI_CI_DEFER_NONINDEXED_TRIMMING ) );
  426. Win4Assert( ISAPI_CICANONICALOUTPUT_HASH == ISAPI_IDQHash(ISAPI_CI_CANONICAL_OUTPUT ) );
  427. Win4Assert( ISAPI_CIDONTTIMEOUT_HASH == ISAPI_IDQHash(ISAPI_CI_DONT_TIMEOUT ) );
  428. _wcsupr( wcsAttribute.GetPointer() );
  429. ULONG ulHash = ISAPI_IDQHash( wcsAttribute.GetPointer() );
  430. switch ( ulHash )
  431. {
  432. case ISAPI_CICOLUMNS_HASH:
  433. GetStringValue( scan, iLine, &_wcsColumns );
  434. break;
  435. case ISAPI_CIFLAGS_HASH:
  436. GetStringValue( scan, iLine, &_wcsCiFlags );
  437. break;
  438. case ISAPI_CIMAXRECORDSINRESULTSET_HASH:
  439. GetStringValue( scan, iLine, &_wcsMaxRecordsInResultSet );
  440. break;
  441. case ISAPI_CIMAXRECORDSPERPAGE_HASH:
  442. GetStringValue( scan, iLine, &_wcsMaxRecordsPerPage );
  443. break;
  444. case ISAPI_CIFIRSTROWSINRESULTSET_HASH:
  445. GetStringValue( scan, iLine, &_wcsFirstRowsInResultSet );
  446. break;
  447. case ISAPI_CIRESTRICTION_HASH:
  448. GetStringValue( scan, iLine, &_wcsRestriction );
  449. break;
  450. case ISAPI_CIDIALECT_HASH:
  451. GetStringValue( scan, iLine, &_wcsDialect );
  452. break;
  453. case ISAPI_CISCOPE_HASH:
  454. GetStringValue( scan, iLine, &_wcsScope, FALSE );
  455. break;
  456. case ISAPI_CISORT_HASH:
  457. GetStringValue( scan, iLine, &_wcsSort );
  458. break;
  459. case ISAPI_CITEMPLATE_HASH:
  460. GetStringValue( scan, iLine, &_wcsHTXFileName );
  461. break;
  462. case ISAPI_CICATALOG_HASH:
  463. GetStringValue( scan, iLine, &_wcsCatalog );
  464. break;
  465. case ISAPI_CIBOOLVECTORPREFIX_HASH:
  466. GetStringValue( scan, iLine, &_wcsBoolVectorPrefix );
  467. break;
  468. case ISAPI_CIBOOLVECTORSEPARATOR_HASH:
  469. GetStringValue( scan, iLine, &_wcsBoolVectorSeparator );
  470. break;
  471. case ISAPI_CIBOOLVECTORSUFFIX_HASH:
  472. GetStringValue( scan, iLine, &_wcsBoolVectorSuffix );
  473. break;
  474. case ISAPI_CICURRENCYVECTORPREFIX_HASH:
  475. GetStringValue( scan, iLine, &_wcsCurrencyVectorPrefix );
  476. break;
  477. case ISAPI_CICURRENCYVECTORSEPARATOR_HASH:
  478. GetStringValue( scan, iLine, &_wcsCurrencyVectorSeparator );
  479. break;
  480. case ISAPI_CICURRENCYVECTORSUFFIX_HASH:
  481. GetStringValue( scan, iLine, &_wcsCurrencyVectorSuffix );
  482. break;
  483. case ISAPI_CIDATEVECTORPREFIX_HASH:
  484. GetStringValue( scan, iLine, &_wcsDateVectorPrefix );
  485. break;
  486. case ISAPI_CIDATEVECTORSEPARATOR_HASH:
  487. GetStringValue( scan, iLine, &_wcsDateVectorSeparator );
  488. break;
  489. case ISAPI_CIDATEVECTORSUFFIX_HASH:
  490. GetStringValue( scan, iLine, &_wcsDateVectorSuffix );
  491. break;
  492. case ISAPI_CINUMBERVECTORPREFIX_HASH:
  493. GetStringValue( scan, iLine, &_wcsNumberVectorPrefix );
  494. break;
  495. case ISAPI_CINUMBERVECTORSEPARATOR_HASH:
  496. GetStringValue( scan, iLine, &_wcsNumberVectorSeparator );
  497. break;
  498. case ISAPI_CINUMBERVECTORSUFFIX_HASH:
  499. GetStringValue( scan, iLine, &_wcsNumberVectorSuffix );
  500. break;
  501. case ISAPI_CISTRINGVECTORPREFIX_HASH:
  502. GetStringValue( scan, iLine, &_wcsStringVectorPrefix );
  503. break;
  504. case ISAPI_CISTRINGVECTORSEPARATOR_HASH:
  505. GetStringValue( scan, iLine, &_wcsStringVectorSeparator );
  506. break;
  507. case ISAPI_CISTRINGVECTORSUFFIX_HASH:
  508. GetStringValue( scan, iLine, &_wcsStringVectorSuffix );
  509. break;
  510. case ISAPI_CIFORCEUSECI_HASH:
  511. GetStringValue( scan, iLine, &_wcsForceUseCi );
  512. break;
  513. case ISAPI_CIDEFERTRIMMING_HASH:
  514. GetStringValue( scan, iLine, &_wcsDeferTrimming );
  515. break;
  516. case ISAPI_CILOCALE_HASH:
  517. GetStringValue( scan, iLine, &_wcsLocale );
  518. break;
  519. case ISAPI_CICANONICALOUTPUT_HASH:
  520. GetStringValue( scan, iLine, &_wcsCanonicalOutput );
  521. break;
  522. case ISAPI_CIDONTTIMEOUT_HASH:
  523. GetStringValue( scan, iLine, &_wcsDontTimeout );
  524. break;
  525. default:
  526. //
  527. // We've found a keyword/attribute that we don't support.
  528. // Don't report an error. This will allow this version of the
  529. // parser to work with newer .IDQ file versions with new parameters.
  530. //
  531. ciGibDebugOut(( DEB_ERROR,
  532. "Invalid string in hash table for %ws; hash = 0x%x\n",
  533. wcsAttribute.GetPointer(),
  534. ulHash ));
  535. break;
  536. }
  537. }
  538. //+---------------------------------------------------------------------------
  539. //
  540. // Member: CIDQFile::ParseColumns, public
  541. //
  542. // Synopsis: Parses the columns attribute
  543. //
  544. // Arguments: [wcsColumns] -- string to convert
  545. // [variableSet] -- list of replaceable parameters
  546. // [varColumns] -- Column variables returned here
  547. //
  548. // Returns: CDbColumns* - counted array of column IDs
  549. //
  550. // History: 96/Jan/03 DwightKr created
  551. // 96/Feb/23 DwightKr Add check for duplicate value
  552. // 96/Mar/12 DwightKr Made public
  553. // 96/May/23 AlanW Detect duplicate column names
  554. //
  555. //----------------------------------------------------------------------------
  556. CDbColumns * CIDQFile::ParseColumns( WCHAR const * wcsColumns,
  557. CVariableSet & variableSet,
  558. CDynArray<WCHAR> & awcsColumns )
  559. {
  560. return ::ParseStringColumns( wcsColumns,
  561. _xList.GetPointer(),
  562. GetUserDefaultLCID(),
  563. &variableSet,
  564. &awcsColumns );
  565. }
  566. //+---------------------------------------------------------------------------
  567. //
  568. // Member: CIDQFile::ParseFlags, private
  569. //
  570. // Synopsis: Parses the flags attribute
  571. //
  572. // Arguments: [wcsCiFlags] -- flags
  573. //
  574. // History: 96/Jan/03 DwightKr created
  575. // 96/Apr/12 DwightKr mad a replaceable parameter
  576. //
  577. //----------------------------------------------------------------------------
  578. ULONG CIDQFile::ParseFlags( WCHAR const * wcsCiFlags )
  579. {
  580. if ( 0 == wcsCiFlags )
  581. {
  582. return QUERY_DEEP;
  583. }
  584. ULONG ulFlags;
  585. if ( _wcsicmp(wcsCiFlags, L"SHALLOW") == 0 )
  586. {
  587. ulFlags = QUERY_SHALLOW;
  588. }
  589. else if ( _wcsicmp(wcsCiFlags, L"DEEP") == 0 )
  590. {
  591. ulFlags = QUERY_DEEP;
  592. }
  593. else
  594. {
  595. THROW( CIDQException(MSG_CI_IDQ_EXPECTING_SHALLOWDEEP, 0) );
  596. }
  597. return ulFlags;
  598. }
  599. //+---------------------------------------------------------------------------
  600. //
  601. // Member: CIDQFile::IsCanonicalOutput
  602. //
  603. // Synopsis: Tests if canonical output is enabled.
  604. //
  605. // Returns: TRUE if canonical output is needed; FALSE o/w
  606. //
  607. // History: 6-14-96 srikants Created
  608. //
  609. // Notes: Assumed here that it is not a replaceable parameter.
  610. //
  611. //----------------------------------------------------------------------------
  612. BOOL CIDQFile::IsCanonicalOutput() const
  613. {
  614. if ( 0 == _wcsCanonicalOutput )
  615. return FALSE;
  616. return _wcsicmp(_wcsCanonicalOutput, L"TRUE") == 0;
  617. }
  618. //+---------------------------------------------------------------------------
  619. //
  620. // Member: CIDQFile::IsDontTimeout
  621. //
  622. // Synopsis: Specifies if the don't timeout parameter is true
  623. //
  624. // History: 9-13-96 srikants Created
  625. //
  626. //----------------------------------------------------------------------------
  627. BOOL CIDQFile::IsDontTimeout() const
  628. {
  629. if ( 0 == _wcsDontTimeout )
  630. return FALSE;
  631. return _wcsicmp(_wcsDontTimeout, L"TRUE") == 0;
  632. }
  633. //+---------------------------------------------------------------------------
  634. //
  635. // Member: CIDQFile::GetStringValue - private
  636. //
  637. // Synopsis: Gets the string value on the currenct line
  638. //
  639. // Arguments: [scan] -- scanner initialized with the current line
  640. // [iLine] -- current line number
  641. // [pwcsStringValue] -- value to put string into
  642. // [fParseQuotes] -- if TRUE, remove first and trailing quotes
  643. //
  644. // History: 96/Jan/03 DwightKr created
  645. // 96/Feb/23 DwightKr Add check for duplicate value
  646. //
  647. //----------------------------------------------------------------------------
  648. void CIDQFile::GetStringValue( CQueryScanner & scan,
  649. unsigned iLine,
  650. WCHAR ** pwcsStringValue,
  651. BOOL fParseQuotes )
  652. {
  653. if ( 0 != *pwcsStringValue )
  654. {
  655. ciGibDebugOut(( DEB_IWARN,
  656. "Duplicate CiXX=value in IDQ file on line #%d\n",
  657. iLine ));
  658. THROW( CIDQException(MSG_CI_IDQ_DUPLICATE_ENTRY, iLine) );
  659. }
  660. *pwcsStringValue = scan.AcqLine( fParseQuotes );
  661. if ( IsAReplaceableParameter( *pwcsStringValue ) != eIsSimpleString )
  662. {
  663. _cReplaceableParameters++;
  664. }
  665. }
  666. //+---------------------------------------------------------------------------
  667. //
  668. // Member: CIDQFile::IsCachedDataValid - public
  669. //
  670. // Synopsis: Determines if the IDQ file is still vaid, or has it
  671. // changed since it was last read.
  672. //
  673. // History: 96/Jan/03 DwightKr created
  674. //
  675. //----------------------------------------------------------------------------
  676. BOOL CIDQFile::IsCachedDataValid()
  677. {
  678. FILETIME ft;
  679. SCODE sc = GetLastWriteTime( _wcsIDQFileName, ft );
  680. // this usually fails because the file no longer exists
  681. if ( FAILED( sc ) )
  682. return FALSE;
  683. return ( (_ftIDQLastWriteTime.dwLowDateTime == ft.dwLowDateTime) &&
  684. (_ftIDQLastWriteTime.dwHighDateTime == ft.dwHighDateTime) );
  685. }
  686. //+---------------------------------------------------------------------------
  687. //
  688. // Function: GetLastWriteTime
  689. //
  690. // Purpose: Gets the last change time of the file specified
  691. //
  692. // Arguments: [wcsFileName] - name of file to get last write time of
  693. // [filetime] - where the filetime is returned
  694. //
  695. // Returns: SCODE result
  696. //
  697. // History: 96/Jan/23 DwightKr Created
  698. // 96/Mar/13 DwightKr Changed to use GetFileAttributesEx()
  699. //
  700. //----------------------------------------------------------------------------
  701. SCODE GetLastWriteTime(
  702. WCHAR const * wcsFileName,
  703. FILETIME & filetime )
  704. {
  705. Win4Assert( 0 != wcsFileName );
  706. // CImpersonateRemoteAccess imprsnat;
  707. // imprsnat.ImpersonateIf( wcsFileName );
  708. WIN32_FIND_DATA ffData;
  709. if ( !GetFileAttributesEx( wcsFileName, GetFileExInfoStandard, &ffData ) )
  710. {
  711. ULONG error = GetLastError();
  712. ciGibDebugOut(( DEB_IERROR,
  713. "Unable to GetFileAttributesEx(%ws) GetLastError=0x%x\n",
  714. wcsFileName,
  715. error ));
  716. return HRESULT_FROM_WIN32( error );
  717. }
  718. filetime = ffData.ftLastWriteTime;
  719. return S_OK;
  720. }
  721. //+---------------------------------------------------------------------------
  722. //
  723. // Member: CIDQFile::ParseForceUseCI - public
  724. //
  725. // Synopsis: Gets the TRUE/FALSE value for CiForceUseCI
  726. //
  727. // Arguments: [wcsForceUseCi] -- string to parse
  728. //
  729. // History: 96/Mar/03 DwightKr created
  730. //
  731. //----------------------------------------------------------------------------
  732. BOOL CIDQFile::ParseForceUseCI( WCHAR const * wcsForceUseCi )
  733. {
  734. if ( 0 == wcsForceUseCi )
  735. {
  736. return FALSE;
  737. }
  738. BOOL fForceUseCi;
  739. if ( _wcsicmp( wcsForceUseCi, L"FALSE" ) == 0 )
  740. {
  741. fForceUseCi = FALSE;
  742. }
  743. else if ( _wcsicmp( wcsForceUseCi, L"TRUE" ) == 0 )
  744. {
  745. fForceUseCi = TRUE;
  746. }
  747. else
  748. {
  749. THROW( CIDQException(MSG_CI_IDQ_EXPECTING_TRUEFALSE, 0) );
  750. }
  751. return fForceUseCi;
  752. }
  753. //+---------------------------------------------------------------------------
  754. //
  755. // Member: CIDQFile::ParseDeferTrimming - public
  756. //
  757. // Synopsis: Gets the TRUE/FALSE value for CiDeferNonIndexedTrimming
  758. //
  759. // Arguments: [wcsDeferTrimming] -- string to parse
  760. //
  761. // History: 96/Mar/03 DwightKr created
  762. //
  763. //----------------------------------------------------------------------------
  764. BOOL CIDQFile::ParseDeferTrimming( WCHAR const * wcsDeferTrimming )
  765. {
  766. if ( 0 == wcsDeferTrimming )
  767. {
  768. return FALSE;
  769. }
  770. BOOL fDeferTrimming;
  771. if ( _wcsicmp( wcsDeferTrimming, L"FALSE" ) == 0 )
  772. {
  773. fDeferTrimming = FALSE;
  774. }
  775. else if ( _wcsicmp( wcsDeferTrimming, L"TRUE" ) == 0 )
  776. {
  777. fDeferTrimming = TRUE;
  778. }
  779. else
  780. {
  781. THROW( CIDQException(MSG_CI_IDQ_EXPECTING_TRUEFALSE, 0) );
  782. }
  783. return fDeferTrimming;
  784. }
  785. //+---------------------------------------------------------------------------
  786. //
  787. // Member: CIDQFile::GetVectorFormatting, public
  788. //
  789. // Synopsis: Sets up the vector formatting for output
  790. //
  791. // Arguments: [outputFormat] -- the output format object to setup
  792. //
  793. // History: 96/Feb/26 DwightKr created
  794. //
  795. //----------------------------------------------------------------------------
  796. void CIDQFile::GetVectorFormatting( COutputFormat & outputFormat )
  797. {
  798. outputFormat.SetBoolVectorFormat( _wcsBoolVectorPrefix,
  799. _wcsBoolVectorSeparator,
  800. _wcsBoolVectorSuffix );
  801. outputFormat.SetCurrencyVectorFormat( _wcsCurrencyVectorPrefix,
  802. _wcsCurrencyVectorSeparator,
  803. _wcsCurrencyVectorSuffix );
  804. outputFormat.SetDateVectorFormat( _wcsDateVectorPrefix,
  805. _wcsDateVectorSeparator,
  806. _wcsDateVectorSuffix );
  807. outputFormat.SetNumberVectorFormat( _wcsNumberVectorPrefix,
  808. _wcsNumberVectorSeparator,
  809. _wcsNumberVectorSuffix );
  810. outputFormat.SetStringVectorFormat( _wcsStringVectorPrefix,
  811. _wcsStringVectorSeparator,
  812. _wcsStringVectorSuffix );
  813. }
  814. //+---------------------------------------------------------------------------
  815. //
  816. // Member: CIDQFileList::Find - public
  817. //
  818. // Synopsis: Finds a matching parsed IDQ file in list, or builds a new
  819. // one if a match can not be found.
  820. //
  821. // Arguments: [wcsFileName] -- full path to IDQ file
  822. // [codePage] -- code page of parsed IDQ file
  823. //
  824. // History: 96/Mar/27 DwightKr Created.
  825. //
  826. //----------------------------------------------------------------------------
  827. CIDQFile * CIDQFileList::Find( WCHAR const * wcsFileName,
  828. UINT codePage,
  829. CSecurityIdentity const & securityIdentity )
  830. {
  831. //
  832. // Refcount everything in the list so that we can examine the list
  833. // outside of the lock.
  834. //
  835. ULONG cItems;
  836. XArray<CIDQFile *> aIDQFile;
  837. // ==========================================
  838. {
  839. CLock lock( _mutex );
  840. cItems = _aIDQFile.Count(); // Save count of items to examine
  841. aIDQFile.Init( cItems );
  842. for (unsigned i=0; i<cItems; i++)
  843. {
  844. aIDQFile[i] = _aIDQFile[i];
  845. aIDQFile[i]->LokAddRef();
  846. }
  847. }
  848. // ==========================================
  849. // Can't throw while the .idq files are addref'ed -- remember the
  850. // error and throw it after the .idq files are released.
  851. // IsCachedDataValid() throws!
  852. SCODE sc = S_OK;
  853. CIDQFile * pIDQFile = 0;
  854. TRY
  855. {
  856. //
  857. // Now walk though the list looking for a match; outside of the lock.
  858. //
  859. for (unsigned i=0; i<cItems; i++)
  860. {
  861. if ( (_wcsicmp(aIDQFile[i]->GetIDQFileName(), wcsFileName) == 0) &&
  862. (aIDQFile[i]->GetCodePage() == codePage) &&
  863. (aIDQFile[i]->IsCachedDataValid() )
  864. )
  865. {
  866. pIDQFile = aIDQFile[i];
  867. ciGibDebugOut(( DEB_ITRACE,
  868. "A cached version of IDQ file %ws was found\n",
  869. wcsFileName ));
  870. break;
  871. }
  872. }
  873. }
  874. CATCH( CException, e )
  875. {
  876. sc = e.GetErrorCode();
  877. }
  878. END_CATCH
  879. //
  880. // If pIDQFile is non-0, we've found a match. Decrement the ref-count
  881. // for all items which did not match.
  882. //
  883. for (unsigned i=0; i<cItems; i++)
  884. {
  885. if ( pIDQFile != aIDQFile[i] )
  886. {
  887. aIDQFile[i]->Release();
  888. }
  889. }
  890. if ( S_OK != sc )
  891. {
  892. Win4Assert( 0 == pIDQFile );
  893. THROW( CException( sc ) );
  894. }
  895. //
  896. // We may have matched, but still not have access to this file. First, make
  897. // a quick check for an exact match on security token, and then try harder
  898. // by opening the file.
  899. //
  900. if ( 0 != pIDQFile )
  901. {
  902. if ( !pIDQFile->CheckSecurity( securityIdentity ) )
  903. {
  904. HANDLE h = CreateFile( wcsFileName,
  905. GENERIC_READ,
  906. FILE_SHARE_READ,
  907. 0,
  908. OPEN_EXISTING,
  909. 0,
  910. 0 );
  911. //
  912. // Don't try to determine here if security caused the problem.
  913. // Just let the standard exception handling below in file parsing
  914. // deal with the error.
  915. //
  916. if ( INVALID_HANDLE_VALUE == h )
  917. {
  918. pIDQFile->Release();
  919. pIDQFile = 0;
  920. }
  921. else
  922. {
  923. CloseHandle( h );
  924. //
  925. // Update the security token of the cached Idq file,
  926. // to optimize away the CreateFile check in two cases:
  927. // 1. When the file is first parsed with admin
  928. // privileges, and all subsequent queries are with
  929. // anonymous privileges.
  930. // 2. When the security token changes over time
  931. //
  932. pIDQFile->SetSecurityToken( securityIdentity );
  933. }
  934. }
  935. }
  936. //
  937. // If we didn't find a match, then open and parse a new IDQ file, and
  938. // add it to the list of parsed IDQ files
  939. //
  940. if ( 0 == pIDQFile )
  941. {
  942. ciGibDebugOut(( DEB_ITRACE, "Adding IDQ file %ws to cache\n", wcsFileName ));
  943. pIDQFile = new CIDQFile(wcsFileName, codePage, securityIdentity);
  944. XPtr<CIDQFile> xIDQFile( pIDQFile );
  945. pIDQFile->ParseFile();
  946. {
  947. // ==========================================
  948. CLock lock( _mutex );
  949. _aIDQFile.Add( pIDQFile, _aIDQFile.Count() );
  950. pIDQFile->LokAddRef();
  951. // ==========================================
  952. }
  953. xIDQFile.Acquire();
  954. }
  955. return pIDQFile;
  956. }
  957. //+---------------------------------------------------------------------------
  958. //
  959. // Member: CIDQFileList::~CIDQFileList - public destructor
  960. //
  961. // History: 96/Mar/27 DwightKr Created.
  962. //
  963. //----------------------------------------------------------------------------
  964. CIDQFileList::~CIDQFileList()
  965. {
  966. for (unsigned i=0; i<_aIDQFile.Count(); i++)
  967. {
  968. ciGibDebugOut(( DEB_ITRACE,
  969. "Deleting IDQ cache entry %ws\n",
  970. _aIDQFile[i]->GetIDQFileName() ));
  971. delete _aIDQFile[i];
  972. }
  973. }
  974. //+---------------------------------------------------------------------------
  975. //
  976. // Member: CIDQFileList::Release - public
  977. //
  978. // Synopsis: Releases the IDQ file by decrementing its refcount.
  979. //
  980. // Arguments: [idqFile] -- pointer to the IDQ file object
  981. //
  982. // History: 96/Mar/27 DwightKr Created.
  983. //
  984. //----------------------------------------------------------------------------
  985. void CIDQFileList::Release( CIDQFile & idqFile )
  986. {
  987. idqFile.Release();
  988. }
  989. //+---------------------------------------------------------------------------
  990. //
  991. // Member: CIDQFileList::DeleteZombies - public
  992. //
  993. // Synopsis: Removes IDQ files that are zombies; i.e. out of date
  994. //
  995. // History: 96/Mar/28 DwightKr Created.
  996. //
  997. //----------------------------------------------------------------------------
  998. void CIDQFileList::DeleteZombies()
  999. {
  1000. // ==========================================
  1001. CLock lock( _mutex );
  1002. unsigned i=0;
  1003. while ( i<_aIDQFile.Count() )
  1004. {
  1005. if ( _aIDQFile[i]->LokGetRefCount() == 0 &&
  1006. !_aIDQFile[i]->IsCachedDataValid() )
  1007. {
  1008. CIDQFile * pIDQFile = _aIDQFile[i];
  1009. _aIDQFile.Remove(i);
  1010. ciGibDebugOut(( DEB_ITRACE,
  1011. "Deleting zombie IDQ cache entry %ws, %d entries cached\n",
  1012. pIDQFile->GetIDQFileName(),
  1013. _aIDQFile.Count() ));
  1014. delete pIDQFile;
  1015. }
  1016. else
  1017. {
  1018. ciGibDebugOut(( DEB_ITRACE,
  1019. "IDQ cache entry %ws was not deleted, refCount=%d\n",
  1020. _aIDQFile[i]->GetIDQFileName(),
  1021. _aIDQFile[i]->LokGetRefCount() ));
  1022. i++;
  1023. }
  1024. }
  1025. // ==========================================
  1026. }