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.

2392 lines
73 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: linkhits.cxx
  7. //
  8. // Contents: classes to insert links among query hits in HTML format
  9. //
  10. //--------------------------------------------------------------------------
  11. #include<pch.cxx>
  12. #pragma hdrstop
  13. #include <locale.h>
  14. #include <mbutil.hxx>
  15. #include <htmlchar.hxx>
  16. #include <codepage.hxx>
  17. #include <cgiesc.hxx>
  18. #include <weblcid.hxx>
  19. #include "webdbg.hxx"
  20. #include "whmsg.h"
  21. #include "linkhits.hxx"
  22. #include "whtmplat.hxx"
  23. extern int _cdecl ComparePositions(const void* pPos1, const void* pPos2);
  24. const WCHAR VPathWebHitsFile[]=L"CiWebHitsFile";
  25. const WCHAR CommandLineVarName[]=L"QUERY_STRING";
  26. const WCHAR RestrictionVarName[]=L"CiRestriction";
  27. const WCHAR IDQFilenameVarName[]=L"CiQueryFile";
  28. const WCHAR WTXFilenameVarName[]=L"CiTemplateFile";
  29. const WCHAR HiliteTypeVarName[]=L"CiHiliteType";
  30. const WCHAR ColorVarName[]=L"CiHiliteColor";
  31. const WCHAR BoldVarName[]=L"CiBold";
  32. const WCHAR ItalicVarName[]=L"CiItalic";
  33. const WCHAR MaxLineLength[]=L"CiMaxLineLength";
  34. const WCHAR LocaleVar[]=L"CiLocale";
  35. const WCHAR BeginHiliteVar[]=L"CiBeginHilite";
  36. const WCHAR EndHiliteVar[]=L"CiEndHilite";
  37. const WCHAR NullHTWFile[]=L"null.htw";
  38. const WCHAR CodepageVar[]=L"CiCodepage";
  39. const WCHAR DialectVar[]=L"CiDialect";
  40. const WCHAR ParaTag[]=L"<P>\n";
  41. const WCHAR HRule[]=L"<HR>\n";
  42. const WCHAR Red24BitMask[]=L"#FF0000";
  43. const WCHAR Blue24BitMask[]=L"#0000FF";
  44. const WCHAR Green24BitMask[]=L"#00FF00";
  45. const WCHAR Black24BitMask[]=L"#000000";
  46. const WCHAR Yellow24BitMask[]=L"#FFFF00";
  47. //
  48. // List of replacable parameters in the htx file for output generation.
  49. //
  50. const WCHAR wcsParamCiUrl[] = L"CIURL";
  51. const WCHAR wcsParamRestriction[] = L"CIRESTRICTION";
  52. const WCHAR wcsCharSet[] = L"CICHARSET";
  53. const WCHAR wcsLocale[] = L"CILOCALE";
  54. const WCHAR wcsCodepage[] = L"CICODEPAGE";
  55. const WCHAR wcsUserParamPrefix[] = L"CIUSERPARAM";
  56. const ULONG cwcUserParamPrefix = (sizeof(wcsUserParamPrefix)/sizeof(WCHAR))-1;
  57. const WCHAR * awcsUserParamNames[] = {
  58. L"CIUSERPARAM1",
  59. L"CIUSERPARAM2",
  60. L"CIUSERPARAM3",
  61. L"CIUSERPARAM4",
  62. L"CIUSERPARAM5",
  63. L"CIUSERPARAM6",
  64. L"CIUSERPARAM7",
  65. L"CIUSERPARAM8",
  66. L"CIUSERPARAM9",
  67. L"CIUSERPARAM10",
  68. };
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Member: CInternalQuery::CinternalQuery, public constructor
  72. //
  73. // Arguments: [rGetEnvVars] - object that contains CGI env. variables
  74. // [rPList] - property list of properties to query
  75. // [lcid] - LCID (locale identifier)
  76. //
  77. // Synopsis: rGetEnvVars yields the textual restriction.
  78. // GetStringDbRestriction then converts it into a DbRestriction.
  79. //
  80. //--------------------------------------------------------------------------
  81. CInternalQuery::CInternalQuery(
  82. CGetEnvVars& rGetEnvVars,
  83. CEmptyPropertyList& rPList,
  84. LCID lcid ):
  85. _pDbRestriction(0),
  86. _pISearch(0)
  87. {
  88. TRY
  89. {
  90. _pDbRestriction = GetStringDbRestriction( rGetEnvVars.GetRestriction(),
  91. rGetEnvVars.GetDialect(),
  92. &rPList,
  93. lcid);
  94. }
  95. CATCH( CException, e)
  96. {
  97. webDebugOut(( DEB_ERROR, "WEBHITS: failed to get DbRestriction\n" ));
  98. delete _pDbRestriction;
  99. RETHROW();
  100. }
  101. END_CATCH
  102. }
  103. void CInternalQuery::CreateISearch( WCHAR const * pwszPath )
  104. {
  105. Win4Assert( 0 == _pISearch );
  106. SCODE sc = MakeISearch( &_pISearch, _pDbRestriction, pwszPath );
  107. if ( FAILED( sc ) )
  108. THROW( CException( sc ) );
  109. } //CreateISearch
  110. //+-------------------------------------------------------------------------
  111. //
  112. // Member: CURLUnescaper::CURLUnescaper public constructor
  113. //
  114. //--------------------------------------------------------------------------
  115. CURLUnescaper::CURLUnescaper( UINT codePage ) :
  116. _codePage(codePage)
  117. {
  118. }
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Member: CURLUnescaper::UnescapeAndConvertToUnicode
  122. //
  123. // Synopsis: Converts the given multi-byte string into a unicode string
  124. // based on the code page. Decodes URL escape sequences along
  125. // the way.
  126. //
  127. // Arguments: [pszMbStr] - smart array pointer to input string
  128. // [cch] - length of input string
  129. // [xwcsBuffer] -
  130. //
  131. // Returns: Number of characters in target buffer, excluding the
  132. // terminating NULL.
  133. //
  134. // History: 24 Nov 1997 AlanW Created
  135. //
  136. //----------------------------------------------------------------------------
  137. ULONG CURLUnescaper::UnescapeAndConvertToUnicode( char const * pszMbStr,
  138. ULONG cch,
  139. XArray<WCHAR> & xwcsBuffer )
  140. {
  141. if ( xwcsBuffer.Get() == 0 || cch+1 > xwcsBuffer.Count() )
  142. {
  143. delete [] xwcsBuffer.Acquire();
  144. xwcsBuffer.Init( cch+1 );
  145. }
  146. DecodeURLEscapes( (BYTE *)pszMbStr,
  147. cch,
  148. xwcsBuffer.Get(),
  149. _codePage );
  150. return cch;
  151. }
  152. //+-------------------------------------------------------------------------
  153. //
  154. // Member: CCollectVar::CCollectVar, public constructor
  155. //
  156. // Arguments: [rUnescaper] - reference to an unescaper object - it will
  157. // be used to unescape variables stored in
  158. // the local buffer
  159. // [webServer] - web server object from which variables
  160. // are read.
  161. //
  162. //--------------------------------------------------------------------------
  163. CCollectVar::CCollectVar(
  164. CURLUnescaper& rUnescaper,
  165. CWebServer & webServer ):
  166. _rUnescaper(rUnescaper),
  167. _webServer( webServer ),
  168. _xwcsBuffer(DEFAULT_BUFF_SIZE),
  169. _cwcVarSize(0),
  170. _xszBuffer(DEFAULT_BUFF_SIZE),
  171. _cbVarSize(0)
  172. {
  173. }
  174. //+-------------------------------------------------------------------------
  175. //
  176. // Member: CCollectVar::GetEnvVar
  177. //
  178. // Arguments: [pwcsVariableName] - the name of the variable to be retrieved
  179. //
  180. // Synopsis: Returns TRUE if the specified variable was retrieved and
  181. // FALSE otherwise.
  182. //
  183. //--------------------------------------------------------------------------
  184. BOOL CCollectVar::GetEnvVar( CHAR const * pszVariableName)
  185. {
  186. //
  187. // Prime to indicate that the WIDE-CHAR form of the string is
  188. // not valid anymore.
  189. //
  190. _cwcVarSize = 0;
  191. _cbVarSize = 0;
  192. //
  193. // Retrieve the variable as an ascii string
  194. //
  195. webDebugOut(( DEB_ITRACE, "WEBHITS: Getting environment variable\n" ));
  196. ULONG cb = _xszBuffer.Count();
  197. if ( ! _webServer.GetCGIVariable( pszVariableName,
  198. _xszBuffer.GetPointer(),
  199. & cb ) )
  200. {
  201. if ( cb > _xszBuffer.Count() )
  202. {
  203. //
  204. // have to re-size and incur the cost of the memory allocation
  205. //
  206. delete[] _xszBuffer.Acquire();
  207. _xszBuffer.Init( cb );
  208. if ( ! _webServer.GetCGIVariable( pszVariableName,
  209. _xszBuffer.GetPointer(),
  210. & cb ) )
  211. return FALSE;
  212. }
  213. else
  214. {
  215. return FALSE;
  216. }
  217. }
  218. _cbVarSize = cb;
  219. return TRUE;
  220. }
  221. //+-------------------------------------------------------------------------
  222. //
  223. // Member: CCollectVar::UnescapeAndConvertToUnicode
  224. //
  225. // Synopsis: Unescapes the variable currently stored in _xszBuffer.
  226. //
  227. //--------------------------------------------------------------------------
  228. inline void CCollectVar::UnescapeAndConvertToUnicode()
  229. {
  230. //
  231. // Convert the multi-byte string into a UNICODE string.
  232. //
  233. _cwcVarSize = _rUnescaper.UnescapeAndConvertToUnicode( _xszBuffer.Get(),
  234. _cbVarSize,
  235. _xwcsBuffer );
  236. }
  237. //+-------------------------------------------------------------------------
  238. //
  239. // Member: CSmartByteArray::CSmartByteArray - public constructor
  240. //
  241. // Synopsis: allocates memory for the buffer
  242. //--------------------------------------------------------------------------
  243. CSmartByteArray::CSmartByteArray():
  244. _xszBuffer(DEFAULT_BUFFER_SIZE)
  245. {
  246. }
  247. //+-------------------------------------------------------------------------
  248. //
  249. // Member: CSmartByteArray::CopyTo
  250. //
  251. // Arguments: [pwcText] - pointer to text to be copied
  252. // [cwcToCopy] - the number of characters to be copied
  253. //
  254. // Synopsis: copies the text pointed to by [pwcText] to the buffer,
  255. // enlarging it if necessary. A L'\0' is appended to the end
  256. // automatically, since this method is used to copy non-null
  257. // terminated strings.
  258. //
  259. //--------------------------------------------------------------------------
  260. void CSmartByteArray::CopyTo(char * pszText, ULONG cbToCopy)
  261. {
  262. //
  263. // if a buffer larger than the default one is being allocated, then
  264. // re-size it
  265. //
  266. if ( cbToCopy >= _xszBuffer.Count() )
  267. {
  268. delete[] _xszBuffer.Acquire();
  269. ULONG cbNew = max(2*_xszBuffer.Count(), cbToCopy+1);
  270. _xszBuffer.Init(cbNew);
  271. }
  272. RtlCopyMemory(_xszBuffer.GetPointer(),pszText,cbToCopy);
  273. // insert null terminator
  274. _xszBuffer[cbToCopy] = 0;
  275. }
  276. //+-------------------------------------------------------------------------
  277. //
  278. // Member: CQueryStringParser::CQueryStringParser, public constructor
  279. //
  280. // Arguments: [pwszQUERY_STRING] - buffer in which the *ESCAPED*
  281. // QUERY_STRING is stored
  282. // [rUnescaper] - ref. to unescaper object
  283. //
  284. // Synopsis: The QUERY_STRING must be passed in *ESCAPED* form, otherwise
  285. // it's difficult to say for example whether an ampersand delimits
  286. // consecutive variables or is part of the restriction
  287. //
  288. //--------------------------------------------------------------------------
  289. CQueryStringParser::CQueryStringParser( char * pszQUERY_STRING,
  290. CURLUnescaper& rUnescaper):
  291. _pszQS(pszQUERY_STRING),
  292. _pszQSEnd(_pszQS+strlen(_pszQS)),
  293. _pBeg(_pszQS),
  294. _pEnd(_pszQSEnd),
  295. _isNull(TRUE),
  296. _rUnescaper(rUnescaper)
  297. {
  298. }
  299. //+-------------------------------------------------------------------------
  300. //
  301. // Member: CQueryStringParser::FindVarEnd
  302. //
  303. // Arguments: [pwc] - pointer to character at which to begin 'searching'
  304. // for the end of the current variable assignment
  305. //
  306. // Synopsis: returns a pointer to the end of the variable assignment inside
  307. // of which pwc points - this is the next '&' if there are more
  308. // variable assignments following, or the terminating L'\0'
  309. // of QUERY_STRING if this is the last one.
  310. //
  311. //--------------------------------------------------------------------------
  312. CHAR* CQueryStringParser::FindVarEnd(CHAR* psz)
  313. {
  314. if (!psz)
  315. return NULL;
  316. while( (psz < _pszQSEnd) && *psz != '&')
  317. psz++;
  318. return psz;
  319. }
  320. //+-------------------------------------------------------------------------
  321. //
  322. // Member: CQueryStringParser::EatChar
  323. //
  324. // Arguments: [pwc] - pointer to the character that is to be eaten
  325. //
  326. // Synopsis: If [pwc] points to the character before the null terminator
  327. // of the string, returns NULL. Otherwise, returns [pwc]+1.
  328. //
  329. //--------------------------------------------------------------------------
  330. CHAR* CQueryStringParser::EatChar(char * psz)
  331. {
  332. if (!psz)
  333. return NULL;
  334. psz++;
  335. if (*psz)
  336. return psz;
  337. else
  338. return NULL;
  339. }
  340. //+-------------------------------------------------------------------------
  341. //
  342. // Member: CQueryStringParser::EatVariableName
  343. //
  344. // Arguments: [pwc] - pointer to the character at which to start eating
  345. //
  346. // Synopsis: Eat text until a '\0', whitespace, or '=' is encountered. If
  347. // a '\0' is encountered, return NULL, otherwise return a pointer
  348. // to the first non-blob character, where a blob character is
  349. // defined as anything except for whitespace, '\0', and '='.
  350. //
  351. //--------------------------------------------------------------------------
  352. char * CQueryStringParser::EatVariableName(char * psz)
  353. {
  354. if (!psz)
  355. return NULL;
  356. //
  357. // Note: this limits us to Ascii for variable names, which isn't
  358. // really a problem since we define all the variables.
  359. //
  360. while ( (*psz) && !isspace(*psz) && ('=' != *psz))
  361. psz++;
  362. if (*psz)
  363. return psz;
  364. return NULL;
  365. } //EatVariableName
  366. //+-------------------------------------------------------------------------
  367. //
  368. // Member: CQueryStringParser::ValidateArgument
  369. //
  370. // Arguments: [pwc] - pointer to the character string to validate
  371. //
  372. // Synopsis: Returns the pointer if valid or 0 otherwise.
  373. //
  374. //--------------------------------------------------------------------------
  375. char * CQueryStringParser::ValidateArgument(char * psz)
  376. {
  377. if ( ( 0 == psz ) || ( 0 == *psz ) )
  378. return 0;
  379. return psz;
  380. }
  381. //+-------------------------------------------------------------------------
  382. //
  383. // Member: CQueryStringParser::NextVar
  384. //
  385. // Synopsis: Extract the next command-line variable contained
  386. // in QUERY_STRING. Returns TRUE if the next variable was
  387. // successfully extracted, and FALSE otherwise
  388. //
  389. //--------------------------------------------------------------------------
  390. BOOL CQueryStringParser::NextVar()
  391. {
  392. //
  393. // set the NULL flag
  394. //
  395. _isNull = TRUE;
  396. // we've hit the end of the buffer
  397. if (!_pBeg)
  398. return FALSE;
  399. // find the end of the variable assignment within the buffer
  400. _pEnd = FindVarEnd(_pBeg);
  401. if (!_pEnd || _pEnd == _pBeg)
  402. {
  403. THROW( CException(MSG_WEBHITS_QS_FORMAT_INVALID));
  404. }
  405. //
  406. // copy the chunk of the QUERY_STRING into the temporary buffer for
  407. // unescaping
  408. //
  409. _smartBuffer.CopyTo(_pBeg, (ULONG)(_pEnd-_pBeg)); // L'\0' appended
  410. //_rUnescaper.Unescape(_smartBuffer.GetXPtr(), _pEnd-_pBeg);
  411. // move to the variable name
  412. CHAR* pTemp1 = ValidateArgument( _smartBuffer.GetPointer() );
  413. if (!pTemp1)
  414. {
  415. THROW( CException(MSG_WEBHITS_QS_FORMAT_INVALID));
  416. }
  417. CHAR* pTemp2 = EatVariableName(pTemp1);
  418. if (!pTemp2)
  419. {
  420. THROW( CException(MSG_WEBHITS_QS_FORMAT_INVALID));
  421. }
  422. //
  423. // Convert the variable name into a Unicode string.
  424. //
  425. ULONG cbToConvert = (ULONG)(pTemp2-pTemp1) ;
  426. _rUnescaper.UnescapeAndConvertToUnicode( pTemp1, cbToConvert, _xwszVarName );
  427. // move to the equal sign
  428. pTemp1=ValidateArgument(pTemp2);
  429. if (!pTemp1 || (*pTemp1 != L'='))
  430. {
  431. THROW( CException(MSG_WEBHITS_QS_FORMAT_INVALID));
  432. }
  433. pTemp1 = EatChar(pTemp1);
  434. //
  435. // if not a null value keep on eating away
  436. //
  437. if (ValidateArgument(pTemp1))
  438. {
  439. // move to the variable value
  440. pTemp1 = ValidateArgument(pTemp1);
  441. if (!pTemp1)
  442. {
  443. THROW( CException(MSG_WEBHITS_QS_FORMAT_INVALID));
  444. }
  445. // get the variable value
  446. cbToConvert = strlen(pTemp1);
  447. _rUnescaper.UnescapeAndConvertToUnicode( pTemp1, cbToConvert, _xwszVarValue );
  448. //
  449. // if we got this far, the variable had a value
  450. //
  451. _isNull = FALSE;
  452. }
  453. else
  454. {
  455. //
  456. // null value - delete the string name
  457. //
  458. delete _xwszVarName.Acquire();
  459. }
  460. // advance to the next variable assignment
  461. if (_pEnd < _pszQSEnd)
  462. {
  463. _pBeg = ++_pEnd;
  464. }
  465. else
  466. {
  467. _pBeg = NULL;
  468. }
  469. return TRUE;
  470. }
  471. //+-------------------------------------------------------------------------
  472. //
  473. // Member: CGetEnvVars::CGetEnvVars(), public constructor
  474. //
  475. // Arguments: [webServer] - web server to use
  476. // [langInfo] - language-specific info
  477. // [rCollectVar] - ref. to a variable-retrieving object
  478. // [rUnescaper] - ref. to unescaper object
  479. //
  480. // Synopsis: The constructor retrieves the Filename, VPath, QUERY_STRING,
  481. // and Restriction.
  482. //--------------------------------------------------------------------------
  483. CGetEnvVars::CGetEnvVars(
  484. CWebServer & webServer,
  485. CLanguageInfo & langInfo,
  486. CCollectVar& rCollectVar,
  487. CURLUnescaper& rUnescaper ) :
  488. _lcid(langInfo.GetUrlCodePage()),
  489. _hiliteType(SUMMARY),
  490. _rCollectVar( rCollectVar ),
  491. _rUnescaper(rUnescaper),
  492. _isBold(FALSE),
  493. _isItalic(FALSE),
  494. _isFixedFont(FALSE),
  495. _ccFixedFontLine(1),
  496. _xwc24BitColourMask(new WCHAR[8]),
  497. _aUserParams(eMaxUserReplParams),
  498. _langInfo( langInfo ),
  499. _webServer( webServer ),
  500. _dwWebHitsFileFlags( 0 ),
  501. _dwQueryFileFlags( 0 ),
  502. _dwTemplateFileFlags( 0 ),
  503. _dialect( ISQLANG_V2 )
  504. {
  505. for ( ULONG i = 0; i < eMaxUserReplParams; i++ )
  506. _aUserParams[i] = 0;
  507. wcscpy(_xwc24BitColourMask.GetPointer(),L"#FF0000");
  508. //
  509. // We support only the GET and POST methods -- verify
  510. //
  511. BYTE * pszBuffer;
  512. ULONG cbBuffer;
  513. if ( ( strcmp( webServer.GetMethod(), "GET" ) != 0 ) &&
  514. ( strcmp( webServer.GetMethod(), "POST" ) != 0 ) )
  515. {
  516. webDebugOut(( DEB_ERROR, "WEBHITS: invalid REQUEST_METHOD\n" ));
  517. THROW( CException(MSG_WEBHITS_REQUEST_METHOD_INVALID) );
  518. }
  519. XArray<WCHAR> xHTW;
  520. ULONG cwc;
  521. if ( webServer.GetCGI_PATH_INFO( xHTW, cwc ) )
  522. {
  523. webDebugOut(( DEB_ITRACE, "htw file: '%ws'\n", xHTW.GetPointer() ));
  524. // Allow null.htw files to not exist, in which case the file just
  525. // serves as a script map trigger with default formatting info.
  526. WCHAR *pwc = wcsrchr( xHTW.GetPointer(), L'/' );
  527. if ( ( 0 != pwc ) && ( _wcsicmp( pwc+1, NullHTWFile ) ) )
  528. _xwcsTemplateFileVPath.Set( xHTW.Acquire() );
  529. }
  530. //
  531. // retrieve and parse the command line - we store in the same
  532. // buffer in both places
  533. //
  534. RetrieveQueryString();
  535. ParseQUERY_STRING();
  536. }
  537. //+-------------------------------------------------------------------------
  538. //
  539. // Member: CGetEnvVars::ParseQUERY_STRING()
  540. //
  541. // Synopsis: parses QUERY_STRING for the various command-line parameters.
  542. // This method must be called AFTER RetrieveQueryString. If a
  543. // "crucial" variable remains unset at the end, an exception is
  544. // is thrown.
  545. //
  546. //--------------------------------------------------------------------------
  547. void CGetEnvVars::ParseQUERY_STRING()
  548. {
  549. webDebugOut(( DEB_ITRACE, "WEBHITS: parsing QS '%s'\n",
  550. _xszQueryString.GetPointer() ));
  551. CQueryStringParser QSParser( _xszQueryString.GetPointer(), _rUnescaper );
  552. while(QSParser.NextVar())
  553. {
  554. XPtrST<WCHAR> xwcTempVarName;
  555. XPtrST<WCHAR> xwcTempVarValue;
  556. //
  557. // acquire the variable name and value from the parser, and hand it over to SetVar
  558. //
  559. if (!QSParser.IsNull())
  560. {
  561. QSParser.GetVarName(xwcTempVarName);
  562. QSParser.GetVarValue(xwcTempVarValue);
  563. SetVar(xwcTempVarName,xwcTempVarValue);
  564. }
  565. }
  566. VerifyQSVariablesComplete();
  567. }
  568. //+---------------------------------------------------------------------------
  569. //
  570. // Member: CGetEnvVars::IsUserParam
  571. //
  572. // Synopsis:
  573. //
  574. // Arguments: [pwcsParam] -
  575. //
  576. // Returns:
  577. //
  578. // Modifies:
  579. //
  580. // History: 9-10-96 srikants Created
  581. //
  582. // Notes:
  583. //
  584. //----------------------------------------------------------------------------
  585. inline ULONG CGetEnvVars::IsUserParam( const WCHAR * pwcsParam )
  586. {
  587. if ( 0 == _wcsnicmp( pwcsParam, wcsUserParamPrefix, cwcUserParamPrefix) )
  588. {
  589. int i = _wtoi( pwcsParam+cwcUserParamPrefix );
  590. if ( i > 0 && i <= eMaxUserReplParams )
  591. return (ULONG) i;
  592. else return 0;
  593. }
  594. else
  595. {
  596. return 0;
  597. }
  598. }
  599. //+-------------------------------------------------------------------------
  600. //
  601. // Member: CGetEnvVars::SetVar
  602. //
  603. // Arguments: [xwszVarName] - the name of the variable being set
  604. // [xwszVarValue]- the value it is being set to
  605. //
  606. // Synopsis: Sets the command-line variable [xwszVarName] to [xwszVarValue]
  607. // and throws if the variable name is invalid. The string
  608. // containing the variable name is deleted here, as is the
  609. // string containing the variable value if the latter is of no
  610. // use and should not be stored.
  611. //
  612. //--------------------------------------------------------------------------
  613. void CGetEnvVars::SetVar(XPtrST<WCHAR>& xwszVarName,
  614. XPtrST<WCHAR>& xwszVarValue)
  615. {
  616. //
  617. // create local copies of the smart pointers, ensuring deletion at the end
  618. //
  619. XPtrST<WCHAR> xwszLocalVarName(xwszVarName.Acquire());
  620. XPtrST<WCHAR> xwszLocalVarValue(xwszVarValue.Acquire());
  621. webDebugOut(( DEB_ITRACE, "var '%ws', value '%ws'\n",
  622. xwszLocalVarName.GetPointer(),
  623. xwszLocalVarValue.GetPointer() ));
  624. if(_wcsicmp(xwszLocalVarName.GetPointer(),RestrictionVarName) == 0)
  625. {
  626. if ( 0 != _xwcsRestriction.GetPointer() )
  627. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  628. _xwcsRestriction.Set(xwszLocalVarValue.Acquire());
  629. }
  630. else if (_wcsicmp(xwszLocalVarName.GetPointer(),HiliteTypeVarName) == 0)
  631. {
  632. if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"full") == 0)
  633. {
  634. _hiliteType = FULL;
  635. }
  636. }
  637. else if (_wcsicmp(xwszLocalVarName.GetPointer(),IDQFilenameVarName) == 0)
  638. {
  639. if ( 0 != _xwcsQueryFileVPath.GetPointer() )
  640. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  641. _xwcsQueryFileVPath.Set(xwszLocalVarValue.Acquire());
  642. }
  643. else if (_wcsicmp(xwszLocalVarName.GetPointer(),ColorVarName)==0)
  644. {
  645. if ( (*(xwszLocalVarValue.GetPointer()) == L'0') &&
  646. (wcslen(xwszLocalVarValue.GetPointer()) == 8))
  647. {
  648. //
  649. // a 24-bit colour spec is being passed in
  650. //
  651. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),xwszLocalVarValue.GetPointer()+1,
  652. sizeof(Red24BitMask));
  653. *(_xwc24BitColourMask.GetPointer())=L'#';
  654. }
  655. else if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"red")==0)
  656. {
  657. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),Red24BitMask,sizeof(Red24BitMask));
  658. }
  659. else if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"blue")==0)
  660. {
  661. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),Blue24BitMask,sizeof(Blue24BitMask));
  662. }
  663. else if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"green")==0)
  664. {
  665. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),Green24BitMask,sizeof(Green24BitMask));
  666. }
  667. else if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"black")==0)
  668. {
  669. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),Black24BitMask,sizeof(Black24BitMask));
  670. }
  671. else if (_wcsicmp(xwszLocalVarValue.GetPointer(),L"yellow")==0)
  672. {
  673. RtlCopyMemory(_xwc24BitColourMask.GetPointer(),Yellow24BitMask,sizeof(Yellow24BitMask));
  674. }
  675. }
  676. else if (_wcsicmp(xwszLocalVarName.GetPointer(),VPathWebHitsFile) == 0)
  677. {
  678. if ( 0 != _xwcsWebHitsFileVPath.GetPointer() )
  679. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  680. _xwcsWebHitsFileVPath.Set(xwszLocalVarValue.Acquire());
  681. }
  682. else if (_wcsicmp(xwszLocalVarName.GetPointer(),BoldVarName) == 0)
  683. {
  684. _isBold=TRUE;
  685. }
  686. else if (_wcsicmp(xwszLocalVarName.GetPointer(),ItalicVarName)==0)
  687. {
  688. _isItalic=TRUE;
  689. }
  690. else if ( _wcsicmp(xwszLocalVarName.GetPointer(),MaxLineLength) == 0 )
  691. {
  692. _isFixedFont = TRUE;
  693. if ( xwszLocalVarValue.GetPointer() )
  694. _ccFixedFontLine = _wtoi( xwszLocalVarValue.GetPointer() );
  695. _ccFixedFontLine = max( _ccFixedFontLine, 1 );
  696. }
  697. else if ( _wcsicmp(xwszLocalVarName.GetPointer(),LocaleVar) == 0 )
  698. {
  699. //
  700. // Set the output and cirestriction locale info now.
  701. //
  702. if ( xwszLocalVarValue.GetPointer() )
  703. {
  704. if ( !_locale.IsNull() )
  705. delete _locale.Acquire();
  706. LCID lcid = GetLCIDFromString( xwszLocalVarValue.GetPointer() );
  707. _locale.Init(1+wcslen(xwszLocalVarValue.GetPointer()));
  708. wcscpy(_locale.GetPointer(), xwszLocalVarValue.GetPointer());
  709. //
  710. // The output will be generated using this codepage and for
  711. // interpretation of the "CiRestriction".
  712. //
  713. _langInfo.SetRestrictionLocale( lcid );
  714. }
  715. }
  716. else if ( _wcsicmp(xwszLocalVarName.GetPointer(), CodepageVar) == 0)
  717. {
  718. if (xwszLocalVarValue.GetPointer() )
  719. {
  720. if ( !_codepage.IsNull() )
  721. delete _codepage.Acquire();
  722. _codepage.Init(1+wcslen(xwszLocalVarValue.GetPointer()));
  723. wcscpy(_codepage.GetPointer(), xwszLocalVarValue.GetPointer());
  724. }
  725. }
  726. else if ( _wcsicmp(xwszLocalVarName.GetPointer(), DialectVar) == 0)
  727. {
  728. if ( xwszLocalVarValue.GetPointer() )
  729. {
  730. ULONG d = (ULONG) _wtoi( xwszLocalVarValue.GetPointer() );
  731. if ( d > ISQLANG_V2 || d < ISQLANG_V1 )
  732. THROW( CException( MSG_WEBHITS_INVALID_DIALECT ) );
  733. _dialect = d;
  734. }
  735. }
  736. else if ( _wcsicmp(xwszLocalVarName.GetPointer(),BeginHiliteVar) == 0 )
  737. {
  738. if ( 0 != _xwcsBeginHiliteTag.GetPointer() )
  739. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  740. #if 0 // security hole -- we can't display random html from users
  741. _xwcsBeginHiliteTag.Set(xwszLocalVarValue.Acquire());
  742. #endif
  743. }
  744. else if ( _wcsicmp(xwszLocalVarName.GetPointer(),EndHiliteVar) == 0 )
  745. {
  746. if ( 0 != _xwcsEndHiliteTag.GetPointer() )
  747. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  748. #if 0 // security hole -- we can't display random html from users
  749. _xwcsEndHiliteTag.Set(xwszLocalVarValue.Acquire());
  750. #endif
  751. }
  752. else
  753. {
  754. ULONG nUserParam = IsUserParam( xwszLocalVarName.GetPointer() );
  755. if ( nUserParam > 0 )
  756. {
  757. if ( 0 != _aUserParams[nUserParam-1] )
  758. THROW( CException( MSG_WEBHITS_DUPLICATE_PARAMETER ) );
  759. _aUserParams[nUserParam-1] = xwszLocalVarValue.Acquire();
  760. }
  761. else
  762. {
  763. //
  764. // the variable name is not recognized - throw. We don't need to
  765. // delete the strings as they are contained in smart pointers
  766. //
  767. webDebugOut((DEB_ERROR,"WEBHITS: bad variable name:%ws\n",
  768. xwszLocalVarName.GetPointer() ));
  769. THROW(CException(MSG_WEBHITS_VARNAME_INVALID));
  770. }
  771. }
  772. }
  773. //+-------------------------------------------------------------------------
  774. //
  775. // Member: CGetEnvVars::VerifyQSVariablesComplete()
  776. //
  777. // Synopsis: Checks whether all the "crucial" variables that were to be
  778. // set as part of QUERY_STRING have been set, and throws an
  779. // exception otherwise.
  780. //
  781. //--------------------------------------------------------------------------
  782. void CGetEnvVars::VerifyQSVariablesComplete()
  783. {
  784. if(_xwcsRestriction.IsNull())
  785. {
  786. webDebugOut(( DEB_ERROR,
  787. "WEBHITS: incomplete variable set read from QS\n" ));
  788. THROW(CException(MSG_WEBHITS_INVALID_QUERY));
  789. }
  790. }
  791. //+-------------------------------------------------------------------------
  792. //
  793. // Member: CGetEnvVars::RetrieveCONTENT_LENGTH
  794. //
  795. // Synopsis: retrieves and returns the value of CONTENT_LENGTH,
  796. // and throws if unable to retrieve
  797. //
  798. //--------------------------------------------------------------------------
  799. int CGetEnvVars::RetrieveCONTENT_LENGTH()
  800. {
  801. if(!_rCollectVar.GetEnvVar("CONTENT_LENGTH"))
  802. {
  803. webDebugOut(( DEB_ERROR, "WEBHITS: failed to get CONTENT_LENGTH\n" ));
  804. return 0;
  805. THROW( CException(MSG_WEBHITS_CONTENT_LENGTH_INVALID) );
  806. }
  807. else
  808. {
  809. //
  810. // get the number of bytes
  811. //
  812. return _wtoi(_rCollectVar.GetVarValue());
  813. }
  814. }
  815. //+-------------------------------------------------------------------------
  816. //
  817. // Member: CGetEnvVars::RetrieveQueryString
  818. //
  819. // Synopsis: retrieves the value of QUERY_STRING, setting _xwcsQueryString
  820. // to point to it, and throws otherwise
  821. //
  822. //--------------------------------------------------------------------------
  823. void CGetEnvVars::RetrieveQueryString()
  824. {
  825. if(!_rCollectVar.GetEnvVar("QUERY_STRING"))
  826. {
  827. webDebugOut(( DEB_ERROR, "WEBHITS: failed to get QS\n" ));
  828. THROW( CException(MSG_WEBHITS_INVALID_QUERY) );
  829. }
  830. else
  831. {
  832. int cbToCopy = _rCollectVar.GetMultiByteStrLen();
  833. //
  834. // we do not unescape QUERY_STRING to preserve delimiting information
  835. //
  836. _xszQueryString.Init(cbToCopy+1);
  837. RtlCopyMemory( _xszQueryString.GetPointer(),
  838. _rCollectVar.GetMultiByteStr(),
  839. cbToCopy );
  840. _xszQueryString[cbToCopy] = 0;
  841. }
  842. }
  843. //+-------------------------------------------------------------------------
  844. //
  845. // function GetLCID
  846. //
  847. // Synopsis: returns the locale in HTTP_ACCEPT_LANGUAGE, or if that one is
  848. // is not set, the one obtained from GetSystemDefaultLCID()
  849. //
  850. //--------------------------------------------------------------------------
  851. LCID GetLCID( CWebServer & webServer )
  852. {
  853. webDebugOut(( DEB_ITRACE,
  854. "WEBHITS: Getting HTTP_ACCEPT_LANGUAGE variable\n" ));
  855. XArray<WCHAR> xBuffer;
  856. ULONG cwcBuffer;
  857. BOOL fOK = webServer.GetCGIVariableW( L"HTTP_ACCEPT_LANGUAGE",
  858. xBuffer,
  859. cwcBuffer );
  860. if ( !fOK )
  861. {
  862. LCID locale = GetSystemDefaultLCID();
  863. return locale;
  864. }
  865. LCID lcid = GetLCIDFromString( xBuffer.GetPointer() );
  866. if ( 0xFFFFFFFF == lcid )
  867. lcid = GetSystemDefaultLCID();
  868. return lcid;
  869. }
  870. //+---------------------------------------------------------------------------
  871. //
  872. // Function: SetCodePageForCRunTimes
  873. //
  874. // Synopsis: Set the appropriate code page for the c-runtimes so that
  875. // swprintf, putchar, etc correctly translate the unicode into
  876. // the appropriate multi-byte sequence.
  877. //
  878. // Arguments: [codePage] - Code page of the client.
  879. //
  880. // History: 9-06-96 srikants Created
  881. //
  882. //----------------------------------------------------------------------------
  883. UINT CLanguageInfo::SetCodePageForCRunTimes( UINT codePage )
  884. {
  885. char szCodePage[20];
  886. sprintf( szCodePage,".%d", codePage );
  887. char * p = setlocale( LC_ALL, szCodePage );
  888. if ( 0 == p )
  889. {
  890. webDebugOut(( DEB_WARN,
  891. "Could not set code page for %d\n. Going to system default",
  892. codePage ));
  893. LCID lcid = GetSystemDefaultLCID();
  894. codePage = LocaleToCodepage( lcid );
  895. sprintf( szCodePage,".%d", codePage );
  896. char * p = setlocale( LC_ALL, szCodePage );
  897. }
  898. return codePage;
  899. }
  900. //+-------------------------------------------------------------------------
  901. //
  902. // Member: CSortQueryHits::Init()
  903. //
  904. // Synopsis: Initialization function for CSortQueryHits (need to do this
  905. // as a HitIter& is needed to fully construct this class).
  906. // creates array of positions sorted in order of occurrence
  907. // within the document (note that a position may occur several
  908. // times).
  909. //
  910. //--------------------------------------------------------------------------
  911. void CSortQueryHits::Init()
  912. {
  913. Win4Assert(0 == _aPosition);
  914. _positionCount = CountPositions();
  915. if (0 != _positionCount)
  916. {
  917. _aPosition = new Position[_positionCount];
  918. int iPosition=0;
  919. for (BOOL fOk=_rHitIter.FirstHit();fOk;fOk=_rHitIter.NextHit())
  920. {
  921. int posInHit=_rHitIter.GetPositionCount();
  922. for (int i=0;i<posInHit;i++)
  923. _aPosition[iPosition++] = _rHitIter.GetPosition(i);
  924. }
  925. Win4Assert(iPosition == _positionCount);
  926. qsort(_aPosition,_positionCount,sizeof(Position),&ComparePositions);
  927. }
  928. }
  929. //+-------------------------------------------------------------------------
  930. //
  931. // Member: CSortQueryHits::CountPositions()
  932. //
  933. // Synopsis: Count the total number of positions across all hits returned
  934. // by ISearch.
  935. //
  936. //--------------------------------------------------------------------------
  937. int CSortQueryHits::CountPositions()
  938. {
  939. int count=0;
  940. for (BOOL fOk = _rHitIter.FirstHit();fOk;fOk=_rHitIter.NextHit() )
  941. {
  942. count +=_rHitIter.GetPositionCount();
  943. webDebugOut(( DEB_ITRACE, "Count = %d\n", count ));
  944. }
  945. return count;
  946. }
  947. //+-------------------------------------------------------------------------
  948. //
  949. // Member: CLinkQueryHits::CLinkQueryHits, public constructor
  950. //
  951. // Arguments: [rInternalQuery] - DbRestriction
  952. // [rGetEnvVars] - object containing CGI env. variables
  953. // [rHttpOutput] - HTTP output object
  954. // [cmsReadTimeout] - Read timeout for IFilter on the doc
  955. // [lockSingleThreadedFilter] - lock for single-threaded filters
  956. // [propertyList] - Properties to webhit
  957. // [ulDisplayScript] - Flags for displaying scripts
  958. //
  959. //--------------------------------------------------------------------------
  960. CLinkQueryHits::CLinkQueryHits(
  961. CInternalQuery & rInternalQuery,
  962. CGetEnvVars & rGetEnvVars,
  963. PHttpFullOutput& rHttpOutput,
  964. DWORD cmsReadTimeout,
  965. CReleasableLock & lockSingleThreadedFilter,
  966. CEmptyPropertyList & propertyList,
  967. ULONG ulDisplayScript ) :
  968. _document( (WCHAR*) rGetEnvVars.GetWebHitsFilePPath(),
  969. BOGUS_RANK,
  970. rInternalQuery.GetISearchRef(),
  971. cmsReadTimeout,
  972. lockSingleThreadedFilter,
  973. propertyList,
  974. ulDisplayScript ),
  975. _rGetEnvVars(rGetEnvVars),
  976. _rInternalQuery(rInternalQuery),
  977. _rHttpOutput(rHttpOutput),
  978. _HitIter(),
  979. _sortedHits(_HitIter),
  980. _currentOffset(0),
  981. _posIndex(0),
  982. _tagCount(0),
  983. _ccOutputBuffer(0)
  984. {
  985. //
  986. // initialize the iterator
  987. //
  988. _HitIter.Init(&_document);
  989. _sortedHits.Init();
  990. //
  991. // set the total count of positions
  992. //
  993. _posCount = _sortedHits.GetPositionCount();
  994. //
  995. // if there are any positions, initialize the "next position" data members
  996. // to the first one
  997. //
  998. if (_posCount > 0)
  999. {
  1000. Position nextPos = _sortedHits.GetPosition(0);
  1001. _nextBegOffset = nextPos.GetBegOffset();
  1002. _nextEndOffset = nextPos.GetEndOffset();
  1003. }
  1004. }
  1005. //+-------------------------------------------------------------------------
  1006. //
  1007. // Member: CLinkQueryHits::IsSeparatedBySpaces
  1008. //
  1009. // Arguments: [startOffset] - beginning offset
  1010. // [endOffset] - ending offset
  1011. //
  1012. // Synopsis: returns TRUE if the positions in the current paragraph
  1013. // determined by [startOffset] and [endOffset] are separated
  1014. // by whitespace characters.
  1015. //
  1016. // Note: There is a maximum 'allowed' separation, beyond which
  1017. // whitespace is considered significant.
  1018. //
  1019. //--------------------------------------------------------------------------
  1020. unsigned const ccSignificantWhitespace = 20;
  1021. BOOL CLinkQueryHits::IsSeparatedBySpaces(int startOffset, int endOffset)
  1022. {
  1023. Win4Assert( startOffset <= endOffset );
  1024. if (startOffset > endOffset)
  1025. return FALSE;
  1026. //
  1027. // Small buffer for calls to GetStringTypeW
  1028. //
  1029. WORD awCharType[ccSignificantWhitespace];
  1030. int len = endOffset - startOffset;
  1031. if ( 0 == len )
  1032. return TRUE;
  1033. if ( len > ccSignificantWhitespace )
  1034. return FALSE;
  1035. const WCHAR* pStart = _document.GetPointerToOffset(startOffset);
  1036. //
  1037. // Check for whitespace
  1038. //
  1039. if ( !GetStringTypeW( CT_CTYPE1, pStart, len, awCharType ) )
  1040. {
  1041. webDebugOut(( DEB_ERROR, "GetStringType returned %d\n", GetLastError() ));
  1042. return FALSE;
  1043. }
  1044. //
  1045. // Only blanks are legal 'spaces'
  1046. //
  1047. for ( int i = 0; i < len; i++ )
  1048. {
  1049. if ( 0 == (awCharType[i] & C1_BLANK) )
  1050. return FALSE;
  1051. }
  1052. return TRUE;
  1053. }
  1054. //+-------------------------------------------------------------------------
  1055. //
  1056. // Member: CLinkQueryHits::InsertLinks
  1057. //
  1058. // Synopsis: Hit highlight the document by inserting linked HTML tags
  1059. //
  1060. //--------------------------------------------------------------------------
  1061. void CLinkQueryHits::InsertLinks()
  1062. {
  1063. if ( !_rHttpOutput.IsTemplateFilePresent() )
  1064. _rHttpOutput.TagPosition(-1);
  1065. _rHttpOutput.OutputFullHeader();
  1066. //
  1067. // Determine if this is a mainly text document.
  1068. //
  1069. if ( _rGetEnvVars.IsFixedFont() )
  1070. _rHttpOutput.OutputPreformattedTag();
  1071. ULONG eofOffset = _document.GetEOFOffset();
  1072. if (_sortedHits.GetPositionCount() == 0)
  1073. {
  1074. //
  1075. // There are no hits. Just render the whole text.
  1076. //
  1077. WCHAR* pText = _document.GetWritablePointerToOffset(0);
  1078. _rHttpOutput.OutputHttpText(pText,eofOffset);
  1079. }
  1080. else
  1081. {
  1082. BOOL openTag = FALSE;
  1083. while(_currentOffset < (int) eofOffset)
  1084. {
  1085. WCHAR* pText = _document.GetWritablePointerToOffset(_currentOffset);
  1086. const ULONG cSectionSize = _nextBegOffset - _currentOffset;
  1087. if ( cSectionSize > 0 )
  1088. {
  1089. _rHttpOutput.OutputHttpText(pText,cSectionSize);
  1090. _currentOffset +=cSectionSize;
  1091. if ( (int) eofOffset == _currentOffset )
  1092. break;
  1093. pText+=cSectionSize;
  1094. }
  1095. const ULONG cHiliteSize = _nextEndOffset - _nextBegOffset;
  1096. if ( cHiliteSize > 0 )
  1097. {
  1098. //
  1099. // display the "<<" tag - if a tag is not already open
  1100. //
  1101. if (!openTag)
  1102. {
  1103. _rHttpOutput.OutputLeftTag(_tagCount-1);
  1104. _rHttpOutput.TagPosition(_tagCount);
  1105. openTag = TRUE;
  1106. }
  1107. //
  1108. // display the highlited position text
  1109. //
  1110. _rHttpOutput.OutputHilite(pText, cHiliteSize);
  1111. _currentOffset += cHiliteSize;
  1112. Win4Assert(_currentOffset == _nextEndOffset);
  1113. }
  1114. //
  1115. // get the next distinct position
  1116. //
  1117. BOOL existsNextPosition = MoveToNextDifferentPosition();
  1118. //
  1119. // display the ">>" tag unless separated only by spaces or
  1120. // last tag in doc in which case we have to make it point to the
  1121. // top
  1122. if ( !existsNextPosition )
  1123. {
  1124. if ( openTag )
  1125. {
  1126. _rHttpOutput.OutputRightTag(-1);
  1127. openTag = FALSE;
  1128. }
  1129. _nextBegOffset = _nextEndOffset = eofOffset;
  1130. }
  1131. else if ( openTag && !IsSeparatedBySpaces(_currentOffset,_nextBegOffset) )
  1132. {
  1133. _rHttpOutput.OutputRightTag(_tagCount+1);
  1134. _tagCount++;
  1135. openTag = FALSE;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. //+-------------------------------------------------------------------------
  1141. //
  1142. // Member: CExtractedHit::CExtractedHit, public constructor
  1143. //
  1144. // Arguments: [rDocument] - ref. to document being hilited
  1145. // [rHit] - ref. to hit being hilited
  1146. // [rOutput] - ref. to Http Output object
  1147. // [cwcMargin] - number of chars. to be printed before and
  1148. // after the hit
  1149. // [cwcSeparation]- maximum number of characters that may
  1150. // separate consecutive positions before
  1151. // truncation occurs
  1152. // [cwcDelim] - the number of characters to print before and
  1153. // after a position in the case of truncation
  1154. //--------------------------------------------------------------------------
  1155. CExtractedHit::CExtractedHit( CDocument& rDocument,
  1156. Hit& rHit,
  1157. PHttpOutput& rOutput,
  1158. int cwcMargin,
  1159. int cwcSeparation,
  1160. int cwcDelim ):
  1161. _rDocument(rDocument),
  1162. _rHit(rHit),
  1163. _cwcMargin(cwcMargin),
  1164. _rOutput(rOutput),
  1165. _cwcSeparation(cwcSeparation),
  1166. _cwcDelim(cwcDelim),
  1167. _cwcOutputBuffer(0)
  1168. {
  1169. SortHit();
  1170. }
  1171. //+-------------------------------------------------------------------------
  1172. //
  1173. // Member: CExtractedHit::SortHit()
  1174. //
  1175. // Synopsis: Sort the positions in the hit in the order in which they occur
  1176. // in the document
  1177. //
  1178. //--------------------------------------------------------------------------
  1179. void CExtractedHit::SortHit()
  1180. {
  1181. qsort( _rHit._aPos,
  1182. _rHit.GetPositionCount(),
  1183. sizeof(Position),
  1184. &ComparePositions );
  1185. }
  1186. //+-------------------------------------------------------------------------
  1187. //
  1188. // Member: CExtractedHit::DisplayPosition
  1189. //
  1190. // Arguments: [rPos] - ref. to position being displayed
  1191. //
  1192. // Synopsis: Display the highlighted position (i.e. JUST the position)
  1193. //
  1194. //--------------------------------------------------------------------------
  1195. void CExtractedHit::DisplayPosition(const Position& rPos)
  1196. {
  1197. const WCHAR* pText = _rDocument.GetPointerToOffset(rPos.GetBegOffset());
  1198. _rOutput.OutputHilite(pText,rPos.GetLength());
  1199. }
  1200. //+-------------------------------------------------------------------------
  1201. //
  1202. // Member: CExtractedHit::ExtractHit()
  1203. //
  1204. // Synopsis: Extract the hit - i.e. display all of the positions and
  1205. // the associated preamble/postamble text
  1206. //
  1207. //--------------------------------------------------------------------------
  1208. void CExtractedHit::ExtractHit()
  1209. {
  1210. //
  1211. // make sure that we are not dealing with a null hit - i.e. a hit composed
  1212. // entirely of null positions
  1213. if (_rHit.IsNullHit())
  1214. return;
  1215. // stores the number of positions in the hit
  1216. int cPositions = _rHit.GetPositionCount();
  1217. //
  1218. // introduce new paragraph
  1219. //
  1220. _rOutput.OutputParaTag();
  1221. _rOutput.OutputEllipsis();
  1222. //
  1223. // go through displaying each position
  1224. //
  1225. //
  1226. // find the first non-null position in the hit
  1227. //
  1228. int firstRealPos = EatNullPositions();
  1229. //
  1230. // display the preamble
  1231. //
  1232. PrintPreamble(_rHit.GetPos(firstRealPos),_cwcMargin);
  1233. //
  1234. // display the positions and the stuff in between the positions
  1235. //
  1236. for (int i=firstRealPos;i < cPositions; i++)
  1237. {
  1238. DisplayPosition(_rHit.GetPos(i));
  1239. // the stuff between consecutive positions
  1240. if (i != cPositions - 1)
  1241. {
  1242. //
  1243. // guard against the case where multiple identical positions are
  1244. // returned as part of the same hit
  1245. //
  1246. if (_rHit.GetPos(i).GetBegOffset() <
  1247. _rHit.GetPos(i+1).GetBegOffset())
  1248. {
  1249. PrintBtwPositions(_rHit.GetPos(i),_rHit.GetPos(i+1));
  1250. }
  1251. else
  1252. {
  1253. while ( ( i != ( cPositions - 1 ) ) &&
  1254. ( _rHit.GetPos(i).GetBegOffset() ==
  1255. _rHit.GetPos(i+1).GetBegOffset() ) )
  1256. i++;
  1257. }
  1258. }
  1259. }
  1260. //
  1261. // display the postamble
  1262. //
  1263. PrintPostamble(_rHit.GetPos(cPositions-1),_cwcMargin);
  1264. _rOutput.OutputEllipsis();
  1265. _rOutput.OutputHRULE();
  1266. } //ExtractHit
  1267. //+-------------------------------------------------------------------------
  1268. //
  1269. // Member: CExtractedHit::ComputeDistance
  1270. //
  1271. // Arguments: [rStartPos] - ref. to starting position
  1272. // [rEndPos] - ref. to end position
  1273. //
  1274. // Synopsis: Compute the distance in characters between the start and
  1275. // end positions
  1276. //
  1277. //--------------------------------------------------------------------------
  1278. ULONG CExtractedHit::ComputeDistance (const Position& rStartPos,
  1279. const Position& rEndPos)
  1280. {
  1281. return rEndPos.GetBegOffset() - rStartPos.GetEndOffset();
  1282. }
  1283. //+-------------------------------------------------------------------------
  1284. //
  1285. // Member: CExtractedHit::PrintPreamble
  1286. //
  1287. // Arguments: [rStartPosition] - ref. to start position
  1288. // [cwcDist] - maximum number of characters to print
  1289. //
  1290. //
  1291. // Synopsis: Prints the context text preceding the hit - the number of
  1292. // characters printed depends on cwcDist. The break is made
  1293. // at a word boundary
  1294. //
  1295. //--------------------------------------------------------------------------
  1296. void CExtractedHit::PrintPreamble(const Position& rStartPosition,int cwcDist)
  1297. {
  1298. WCHAR* pBeg = _rDocument.GetWritablePointerToOffset(
  1299. rStartPosition.GetBegOffset()-cwcDist);
  1300. const WCHAR* pEnd = _rDocument.GetPointerToOffset(
  1301. rStartPosition.GetBegOffset());
  1302. // Boundary case - if the beginning of the document, don't skip any thing
  1303. if ( pBeg != _rDocument.GetPointerToOffset(0) )
  1304. {
  1305. while( (pBeg < pEnd) &&
  1306. !iswspace(*pBeg) &&
  1307. !(UNICODE_PARAGRAPH_SEPARATOR == *pBeg))
  1308. pBeg++;
  1309. }
  1310. Win4Assert(pBeg <= pEnd);
  1311. _rOutput.OutputHttpText(pBeg, CiPtrToUlong( pEnd-pBeg ));
  1312. } //PrintPreamble
  1313. //+-------------------------------------------------------------------------
  1314. //
  1315. // Member: CExtractedHit::PrintPostamble
  1316. //
  1317. // Arguments: [rStartPosition] - ref. to start position
  1318. // [cwcDist] - maximum number of characters to be printed
  1319. //
  1320. // Synopsis: Print the context text following the hit - the number of
  1321. // characters printed depends on cwcDist. The break is made
  1322. // at a word boundary
  1323. //
  1324. //--------------------------------------------------------------------------
  1325. void CExtractedHit::PrintPostamble(const Position& rStartPosition, int cwcDist)
  1326. {
  1327. WCHAR* pBeg = _rDocument.GetWritablePointerToOffset(
  1328. rStartPosition.GetEndOffset());
  1329. const WCHAR* pEnd = _rDocument.GetPointerToOffset(
  1330. rStartPosition.GetEndOffset()+cwcDist);
  1331. while( (pEnd > pBeg) &&
  1332. !iswspace(*pEnd) &&
  1333. !(UNICODE_PARAGRAPH_SEPARATOR == *pEnd) )
  1334. pEnd--;
  1335. Win4Assert(pEnd >= pBeg);
  1336. _rOutput.OutputHttpText( pBeg, CiPtrToUlong( pEnd-pBeg ));
  1337. } //PrintPostamble
  1338. //+-------------------------------------------------------------------------
  1339. //
  1340. // Member: CExtractedHit::PrintBtwPositions
  1341. //
  1342. // Arguments: [rStartPosition] - ref. to start position
  1343. // [rEndPosition] - ref. to end position
  1344. //
  1345. // Synopsis: Display the text between the two positions, breaking at word
  1346. // boundaries. If the positions are separated by a distance
  1347. // greated than _cwcSeparation, then the text in-between is
  1348. // truncated, and up to _cwcDelim characters after the first and
  1349. // before the second position are printed, separated by an
  1350. // ellipsis
  1351. //
  1352. //--------------------------------------------------------------------------
  1353. void CExtractedHit::PrintBtwPositions( const Position& rStartPosition,
  1354. const Position& rEndPosition)
  1355. {
  1356. long dist;
  1357. if ((dist=ComputeDistance(rStartPosition,rEndPosition)) > _cwcSeparation)
  1358. {
  1359. PrintPostamble(rStartPosition,_cwcDelim);
  1360. _rOutput.OutputEllipsis();
  1361. PrintPreamble(rEndPosition,_cwcDelim);
  1362. }
  1363. else
  1364. {
  1365. WCHAR* pText = _rDocument.GetWritablePointerToOffset(
  1366. rStartPosition.GetEndOffset() );
  1367. _rOutput.OutputHttpText(pText,dist);
  1368. }
  1369. } //PrintBtwPositions
  1370. //+-------------------------------------------------------------------------
  1371. //
  1372. // Member: CExtractedHits::ExtractHits
  1373. //
  1374. // Arguments: same as CExtractHit constructor, except rHitIter - a hit
  1375. // iterator replaces the hit reference
  1376. //
  1377. // Synopsis: Class functor to encapsulate the action of highliting the
  1378. // hits in rHitIter. A temporary CExtractHit object is created
  1379. // for each hit.
  1380. //
  1381. //--------------------------------------------------------------------------
  1382. CExtractHits::CExtractHits(CDocument& rDocument,
  1383. HitIter& rHitIter,
  1384. PHttpOutput& rOutput,
  1385. int cwcMargin,
  1386. int cwcDelim,
  1387. int cwcSeparation )
  1388. {
  1389. for (BOOL fOK=rHitIter.FirstHit(); fOK; fOK = rHitIter.NextHit())
  1390. {
  1391. CExtractedHit extractedHit( rDocument,
  1392. rHitIter.GetHit(),
  1393. rOutput,
  1394. cwcMargin,
  1395. cwcDelim,
  1396. cwcSeparation );
  1397. extractedHit.ExtractHit();
  1398. }
  1399. } //CExtractHits
  1400. //+-------------------------------------------------------------------------
  1401. //
  1402. // Member: PHttpOutput::PHttpOutput - public constructor
  1403. //
  1404. // Arguments: [webServer] -- The web server to write to
  1405. // [langInfo] -- Language information
  1406. //
  1407. //--------------------------------------------------------------------------
  1408. PHttpOutput::PHttpOutput(
  1409. CWebServer & webServer,
  1410. CLanguageInfo & langInfo ):
  1411. _hasPrintedHeader(FALSE),
  1412. _xwc24BitColourMask(new WCHAR[8]),
  1413. _isBold(FALSE),
  1414. _isItalic(FALSE),
  1415. _isInPreformat(FALSE),
  1416. _newLine(FALSE),
  1417. _cwcOutputBuffer(0),
  1418. _pGetEnvVars(NULL),
  1419. _pTemplate(NULL),
  1420. _fUseHiliteTags(FALSE),
  1421. _cwcBeginHiliteTag(0),
  1422. _cwcEndHiliteTag(0),
  1423. _webServer( webServer ),
  1424. _langInfo( langInfo )
  1425. {
  1426. wcscpy(_xwc24BitColourMask.GetPointer(),L"#FF0000");
  1427. _mbStr.Init( MAX_OUTPUT_BUF );
  1428. }
  1429. //+---------------------------------------------------------------------------
  1430. //
  1431. // Member: PHttpOutput::Init
  1432. //
  1433. // Synopsis: Initializes the output generation class with the environment
  1434. // variables object and the template object.
  1435. //
  1436. // Arguments: [pGetEnvVars] - Pointer to the object that has the relevant
  1437. // environment variables.
  1438. // [pTemplate] - [OPTIONAL] - Pointer to the template object.
  1439. // If non-zero, this will be used to generate the output for
  1440. // hit-highlighter.
  1441. //
  1442. // History: 9-09-96 srikants Created
  1443. //
  1444. //----------------------------------------------------------------------------
  1445. void PHttpOutput::Init(CGetEnvVars* pGetEnvVars, CWebhitsTemplate * pTemplate )
  1446. {
  1447. Win4Assert( 0 != pGetEnvVars );
  1448. delete[] _xwc24BitColourMask.Acquire();
  1449. _pGetEnvVars = pGetEnvVars;
  1450. _xwc24BitColourMask.Set(_pGetEnvVars->GetColour().Acquire());
  1451. _isItalic = _pGetEnvVars->GetItalic();
  1452. _isBold = _pGetEnvVars->GetBold();
  1453. _ccCurrLine = 0;
  1454. _ccMaxLine = _pGetEnvVars->GetFixedFontLineLen();
  1455. _pTemplate = pTemplate;
  1456. _fUseHiliteTags = _pGetEnvVars->GetBeginHiliteTag() &&
  1457. _pGetEnvVars->GetEndHiliteTag();
  1458. if ( _fUseHiliteTags )
  1459. {
  1460. _cwcBeginHiliteTag = wcslen( _pGetEnvVars->GetBeginHiliteTag() );
  1461. _cwcEndHiliteTag = wcslen( _pGetEnvVars->GetEndHiliteTag() );
  1462. }
  1463. }
  1464. #define WCHAR_COUNT(x) ( (sizeof(x)/sizeof(WCHAR))-1 )
  1465. //+-------------------------------------------------------------------------
  1466. //
  1467. // Member: PHttpOutput::OutputHtmlHeader()
  1468. //
  1469. // Synopsis: Output the HTML header
  1470. //
  1471. //--------------------------------------------------------------------------
  1472. void PHttpOutput::OutputHTMLHeader()
  1473. {
  1474. if ( 0 == _pTemplate || !_pTemplate->DoesHeaderExist() )
  1475. {
  1476. WCHAR* pwszTemp;
  1477. static const WCHAR wszHdr1[] = L"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<HTML>\n<HEAD>\n";
  1478. static const ULONG ccHdr1 = WCHAR_COUNT(wszHdr1);
  1479. OutputHttp( wszHdr1, ccHdr1 );
  1480. static const WCHAR wszHdr2[] = L"<TITLE>Query Results</TITLE>\n</HEAD>\n";
  1481. static const ULONG ccHdr2 = WCHAR_COUNT(wszHdr2);
  1482. OutputHttp( wszHdr2, ccHdr2 );
  1483. static const WCHAR wszHdr3[] = L"<H2>\"";
  1484. static const ULONG ccHdr3 = WCHAR_COUNT(wszHdr3);
  1485. OutputHttp( wszHdr3, ccHdr3 );
  1486. pwszTemp = (WCHAR*) _pGetEnvVars->GetRestriction();
  1487. OutputHttpText(pwszTemp, wcslen(pwszTemp));
  1488. static const WCHAR wszHdr4[] = L"\" in </H2>\n";
  1489. static const ULONG ccHdr4 = WCHAR_COUNT( wszHdr4 );
  1490. OutputHttp( wszHdr4, ccHdr4 );
  1491. static const WCHAR wszHdr5[] = L"<H2><a href=\"";
  1492. static const ULONG ccHdr5 = WCHAR_COUNT(wszHdr5);
  1493. OutputHttp( wszHdr5, ccHdr5 );
  1494. pwszTemp = (WCHAR*) _pGetEnvVars->GetWebHitsFileVPath();
  1495. OutputHttp(pwszTemp,wcslen(pwszTemp));
  1496. static const WCHAR wszHdr6[] = L"\">";
  1497. static const ULONG ccHdr6 = WCHAR_COUNT(wszHdr6);
  1498. OutputHttp( wszHdr6, ccHdr6 );
  1499. OutputHttpText(pwszTemp,wcslen(pwszTemp));
  1500. static const WCHAR wszHdr7[] = L"</a> </H2><P><HR>\n<BODY>";
  1501. static const ULONG ccHdr7 = WCHAR_COUNT(wszHdr7);
  1502. OutputHttp( wszHdr7, ccHdr7 );
  1503. }
  1504. else
  1505. {
  1506. static const WCHAR wszHdr8[] = L"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n";
  1507. static const ULONG ccHdr8 = WCHAR_COUNT(wszHdr8);
  1508. OutputHttp( wszHdr8, ccHdr8 );
  1509. CVirtualString str;
  1510. _pTemplate->GetWTXFile().GetHeader( str, _pTemplate->GetVariableSet() );
  1511. OutputHttp( str.Get(), str.StrLen() );
  1512. }
  1513. _hasPrintedHeader = TRUE;
  1514. } //OutputHTMLHeader
  1515. //+-------------------------------------------------------------------------
  1516. //
  1517. // Member: PHttpOutput::OutputHtmlFooter
  1518. //
  1519. // Synopsis: Output HTML footer
  1520. //
  1521. //--------------------------------------------------------------------------
  1522. void PHttpOutput::OutputHTMLFooter()
  1523. {
  1524. if ( _isInPreformat )
  1525. {
  1526. static const WCHAR wszTag1[] = L"</pre>";
  1527. static const ULONG ccTag1 = WCHAR_COUNT( wszTag1 );
  1528. OutputHttp( wszTag1, ccTag1 );
  1529. }
  1530. if ( 0 == _pTemplate || !_pTemplate->DoesFooterExist() )
  1531. {
  1532. static const WCHAR wszTag2[] = L"</BODY>\n </HTML>";
  1533. static const ULONG ccTag2 = WCHAR_COUNT( wszTag2 );
  1534. OutputHttp( wszTag2, ccTag2 );
  1535. }
  1536. else
  1537. {
  1538. CVirtualString str;
  1539. _pTemplate->GetWTXFile().GetFooter( str,
  1540. _pTemplate->GetVariableSet() );
  1541. OutputHttp( str.Get(), str.StrLen() );
  1542. }
  1543. } //OutputHTMLFooter
  1544. //+-----------------------------------------------------------------------
  1545. //
  1546. // Member: PHttpOutput::OutputHilite()
  1547. //
  1548. // Arguments: [pwszBuffer] - pointer to the buffer to be output highlited
  1549. // [cwcBuffLength] - number of characters to print from the buff.
  1550. //
  1551. // Synopsis: Output the buffer in highlited form
  1552. //
  1553. //+-----------------------------------------------------------------------
  1554. void PHttpOutput::OutputHilite(const WCHAR* pwszBuffer, ULONG cwcBuffLength)
  1555. {
  1556. if ( !_fUseHiliteTags )
  1557. {
  1558. WCHAR wcsColourCodeEnd[] = L"</font>";
  1559. WCHAR wcsColourTag[50];
  1560. swprintf(wcsColourTag,L"<font color=\"%s\">",_xwc24BitColourMask.GetPointer());
  1561. static const WCHAR wcsBoldBegin[]=L"<B>";
  1562. static const cwcBoldBegin = wcslen( wcsBoldBegin );
  1563. static const WCHAR wcsItalicBegin[]=L"<em>";
  1564. static const cwcItalicBegin = wcslen( wcsItalicBegin );
  1565. static const WCHAR wcsBoldEnd[]=L"</B>";
  1566. static const cwcBoldEnd = wcslen(wcsBoldEnd);
  1567. static const WCHAR wcsItalicEnd[]=L"</em>";
  1568. static const cwcItalicEnd=wcslen(wcsItalicEnd);
  1569. if (_isBold)
  1570. {
  1571. OutputHttp( wcsBoldBegin,cwcBoldBegin);
  1572. }
  1573. if (_isItalic)
  1574. {
  1575. OutputHttp( wcsItalicBegin, cwcItalicBegin);
  1576. }
  1577. OutputHttp(wcsColourTag,wcslen(wcsColourTag));
  1578. OutputHttp(pwszBuffer,cwcBuffLength);
  1579. OutputHttp(wcsColourCodeEnd,wcslen(wcsColourCodeEnd));
  1580. if (_isItalic)
  1581. {
  1582. OutputHttp( wcsItalicEnd, cwcItalicEnd );
  1583. }
  1584. if (_isBold)
  1585. {
  1586. OutputHttp( wcsBoldEnd, cwcBoldEnd );
  1587. }
  1588. }
  1589. else
  1590. {
  1591. OutputHttp( _pGetEnvVars->GetBeginHiliteTag(), _cwcBeginHiliteTag );
  1592. OutputHttp( pwszBuffer,cwcBuffLength );
  1593. OutputHttp( _pGetEnvVars->GetEndHiliteTag(), _cwcEndHiliteTag );
  1594. }
  1595. } //OutputHilite
  1596. //+-----------------------------------------------------------------------
  1597. //
  1598. // Member: PHttpOutput::OutputLeftTag()
  1599. //
  1600. // Arguments: [tagParam] - integer to be used in setting destination tag
  1601. //
  1602. // Synopsis: Output the "<<" tag, making it refer to "Tag[tagParam]"
  1603. //
  1604. //+-----------------------------------------------------------------------
  1605. void PHttpOutput::OutputLeftTag(int tagParam)
  1606. {
  1607. _cwcOutputBuffer = swprintf(_wcOutputBuffer,L"%s\"%s%d\"%s",
  1608. L"<a href=",L"#CiTag",tagParam,L">&lt;&lt;</a>");
  1609. OutputHttp(_wcOutputBuffer,_cwcOutputBuffer);
  1610. }
  1611. //+-----------------------------------------------------------------------
  1612. //
  1613. // Member: PHttpOutput::OutputRightTag()
  1614. //
  1615. // Arguments: [tagParam] - integer to be used in setting destination tag
  1616. //
  1617. // Synopsis: Output the ">>" tag, making it refer to "Tag[tagParam]"
  1618. //
  1619. //+-----------------------------------------------------------------------
  1620. void PHttpOutput::OutputRightTag(int tagParam)
  1621. {
  1622. _cwcOutputBuffer = swprintf(_wcOutputBuffer, L"%s\"%s%d\"%s",L"<a href=",
  1623. L"#CiTag", tagParam, L">&gt;&gt;</a>&nbsp;");
  1624. OutputHttp(_wcOutputBuffer,_cwcOutputBuffer);
  1625. }
  1626. //+-----------------------------------------------------------------------
  1627. //
  1628. // Member: PHttpOutput::OutputEllipsis()
  1629. //
  1630. // Synopsis: Output the ellipsis that separates the truncated text between
  1631. // two consecutive positions
  1632. //
  1633. //+-----------------------------------------------------------------------
  1634. void PHttpOutput::OutputEllipsis()
  1635. {
  1636. OutputHttp(L" ... ",5);
  1637. }
  1638. //+-----------------------------------------------------------------------
  1639. //
  1640. // Member: PHttpOutput::OutputFullHeader()
  1641. //
  1642. // Synopsis: Output the additional header information specific to the
  1643. // full hit-highliting
  1644. //
  1645. //+-----------------------------------------------------------------------
  1646. void PHttpFullOutput::OutputFullHeader()
  1647. {
  1648. if ( 0 == _pTemplate || !_pTemplate->DoesHeaderExist() )
  1649. {
  1650. _cwcOutputBuffer = swprintf(_wcOutputBuffer,
  1651. L"%s\"%s\"%s %s %s\"%s\"%s",
  1652. L"<h3><b> <font color=",
  1653. L"#FF0000",
  1654. L">",
  1655. L"&lt;&lt; </font> takes you to the previous hit. ",
  1656. L"<font color=",L"#FF0000",
  1657. L"> &gt;&gt; </font> takes you to the next hit.</b></h3><P>\n");
  1658. OutputHttp(_wcOutputBuffer,_cwcOutputBuffer);
  1659. _cwcOutputBuffer = swprintf(_wcOutputBuffer, L"%s\"%s\"%s %s",
  1660. L"<b>Click <a href=",L"#CiTag0",
  1661. L"> &gt;&gt; </a> to go to the first hit</b>\n", L"<HR>\n" );
  1662. OutputHttp(_wcOutputBuffer, _cwcOutputBuffer);
  1663. }
  1664. } //OutputFullHeader
  1665. //+---------------------------------------------------------------------------
  1666. //
  1667. // Member: PHttpOutput::WriteToStdout
  1668. //
  1669. // Synopsis:
  1670. //
  1671. // Arguments: [pwcsBuffer] - the buffer
  1672. // [cLength] - count of wide characters
  1673. //
  1674. // History: 11-15-96 srikants Created
  1675. //
  1676. //----------------------------------------------------------------------------
  1677. void PHttpOutput::WriteToStdout( WCHAR const * pwcsBuffer, ULONG cLength )
  1678. {
  1679. if ( 0 != cLength )
  1680. _vsResult.StrCat( pwcsBuffer, cLength );
  1681. } //WriteToStdout
  1682. //+---------------------------------------------------------------------------
  1683. //
  1684. // Member: PHttpOutput::Flush
  1685. //
  1686. // Synopsis: Flushes the buffer to the web server
  1687. //
  1688. // History: 10-10-97 dlee Created
  1689. //
  1690. //----------------------------------------------------------------------------
  1691. void PHttpOutput::Flush()
  1692. {
  1693. if ( 0 != _vsResult.StrLen() )
  1694. {
  1695. DWORD cbToWrite = WideCharToXArrayMultiByte(
  1696. _vsResult.Get(),
  1697. _vsResult.StrLen(),
  1698. _langInfo.GetOutputCodePage(),
  1699. _mbStr );
  1700. if ( 0 != cbToWrite )
  1701. _webServer.RawWriteClient( _mbStr.Get(), cbToWrite );
  1702. _vsResult.Empty();
  1703. }
  1704. } //Flush
  1705. //+---------------------------------------------------------------------------
  1706. //
  1707. // Member: PHttpOutput::OutputPreformattedTag
  1708. //
  1709. // Synopsis: Outputs the pre-formatted tag if not already emitted.
  1710. //
  1711. //----------------------------------------------------------------------------
  1712. void PHttpOutput::OutputPreformattedTag()
  1713. {
  1714. if ( !_isInPreformat )
  1715. {
  1716. static WCHAR wszTag[] = L"<pre>";
  1717. static const len = ( sizeof(wszTag)/sizeof(WCHAR) ) - 1;
  1718. WriteToStdout( wszTag, len );
  1719. _isInPreformat = TRUE;
  1720. }
  1721. }
  1722. //+---------------------------------------------------------------------------
  1723. //
  1724. // Member: PHttpOutput::OutputPreFormatRawText
  1725. //
  1726. // Synopsis: Outputs the text for pre-formatted type.
  1727. //
  1728. // Arguments: [pwcsBuffer] -
  1729. // [cLength] -
  1730. //
  1731. // History: 11-15-96 srikants Created
  1732. //
  1733. //----------------------------------------------------------------------------
  1734. void PHttpOutput::OutputPreFormatRawText( const WCHAR * pwcsBuffer,
  1735. ULONG cLength )
  1736. {
  1737. Win4Assert( _isInPreformat );
  1738. WCHAR const * pwcsCurrLineBegin = pwcsBuffer;
  1739. for ( ULONG i=0, cwcToWrite = 0;
  1740. i< cLength;
  1741. i++ )
  1742. {
  1743. if ( IsNewLine( pwcsBuffer[i] ) )
  1744. {
  1745. //
  1746. // Empty out the current line - as much as has been
  1747. // accumulated.
  1748. //
  1749. WriteToStdout( pwcsCurrLineBegin, cwcToWrite );
  1750. WriteNewline();
  1751. if ( pwcsBuffer[i] == '\r' && pwcsBuffer[i+1] == '\n' )
  1752. i++;
  1753. _ccCurrLine = cwcToWrite = 0;
  1754. pwcsCurrLineBegin = pwcsBuffer+i+1; // Position at the next character
  1755. }
  1756. else
  1757. {
  1758. //
  1759. // Include this character in the current line.
  1760. //
  1761. cwcToWrite++;
  1762. //
  1763. // _ccCurrLine is cumulative from multiple invocations.
  1764. //
  1765. _ccCurrLine++;
  1766. if ( _ccCurrLine > _ccMaxLine && iswspace( pwcsBuffer[i] ) )
  1767. {
  1768. //
  1769. // Write out the line and force a line feed.
  1770. //
  1771. WriteToStdout( pwcsCurrLineBegin, cwcToWrite );
  1772. WriteNewline();
  1773. pwcsCurrLineBegin += cwcToWrite;
  1774. Win4Assert( pwcsCurrLineBegin == pwcsBuffer+i+1 );
  1775. _ccCurrLine = cwcToWrite = 0;
  1776. }
  1777. }
  1778. }
  1779. WriteToStdout( pwcsCurrLineBegin, cwcToWrite );
  1780. } //OutputPreFormatRawText
  1781. void PHttpOutput::WriteNewline()
  1782. {
  1783. static WCHAR wcNewLine[] = L"\r\n";
  1784. static const len = (sizeof(wcNewLine)/sizeof(WCHAR))-1;
  1785. WriteToStdout( wcNewLine, len );
  1786. }
  1787. void PHttpOutput::WriteBreakTag()
  1788. {
  1789. static WCHAR wcBreakTag[] = L"<BR>";
  1790. static const len = (sizeof(wcBreakTag)/sizeof(WCHAR)) - 1;
  1791. WriteToStdout( wcBreakTag, len );
  1792. }
  1793. //+-----------------------------------------------------------------------
  1794. //
  1795. // Member: PHttpOutput::OutputHttp
  1796. //
  1797. // Arguments: [pwcsBuffer] - pointer to buffer containing text
  1798. // [cLength] - the number of characters to print
  1799. // [fRawText] - if TRUE, convert cr, lf and paragraph
  1800. // mark to <BR> or newline
  1801. //
  1802. // Synopsis: Encapsulates the output operation - for now, writes to stdout
  1803. //
  1804. //+-----------------------------------------------------------------------
  1805. void PHttpOutput::OutputHttp( const WCHAR* pwcsBuffer, ULONG cLength,
  1806. BOOL fRawText )
  1807. {
  1808. if ( !fRawText )
  1809. {
  1810. //
  1811. // This is HTML header or footer or formatting. No need to
  1812. // introduce <BR> tags for new-lines and paragraphs.
  1813. //
  1814. WriteToStdout( pwcsBuffer, cLength );
  1815. return;
  1816. }
  1817. else if ( _isInPreformat )
  1818. {
  1819. //
  1820. // We can emit cr-lf as cr-lf. No need to convert to <BR> tags.
  1821. // However, we have to respect the max-line length.
  1822. //
  1823. OutputPreFormatRawText( pwcsBuffer, cLength );
  1824. return;
  1825. }
  1826. //
  1827. // We must output raw text that is not pre-formatted. We have to
  1828. // convert the newlines, paragraph separators to BreakTags.
  1829. //
  1830. WCHAR const * pwcsCurrLineBegin = pwcsBuffer;
  1831. for ( ULONG i=0, cwcToWrite = 0;
  1832. i< cLength;
  1833. i++ )
  1834. {
  1835. if ( IsNewLine( pwcsBuffer[i] ) )
  1836. {
  1837. WriteToStdout( pwcsCurrLineBegin, cwcToWrite );
  1838. WriteBreakTag();
  1839. if ( pwcsBuffer[i] == '\r' && pwcsBuffer[i+1] == '\n' )
  1840. i++;
  1841. cwcToWrite = 0;
  1842. pwcsCurrLineBegin = pwcsBuffer+i+1;
  1843. }
  1844. else
  1845. {
  1846. cwcToWrite++;
  1847. }
  1848. }
  1849. WriteToStdout( pwcsCurrLineBegin, cwcToWrite );
  1850. } //OutputHttp
  1851. //+-----------------------------------------------------------------------
  1852. //
  1853. // Member: PHttpOutput::OutputErrorHeader()
  1854. //
  1855. // Synopsis: Output an "ERROR" header
  1856. //
  1857. //+-----------------------------------------------------------------------
  1858. void PHttpOutput::OutputErrorHeader()
  1859. {
  1860. static const WCHAR wszHdr[] = L"HTTP/1.0 200 OK \r\nContent-Type: text/html\r\n\r\n<HTML>\n<BODY>\n";
  1861. static const ULONG ccHdr = WCHAR_COUNT( wszHdr );
  1862. OutputHttp( wszHdr, ccHdr );
  1863. }
  1864. //+-----------------------------------------------------------------------
  1865. //
  1866. // Member: PHttpOutput::OutputErrorMessage
  1867. //
  1868. // Synopsis: Send error message to stdout / web page
  1869. //
  1870. // Arguments: [pwcsBuffer] -- Error message
  1871. // [ccBuffer] -- Size in characters of [pwcsBuffer]
  1872. //
  1873. // History: 31-Jul-97 KyleP Added header
  1874. //
  1875. //+-----------------------------------------------------------------------
  1876. void PHttpOutput::OutputErrorMessage( WCHAR * pwcsBuffer, ULONG ccBuffer )
  1877. {
  1878. static const WCHAR wszTag1[] = L"<p><h3><center>";
  1879. static const ULONG ccTag1 = WCHAR_COUNT( wszTag1 );
  1880. OutputHttp( wszTag1, ccTag1 );
  1881. OutputHttpText( pwcsBuffer, ccBuffer );
  1882. static const WCHAR wszTag2[] = L"</center></h3><BR>";
  1883. static const ULONG ccTag2 = WCHAR_COUNT( wszTag2 );
  1884. OutputHttp( wszTag2, ccTag2 );
  1885. }
  1886. //+-----------------------------------------------------------------------
  1887. //
  1888. // Member: PHttpOutput::TagPosition
  1889. //
  1890. // Arguments: [tagParam] - output a <NAME="Tag[tagParam]"> tag
  1891. //
  1892. // Synopsis: Tag the current position
  1893. //
  1894. //+-----------------------------------------------------------------------
  1895. void PHttpOutput::TagPosition(int tagParam)
  1896. {
  1897. _cwcOutputBuffer= swprintf(_wcOutputBuffer,L"%s\"%s%d\"%s",
  1898. L"<a NAME=",L"CiTag",tagParam,L"> </a>");
  1899. OutputHttp(_wcOutputBuffer,_cwcOutputBuffer);
  1900. }
  1901. //+---------------------------------------------------------------------------
  1902. //
  1903. // Member: PHttpOutput::OutputHttpText
  1904. //
  1905. // Synopsis: Outputs the given data as "text" and not as html formatting.
  1906. //
  1907. // Arguments: [pwcsBuffer] - buffer to be output
  1908. // [cchLength] - length of pwcsBuffer
  1909. //
  1910. // Notes: Any UNICODE_PARAGRAPH_SEPARATOR characters in the buffer
  1911. // need to be preserved for use by OutputHttp
  1912. //
  1913. // History: 9-09-96 srikants Created
  1914. //
  1915. //----------------------------------------------------------------------------
  1916. void PHttpOutput::OutputHttpText( WCHAR * pwcsBuffer, ULONG cchLength )
  1917. {
  1918. if ( cchLength > 0 )
  1919. {
  1920. //
  1921. // NOTE - HTMLEscapeW expects the string to be NULL terminated. It
  1922. // does not accept a length field. HTMLEscapeW is one of the most
  1923. // frequently executed routines in idq.dll and so changing it to
  1924. // optionally take in a length parameter may affect performance.
  1925. // That is why I have chosen to overwrite the current buffer with
  1926. // a NULL at cchLength and restore it after the escaping - srikants.
  1927. //
  1928. const WCHAR wcTemp = pwcsBuffer[cchLength];
  1929. pwcsBuffer[cchLength] = 0;
  1930. WCHAR * pwcsTmpBuf = pwcsBuffer;
  1931. WCHAR * pwcsParaMark = wcschr( pwcsTmpBuf, UNICODE_PARAGRAPH_SEPARATOR );
  1932. while ( 0 != pwcsParaMark )
  1933. {
  1934. _escapedStr.Empty();
  1935. *pwcsParaMark = 0;
  1936. HTMLEscapeW( pwcsTmpBuf, _escapedStr, _langInfo.GetOutputCodePage() );
  1937. _escapedStr.CharCat( UNICODE_PARAGRAPH_SEPARATOR );
  1938. OutputHttp( _escapedStr.Get(), _escapedStr.StrLen(), TRUE );
  1939. *pwcsParaMark = UNICODE_PARAGRAPH_SEPARATOR;
  1940. pwcsTmpBuf = pwcsParaMark + 1;
  1941. pwcsParaMark = wcschr( pwcsTmpBuf, UNICODE_PARAGRAPH_SEPARATOR );
  1942. }
  1943. if (*pwcsTmpBuf)
  1944. {
  1945. _escapedStr.Empty();
  1946. HTMLEscapeW( pwcsTmpBuf, _escapedStr, _langInfo.GetOutputCodePage() );
  1947. OutputHttp( _escapedStr.Get(), _escapedStr.StrLen(), TRUE );
  1948. }
  1949. pwcsBuffer[cchLength] = wcTemp;
  1950. }
  1951. } //OutputHttpText
  1952. //+---------------------------------------------------------------------------
  1953. //
  1954. // Member: CWebhitsTemplate::CWebhitsTemplate
  1955. //
  1956. // Synopsis: Constructor of the webhits template file. It takes the
  1957. // environment variables object and reads in the htx file,
  1958. // processes it. Also, adds the appropriate replaceable
  1959. // parameters.
  1960. //
  1961. // Arguments: [envVars] - Environment variables to use
  1962. // [codePage] - Codepage to use for the template
  1963. //
  1964. // History: 9-09-96 srikants Created
  1965. //
  1966. //----------------------------------------------------------------------------
  1967. CWebhitsTemplate::CWebhitsTemplate(
  1968. CGetEnvVars const & envVars,
  1969. ULONG codePage )
  1970. : _wtxFile( envVars.GetTemplateFileVPath(),
  1971. envVars.GetTemplateFilePPath(),
  1972. codePage )
  1973. {
  1974. //
  1975. // Add the replacable parameters to the variable set.
  1976. //
  1977. _variableSet.AddParam( wcsParamCiUrl, envVars.GetWebHitsFileVPath() );
  1978. _variableSet.AddParam( wcsParamRestriction, envVars.GetRestriction() );
  1979. if (envVars.GetLocale())
  1980. _variableSet.AddParam( wcsLocale, envVars.GetLocale() );
  1981. if (envVars.GetCodepage())
  1982. _variableSet.AddParam( wcsCodepage, envVars.GetCodepage() );
  1983. //
  1984. // Add user definable parameters.
  1985. //
  1986. for ( ULONG i = 0; i < CGetEnvVars::eMaxUserReplParams; i++ )
  1987. {
  1988. if ( envVars.GetUserParam(i+1) )
  1989. {
  1990. _variableSet.AddParam( awcsUserParamNames[i],
  1991. envVars.GetUserParam(i+1) );
  1992. }
  1993. }
  1994. //
  1995. // Parse the htx file.
  1996. //
  1997. _wtxFile.ParseFile( _variableSet );
  1998. } //CWebhitsTemplate