Source code of Windows XP (NT5)
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.

1061 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1996 - 1998, Microsoft Corporation.
  4. //
  5. // File: htx.cxx
  6. //
  7. // Contents: Parser for a HTX file
  8. //
  9. // History: 96/Jan/3 DwightKr Created
  10. //
  11. //----------------------------------------------------------------------------
  12. #include <pch.cxx>
  13. #pragma hdrstop
  14. #include <cgiesc.hxx>
  15. #include <htmlchar.hxx>
  16. #include "whtmplat.hxx"
  17. #include "webdbg.hxx"
  18. #include "whmsg.h"
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CWTXScanner::CWTXScanner - public constructor
  22. //
  23. // Synopsis: Builds a scanner for a section within a HTX file
  24. //
  25. // Arguments: [variableSet] - list of replaceable parameters
  26. // [wcsPrefix] - prefix delimiter for replacable parameters
  27. // [wcsSuffix] - suffix delimiter for replacable parameters
  28. //
  29. // Notes: The wcsPrefix and wcsSuffix are expected to be the same
  30. // length and either one or two characters.
  31. //
  32. // History: 96/Jan/03 DwightKr created
  33. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  34. // htx.cxx/htx.hxx
  35. //
  36. //----------------------------------------------------------------------------
  37. CWTXScanner::CWTXScanner( CWHVarSet & variableSet,
  38. WCHAR const * wcsPrefix,
  39. WCHAR const * wcsSuffix ) :
  40. _wcsPrefix(wcsPrefix),
  41. _wcsSuffix(wcsSuffix),
  42. _variableSet(variableSet),
  43. _type(eNone),
  44. _nextType(eNone),
  45. _wcsString(0),
  46. _wcsPrefixToken(0),
  47. _wcsSuffixToken(0)
  48. {
  49. Win4Assert( wcslen( _wcsPrefix ) == wcslen( _wcsSuffix ) &&
  50. wcslen( _wcsPrefix ) <= 2 );
  51. if ( _wcsPrefix[1] == L'\0' )
  52. _cchPrefix = _cchSuffix = 1;
  53. else
  54. _cchPrefix = _cchSuffix = 2;
  55. }
  56. //+---------------------------------------------------------------------------
  57. //
  58. // Member: CWTXScanner::Init - public
  59. //
  60. // Synopsis: Saves a pointer to the string to be parsed.
  61. //
  62. // Arguments: [wcsString] - the string to be parsed
  63. //
  64. // History: 96/Jan/03 DwightKr created
  65. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  66. // htx.cxx/htx.hxx
  67. //
  68. // NOTES: THIS STRING WILL BE MODIFIED BY SUBSEQUENT CALLS TO MEMBER
  69. // FUNCTIONS OF THIS CLASS.
  70. //
  71. //----------------------------------------------------------------------------
  72. void CWTXScanner::Init( WCHAR * wcsString )
  73. {
  74. _wcsString = wcsString;
  75. }
  76. //+---------------------------------------------------------------------------
  77. //
  78. // Member: CWTXScanner::IsToken - private
  79. //
  80. // Synopsis: Determines if a string is a special token.
  81. //
  82. // Arguments: [wcs] - start of string to be tested.
  83. //
  84. // Notes: If the string is a token, the members _type, _wcsPrefixToken
  85. // and _wcsSuffixToken are set appropriately.
  86. //
  87. // History: 96/Apr/02 AlanW Created
  88. // 96/May/17 DwightKr Treat all <%..%> as variables
  89. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  90. // htx.cxx/htx.hxx
  91. //
  92. //----------------------------------------------------------------------------
  93. BOOL CWTXScanner::IsToken(WCHAR * wcs)
  94. {
  95. if ( wcsncmp( _wcsPrefix, wcs, _cchPrefix ) != 0 )
  96. {
  97. webDebugOut(( DEB_USER1, "CWTXScanner::IsToken end of string\n" ));
  98. return FALSE;
  99. }
  100. wcs += _cchPrefix;
  101. WCHAR * wcsSuffixTok = wcs2chr( wcs, _wcsSuffix );
  102. if ( 0 == wcsSuffixTok )
  103. {
  104. webDebugOut(( DEB_USER1, "CWTXScanner::IsToken no suffix token\n" ));
  105. return FALSE;
  106. }
  107. *wcsSuffixTok = L'\0';
  108. _wcsPrefixToken = wcs - _cchPrefix;
  109. _wcsupr( wcs );
  110. //
  111. // Strip leading spaces before token
  112. //
  113. while ( iswspace(*wcs) && (wcs < wcsSuffixTok) )
  114. {
  115. wcs++;
  116. }
  117. //
  118. // Strip trailing spaces after token
  119. //
  120. WCHAR * wcsSuffix = wcsSuffixTok - 1;
  121. while ( iswspace(*wcsSuffix) && (wcsSuffix > wcs) )
  122. {
  123. *wcsSuffix = 0;
  124. wcsSuffix--;
  125. }
  126. webDebugOut(( DEB_USER1, "CWTXScanner::IsToken wcs=%ws\n", wcs ));
  127. if ( wcsncmp( wcs, L"ESCAPEHTML ", 11 ) == 0 )
  128. {
  129. _type = eEscapeHTML;
  130. }
  131. else if ( wcsncmp( wcs, L"ESCAPEURL ", 10 ) == 0 )
  132. {
  133. _type = eEscapeURL;
  134. }
  135. else if ( wcsncmp( wcs, L"ESCAPERAW ", 10 ) == 0 )
  136. {
  137. _type = eEscapeRAW;
  138. }
  139. else
  140. {
  141. //
  142. // Find this name in the list of replaceable parameters. Note that
  143. // if we can't find this variable in the list of replaceable
  144. // parameters, we've converted some output text to uppercase. This
  145. // is probably OK since the user used <% ... %> to delimit their
  146. // output; <% & %> are reserved tokens hence this would be an error.
  147. //
  148. WCHAR const *pVariable = _variableSet.Find( wcs );
  149. _type = eParameter;
  150. if ( 0 == pVariable )
  151. {
  152. webDebugOut(( DEB_IWARN,
  153. "Warning: CWTXScanner::IsToken found a unknown variable: '%ws'\n",
  154. wcs ));
  155. }
  156. }
  157. *_wcsPrefixToken = L'\0';
  158. _wcsSuffixToken = wcsSuffixTok;
  159. _wcsNextToken = wcsSuffixTok + _cchSuffix;
  160. return TRUE;
  161. }
  162. //+---------------------------------------------------------------------------
  163. //
  164. // Member: CWTXScanner::FindNextToken - public
  165. //
  166. // Synopsis: Locates the next token in the string.
  167. //
  168. // History: 96/Jan/03 DwightKr created
  169. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  170. // htx.cxx/htx.hxx
  171. //
  172. //----------------------------------------------------------------------------
  173. BOOL CWTXScanner::FindNextToken()
  174. {
  175. if (_nextType != eNone)
  176. {
  177. //
  178. // Found a token on the previous call. Just return it.
  179. //
  180. Win4Assert ( _wcsPrefixToken && _wcsSuffixToken > _wcsPrefixToken );
  181. _type = _nextType;
  182. _nextType = eNone;
  183. _wcsString = _wcsNextToken = _wcsSuffixToken + _cchSuffix;
  184. return TRUE;
  185. }
  186. if ( (0 == _wcsString) || (0 == *_wcsString) )
  187. {
  188. _type = eNone;
  189. _wcsNextToken = 0;
  190. return FALSE;
  191. }
  192. if ( *_wcsString == *_wcsPrefix &&
  193. IsToken( _wcsString ) )
  194. {
  195. _nextType = eNone;
  196. return TRUE;
  197. }
  198. //
  199. // The string doesn't start with one of our special keywords.
  200. // Treat it as an ordinary string, and look ahead to the next
  201. // valid token.
  202. //
  203. _wcsPrefixToken = wcs2chr( _wcsString+1, _wcsPrefix );
  204. while ( _wcsPrefixToken )
  205. {
  206. if ( IsToken( _wcsPrefixToken ) )
  207. {
  208. _nextType = _type;
  209. _wcsNextToken = _wcsPrefixToken;
  210. _type = eString;
  211. return TRUE;
  212. }
  213. _wcsPrefixToken = wcs2chr( _wcsPrefixToken+_cchPrefix, _wcsPrefix );
  214. }
  215. _nextType = eNone;
  216. _type = eString;
  217. _wcsNextToken = _wcsString + wcslen( _wcsString );
  218. return TRUE;
  219. }
  220. //+---------------------------------------------------------------------------
  221. //
  222. // Member: CWTXScanner::GetToken - public
  223. //
  224. // Synopsis: Returns a pointer to the replaceable parameter token found.
  225. // Prepares the scanner to return the next token.
  226. //
  227. // History: 96/Jan/03 DwightKr created
  228. // 96/Mar/13 DwightKr add support for eEscapeURL &
  229. // eEscapeHTML
  230. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  231. // htx.cxx/htx.hxx
  232. //
  233. //----------------------------------------------------------------------------
  234. WCHAR * CWTXScanner::GetToken()
  235. {
  236. if ( eString == _type )
  237. {
  238. if ( 0 != _wcsString )
  239. {
  240. WCHAR * wcsString = _wcsString;
  241. _wcsString = _wcsNextToken;
  242. return wcsString;
  243. }
  244. }
  245. else if ( eEscapeHTML == _type )
  246. {
  247. WCHAR * wcsString = _wcsPrefixToken + _cchPrefix;
  248. wcsString += 10; // Skip 'EscapeHTML'
  249. *_wcsSuffixToken = 0; // Null terminate
  250. while ( (0 != *wcsString) && iswspace(*wcsString) )
  251. {
  252. wcsString++;
  253. }
  254. _wcsString = _wcsNextToken;
  255. return wcsString;
  256. }
  257. else if ( eEscapeURL == _type ||
  258. eEscapeRAW == _type )
  259. {
  260. WCHAR * wcsString = _wcsPrefixToken + _cchPrefix;
  261. wcsString += 9; // Skip 'EscapeURL'
  262. *_wcsSuffixToken = 0; // Null terminate
  263. while ( (0 != *wcsString) && iswspace(*wcsString) )
  264. {
  265. wcsString++;
  266. }
  267. _wcsString = _wcsNextToken;
  268. return wcsString;
  269. }
  270. else
  271. {
  272. if ( 0 != _wcsPrefixToken )
  273. {
  274. Win4Assert( 0 != _wcsSuffixToken &&
  275. _wcsPrefixToken < _wcsSuffixToken &&
  276. _wcsSuffixToken < _wcsNextToken );
  277. *_wcsPrefixToken = 0;
  278. *_wcsSuffixToken = 0;
  279. _wcsString = _wcsNextToken;
  280. WCHAR * wcsString = _wcsPrefixToken + _cchPrefix;
  281. while ( (0 != *wcsString) && iswspace(*wcsString) )
  282. {
  283. wcsString++;
  284. }
  285. return wcsString;
  286. }
  287. }
  288. return 0;
  289. }
  290. //+---------------------------------------------------------------------------
  291. //
  292. // Member: CWTXFile::CWTXFile - public constructor
  293. //
  294. // Synopsis: Builds a CWTXFile object and initializes values.
  295. //
  296. // History: 96/Jan/03 DwightKr created
  297. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  298. // htx.cxx/htx.hxx
  299. //
  300. //----------------------------------------------------------------------------
  301. CWTXFile::CWTXFile( WCHAR const * wcsTemplate,
  302. WCHAR const * wcsPhysicalName,
  303. UINT codePage) :
  304. _wcsVirtualName( wcsTemplate ),
  305. _wcsPhysicalName( wcsPhysicalName ),
  306. _pVarHeader(0),
  307. _pVarRowDetails(0),
  308. _pVarFooter(0),
  309. _wcsFileBuffer(0),
  310. _codePage(codePage)
  311. {
  312. }
  313. //+---------------------------------------------------------------------------
  314. //
  315. // Member: CWTXFile::~CWTXFile - public destructor
  316. //
  317. // History: 96/Jan/03 DwightKr created
  318. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  319. // htx.cxx/htx.hxx
  320. //
  321. //----------------------------------------------------------------------------
  322. CWTXFile::~CWTXFile()
  323. {
  324. delete _pVarHeader;
  325. delete _pVarRowDetails;
  326. delete _pVarFooter;
  327. delete _wcsFileBuffer;
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Member: CWTXFile::ParseFile - public
  332. //
  333. // Synopsis: Parses the HTX file and breaks it up into its sections.
  334. //
  335. // History: 96/Jan/03 DwightKr created
  336. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  337. // htx.cxx/htx.hxx
  338. //
  339. //----------------------------------------------------------------------------
  340. void CWTXFile::ParseFile( CWHVarSet & variableSet )
  341. {
  342. //
  343. // Read the entire file into a buffer
  344. //
  345. _wcsFileBuffer = ReadFile( _wcsPhysicalName );
  346. Win4Assert( 0 != _wcsFileBuffer );
  347. //
  348. // Break the buffer into the sections; the header, the detail section,
  349. // and the footer. Verify that if there is a <%BeginDetail%>
  350. // section, then there MUST be a <%EndDetail%> section AFTER it, not
  351. // before. Neither <%EndDetail%> nor <%BeginDetail%> can appear on
  352. // their own.
  353. //
  354. //
  355. // Find the <%BeginDetail%> and <%EndDetail%> sections
  356. //
  357. WCHAR * wcsHeader = _wcsFileBuffer; // Assume a header
  358. WCHAR * wcsRowDetails = wcsipattern(wcsHeader, L"<%BEGINDETAIL%>" );
  359. WCHAR * wcsFooter = wcsipattern(wcsHeader, L"<%ENDDETAIL%>" );
  360. if ( wcsHeader == wcsRowDetails )
  361. {
  362. //
  363. // No header found in this file; it begins with the detail section.
  364. //
  365. wcsHeader = 0;
  366. }
  367. const int cwcBeginDetail = 15;
  368. const int cwcEndDetail = 13;
  369. Win4Assert( cwcBeginDetail == wcslen( L"<%BEGINDETAIL%>" ) );
  370. Win4Assert( cwcEndDetail == wcslen( L"<%ENDDETAIL%>" ) );
  371. if ( 0 != wcsRowDetails )
  372. {
  373. //
  374. // A <%BeginDetail%> section was found. We better also have an
  375. // <%EndDetail%> section AFTER the <%BeginDetail%> section.
  376. //
  377. *wcsRowDetails = 0; // Null terminate the header string
  378. wcsRowDetails += cwcBeginDetail;
  379. if ( 0 != wcsFooter )
  380. {
  381. if ( wcsFooter < wcsRowDetails )
  382. {
  383. //
  384. // The <%EndDetail%> was found before the <%BeginDetail%>
  385. //
  386. WCHAR * wcsHTXFileName;
  387. LONG lLineNumber;
  388. GetFileNameAndLineNumber( CiPtrToInt( wcsFooter - _wcsFileBuffer ),
  389. wcsHTXFileName,
  390. lLineNumber );
  391. THROW( CWTXException(MSG_WEBHITS_ENDDETAIL_BEFORE_BEGINDETAIL,
  392. wcsHTXFileName,
  393. lLineNumber) );
  394. }
  395. *wcsFooter = 0; // Null terminate the BeginDetail section
  396. wcsFooter += cwcEndDetail;
  397. }
  398. else
  399. {
  400. //
  401. // Report an error: <%BeginDetail%> without an <%EndDetail%>
  402. //
  403. WCHAR * wcsHTXFileName;
  404. LONG lLineNumber;
  405. GetFileNameAndLineNumber( CiPtrToInt( wcsRowDetails - _wcsFileBuffer ),
  406. wcsHTXFileName,
  407. lLineNumber );
  408. THROW( CWTXException(MSG_WEBHITS_NO_ENDDETAIL_SECTION,
  409. wcsHTXFileName,
  410. lLineNumber) );
  411. }
  412. }
  413. else if ( 0 != wcsFooter )
  414. {
  415. //
  416. // A <%BeginDetail%> section could be found. There should
  417. // be no <%EndDetail%> section either.
  418. //
  419. WCHAR * wcsHTXFileName;
  420. LONG lLineNumber;
  421. GetFileNameAndLineNumber( CiPtrToInt( wcsFooter - _wcsFileBuffer ),
  422. wcsHTXFileName,
  423. lLineNumber );
  424. THROW( CWTXException(MSG_WEBHITS_NO_BEGINDETAIL_SECTION,
  425. wcsHTXFileName,
  426. lLineNumber) );
  427. }
  428. if ( 0 != wcsHeader )
  429. {
  430. _pVarHeader = new CWHParamReplacer ( wcsHeader,
  431. L"<%",
  432. L"%>" );
  433. _pVarHeader->ParseString( variableSet );
  434. }
  435. if ( 0 != wcsRowDetails )
  436. {
  437. _pVarRowDetails = new CWHParamReplacer ( wcsRowDetails,
  438. L"<%",
  439. L"%>" );
  440. _pVarRowDetails->ParseString( variableSet );
  441. }
  442. if ( 0 != wcsFooter )
  443. {
  444. _pVarFooter = new CWHParamReplacer ( wcsFooter,
  445. L"<%",
  446. L"%>" );
  447. _pVarFooter->ParseString( variableSet );
  448. }
  449. }
  450. //+---------------------------------------------------------------------------
  451. //
  452. // Member: CWTXFile::ReadFile - public
  453. //
  454. // Synopsis: Read the HTX file into a buffer
  455. //
  456. // Arguments: [wcsFileName] - full physical path name of file
  457. //
  458. // History: 96/Jan/03 DwightKr created
  459. // 96/Apr/06 DwightKr add support for unicode files
  460. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  461. // htx.cxx/htx.hxx
  462. //
  463. //----------------------------------------------------------------------------
  464. WCHAR * CWTXFile::ReadFile( WCHAR const * wcsFileName )
  465. {
  466. Win4Assert ( 0 != wcsFileName );
  467. //
  468. // Verify the HTX file exists, and is a file, not a directory.
  469. //
  470. WIN32_FIND_DATA ffData;
  471. if ( !GetFileAttributesEx( wcsFileName, GetFileExInfoStandard, &ffData ) )
  472. {
  473. ULONG error = GetLastError();
  474. webDebugOut(( DEB_IERROR,
  475. "Unable to GetFileAttributesEx(%ws) GetLastError=0x%x\n",
  476. wcsFileName,
  477. error ));
  478. THROW( CWTXException(MSG_WEBHITS_NO_SUCH_TEMPLATE, _wcsVirtualName, 0) );
  479. }
  480. if ( (ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 )
  481. {
  482. THROW( CWTXException(MSG_WEBHITS_NO_SUCH_TEMPLATE, _wcsVirtualName, 0) );
  483. }
  484. //
  485. // Open the file and map its contents
  486. //
  487. CFileMapView mapView( wcsFileName );
  488. mapView.Init();
  489. int cbBuffer = mapView.GetBufferSize() + 1;
  490. XArray<WCHAR> pwBuffer(cbBuffer);
  491. //
  492. // If the first two BYTES of the file are 0xFF 0xFE, then this is a
  493. // unicode file, and we don't need to convert it.
  494. //
  495. if ( mapView.IsUnicode() )
  496. {
  497. RtlCopyMemory( pwBuffer.Get(), mapView.GetBuffer()+2, cbBuffer-2 );
  498. pwBuffer[ ( cbBuffer - 2 ) / sizeof WCHAR ] = 0;
  499. return pwBuffer.Acquire();
  500. }
  501. //
  502. // Copy & convert the ASCII buffer to a WCHAR buffer.
  503. //
  504. int cwBuffer = mapView.GetBufferSize() + 1;
  505. int cwConvert;
  506. do
  507. {
  508. cwConvert = MultiByteToWideChar( _codePage,
  509. 0,
  510. (const char *) mapView.GetBuffer(), // Ptr to input buf
  511. mapView.GetBufferSize(),// Size of input buf
  512. pwBuffer.Get(), // Ptr to output buf
  513. cwBuffer - 1 ); // Size of output buf
  514. if ( 0 == cwConvert )
  515. {
  516. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  517. {
  518. cwBuffer += (cwBuffer/2);
  519. delete pwBuffer.Acquire();
  520. pwBuffer.Init(cwBuffer);
  521. }
  522. else
  523. {
  524. THROW( CException() );
  525. }
  526. }
  527. else
  528. {
  529. pwBuffer[cwConvert] = 0; // Null terminate the buffer
  530. }
  531. Win4Assert( cwConvert < cwBuffer );
  532. } while ( 0 == cwConvert );
  533. return pwBuffer.Acquire();
  534. }
  535. //+---------------------------------------------------------------------------
  536. //
  537. // Member: CWTXFile::GetFileNameAndLineNumber
  538. //
  539. // Synopsis: Determines the filename & line number amoung a group of
  540. // nested includes for a particular offset into the buffer.
  541. //
  542. // Arguments: [offset] - offset of the error in the overall buffer
  543. // [wcsFileName] - resulting name of file containing error
  544. // [lineNumber] - line # containing the error
  545. //
  546. // History: 96/Jun/25 DwightKr created
  547. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  548. // htx.cxx/htx.hxx
  549. //
  550. //----------------------------------------------------------------------------
  551. void CWTXFile::GetFileNameAndLineNumber( int offset,
  552. WCHAR const *& wcsFileName,
  553. LONG & lineNumber )
  554. {
  555. //
  556. // Save a pointer to the name of the file containing the error
  557. //
  558. WCHAR const * pCurrent = _wcsFileBuffer;
  559. wcsFileName = _wcsVirtualName;
  560. //
  561. // Count the number of lines in this sub-file
  562. //
  563. Win4Assert( 0 != _wcsFileBuffer );
  564. WCHAR const * pEnd = _wcsFileBuffer + offset;
  565. lineNumber = CountLines( pCurrent, pEnd );
  566. }
  567. //+---------------------------------------------------------------------------
  568. //
  569. // Member: CWTXFile::CountLines - private
  570. //
  571. // Synopsis: Deterines the number of lines (CR's) between the start
  572. // of the buffer and the end.
  573. //
  574. // Arguments: [wcsStart] - start location of search
  575. // [wcsEnd] - end of search
  576. //
  577. // History: 96/Jun/25 DwightKr created
  578. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  579. // htx.cxx/htx.hxx
  580. //
  581. //----------------------------------------------------------------------------
  582. LONG CWTXFile::CountLines( WCHAR const * wcsStart,
  583. WCHAR const * wcsEnd ) const
  584. {
  585. Win4Assert( 0 != wcsStart );
  586. Win4Assert( 0 != wcsEnd );
  587. LONG cLines = 1;
  588. while ( wcsStart <= wcsEnd )
  589. {
  590. if ( L'\n' == *wcsStart )
  591. {
  592. cLines++;
  593. }
  594. wcsStart++;
  595. }
  596. return cLines;
  597. }
  598. //+---------------------------------------------------------------------------
  599. //
  600. // Member: CWTXFile::GetHeader - public
  601. //
  602. // Synopsis: Appends to a CVirtualString the data in the HTX file BEFORE
  603. // the <%begindetail%> section. This may require replacing
  604. // parameters.
  605. //
  606. // Arguments: [string] - the CVirtualString to append data to
  607. // [variableSet] - a list of replaceable parameters
  608. // [outputFormat] - format for numbers & dates
  609. //
  610. // History: 96/Jan/03 DwightKr created
  611. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  612. // htx.cxx/htx.hxx
  613. //
  614. //----------------------------------------------------------------------------
  615. void CWTXFile::GetHeader( CVirtualString & string,
  616. CWHVarSet & variableSet )
  617. {
  618. if ( 0 != _pVarHeader )
  619. {
  620. _pVarHeader->ReplaceParams( string, variableSet, _codePage );
  621. }
  622. }
  623. //+---------------------------------------------------------------------------
  624. //
  625. // Member: CWTXFile::GetFooter - public
  626. //
  627. // Synopsis: Appends to a CVirtualString the data in the HTX file AFTER
  628. // the <%enddetail%> section. This may require replacing
  629. // parameters.
  630. //
  631. // Arguments: [string] - the CVirtualString to append data to
  632. // [variableSet] - a list of replaceable parameters
  633. // [outputFormat] - format for numbers & dates
  634. //
  635. // History: 96/Jan/03 DwightKr created
  636. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  637. // htx.cxx/htx.hxx
  638. //
  639. //----------------------------------------------------------------------------
  640. void CWTXFile::GetFooter( CVirtualString & string,
  641. CWHVarSet & variableSet )
  642. {
  643. if ( 0 != _pVarFooter )
  644. {
  645. _pVarFooter->ReplaceParams( string, variableSet, _codePage );
  646. }
  647. }
  648. //+---------------------------------------------------------------------------
  649. //
  650. // Member: CWHVarSet::GetStringValueHTML
  651. //
  652. // Synopsis: Get variable value formatted as HTML
  653. //
  654. // Arguments: [wcsName] -
  655. // [str] -
  656. // [ulCodepage] - code page for translation
  657. //
  658. // History: 9-09-96 srikants Created
  659. //
  660. //----------------------------------------------------------------------------
  661. BOOL CWHVarSet::GetStringValueHTML( WCHAR const * wcsName,
  662. CVirtualString & str,
  663. ULONG ulCodepage )
  664. {
  665. WCHAR const * pwcsValue = Find( wcsName );
  666. if ( pwcsValue )
  667. {
  668. HTMLEscapeW( pwcsValue, str, ulCodepage );
  669. return TRUE;
  670. }
  671. else return FALSE;
  672. }
  673. //+---------------------------------------------------------------------------
  674. //
  675. // Member: CWHVarSet::GetStringValueURL
  676. //
  677. // Synopsis: Get variable value formatted as for a URL
  678. //
  679. // Arguments: [wcsName] -
  680. // [str] -
  681. // [ulCodepage] - code page for translation
  682. //
  683. // History: 9-09-96 srikants Created
  684. //
  685. //----------------------------------------------------------------------------
  686. BOOL CWHVarSet::GetStringValueURL( WCHAR const * wcsName,
  687. CVirtualString & str,
  688. ULONG ulCodepage )
  689. {
  690. WCHAR const * pwcsValue = Find( wcsName );
  691. if ( pwcsValue )
  692. {
  693. URLEscapeW( pwcsValue, str, ulCodepage );
  694. return TRUE;
  695. }
  696. else return FALSE;
  697. }
  698. //+---------------------------------------------------------------------------
  699. //
  700. // Member: CWHParamNode::~CWHParamNode
  701. //
  702. // Synopsis:
  703. //
  704. // History: 9-09-96 srikants Created
  705. //
  706. //----------------------------------------------------------------------------
  707. CWHParamNode::~CWHParamNode()
  708. {
  709. if ( 0 != _pNext )
  710. delete _pNext;
  711. }
  712. //+---------------------------------------------------------------------------
  713. //
  714. // Member: CWHParamReplacer::CWHParamReplacer
  715. //
  716. // Synopsis:
  717. //
  718. // Arguments: [wcsString] -
  719. // [wcsPrefix] -
  720. // [wcsSuffix] -
  721. //
  722. // History: 9-09-96 srikants Created
  723. //
  724. //----------------------------------------------------------------------------
  725. CWHParamReplacer::CWHParamReplacer( WCHAR const * wcsString,
  726. WCHAR const * wcsPrefix,
  727. WCHAR const * wcsSuffix ) :
  728. _wcsString(0),
  729. _wcsPrefix(wcsPrefix),
  730. _wcsSuffix(wcsSuffix),
  731. _ulFlags(0),
  732. _paramNode(L"Top")
  733. {
  734. Win4Assert( 0 != wcsString );
  735. Win4Assert( 0 != wcsPrefix );
  736. Win4Assert( 0 != wcsSuffix );
  737. ULONG cwcString = wcslen(wcsString) + 1;
  738. _wcsString = new WCHAR[ cwcString ];
  739. RtlCopyMemory( _wcsString, wcsString, cwcString * sizeof(WCHAR) );
  740. }
  741. //+---------------------------------------------------------------------------
  742. //
  743. // Member: CWHParamReplacer::ParseString
  744. //
  745. // Synopsis:
  746. //
  747. // Arguments: [variableSet] -
  748. //
  749. // History: 9-09-96 srikants Created
  750. //
  751. //----------------------------------------------------------------------------
  752. void CWHParamReplacer::ParseString( CWHVarSet & variableSet )
  753. {
  754. CWTXScanner scanner( variableSet, _wcsPrefix, _wcsSuffix );
  755. scanner.Init( _wcsString );
  756. BuildList( scanner, &_paramNode );
  757. }
  758. //+---------------------------------------------------------------------------
  759. //
  760. // Member: CWHParamReplacer::ReplaceParams - public
  761. //
  762. // Synopsis: Generates a new string replacing all %values% in the original
  763. // string
  764. //
  765. // Arguments: [StrResult] - a safe string to append the new params to
  766. // [variableSet] - the list of replaceable parameter values
  767. //
  768. // Notes: If expressions are handled in the parameter node iterator.
  769. //
  770. // History: 96/Jan/03 DwightKr Created.
  771. // 96/Sep/07 SrikantS Copied and adapted to webhits use from
  772. // htx.cxx/htx.hxx
  773. //
  774. //----------------------------------------------------------------------------
  775. void CWHParamReplacer::ReplaceParams( CVirtualString & StrResult,
  776. CWHVarSet & variableSet,
  777. ULONG ulCodepage )
  778. {
  779. for ( CWHParamNodeIter iter(&_paramNode);
  780. !iter.AtEnd();
  781. iter.Next() )
  782. {
  783. CWHParamNode * pNode = iter.Get();
  784. ULONG type = pNode->Type() & eJustParamMask;
  785. switch ( type )
  786. {
  787. case eString:
  788. StrResult.StrCat( pNode->String(), pNode->Length() );
  789. break;
  790. case eParameter:
  791. case eEscapeHTML:
  792. {
  793. if (! variableSet.GetStringValueHTML( pNode->String(),
  794. StrResult, ulCodepage ) )
  795. {
  796. webDebugOut(( DEB_IWARN,
  797. "Warning: CWHParamReplacer::ReplaceParams GetStringValueHTML returned FALSE for '%ws'\n",
  798. pNode->String() ));
  799. if ( eParameter == type )
  800. StrResult.StrCat( _wcsPrefix );
  801. HTMLEscapeW( pNode->String(), StrResult, ulCodepage );
  802. if ( eParameter == type )
  803. StrResult.StrCat( _wcsSuffix );
  804. }
  805. }
  806. break;
  807. case eEscapeURL:
  808. {
  809. if (! variableSet.GetStringValueURL( pNode->String(),
  810. StrResult, ulCodepage ) )
  811. {
  812. webDebugOut(( DEB_IWARN,
  813. "Warning: CWHParamReplacer::ReplaceParams GetStringValueURL returned FALSE for '%ws'\n",
  814. pNode->String() ));
  815. URLEscapeW( pNode->String(), StrResult, ulCodepage );
  816. }
  817. }
  818. break;
  819. case eEscapeRAW:
  820. {
  821. ULONG cwcValue;
  822. WCHAR const * wcsValue = variableSet.GetStringValueRAW( pNode->String(),
  823. cwcValue );
  824. if ( 0 != wcsValue )
  825. {
  826. StrResult.StrCat( wcsValue, cwcValue );
  827. }
  828. else
  829. {
  830. webDebugOut(( DEB_IWARN,
  831. "Warning: CWHParamReplacer::ReplaceParams GetStringValueRAW returned NULL for '%ws'\n",
  832. pNode->String() ));
  833. StrResult.StrCat( pNode->String(), pNode->Length() );
  834. }
  835. }
  836. break;
  837. #if DBG==1
  838. case eNone :
  839. break;
  840. default :
  841. DbgPrint(" unexpected param type: 0x%lx\n", type );
  842. Win4Assert( !"unexpected parameter type" );
  843. break;
  844. #endif // DBG==1
  845. }
  846. }
  847. }
  848. //+---------------------------------------------------------------------------
  849. //
  850. // Member: CWHParamReplacer::BuildList
  851. //
  852. // Synopsis: Builds a list of the parameters.
  853. //
  854. // Arguments: [scanner] -
  855. // [pPrev] -
  856. //
  857. // History: 9-09-96 srikants Created
  858. //
  859. //----------------------------------------------------------------------------
  860. void CWHParamReplacer::BuildList( CWTXScanner & scanner,
  861. CWHParamNode *pPrev )
  862. {
  863. CWHParamNode *pNode = 0;
  864. while ( scanner.FindNextToken() )
  865. {
  866. switch ( scanner.TokenType() & eParamMask )
  867. {
  868. case eString:
  869. {
  870. //
  871. // A non-replaceable wcsString was found before any replaceable/
  872. // conditional nodes. Save the wcsString in a node;
  873. //
  874. pNode = new CWHParamNode( scanner.GetToken(), eString );
  875. pPrev->SetNextNode( pNode );
  876. pPrev = pNode;
  877. break;
  878. }
  879. case eParameter:
  880. {
  881. //
  882. // We've found a replaceable node.
  883. //
  884. WCHAR * wcsParameter = scanner.GetToken();
  885. pNode = new CWHParamNode( wcsParameter, eParameter );
  886. pPrev->SetNextNode( pNode );
  887. pPrev = pNode;
  888. break;
  889. }
  890. case eEscapeHTML:
  891. {
  892. WCHAR * wcsParameter = scanner.GetToken();
  893. pNode = new CWHParamNode( wcsParameter, eEscapeHTML );
  894. pPrev->SetNextNode( pNode );
  895. pPrev = pNode;
  896. }
  897. break;
  898. case eEscapeURL:
  899. {
  900. WCHAR * wcsParameter = scanner.GetToken();
  901. pNode = new CWHParamNode( wcsParameter, eEscapeURL );
  902. pPrev->SetNextNode( pNode );
  903. pPrev = pNode;
  904. }
  905. break;
  906. case eEscapeRAW:
  907. {
  908. WCHAR * wcsParameter = scanner.GetToken();
  909. pNode = new CWHParamNode( wcsParameter, eEscapeRAW );
  910. pPrev->SetNextNode( pNode );
  911. pPrev = pNode;
  912. }
  913. break;
  914. }
  915. }
  916. }