windows-nt/Source/XPSP1/NT/enduser/troubleshoot/control/apgtshtx.cpp
2020-09-26 16:20:57 +08:00

552 lines
12 KiB
C++

//
// MODULE: APGTSHTX.CPP
//
// PURPOSE: Template file decoder
//
// PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
//
// COMPANY: Saltmine Creative, Inc. (206)-633-4743 support@saltmine.com
//
// AUTHOR: Roman Mach
//
// ORIGINAL DATE: 8-2-96
//
// NOTES:
// 1. Based on Print Troubleshooter DLL
//
// Version Date By Comments
//--------------------------------------------------------------------
// V0.1 - RM Original
// V0.15 8/15/96 VM New htx format
// V0.2 6/4/97 RWM Local Version for Memphis
// V0.3 04/09/98 JM/OK+ Local Version for NT5
//
#include "stdafx.h"
//#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <search.h>
#include <dos.h>
#include <ctype.h>
#include <limits.h>
#include <time.h>
#include "apgts.h"
#include "ErrorEnums.h"
#include "bnts.h"
#include "BackupInfo.h"
#include "cachegen.h"
#include "apgtsinf.h"
#include "apgtscmd.h"
#include "apgtshtx.h"
#include "TSHOOT.h"
#include "chmread.h"
//
//
CHTMLInputTemplate::CHTMLInputTemplate(const TCHAR *filename)
{
// initialize a few things
m_dwErr = 0;
m_cur_stack_count=0;
m_command_start = NULL;
_tcscpy(m_filename,filename);
m_cHeaderItems = 0;
m_infer = NULL;
m_strResPath = _T("");
}
//
//
CHTMLInputTemplate::~CHTMLInputTemplate()
{
Destroy();
}
//
// must be locked to use
//
VOID CHTMLInputTemplate::SetInfer(CInfer *infer, TCHAR *vroot)
{
m_infer = infer;
_tcscpy(m_vroot, vroot);
}
//
//
DWORD CHTMLInputTemplate::Initialize(LPCTSTR szResPath, CString strFile)
{
CHAR *filestr;
m_dwErr = 0;
m_strResPath = szResPath;
m_strFile = strFile;
if (strFile.GetLength())
{
// m_filename is CHM file path and name
// and strFile - file name within CHM
if (S_OK != ::ReadChmFile(m_filename, strFile, (void**)&filestr, &m_dwSize))
{
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
return m_dwErr;
}
}
else
{
// m_filename is a free standing file
DWORD nBytesRead;
HANDLE hFile;
BOOL bResult;
hFile = CreateFile( m_filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (hFile == INVALID_HANDLE_VALUE)
{
//???
//ReportError(TSERR_RESOURCE);
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
return m_dwErr;
}
m_dwSize = GetFileSize(hFile, NULL);
filestr = (CHAR *)malloc(m_dwSize+1);
if (!((m_dwSize != 0xFFFFFFFF) && (m_dwSize != 0)) || filestr == NULL)
{
CloseHandle(hFile);
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
return m_dwErr;
}
bResult = ReadFile(hFile, filestr, m_dwSize, &nBytesRead, NULL);
if(!(bResult && nBytesRead == m_dwSize))
{
CloseHandle(hFile);
free(filestr);
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
return m_dwErr;
}
CloseHandle(hFile);
hFile = NULL;
}
filestr[m_dwSize] = '\0';
#ifdef _UNICODE
WCHAR *wfilestr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
WCHAR *wchopstr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
MultiByteToWideChar( CP_ACP, 0, filestr, -1, wfilestr, m_dwSize );
MultiByteToWideChar( CP_ACP, 0, filestr, -1, wchopstr, m_dwSize );
m_startstr = wfilestr;
m_chopstr = wchopstr;
#else
m_startstr = filestr;
m_chopstr = (CHAR *)malloc(m_dwSize+1);
strcpy(m_chopstr, filestr);
#endif
// get locations of start and end blocks
ScanFile();
// copy blocks into ram for speed
BuildInMem();
// free memory
free(filestr);
#ifdef _UNICODE
free(wfilestr);
#endif
free(m_chopstr);
return m_dwErr;
}
//
//
VOID CHTMLInputTemplate::Destroy()
{
HTXCommand *command, *nextcommand;
// free holders
command = m_command_start;
nextcommand = command;
while (command != NULL) {
nextcommand = command->GetNext();
delete command;
command = nextcommand;
}
}
//
//
DWORD CHTMLInputTemplate::Reload()
{
Destroy();
return Initialize((LPCTSTR) m_strResPath, m_strFile);
}
//
//
void CHTMLInputTemplate::ScanFile()
{
UINT start, end;
TCHAR *ptr, *sptr, *eptr, var_name[30];
HTXCommand *tmpCommand, *prevCommand;
UINT var_index;
sptr = m_chopstr;
m_cur_command = new HTXCommand(HTX_TYPESTART,_T(""));
end = start = 0;
m_cur_command->SetStart(start);
m_cur_command->SetEnd(end);
m_command_start = m_cur_command;
// this is bad: if the user does not terminate each command on a separate line
// the file will misbehave, should at least write out a warning or something...
sptr = _tcstok(sptr, _T("\r\n"));
if (sptr)
{
do
{
if ((sptr = _tcsstr(sptr,HTX_COMMAND_START)) != NULL)
{
if ((ptr = _tcsstr(sptr,HTX_ENDIFSTR))!=NULL)
{
tmpCommand = new HTXCommand(HTX_TYPEENDIF,HTX_ENDIFSTR);
prevCommand = Pop();
if (prevCommand->GetType() != HTX_TYPEIF)
{
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
break;
}
prevCommand->SetEndIf(tmpCommand);
}
else if ((ptr = _tcsstr(sptr,HTX_ENDFORSTR))!=NULL)
{
tmpCommand = new HTXCommand(HTX_TYPEENDFOR,HTX_ENDFORSTR);
prevCommand = Pop();
if (prevCommand->GetType() != HTX_TYPEFORANY)
{
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
break;
}
prevCommand->SetEndFor(tmpCommand);
}
else if ((ptr = _tcsstr(sptr,HTX_ELSESTR))!=NULL)
{
tmpCommand = new HTXCommand(HTX_TYPEELSE,HTX_ELSESTR);
prevCommand = Pop();
if (prevCommand->GetType() != HTX_TYPEIF)
{
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
break;
}
prevCommand->SetElse(tmpCommand);
Push(prevCommand);
}
else if ((ptr = _tcsstr(sptr,HTX_IFSTR))!=NULL)
{
// get the variable
ptr = _tcsninc(ptr, _tcslen(HTX_IFSTR));
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
if ((var_index = CheckVariable(var_name)) == FALSE )
{
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
break;
}
tmpCommand = new HTXIfCommand(HTX_TYPEIF,HTX_IFSTR,var_index);
Push(tmpCommand);
}
else if ((ptr = _tcsstr(sptr,HTX_FORANYSTR))!=NULL)
{
// get variable
ptr = _tcsninc(ptr, _tcslen(HTX_FORANYSTR));
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
if ((var_index = CheckVariable(var_name)) == FALSE )
{
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
break;
}
tmpCommand = new HTXForCommand(HTX_TYPEFORANY,HTX_FORANYSTR, var_index);
Push(tmpCommand);
}
else if ((ptr = _tcsstr(sptr,HTX_DISPLAYSTR))!=NULL)
{
// get variable
ptr = _tcsninc(ptr, _tcslen(HTX_DISPLAYSTR));
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
if ((var_index = CheckVariable(var_name)) == FALSE )
{
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
break;
}
tmpCommand = new HTXDisplayCommand(HTX_TYPEDISPLAY,HTX_DISPLAYSTR, var_index);
}
else if ((ptr = _tcsstr(sptr, HTX_RESOURCESTR)) != NULL)
{
ptr = _tcsninc(ptr, _tcslen(HTX_RESOURCESTR));
if (_stscanf(ptr, _T("%s"), var_name) <= 0)
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
if ((var_index = CheckVariable(var_name)) == FALSE)
{
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
break;
}
m_cHeaderItems++;
tmpCommand = new HTXResourceCommand(HTX_TYPERESOURCE, HTX_RESOURCESTR);
((HTXResourceCommand *) tmpCommand)->GetResName(var_name);
}
else
continue;
// get the command terminator
if ((eptr = _tcsstr(ptr,HTX_COMMAND_END)) == NULL)
{
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
eptr = ptr; // try to recover
}
eptr = _tcsninc(eptr, _tcslen(HTX_COMMAND_END));
if (tmpCommand == NULL)
{
m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM;
return;
}
// Add command to command list
if (m_command_start == NULL)
{
m_command_start = tmpCommand;
m_cur_command = tmpCommand;
}
else
{
m_cur_command->SetNext(tmpCommand);
m_cur_command = tmpCommand;
}
CString strCHM = ::ExtractCHM(m_filename);
tmpCommand->GetResource(m_strResPath, strCHM);
start = (UINT)(sptr - m_chopstr); // / sizeof (TCHAR);
end = (UINT)(eptr - m_chopstr); // / sizeof (TCHAR);
tmpCommand->SetStart(start);
tmpCommand->SetEnd(end);
}
} while ((sptr = _tcstok(NULL, _T("\r\n"))) != NULL);
}
if (m_cur_stack_count > 0) // missing and endfor or an endif
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
}
/*
* METHOD: BuildInMem
*
* PURPOSE: This method will read the HTML between commands (after) and associate
* it with the command. As a command is executed the HTML after the
* command is printed
*
*/
UINT CHTMLInputTemplate::BuildInMem()
{
HTXCommand *cur_com, *last_command;
if (m_dwErr)
return (TRUE);
// copy strings from file to
// note duplication of effort (before and after strings may be same string)
cur_com = m_command_start;
last_command = cur_com;
while (cur_com != NULL) {
if (cur_com->GetNext() == NULL) {
if (cur_com->ReadAfterStr(cur_com->GetEnd(), m_dwSize, m_startstr))
return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
}
else {
if (cur_com->ReadAfterStr(cur_com->GetEnd(), cur_com->GetNext()->GetStart(), m_startstr))
return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
}
last_command = cur_com;
cur_com = cur_com->GetNext();
}
return (FALSE);
}
//
//
bool CHTMLInputTemplate::IsFileName(TCHAR *name)
{
bool bFileName;
if (name[0] != _T('$'))
bFileName = false;
else if (NULL == _tcsstr(name, _T(".")))
bFileName = false;
else
bFileName = true;
return bFileName;
}
/*
* METHOD: CheckVariable
*
* PURPOSE: This routine will check to see if the variable name is a valid one
* and if it is will return a UINT that represents that variable.
* Integers are used in other routines when refering to a variable (for
* speed).
*
*/
UINT CHTMLInputTemplate::CheckVariable(TCHAR *var_name)
{
if (!_tcsncmp(DATA_PROBLEM_ASK,var_name, _tcslen(var_name))) {
return (PROBLEM_ASK_INDEX);
}
else if (!_tcsncmp(DATA_RECOMMENDATIONS,var_name, _tcslen(var_name))) {
return (RECOMMENDATIONS_INDEX);
}
else if (!_tcsncmp(DATA_QUESTIONS,var_name, _tcslen(var_name))) {
return (QUESTIONS_INDEX);
}
else if (!_tcsncmp(DATA_STATE,var_name, _tcslen(var_name))) {
return (STATE_INDEX);
}
else if (!_tcsncmp(DATA_BACK,var_name, _tcslen(var_name))) {
return (BACK_INDEX);
}
else if (!_tcsncmp(DATA_TROUBLE_SHOOTERS, var_name, _tcslen(var_name))) {
return (TROUBLE_SHOOTER_INDEX);
}
else if (IsFileName(var_name)) {
return (RESOURCE_INDEX);
}
else return (FALSE);
}
//
//
UINT CHTMLInputTemplate::GetStatus()
{
return (m_dwErr);
}
CHTMLInputTemplate::Push(HTXCommand *command)
{
if (m_cur_stack_count >9)
return(FALSE);
m_command_stack[m_cur_stack_count] = command;
m_cur_stack_count++;
return(TRUE);
}
HTXCommand *CHTMLInputTemplate::Pop()
{
if (m_cur_stack_count <= 0)
return(NULL);
return(m_command_stack[--m_cur_stack_count]);
}
//
//
HTXCommand *CHTMLInputTemplate::GetFirstCommand()
{
return(m_command_start);
}
/*
* ROUTINE: SetType
*
* PURPOSE: This set the TroubleShooter Type in the template
* The type field is printed after the header information
*
*/
void CHTMLInputTemplate::SetType(LPCTSTR type)
{
_stprintf(m_tstype, _T("%s"),type);
}
/*
* ROUTINE: Print
*
* PURPOSE: Prints out the Template. This functions executes the
* commands in the template and generates the output page.
*
*/
CHTMLInputTemplate::Print(UINT nargs, CString *cstr)
{
HTXCommand *cur_com;
CString strTxt;
if (m_dwErr){
strTxt.LoadString(IDS__ER_HTX_PARSE);
*cstr += strTxt;
return(FALSE);
}
cur_com = m_command_start; // get the start command
cur_com = cur_com->Execute(cstr,m_infer); // This prints the header
if (m_cHeaderItems)
{ // The first command prints script. Don't start the form.
int count = m_cHeaderItems;
do
{
cur_com = cur_com->GetNext();
cur_com = cur_com->Execute(cstr, m_infer);
count--;
} while (count > 0);
AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
*cstr += strTxt;
cur_com = cur_com->GetNext();
}
else
{
AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
*cstr += strTxt;
cur_com = cur_com->GetNext();
}
while (cur_com != NULL) {
cur_com = cur_com->Execute(cstr, m_infer);
cur_com = cur_com->GetNext();
}
return(TRUE);
}
// for testing
//
void CHTMLInputTemplate::DumpContentsToStdout()
{
HTXCommand *cur_com;
cur_com = GetFirstCommand();
while( cur_com != NULL){
_tprintf(_T("(%d) before: [%s]\n"), cur_com->GetType(), cur_com->GetBeforeStr());
_tprintf(_T("(%d) after: [%s]\n"), cur_com->GetType(), cur_com->GetAfterStr());
_tprintf(_T("\n"));
cur_com = cur_com->GetNext();
}
}