////////////////////////////////////////////////////////////////////////////////////
//
// File: chm.cpp
//
// History: 21-Mar-00 vadimb Created.
//
// Desc: This file contains all code needed to produce chm project files
//
////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "obj.h"
#include "make.h"
#include "globals.h"
#include "chm.h"
#include "FileIO.h"
TCHAR gszTagXMLBR[] = _T("
");
TCHAR gszTagBR[] = _T("
");
TCHAR gszTagXMLP[] = _T("
");
TCHAR gszTagP[] = _T("");
TCHAR gszHFileName[] = _T("apperr.h");
BOOL ChmMakeFilePath(
CString& csPath,
LPCTSTR lpszPath,
LPCTSTR lpszFileName,
LPCTSTR lpszExt = NULL)
{
csPath.Empty();
if (NULL != lpszPath) {
csPath = lpszPath;
if (csPath.GetLength() >= 1 && csPath.Right(1) != _T("\\")) {
csPath += _T('\\');
}
}
csPath += lpszFileName;
if (NULL != lpszExt) {
csPath += lpszExt;
}
return(csPath.GetLength() > 0);
}
CString ChmConstructArticleName(
SdbOutputFile* pOutputFile,
SdbAppHelp* pAppHelp,
CString& csLangID)
{
CString csArticleName, csLCID;
csArticleName = pOutputFile->GetParameter(_T("ARTICLE NAME TEMPLATE"));
if (!csArticleName.GetLength()) {
csArticleName = _T("idh_w2_$HTMLHELPID$");
}
ReplaceStringNoCase(csArticleName, _T("$HTMLHELPID$"), pAppHelp->m_csName);
ReplaceStringNoCase(csArticleName, _T("$LANGID$"), csLangID);
csLCID.Format(_T("%X"), pAppHelp->m_pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_lcid);
ReplaceStringNoCase(csArticleName, _T("$LCID$"), csLCID);
return csArticleName;
}
BOOL ChmCreatePage(
SdbDatabase* pDB,
SdbOutputFile* pOutputFile,
SdbAppHelp* pAppHelp,
SdbMessage* pMessage,
CString& csTemplate,
CString& csLangID
)
{
CString csHelpID;
CString csFilePath;
CString csTemp;
CString csContents;
BOOL bSuccess = FALSE;
DWORD dwHTMLHelpID;
SdbMessageField FieldIcon;
SdbMessageField FieldMessage;
SdbMessageField FieldMSHAID;
SdbMessageField FieldAName;
SdbMessageField FieldAppTitle;
SdbMessageField FieldAppVersion;
SdbMessageField FieldContactInfo;
SdbMessageField FieldDetails;
SdbMessageField FieldCompanyName;
SdbRefArray rgFields;
CString csURL, csContactInfo, csAppTitle;
CString csDetails, csEncoding;
CTextFile* pFile = NULL;
csEncoding = pOutputFile->GetParameter(_T("ENCODING"));
if (!pMessage->m_pDB->ConstructMessageParts(
pAppHelp,
pMessage,
csLangID,
&dwHTMLHelpID,
&csURL,
&csContactInfo,
&csAppTitle,
NULL,
&csDetails)) {
SDBERROR_PROPOGATE();
goto eh;
}
// generate name for the file -- this name appears also in
// other places like in a tag at the beginning of the page, in
// meta tag and in help project file, as well as in apperr.h
//
// give this entry a name in form idh_w2_helpid
// this is also a filename (sans .htm)
//
csHelpID = ChmConstructArticleName(pOutputFile, pAppHelp, csLangID);
csFilePath.Format(_T("%s%s.htm"), pOutputFile->GetDirectory(), csHelpID);
try {
if (0 == csEncoding.CompareNoCase(_T("ANSI"))) {
pFile = new CANSITextFile(csFilePath,
pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_dwCodePage,
CFile::typeText |
CFile::modeCreate |
CFile::modeWrite |
CFile::shareDenyWrite);
} else {
pFile = new CUTF8TextFile(csFilePath,
CFile::typeText |
CFile::modeCreate |
CFile::modeWrite |
CFile::shareDenyWrite);
}
csContents = csTemplate;
// first up is the MS_HAID
csTemp.Format(_T("\n"), (LPCTSTR)csHelpID);
FieldMSHAID.m_csName = _T("MS_HAID");
FieldMSHAID.m_csValue = csTemp;
//
// problem level...
// will not be used now
switch(pAppHelp->m_Type) {
case SDB_APPHELP_HARDBLOCK:
csTemp = _T("");
break;
case SDB_APPHELP_NOBLOCK:
csTemp = _T("");
break;
}
FieldIcon.m_csName = _T("ICON");
FieldIcon.m_csValue = csTemp;
// next is name
csTemp.Format(_T("
"), (LPCTSTR)csHelpID);
FieldAName.m_csName = _T("A NAME");
FieldAName.m_csValue = csTemp;
csTemp = csAppTitle;
csTemp.Replace(_T("\r\n"), _T("\n"));
FieldAppTitle.m_csName = _T("TITLE");
FieldAppTitle.m_csValue = csTemp;
csTemp = _T("");
csTemp.Replace(_T("\r\n"), _T("\n"));
FieldAppVersion.m_csName = _T("VERSION");
FieldAppVersion.m_csValue = csTemp;
csTemp = csContactInfo;
csTemp.Replace(_T("\r\n"), _T("\n"));
ReplaceStringNoCase(csTemp, gszTagXMLBR, gszTagBR);
ReplaceStringNoCase(csTemp, gszTagXMLP, gszTagP);
FieldContactInfo.m_csName = _T("CONTACT INFO");
FieldContactInfo.m_csValue = csTemp;
csTemp = csDetails;
csTemp.Replace(_T("\r\n"), _T("\n"));
ReplaceStringNoCase(csTemp, gszTagXMLBR, gszTagBR);
ReplaceStringNoCase(csTemp, gszTagXMLP, gszTagP);
FieldDetails.m_csName = _T("DETAILS");
FieldDetails.m_csValue = csTemp;
csTemp = pAppHelp->m_pApp->GetLocalizedVendorName();
FieldCompanyName.m_csName = _T("COMPANY NAME");
FieldCompanyName.m_csValue = csTemp;
rgFields.Add(&FieldIcon);
rgFields.Add(&FieldMessage);
rgFields.Add(&FieldMSHAID);
rgFields.Add(&FieldAName);
rgFields.Add(&FieldAppTitle);
rgFields.Add(&FieldAppVersion);
rgFields.Add(&FieldContactInfo);
rgFields.Add(&FieldDetails);
rgFields.Add(&FieldCompanyName);
if (!pDB->ReplaceFields(csContents, &csContents, &rgFields)) {
goto eh;
}
if (0 == csEncoding.CompareNoCase(_T("ANSI"))) {
ReplaceStringNoCase(
csContents,
_T("%HTML_CHARSET%"),
pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_csHtmlCharset);
} else {
ReplaceStringNoCase(
csContents,
_T("%HTML_CHARSET%"),
_T("UTF-8"));
}
pFile->WriteString(csContents);
pFile->Close();
bSuccess = TRUE;
}
catch(CFileException* pFileEx) {
pFileEx->Delete();
}
catch(CMemoryException* pMemEx) {
pMemEx->Delete();
}
eh:
if (pFile) {
delete pFile;
}
return bSuccess;
}
BOOL ChmUpdateFile(LPCTSTR lpszFilePath, LPCTSTR lpszString)
{
BOOL bSuccess = TRUE;
try {
CStdioFile File(lpszFilePath, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::shareDenyWrite);
File.SeekToEnd();
File.WriteString(lpszString);
}
catch(CFileException* pex) {
bSuccess = FALSE;
pex->Delete();
}
return(bSuccess);
}
//
// generate apperr.h
// generate symbols for every file
//
BOOL ChmCreateHFileEntry(SdbAppHelp* pAppHelp, CString& csEntry)
{
csEntry.Format(_T("#define idh_w2_%s %s"),
pAppHelp->m_csName,
pAppHelp->m_csName);
return(TRUE);
}
BOOL ChmUpdateHFile(
SdbOutputFile* pOutputFile,
SdbMessage* pMessage,
SdbAppHelp* pAppHelp)
{
CString csEntry;
BOOL bSuccess;
CString csFilePath;
csFilePath = pOutputFile->GetFullPathWithoutExtension() + _T(".h");
bSuccess = ChmCreateHFileEntry(pAppHelp, csEntry);
if (bSuccess) {
csEntry += _T("\n");
bSuccess = ChmUpdateFile(csFilePath, csEntry);
}
return(bSuccess);
}
BOOL ChmWriteHHPFileHeader(
SdbDatabase* pDB,
SdbOutputFile* pOutputFile)
{
CString csHeader, csOut;
BOOL bSuccess = FALSE;
csHeader += _T("[OPTIONS] \n");
csHeader += _T("Binary Index=No \n");
csHeader += _T("Compatibility=1.1 \n");
csHeader += _T("Compiled file=%s.chm \n");
csHeader += _T("Default Window=nobrowse \n");
csHeader += _T("Default topic=%s_first_screen.htm \n");
csHeader += _T("Display compile progress=Yes \n");
csHeader += _T("Error log file=%s.log \n");
csHeader += _T(" \n");
csHeader += _T("[WINDOWS] \n");
csHeader += _T("nobrowse=\"\",,,,,,,,,,,0x0,,,,,,,,0 \n");
csHeader += _T(" \n");
csHeader += _T("[MAP] \n");
csHeader += _T(" \n");
csHeader += _T("[FILES] \n");
csHeader += _T("%s_first_screen.htm \n");
CString csNameWithoutExt = pOutputFile->GetNameWithoutExtension();
csOut.Format(csHeader, csNameWithoutExt,
csNameWithoutExt, csNameWithoutExt,
csNameWithoutExt);
try {
CStdioFile File(pOutputFile->GetFullPathWithoutExtension() + _T(".hhp"),
CFile::typeText |
CFile::modeCreate |
CFile::modeWrite |
CFile::shareDenyWrite);
File.WriteString(csOut);
File.Close();
}
catch(...) {
goto eh;
}
bSuccess = TRUE;
eh:
return bSuccess;
}
BOOL ChmWriteFirstScreen(
SdbDatabase* pDB,
SdbOutputFile* pOutputFile)
{
BOOL bSuccess = FALSE;
try {
CStdioFile File(pOutputFile->GetFullPathWithoutExtension() + _T("_first_screen.htm"),
CFile::typeText |
CFile::modeCreate |
CFile::modeWrite |
CFile::shareDenyWrite);
File.WriteString(pDB->m_csHTMLHelpFirstScreen);
File.Close();
}
catch(...) {
goto eh;
}
bSuccess = TRUE;
eh:
return bSuccess;
}
BOOL ChmUpdateHHPFile(
SdbOutputFile* pOutputFile,
SdbAppHelp* pAppHelp,
CString csLangID)
{
CString csEntry;
CString csFilePath;
BOOL bSuccess;
csFilePath = pOutputFile->GetFullPathWithoutExtension() + _T(".hhp");
// we presume to be writing file list now
csEntry = ChmConstructArticleName(pOutputFile, pAppHelp, csLangID);
csEntry += _T(".htm\n");
bSuccess = ChmUpdateFile(csFilePath, csEntry);
return(bSuccess);
}
//
// lpszPath here denotes the path to the help file project's directory
//
BOOL ChmProcessMessageEntry(
SdbDatabase* pDB,
SdbOutputFile* pOutputFile,
SdbAppHelp* pAppHelp,
SdbMessage* pMessage,
CString& csTemplate,
CString& csLangID)
{
BOOL bSuccess;
// 1 - generate chum
bSuccess = ChmCreatePage(pDB, pOutputFile, pAppHelp, pMessage, csTemplate, csLangID);
if (!bSuccess) {
goto eh;
}
// 2 - update hhp -- append filename to it
bSuccess = ChmUpdateHHPFile(pOutputFile, pAppHelp, csLangID);
eh:
return(bSuccess);
}
BOOL ChmPrepareDirectory(
SdbDatabase* pDB,
SdbOutputFile* pOutputFile)
{
CString csDest;
BOOL bSuccess = FALSE;
try {
if (!ChmWriteHHPFileHeader(pDB, pOutputFile)) {
goto eh;
}
if (!ChmWriteFirstScreen(pDB, pOutputFile)) {
goto eh;
}
}
catch(CFileException* pex) {
pex->Delete();
goto eh;
}
bSuccess = TRUE;
eh:
return bSuccess;
}
// go through all the entries in apphelp database
BOOL ChmWriteProject(
SdbOutputFile* pOutputFile,
SdbDatabase* pMessageDB)
{
BOOL bOverallSuccess = FALSE;
SdbMessage* pMessage = NULL;
SdbAppHelp* pAppHelp = NULL;
SdbDatabase* pAppHelpDB = NULL;
SdbLocalizedString* pHTMLHelpTemplate = NULL;
int i, j;
CString csTemplate;
CString csLanguagesParam, csLangID;
CStringArray rgLanguages;
csLanguagesParam = pOutputFile->GetParameter(_T("LANGUAGES"));
if (csLanguagesParam.GetLength()) {
if (!ParseLanguagesString(csLanguagesParam, &rgLanguages))
{
SDBERROR_FORMAT((_T("Error parsing LANGUAGES parameter in makefile: %s\n"), csLanguagesParam));
goto eh;
}
} else {
rgLanguages.Add(pMessageDB->m_pCurrentMakefile->m_csLangID);
}
if (!pOutputFile->GetParameter(_T("HTMLHELP TEMPLATE")).GetLength()) {
SDBERROR(_T("No HTMLHELP_TEMPLATE specified for CHM file generation."));
goto eh;
}
if (!ChmPrepareDirectory(pMessageDB, pOutputFile)) {
SDBERROR(_T("Error preparing HTMLHelp directory."));
goto eh;
}
for (j = 0; j < rgLanguages.GetSize(); j++)
{
csLangID = rgLanguages[j];
pHTMLHelpTemplate = (SdbLocalizedString *) pMessageDB->m_rgHTMLHelpTemplates.LookupName(
pOutputFile->GetParameter(_T("HTMLHELP TEMPLATE")), csLangID);
if (!pHTMLHelpTemplate) {
SDBERROR_FORMAT((_T("HTMLHELP_TEMPLATE not found for LANG \"%s\": \"%s\"\n"),
csLangID, pOutputFile->GetParameter(_T("HTMLHELP_TEMPLATE"))));
goto eh;
}
csTemplate = pHTMLHelpTemplate->m_csValue;
if (csTemplate.GetLength() == 0) {
SDBERROR(_T("No HTMLHelp template specified."));
goto eh;
}
pAppHelpDB = pMessageDB;
for (i = 0; i < pAppHelpDB->m_rgAppHelps.GetSize(); ++i) {
pAppHelp = (SdbAppHelp*)pAppHelpDB->m_rgAppHelps[i];
if (SDB_APPHELP_NONE == pAppHelp->m_Type) {
continue;
}
if (g_dtCurrentWriteRevisionCutoff > pAppHelp->m_dtLastRevision) {
continue;
}
pMessage = (SdbMessage *) pMessageDB->m_rgMessages.LookupName(pAppHelp->m_csMessage, csLangID);
if (pMessage == NULL) {
//
// Message instance not found in localized file.
//
SDBERROR_FORMAT((_T("Localized MESSAGE not found for\n NAME: %s\n HTMLHELPID: %s\n LANG: %s\n"),
pAppHelp->m_csMessage, pAppHelp->m_csName, csLangID));
goto eh;
}
if (!ChmProcessMessageEntry(
pMessageDB,
pOutputFile,
pAppHelp,
pMessage,
csTemplate,
csLangID)) {
SDBERROR_PROPOGATE();
goto eh;
}
}
}
bOverallSuccess = TRUE;
eh:
return(bOverallSuccess);
}