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.

551 lines
12 KiB

  1. //
  2. // MODULE: APGTSHTX.CPP
  3. //
  4. // PURPOSE: Template file decoder
  5. //
  6. // PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
  7. //
  8. // COMPANY: Saltmine Creative, Inc. (206)-633-4743 [email protected]
  9. //
  10. // AUTHOR: Roman Mach
  11. //
  12. // ORIGINAL DATE: 8-2-96
  13. //
  14. // NOTES:
  15. // 1. Based on Print Troubleshooter DLL
  16. //
  17. // Version Date By Comments
  18. //--------------------------------------------------------------------
  19. // V0.1 - RM Original
  20. // V0.15 8/15/96 VM New htx format
  21. // V0.2 6/4/97 RWM Local Version for Memphis
  22. // V0.3 04/09/98 JM/OK+ Local Version for NT5
  23. //
  24. #include "stdafx.h"
  25. //#include <windows.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <search.h>
  31. #include <dos.h>
  32. #include <ctype.h>
  33. #include <limits.h>
  34. #include <time.h>
  35. #include "apgts.h"
  36. #include "ErrorEnums.h"
  37. #include "bnts.h"
  38. #include "BackupInfo.h"
  39. #include "cachegen.h"
  40. #include "apgtsinf.h"
  41. #include "apgtscmd.h"
  42. #include "apgtshtx.h"
  43. #include "TSHOOT.h"
  44. #include "chmread.h"
  45. //
  46. //
  47. CHTMLInputTemplate::CHTMLInputTemplate(const TCHAR *filename)
  48. {
  49. // initialize a few things
  50. m_dwErr = 0;
  51. m_cur_stack_count=0;
  52. m_command_start = NULL;
  53. _tcscpy(m_filename,filename);
  54. m_cHeaderItems = 0;
  55. m_infer = NULL;
  56. m_strResPath = _T("");
  57. }
  58. //
  59. //
  60. CHTMLInputTemplate::~CHTMLInputTemplate()
  61. {
  62. Destroy();
  63. }
  64. //
  65. // must be locked to use
  66. //
  67. VOID CHTMLInputTemplate::SetInfer(CInfer *infer, TCHAR *vroot)
  68. {
  69. m_infer = infer;
  70. _tcscpy(m_vroot, vroot);
  71. }
  72. //
  73. //
  74. DWORD CHTMLInputTemplate::Initialize(LPCTSTR szResPath, CString strFile)
  75. {
  76. CHAR *filestr;
  77. m_dwErr = 0;
  78. m_strResPath = szResPath;
  79. m_strFile = strFile;
  80. if (strFile.GetLength())
  81. {
  82. // m_filename is CHM file path and name
  83. // and strFile - file name within CHM
  84. if (S_OK != ::ReadChmFile(m_filename, strFile, (void**)&filestr, &m_dwSize))
  85. {
  86. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
  87. return m_dwErr;
  88. }
  89. }
  90. else
  91. {
  92. // m_filename is a free standing file
  93. DWORD nBytesRead;
  94. HANDLE hFile;
  95. BOOL bResult;
  96. hFile = CreateFile( m_filename,
  97. GENERIC_READ,
  98. FILE_SHARE_READ,
  99. NULL,
  100. OPEN_EXISTING,
  101. FILE_ATTRIBUTE_NORMAL,
  102. NULL );
  103. if (hFile == INVALID_HANDLE_VALUE)
  104. {
  105. //???
  106. //ReportError(TSERR_RESOURCE);
  107. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
  108. return m_dwErr;
  109. }
  110. m_dwSize = GetFileSize(hFile, NULL);
  111. filestr = (CHAR *)malloc(m_dwSize+1);
  112. if (!((m_dwSize != 0xFFFFFFFF) && (m_dwSize != 0)) || filestr == NULL)
  113. {
  114. CloseHandle(hFile);
  115. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
  116. return m_dwErr;
  117. }
  118. bResult = ReadFile(hFile, filestr, m_dwSize, &nBytesRead, NULL);
  119. if(!(bResult && nBytesRead == m_dwSize))
  120. {
  121. CloseHandle(hFile);
  122. free(filestr);
  123. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
  124. return m_dwErr;
  125. }
  126. CloseHandle(hFile);
  127. hFile = NULL;
  128. }
  129. filestr[m_dwSize] = '\0';
  130. #ifdef _UNICODE
  131. WCHAR *wfilestr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
  132. WCHAR *wchopstr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
  133. MultiByteToWideChar( CP_ACP, 0, filestr, -1, wfilestr, m_dwSize );
  134. MultiByteToWideChar( CP_ACP, 0, filestr, -1, wchopstr, m_dwSize );
  135. m_startstr = wfilestr;
  136. m_chopstr = wchopstr;
  137. #else
  138. m_startstr = filestr;
  139. m_chopstr = (CHAR *)malloc(m_dwSize+1);
  140. strcpy(m_chopstr, filestr);
  141. #endif
  142. // get locations of start and end blocks
  143. ScanFile();
  144. // copy blocks into ram for speed
  145. BuildInMem();
  146. // free memory
  147. free(filestr);
  148. #ifdef _UNICODE
  149. free(wfilestr);
  150. #endif
  151. free(m_chopstr);
  152. return m_dwErr;
  153. }
  154. //
  155. //
  156. VOID CHTMLInputTemplate::Destroy()
  157. {
  158. HTXCommand *command, *nextcommand;
  159. // free holders
  160. command = m_command_start;
  161. nextcommand = command;
  162. while (command != NULL) {
  163. nextcommand = command->GetNext();
  164. delete command;
  165. command = nextcommand;
  166. }
  167. }
  168. //
  169. //
  170. DWORD CHTMLInputTemplate::Reload()
  171. {
  172. Destroy();
  173. return Initialize((LPCTSTR) m_strResPath, m_strFile);
  174. }
  175. //
  176. //
  177. void CHTMLInputTemplate::ScanFile()
  178. {
  179. UINT start, end;
  180. TCHAR *ptr, *sptr, *eptr, var_name[30];
  181. HTXCommand *tmpCommand, *prevCommand;
  182. UINT var_index;
  183. sptr = m_chopstr;
  184. m_cur_command = new HTXCommand(HTX_TYPESTART,_T(""));
  185. end = start = 0;
  186. m_cur_command->SetStart(start);
  187. m_cur_command->SetEnd(end);
  188. m_command_start = m_cur_command;
  189. // this is bad: if the user does not terminate each command on a separate line
  190. // the file will misbehave, should at least write out a warning or something...
  191. sptr = _tcstok(sptr, _T("\r\n"));
  192. if (sptr)
  193. {
  194. do
  195. {
  196. if ((sptr = _tcsstr(sptr,HTX_COMMAND_START)) != NULL)
  197. {
  198. if ((ptr = _tcsstr(sptr,HTX_ENDIFSTR))!=NULL)
  199. {
  200. tmpCommand = new HTXCommand(HTX_TYPEENDIF,HTX_ENDIFSTR);
  201. prevCommand = Pop();
  202. if (prevCommand->GetType() != HTX_TYPEIF)
  203. {
  204. m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
  205. break;
  206. }
  207. prevCommand->SetEndIf(tmpCommand);
  208. }
  209. else if ((ptr = _tcsstr(sptr,HTX_ENDFORSTR))!=NULL)
  210. {
  211. tmpCommand = new HTXCommand(HTX_TYPEENDFOR,HTX_ENDFORSTR);
  212. prevCommand = Pop();
  213. if (prevCommand->GetType() != HTX_TYPEFORANY)
  214. {
  215. m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
  216. break;
  217. }
  218. prevCommand->SetEndFor(tmpCommand);
  219. }
  220. else if ((ptr = _tcsstr(sptr,HTX_ELSESTR))!=NULL)
  221. {
  222. tmpCommand = new HTXCommand(HTX_TYPEELSE,HTX_ELSESTR);
  223. prevCommand = Pop();
  224. if (prevCommand->GetType() != HTX_TYPEIF)
  225. {
  226. m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
  227. break;
  228. }
  229. prevCommand->SetElse(tmpCommand);
  230. Push(prevCommand);
  231. }
  232. else if ((ptr = _tcsstr(sptr,HTX_IFSTR))!=NULL)
  233. {
  234. // get the variable
  235. ptr = _tcsninc(ptr, _tcslen(HTX_IFSTR));
  236. if( _stscanf(ptr,_T("%s"),var_name) <= 0)
  237. m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
  238. if ((var_index = CheckVariable(var_name)) == FALSE )
  239. {
  240. m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
  241. break;
  242. }
  243. tmpCommand = new HTXIfCommand(HTX_TYPEIF,HTX_IFSTR,var_index);
  244. Push(tmpCommand);
  245. }
  246. else if ((ptr = _tcsstr(sptr,HTX_FORANYSTR))!=NULL)
  247. {
  248. // get variable
  249. ptr = _tcsninc(ptr, _tcslen(HTX_FORANYSTR));
  250. if( _stscanf(ptr,_T("%s"),var_name) <= 0)
  251. m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
  252. if ((var_index = CheckVariable(var_name)) == FALSE )
  253. {
  254. m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
  255. break;
  256. }
  257. tmpCommand = new HTXForCommand(HTX_TYPEFORANY,HTX_FORANYSTR, var_index);
  258. Push(tmpCommand);
  259. }
  260. else if ((ptr = _tcsstr(sptr,HTX_DISPLAYSTR))!=NULL)
  261. {
  262. // get variable
  263. ptr = _tcsninc(ptr, _tcslen(HTX_DISPLAYSTR));
  264. if( _stscanf(ptr,_T("%s"),var_name) <= 0)
  265. m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
  266. if ((var_index = CheckVariable(var_name)) == FALSE )
  267. {
  268. m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
  269. break;
  270. }
  271. tmpCommand = new HTXDisplayCommand(HTX_TYPEDISPLAY,HTX_DISPLAYSTR, var_index);
  272. }
  273. else if ((ptr = _tcsstr(sptr, HTX_RESOURCESTR)) != NULL)
  274. {
  275. ptr = _tcsninc(ptr, _tcslen(HTX_RESOURCESTR));
  276. if (_stscanf(ptr, _T("%s"), var_name) <= 0)
  277. m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
  278. if ((var_index = CheckVariable(var_name)) == FALSE)
  279. {
  280. m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
  281. break;
  282. }
  283. m_cHeaderItems++;
  284. tmpCommand = new HTXResourceCommand(HTX_TYPERESOURCE, HTX_RESOURCESTR);
  285. ((HTXResourceCommand *) tmpCommand)->GetResName(var_name);
  286. }
  287. else
  288. continue;
  289. // get the command terminator
  290. if ((eptr = _tcsstr(ptr,HTX_COMMAND_END)) == NULL)
  291. {
  292. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
  293. eptr = ptr; // try to recover
  294. }
  295. eptr = _tcsninc(eptr, _tcslen(HTX_COMMAND_END));
  296. if (tmpCommand == NULL)
  297. {
  298. m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM;
  299. return;
  300. }
  301. // Add command to command list
  302. if (m_command_start == NULL)
  303. {
  304. m_command_start = tmpCommand;
  305. m_cur_command = tmpCommand;
  306. }
  307. else
  308. {
  309. m_cur_command->SetNext(tmpCommand);
  310. m_cur_command = tmpCommand;
  311. }
  312. CString strCHM = ::ExtractCHM(m_filename);
  313. tmpCommand->GetResource(m_strResPath, strCHM);
  314. start = (UINT)(sptr - m_chopstr); // / sizeof (TCHAR);
  315. end = (UINT)(eptr - m_chopstr); // / sizeof (TCHAR);
  316. tmpCommand->SetStart(start);
  317. tmpCommand->SetEnd(end);
  318. }
  319. } while ((sptr = _tcstok(NULL, _T("\r\n"))) != NULL);
  320. }
  321. if (m_cur_stack_count > 0) // missing and endfor or an endif
  322. m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
  323. }
  324. /*
  325. * METHOD: BuildInMem
  326. *
  327. * PURPOSE: This method will read the HTML between commands (after) and associate
  328. * it with the command. As a command is executed the HTML after the
  329. * command is printed
  330. *
  331. */
  332. UINT CHTMLInputTemplate::BuildInMem()
  333. {
  334. HTXCommand *cur_com, *last_command;
  335. if (m_dwErr)
  336. return (TRUE);
  337. // copy strings from file to
  338. // note duplication of effort (before and after strings may be same string)
  339. cur_com = m_command_start;
  340. last_command = cur_com;
  341. while (cur_com != NULL) {
  342. if (cur_com->GetNext() == NULL) {
  343. if (cur_com->ReadAfterStr(cur_com->GetEnd(), m_dwSize, m_startstr))
  344. return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
  345. }
  346. else {
  347. if (cur_com->ReadAfterStr(cur_com->GetEnd(), cur_com->GetNext()->GetStart(), m_startstr))
  348. return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
  349. }
  350. last_command = cur_com;
  351. cur_com = cur_com->GetNext();
  352. }
  353. return (FALSE);
  354. }
  355. //
  356. //
  357. bool CHTMLInputTemplate::IsFileName(TCHAR *name)
  358. {
  359. bool bFileName;
  360. if (name[0] != _T('$'))
  361. bFileName = false;
  362. else if (NULL == _tcsstr(name, _T(".")))
  363. bFileName = false;
  364. else
  365. bFileName = true;
  366. return bFileName;
  367. }
  368. /*
  369. * METHOD: CheckVariable
  370. *
  371. * PURPOSE: This routine will check to see if the variable name is a valid one
  372. * and if it is will return a UINT that represents that variable.
  373. * Integers are used in other routines when refering to a variable (for
  374. * speed).
  375. *
  376. */
  377. UINT CHTMLInputTemplate::CheckVariable(TCHAR *var_name)
  378. {
  379. if (!_tcsncmp(DATA_PROBLEM_ASK,var_name, _tcslen(var_name))) {
  380. return (PROBLEM_ASK_INDEX);
  381. }
  382. else if (!_tcsncmp(DATA_RECOMMENDATIONS,var_name, _tcslen(var_name))) {
  383. return (RECOMMENDATIONS_INDEX);
  384. }
  385. else if (!_tcsncmp(DATA_QUESTIONS,var_name, _tcslen(var_name))) {
  386. return (QUESTIONS_INDEX);
  387. }
  388. else if (!_tcsncmp(DATA_STATE,var_name, _tcslen(var_name))) {
  389. return (STATE_INDEX);
  390. }
  391. else if (!_tcsncmp(DATA_BACK,var_name, _tcslen(var_name))) {
  392. return (BACK_INDEX);
  393. }
  394. else if (!_tcsncmp(DATA_TROUBLE_SHOOTERS, var_name, _tcslen(var_name))) {
  395. return (TROUBLE_SHOOTER_INDEX);
  396. }
  397. else if (IsFileName(var_name)) {
  398. return (RESOURCE_INDEX);
  399. }
  400. else return (FALSE);
  401. }
  402. //
  403. //
  404. UINT CHTMLInputTemplate::GetStatus()
  405. {
  406. return (m_dwErr);
  407. }
  408. CHTMLInputTemplate::Push(HTXCommand *command)
  409. {
  410. if (m_cur_stack_count >9)
  411. return(FALSE);
  412. m_command_stack[m_cur_stack_count] = command;
  413. m_cur_stack_count++;
  414. return(TRUE);
  415. }
  416. HTXCommand *CHTMLInputTemplate::Pop()
  417. {
  418. if (m_cur_stack_count <= 0)
  419. return(NULL);
  420. return(m_command_stack[--m_cur_stack_count]);
  421. }
  422. //
  423. //
  424. HTXCommand *CHTMLInputTemplate::GetFirstCommand()
  425. {
  426. return(m_command_start);
  427. }
  428. /*
  429. * ROUTINE: SetType
  430. *
  431. * PURPOSE: This set the TroubleShooter Type in the template
  432. * The type field is printed after the header information
  433. *
  434. */
  435. void CHTMLInputTemplate::SetType(LPCTSTR type)
  436. {
  437. _stprintf(m_tstype, _T("%s"),type);
  438. }
  439. /*
  440. * ROUTINE: Print
  441. *
  442. * PURPOSE: Prints out the Template. This functions executes the
  443. * commands in the template and generates the output page.
  444. *
  445. */
  446. CHTMLInputTemplate::Print(UINT nargs, CString *cstr)
  447. {
  448. HTXCommand *cur_com;
  449. CString strTxt;
  450. if (m_dwErr){
  451. strTxt.LoadString(IDS__ER_HTX_PARSE);
  452. *cstr += strTxt;
  453. return(FALSE);
  454. }
  455. cur_com = m_command_start; // get the start command
  456. cur_com = cur_com->Execute(cstr,m_infer); // This prints the header
  457. if (m_cHeaderItems)
  458. { // The first command prints script. Don't start the form.
  459. int count = m_cHeaderItems;
  460. do
  461. {
  462. cur_com = cur_com->GetNext();
  463. cur_com = cur_com->Execute(cstr, m_infer);
  464. count--;
  465. } while (count > 0);
  466. AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
  467. *cstr += strTxt;
  468. cur_com = cur_com->GetNext();
  469. }
  470. else
  471. {
  472. AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
  473. *cstr += strTxt;
  474. cur_com = cur_com->GetNext();
  475. }
  476. while (cur_com != NULL) {
  477. cur_com = cur_com->Execute(cstr, m_infer);
  478. cur_com = cur_com->GetNext();
  479. }
  480. return(TRUE);
  481. }
  482. // for testing
  483. //
  484. void CHTMLInputTemplate::DumpContentsToStdout()
  485. {
  486. HTXCommand *cur_com;
  487. cur_com = GetFirstCommand();
  488. while( cur_com != NULL){
  489. _tprintf(_T("(%d) before: [%s]\n"), cur_com->GetType(), cur_com->GetBeforeStr());
  490. _tprintf(_T("(%d) after: [%s]\n"), cur_com->GetType(), cur_com->GetAfterStr());
  491. _tprintf(_T("\n"));
  492. cur_com = cur_com->GetNext();
  493. }
  494. }