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.

554 lines
15 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: chm.cpp
  4. //
  5. // History: 21-Mar-00 vadimb Created.
  6. //
  7. // Desc: This file contains all code needed to produce chm project files
  8. //
  9. ////////////////////////////////////////////////////////////////////////////////////
  10. #include "stdafx.h"
  11. #include "obj.h"
  12. #include "make.h"
  13. #include "globals.h"
  14. #include "chm.h"
  15. #include "FileIO.h"
  16. TCHAR gszTagXMLBR[] = _T("<br/>");
  17. TCHAR gszTagBR[] = _T("<br>");
  18. TCHAR gszTagXMLP[] = _T("<p/>");
  19. TCHAR gszTagP[] = _T("<p>");
  20. TCHAR gszHFileName[] = _T("apperr.h");
  21. BOOL ChmMakeFilePath(
  22. CString& csPath,
  23. LPCTSTR lpszPath,
  24. LPCTSTR lpszFileName,
  25. LPCTSTR lpszExt = NULL)
  26. {
  27. csPath.Empty();
  28. if (NULL != lpszPath) {
  29. csPath = lpszPath;
  30. if (csPath.GetLength() >= 1 && csPath.Right(1) != _T("\\")) {
  31. csPath += _T('\\');
  32. }
  33. }
  34. csPath += lpszFileName;
  35. if (NULL != lpszExt) {
  36. csPath += lpszExt;
  37. }
  38. return(csPath.GetLength() > 0);
  39. }
  40. CString ChmConstructArticleName(
  41. SdbOutputFile* pOutputFile,
  42. SdbAppHelp* pAppHelp,
  43. CString& csLangID)
  44. {
  45. CString csArticleName, csLCID;
  46. csArticleName = pOutputFile->GetParameter(_T("ARTICLE NAME TEMPLATE"));
  47. if (!csArticleName.GetLength()) {
  48. csArticleName = _T("idh_w2_$HTMLHELPID$");
  49. }
  50. ReplaceStringNoCase(csArticleName, _T("$HTMLHELPID$"), pAppHelp->m_csName);
  51. ReplaceStringNoCase(csArticleName, _T("$LANGID$"), csLangID);
  52. csLCID.Format(_T("%X"), pAppHelp->m_pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_lcid);
  53. ReplaceStringNoCase(csArticleName, _T("$LCID$"), csLCID);
  54. return csArticleName;
  55. }
  56. BOOL ChmCreatePage(
  57. SdbDatabase* pDB,
  58. SdbOutputFile* pOutputFile,
  59. SdbAppHelp* pAppHelp,
  60. SdbMessage* pMessage,
  61. CString& csTemplate,
  62. CString& csLangID
  63. )
  64. {
  65. CString csHelpID;
  66. CString csFilePath;
  67. CString csTemp;
  68. CString csContents;
  69. BOOL bSuccess = FALSE;
  70. DWORD dwHTMLHelpID;
  71. SdbMessageField FieldIcon;
  72. SdbMessageField FieldMessage;
  73. SdbMessageField FieldMSHAID;
  74. SdbMessageField FieldAName;
  75. SdbMessageField FieldAppTitle;
  76. SdbMessageField FieldAppVersion;
  77. SdbMessageField FieldContactInfo;
  78. SdbMessageField FieldDetails;
  79. SdbMessageField FieldCompanyName;
  80. SdbRefArray<SdbMessageField> rgFields;
  81. CString csURL, csContactInfo, csAppTitle;
  82. CString csDetails, csEncoding;
  83. CTextFile* pFile = NULL;
  84. csEncoding = pOutputFile->GetParameter(_T("ENCODING"));
  85. if (!pMessage->m_pDB->ConstructMessageParts(
  86. pAppHelp,
  87. pMessage,
  88. csLangID,
  89. &dwHTMLHelpID,
  90. &csURL,
  91. &csContactInfo,
  92. &csAppTitle,
  93. NULL,
  94. &csDetails)) {
  95. SDBERROR_PROPOGATE();
  96. goto eh;
  97. }
  98. // generate name for the file -- this name appears also in
  99. // other places like in a tag at the beginning of the page, in
  100. // meta tag and in help project file, as well as in apperr.h
  101. //
  102. // give this entry a name in form idh_w2_helpid
  103. // this is also a filename (sans .htm)
  104. //
  105. csHelpID = ChmConstructArticleName(pOutputFile, pAppHelp, csLangID);
  106. csFilePath.Format(_T("%s%s.htm"), pOutputFile->GetDirectory(), csHelpID);
  107. try {
  108. if (0 == csEncoding.CompareNoCase(_T("ANSI"))) {
  109. pFile = new CANSITextFile(csFilePath,
  110. pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_dwCodePage,
  111. CFile::typeText |
  112. CFile::modeCreate |
  113. CFile::modeWrite |
  114. CFile::shareDenyWrite);
  115. } else {
  116. pFile = new CUTF8TextFile(csFilePath,
  117. CFile::typeText |
  118. CFile::modeCreate |
  119. CFile::modeWrite |
  120. CFile::shareDenyWrite);
  121. }
  122. csContents = csTemplate;
  123. // first up is the MS_HAID
  124. csTemp.Format(_T("<META NAME=\"MS_HAID\" CONTENT=\"a_%s\">\n"), (LPCTSTR)csHelpID);
  125. FieldMSHAID.m_csName = _T("MS_HAID");
  126. FieldMSHAID.m_csValue = csTemp;
  127. //
  128. // problem level...
  129. // will not be used now
  130. switch(pAppHelp->m_Type) {
  131. case SDB_APPHELP_HARDBLOCK:
  132. csTemp = _T("<IMG SRC=\"apphelp_stop.gif\"/>");
  133. break;
  134. case SDB_APPHELP_NOBLOCK:
  135. csTemp = _T("<IMG SRC=\"apphelp_warn.gif\"/>");
  136. break;
  137. }
  138. FieldIcon.m_csName = _T("ICON");
  139. FieldIcon.m_csValue = csTemp;
  140. // next is name
  141. csTemp.Format(_T("<P><A NAME=\"a_%s\"></A></P>"), (LPCTSTR)csHelpID);
  142. FieldAName.m_csName = _T("A NAME");
  143. FieldAName.m_csValue = csTemp;
  144. csTemp = csAppTitle;
  145. csTemp.Replace(_T("\r\n"), _T("\n"));
  146. FieldAppTitle.m_csName = _T("TITLE");
  147. FieldAppTitle.m_csValue = csTemp;
  148. csTemp = _T("");
  149. csTemp.Replace(_T("\r\n"), _T("\n"));
  150. FieldAppVersion.m_csName = _T("VERSION");
  151. FieldAppVersion.m_csValue = csTemp;
  152. csTemp = csContactInfo;
  153. csTemp.Replace(_T("\r\n"), _T("\n"));
  154. ReplaceStringNoCase(csTemp, gszTagXMLBR, gszTagBR);
  155. ReplaceStringNoCase(csTemp, gszTagXMLP, gszTagP);
  156. FieldContactInfo.m_csName = _T("CONTACT INFO");
  157. FieldContactInfo.m_csValue = csTemp;
  158. csTemp = csDetails;
  159. csTemp.Replace(_T("\r\n"), _T("\n"));
  160. ReplaceStringNoCase(csTemp, gszTagXMLBR, gszTagBR);
  161. ReplaceStringNoCase(csTemp, gszTagXMLP, gszTagP);
  162. FieldDetails.m_csName = _T("DETAILS");
  163. FieldDetails.m_csValue = csTemp;
  164. csTemp = pAppHelp->m_pApp->GetLocalizedVendorName();
  165. FieldCompanyName.m_csName = _T("COMPANY NAME");
  166. FieldCompanyName.m_csValue = csTemp;
  167. rgFields.Add(&FieldIcon);
  168. rgFields.Add(&FieldMessage);
  169. rgFields.Add(&FieldMSHAID);
  170. rgFields.Add(&FieldAName);
  171. rgFields.Add(&FieldAppTitle);
  172. rgFields.Add(&FieldAppVersion);
  173. rgFields.Add(&FieldContactInfo);
  174. rgFields.Add(&FieldDetails);
  175. rgFields.Add(&FieldCompanyName);
  176. if (!pDB->ReplaceFields(csContents, &csContents, &rgFields)) {
  177. goto eh;
  178. }
  179. if (0 == csEncoding.CompareNoCase(_T("ANSI"))) {
  180. ReplaceStringNoCase(
  181. csContents,
  182. _T("%HTML_CHARSET%"),
  183. pDB->m_pCurrentMakefile->GetLangMap(csLangID)->m_csHtmlCharset);
  184. } else {
  185. ReplaceStringNoCase(
  186. csContents,
  187. _T("%HTML_CHARSET%"),
  188. _T("UTF-8"));
  189. }
  190. pFile->WriteString(csContents);
  191. pFile->Close();
  192. bSuccess = TRUE;
  193. }
  194. catch(CFileException* pFileEx) {
  195. pFileEx->Delete();
  196. }
  197. catch(CMemoryException* pMemEx) {
  198. pMemEx->Delete();
  199. }
  200. eh:
  201. if (pFile) {
  202. delete pFile;
  203. }
  204. return bSuccess;
  205. }
  206. BOOL ChmUpdateFile(LPCTSTR lpszFilePath, LPCTSTR lpszString)
  207. {
  208. BOOL bSuccess = TRUE;
  209. try {
  210. CStdioFile File(lpszFilePath, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::shareDenyWrite);
  211. File.SeekToEnd();
  212. File.WriteString(lpszString);
  213. }
  214. catch(CFileException* pex) {
  215. bSuccess = FALSE;
  216. pex->Delete();
  217. }
  218. return(bSuccess);
  219. }
  220. //
  221. // generate apperr.h
  222. // generate symbols for every file
  223. //
  224. BOOL ChmCreateHFileEntry(SdbAppHelp* pAppHelp, CString& csEntry)
  225. {
  226. csEntry.Format(_T("#define idh_w2_%s %s"),
  227. pAppHelp->m_csName,
  228. pAppHelp->m_csName);
  229. return(TRUE);
  230. }
  231. BOOL ChmUpdateHFile(
  232. SdbOutputFile* pOutputFile,
  233. SdbMessage* pMessage,
  234. SdbAppHelp* pAppHelp)
  235. {
  236. CString csEntry;
  237. BOOL bSuccess;
  238. CString csFilePath;
  239. csFilePath = pOutputFile->GetFullPathWithoutExtension() + _T(".h");
  240. bSuccess = ChmCreateHFileEntry(pAppHelp, csEntry);
  241. if (bSuccess) {
  242. csEntry += _T("\n");
  243. bSuccess = ChmUpdateFile(csFilePath, csEntry);
  244. }
  245. return(bSuccess);
  246. }
  247. BOOL ChmWriteHHPFileHeader(
  248. SdbDatabase* pDB,
  249. SdbOutputFile* pOutputFile)
  250. {
  251. CString csHeader, csOut;
  252. BOOL bSuccess = FALSE;
  253. csHeader += _T("[OPTIONS] \n");
  254. csHeader += _T("Binary Index=No \n");
  255. csHeader += _T("Compatibility=1.1 \n");
  256. csHeader += _T("Compiled file=%s.chm \n");
  257. csHeader += _T("Default Window=nobrowse \n");
  258. csHeader += _T("Default topic=%s_first_screen.htm \n");
  259. csHeader += _T("Display compile progress=Yes \n");
  260. csHeader += _T("Error log file=%s.log \n");
  261. csHeader += _T(" \n");
  262. csHeader += _T("[WINDOWS] \n");
  263. csHeader += _T("nobrowse=\"\",,,,,,,,,,,0x0,,,,,,,,0 \n");
  264. csHeader += _T(" \n");
  265. csHeader += _T("[MAP] \n");
  266. csHeader += _T(" \n");
  267. csHeader += _T("[FILES] \n");
  268. csHeader += _T("%s_first_screen.htm \n");
  269. CString csNameWithoutExt = pOutputFile->GetNameWithoutExtension();
  270. csOut.Format(csHeader, csNameWithoutExt,
  271. csNameWithoutExt, csNameWithoutExt,
  272. csNameWithoutExt);
  273. try {
  274. CStdioFile File(pOutputFile->GetFullPathWithoutExtension() + _T(".hhp"),
  275. CFile::typeText |
  276. CFile::modeCreate |
  277. CFile::modeWrite |
  278. CFile::shareDenyWrite);
  279. File.WriteString(csOut);
  280. File.Close();
  281. }
  282. catch(...) {
  283. goto eh;
  284. }
  285. bSuccess = TRUE;
  286. eh:
  287. return bSuccess;
  288. }
  289. BOOL ChmWriteFirstScreen(
  290. SdbDatabase* pDB,
  291. SdbOutputFile* pOutputFile)
  292. {
  293. BOOL bSuccess = FALSE;
  294. try {
  295. CStdioFile File(pOutputFile->GetFullPathWithoutExtension() + _T("_first_screen.htm"),
  296. CFile::typeText |
  297. CFile::modeCreate |
  298. CFile::modeWrite |
  299. CFile::shareDenyWrite);
  300. File.WriteString(pDB->m_csHTMLHelpFirstScreen);
  301. File.Close();
  302. }
  303. catch(...) {
  304. goto eh;
  305. }
  306. bSuccess = TRUE;
  307. eh:
  308. return bSuccess;
  309. }
  310. BOOL ChmUpdateHHPFile(
  311. SdbOutputFile* pOutputFile,
  312. SdbAppHelp* pAppHelp,
  313. CString csLangID)
  314. {
  315. CString csEntry;
  316. CString csFilePath;
  317. BOOL bSuccess;
  318. csFilePath = pOutputFile->GetFullPathWithoutExtension() + _T(".hhp");
  319. // we presume to be writing file list now
  320. csEntry = ChmConstructArticleName(pOutputFile, pAppHelp, csLangID);
  321. csEntry += _T(".htm\n");
  322. bSuccess = ChmUpdateFile(csFilePath, csEntry);
  323. return(bSuccess);
  324. }
  325. //
  326. // lpszPath here denotes the path to the help file project's directory
  327. //
  328. BOOL ChmProcessMessageEntry(
  329. SdbDatabase* pDB,
  330. SdbOutputFile* pOutputFile,
  331. SdbAppHelp* pAppHelp,
  332. SdbMessage* pMessage,
  333. CString& csTemplate,
  334. CString& csLangID)
  335. {
  336. BOOL bSuccess;
  337. // 1 - generate chum
  338. bSuccess = ChmCreatePage(pDB, pOutputFile, pAppHelp, pMessage, csTemplate, csLangID);
  339. if (!bSuccess) {
  340. goto eh;
  341. }
  342. // 2 - update hhp -- append filename to it
  343. bSuccess = ChmUpdateHHPFile(pOutputFile, pAppHelp, csLangID);
  344. eh:
  345. return(bSuccess);
  346. }
  347. BOOL ChmPrepareDirectory(
  348. SdbDatabase* pDB,
  349. SdbOutputFile* pOutputFile)
  350. {
  351. CString csDest;
  352. BOOL bSuccess = FALSE;
  353. try {
  354. if (!ChmWriteHHPFileHeader(pDB, pOutputFile)) {
  355. goto eh;
  356. }
  357. if (!ChmWriteFirstScreen(pDB, pOutputFile)) {
  358. goto eh;
  359. }
  360. }
  361. catch(CFileException* pex) {
  362. pex->Delete();
  363. goto eh;
  364. }
  365. bSuccess = TRUE;
  366. eh:
  367. return bSuccess;
  368. }
  369. // go through all the entries in apphelp database
  370. BOOL ChmWriteProject(
  371. SdbOutputFile* pOutputFile,
  372. SdbDatabase* pMessageDB)
  373. {
  374. BOOL bOverallSuccess = FALSE;
  375. SdbMessage* pMessage = NULL;
  376. SdbAppHelp* pAppHelp = NULL;
  377. SdbDatabase* pAppHelpDB = NULL;
  378. SdbLocalizedString* pHTMLHelpTemplate = NULL;
  379. int i, j;
  380. CString csTemplate;
  381. CString csLanguagesParam, csLangID;
  382. CStringArray rgLanguages;
  383. csLanguagesParam = pOutputFile->GetParameter(_T("LANGUAGES"));
  384. if (csLanguagesParam.GetLength()) {
  385. if (!ParseLanguagesString(csLanguagesParam, &rgLanguages))
  386. {
  387. SDBERROR_FORMAT((_T("Error parsing LANGUAGES parameter in makefile: %s\n"), csLanguagesParam));
  388. goto eh;
  389. }
  390. } else {
  391. rgLanguages.Add(pMessageDB->m_pCurrentMakefile->m_csLangID);
  392. }
  393. if (!pOutputFile->GetParameter(_T("HTMLHELP TEMPLATE")).GetLength()) {
  394. SDBERROR(_T("No HTMLHELP_TEMPLATE <PARAM> specified for CHM file generation."));
  395. goto eh;
  396. }
  397. if (!ChmPrepareDirectory(pMessageDB, pOutputFile)) {
  398. SDBERROR(_T("Error preparing HTMLHelp directory."));
  399. goto eh;
  400. }
  401. for (j = 0; j < rgLanguages.GetSize(); j++)
  402. {
  403. csLangID = rgLanguages[j];
  404. pHTMLHelpTemplate = (SdbLocalizedString *) pMessageDB->m_rgHTMLHelpTemplates.LookupName(
  405. pOutputFile->GetParameter(_T("HTMLHELP TEMPLATE")), csLangID);
  406. if (!pHTMLHelpTemplate) {
  407. SDBERROR_FORMAT((_T("HTMLHELP_TEMPLATE not found for LANG \"%s\": \"%s\"\n"),
  408. csLangID, pOutputFile->GetParameter(_T("HTMLHELP_TEMPLATE"))));
  409. goto eh;
  410. }
  411. csTemplate = pHTMLHelpTemplate->m_csValue;
  412. if (csTemplate.GetLength() == 0) {
  413. SDBERROR(_T("No HTMLHelp template specified."));
  414. goto eh;
  415. }
  416. pAppHelpDB = pMessageDB;
  417. for (i = 0; i < pAppHelpDB->m_rgAppHelps.GetSize(); ++i) {
  418. pAppHelp = (SdbAppHelp*)pAppHelpDB->m_rgAppHelps[i];
  419. if (SDB_APPHELP_NONE == pAppHelp->m_Type) {
  420. continue;
  421. }
  422. if (g_dtCurrentWriteRevisionCutoff > pAppHelp->m_dtLastRevision) {
  423. continue;
  424. }
  425. pMessage = (SdbMessage *) pMessageDB->m_rgMessages.LookupName(pAppHelp->m_csMessage, csLangID);
  426. if (pMessage == NULL) {
  427. //
  428. // Message instance not found in localized file.
  429. //
  430. SDBERROR_FORMAT((_T("Localized MESSAGE not found for\n NAME: %s\n HTMLHELPID: %s\n LANG: %s\n"),
  431. pAppHelp->m_csMessage, pAppHelp->m_csName, csLangID));
  432. goto eh;
  433. }
  434. if (!ChmProcessMessageEntry(
  435. pMessageDB,
  436. pOutputFile,
  437. pAppHelp,
  438. pMessage,
  439. csTemplate,
  440. csLangID)) {
  441. SDBERROR_PROPOGATE();
  442. goto eh;
  443. }
  444. }
  445. }
  446. bOverallSuccess = TRUE;
  447. eh:
  448. return(bOverallSuccess);
  449. }