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.

2717 lines
92 KiB

  1. // Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
  2. #include "header.h"
  3. #include "sitemap.h"
  4. #include <shlobj.h>
  5. #include <wininet.h>
  6. #ifndef HHCTRL
  7. #include "hha_strtable.h"
  8. #else
  9. #include "hha_strtable.h"
  10. #include "hhctrl.h"
  11. #include "strtable.h"
  12. #endif
  13. #include "web.h"
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static const char THIS_FILE[] = __FILE__;
  17. #endif
  18. #ifndef _DEBUG
  19. #pragma optimize("at", on)
  20. #endif
  21. #include "sitechar.cpp"
  22. #ifndef HHCTRL
  23. static const char txtSaveTypeHidden[] = "SaveHidden";
  24. static const char txtSaveTypeExclusive[] = "SaveExclusive";
  25. static const char txtSaveType[] = "SaveType";
  26. static const char txtSaveTypeDesc[] = "SaveTypeDesc";
  27. #endif
  28. class CParseSitemap : public SITEMAP_ENTRY
  29. {
  30. public:
  31. CParseSitemap(CSiteMap* pSiteMap) {
  32. m_pSiteMap = pSiteMap;
  33. Clear();
  34. m_fGlobal = FALSE;
  35. m_cMaxTitles = 50;
  36. m_ppszTitles = (PCSTR*) lcCalloc(m_cMaxTitles * sizeof(PCSTR));
  37. m_pSiteUrl = new CSiteEntryUrl(pSiteMap->InfoTypeSize());
  38. }
  39. ~CParseSitemap() { lcFree(m_ppszTitles); delete m_pSiteUrl; }
  40. BOOL IsGlobal(void) { return m_fGlobal; }
  41. void SetGlobal(BOOL fSetting) { m_fGlobal = fSetting; }
  42. void AddTitle(PCSTR psz);
  43. PCSTR* m_ppszTitles;
  44. int m_cMaxTitles;
  45. CStr m_cszValue;
  46. BOOL m_fGlobal;
  47. CSiteMap* m_pSiteMap;
  48. CSiteEntryUrl* m_pSiteUrl;
  49. void SaveUrlEntry() { m_pSiteUrl->SaveUrlEntry(m_pSiteMap, this); }
  50. operator CStr*() { return &m_cszValue; }
  51. operator PSTR() { return m_cszValue.psz; }
  52. operator PCSTR() const { return m_cszValue.psz; }
  53. };
  54. #ifndef _DEBUG
  55. // REVIEW: check this from time to time to see if it is necessary...
  56. #pragma optimize("a", on)
  57. #endif
  58. // Function prototypes
  59. PSTR FindDblQuote(CAInput* painput, CStr* pcsz, PSTR psz);
  60. PSTR GetValue(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue);
  61. PSTR FindCharacter(CAInput* pinput, CStr* pcsz, PSTR psz, char ch);
  62. PSTR GetType(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue);
  63. #ifdef HHCTRL
  64. #ifdef HHA
  65. BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, CHtmlHelpControl* phhctrl )
  66. #else
  67. BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, CHtmlHelpControl* phhctrl, UINT CodePage )
  68. #endif
  69. #else
  70. BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, PCSTR pszBaseFile)
  71. #endif
  72. {
  73. #ifdef HHCTRL
  74. #ifndef HHA
  75. m_CodePage = CodePage;
  76. #endif
  77. #endif
  78. CAInput ainput;
  79. int curInput = 0;
  80. if (!ainput.Add(pszFileName)) {
  81. #ifdef HHCTRL
  82. if (phhctrl)
  83. phhctrl->AuthorMsg(IDS_CANT_OPEN, pszFileName);
  84. SITEMAP_ENTRY* pSiteMapEntry = AddEntry();
  85. ASSERT_COMMENT(!pSiteMapEntry->iFrameName &&
  86. !pSiteMapEntry->iWindowName,
  87. "Add() function not returning zero'd memory");
  88. pSiteMapEntry->level = 1;
  89. CStr cszLine(IDS_CANT_FIND_FILE, pszFileName);
  90. pSiteMapEntry->pszText = StrDup(cszLine);
  91. pSiteMapEntry->SetTopic(TRUE);
  92. #else
  93. MsgBox(IDS_CANT_OPEN, pszFileName);
  94. #endif
  95. return FALSE;
  96. }
  97. SetSiteMapFile(pszFileName);
  98. m_fIndex = fIndex;
  99. // We don't want the first file to have a basename
  100. #if (defined(HHCTRL) || defined(HHA))
  101. m_pszBase = ainput.GetBaseName();
  102. *m_pszBase = '\0';
  103. #endif
  104. // used for indexes
  105. CParseSitemap cparse(this);
  106. CTable *ptblSubSets=NULL; // To hold any subset declarations.
  107. int curLevel = 0;
  108. CStr cszLine;
  109. BOOL fSiteMap = FALSE;
  110. BOOL fMergePending = FALSE; // TRUE if we need to include another file
  111. CStr cszMergeFile; // file to merge into current
  112. #ifdef _DEBUG
  113. int cLoops = 0; // so we know when to set a breakpoint
  114. #endif
  115. for (;;) {
  116. #ifdef _DEBUG
  117. cLoops++;
  118. // lcHeapCheck();
  119. #endif
  120. if (fMergePending) {
  121. #if (defined(HHCTRL) || defined(HHA))
  122. char szUrl[INTERNET_MAX_URL_LENGTH];
  123. #endif
  124. #ifdef HHA
  125. // When compiling, find the full path to the file
  126. strcpy(szUrl, cszMergeFile);
  127. ConvertToFull(pszBaseFile, szUrl);
  128. ainput.Add(szUrl);
  129. {
  130. #else
  131. if (!ainput.Add(cszMergeFile)) {
  132. #endif
  133. #ifdef HHCTRL
  134. if (ConvertToCacheFile(cszMergeFile, szUrl))
  135. ainput.Add(szUrl);
  136. else if (phhctrl && phhctrl->m_pWebBrowserApp) {
  137. CStr cszUrl;
  138. phhctrl->m_pWebBrowserApp->GetLocationURL(&cszUrl);
  139. PSTR psz = (PSTR) FindFilePortion(cszUrl);
  140. if (psz) {
  141. *psz = '\0';
  142. cszUrl += cszMergeFile;
  143. if (ConvertToCacheFile(cszUrl, szUrl))
  144. ainput.Add(szUrl);
  145. }
  146. }
  147. #endif
  148. }
  149. fMergePending = FALSE;
  150. #if (defined(HHCTRL) || defined(HHA))
  151. m_pszBase = ainput.GetBaseName();
  152. /*
  153. * If we are in the same location as our parent, ignore the
  154. * base name
  155. */
  156. if (!IsEmptyString(m_pszBase)) {
  157. CStr cszBase(m_pszBase);
  158. CStr cszSitemap(GetSiteMapFile());
  159. PSTR psz = (PSTR) FindFilePortion(cszSitemap);
  160. ASSERT(psz);
  161. if (psz)
  162. *psz = '\0';
  163. ConvertBackSlashToForwardSlash(cszBase);
  164. ConvertBackSlashToForwardSlash(cszSitemap);
  165. if (lstrcmpi(cszBase, cszSitemap) == 0)
  166. m_pszBase = NULL;
  167. }
  168. #endif
  169. }
  170. if (curInput < 0)
  171. break;
  172. if (!ainput.getline(&cszLine)) {
  173. if (!ainput.Remove()) {
  174. if (m_fIndex)
  175. return TRUE;
  176. break; // we're all done.
  177. }
  178. /*
  179. * Set parse to global so that if this was part of a merged
  180. * file we won't rewrite the last item when an </OBJECT> is
  181. * encountered.
  182. */
  183. // 16-Dec-1997 [ralphw] Don't call SetGlobal -- it deletes the
  184. // next folder
  185. // cparse.SetGlobal(TRUE);
  186. cparse.Clear();
  187. #if (defined(HHCTRL) || defined(HHA))
  188. m_pszBase = ainput.GetBaseName();
  189. #endif
  190. continue;
  191. }
  192. PSTR psz = FirstNonSpace(cszLine);
  193. Loop:
  194. if ( !psz || !*psz)
  195. continue; // ignore blank lines
  196. if (*psz == '<') {
  197. int cb;
  198. if ((cb = CompareSz(psz, txtParam))) {
  199. psz = FindDblQuote(&ainput, &cszLine, psz + cb);
  200. if (!psz)
  201. goto FlushAndExit;
  202. PSTR pszParamType = psz;
  203. psz = GetValue(&ainput, &cszLine, psz, cparse);
  204. if (!psz)
  205. goto FlushAndExit;
  206. if (ParseSiteMapParam(&cparse, pszParamType, ptblSubSets)) {
  207. goto Loop;
  208. }
  209. else if (isSameString(pszParamType, txtParamHHI)) {
  210. m_pszHHIFile = StrDup(cparse.m_cszValue.psz);
  211. goto Loop;
  212. }
  213. else if (isSameString(pszParamType, txtParamMerge)) {
  214. #if (!defined(HHCTRL) && !defined(HHA))
  215. cszMergeFile = GetStringResource(IDS_INCLUDED_FILE);
  216. cszMergeFile += cparse.m_cszValue.psz;
  217. cparse.pszText = StrDup(cszMergeFile);
  218. cparse.fInclude = TRUE;
  219. cparse.iImage = IMAGE_CLOSED_FOLDER;
  220. AddEntry(&cparse);
  221. cparse.SetGlobal(TRUE); // so end object doesn't rewrite
  222. #elif defined(HHA)
  223. if (stristr(cparse.m_cszValue.psz, ".CHM")) {
  224. cparse.pszText = StrDup(cparse.m_cszValue.psz);
  225. cparse.fInclude = TRUE;
  226. cparse.iImage = IMAGE_CLOSED_FOLDER;
  227. AddEntry(&cparse);
  228. }
  229. else {
  230. cszMergeFile = cparse.m_cszValue.psz;
  231. fMergePending = TRUE;
  232. }
  233. #else
  234. cszMergeFile = cparse.m_cszValue.psz;
  235. fMergePending = TRUE;
  236. #endif
  237. goto Loop;
  238. }
  239. else if (!m_fIndex && isSameString(pszParamType, txtFavorites)) {
  240. #if (defined(HHCTRL) || defined(HHA))
  241. CreateFavorites();
  242. goto Loop;
  243. #endif
  244. // REVIEW: how do we deal with this in HHW?
  245. }
  246. }
  247. else if ((cb = CompareSz(psz, txtBeginList))) {
  248. curLevel++;
  249. psz = FirstNonSpace(psz + cb);
  250. goto Loop;
  251. }
  252. else if ((cb = CompareSz(psz, txtEndList))) {
  253. curLevel--;
  254. psz = FirstNonSpace(psz + cb);
  255. goto Loop;
  256. }
  257. else if ((cb = CompareSz(psz, txtBeginListItem))) {
  258. psz = FindCharacter(&ainput, &cszLine, psz + cb, '>');
  259. if (!psz)
  260. goto FlushAndExit;
  261. if ((cb = CompareSz(psz, txtBeginObject))) {
  262. psz = GetType(&ainput, &cszLine, psz + cb, cparse);
  263. if (!psz) {
  264. if (!ainput.getline(&cszLine))
  265. goto FlushAndExit;
  266. psz = GetType(&ainput, &cszLine, cszLine, cparse);
  267. if (!psz)
  268. goto FlushAndExit;
  269. }
  270. //////////////////// New Node /////////////////////////////////////////////
  271. if (isSameString(cparse, txtSiteMapObject)) {
  272. // Create a new entry
  273. cparse.Clear();
  274. cparse.level = (BYTE)curLevel;
  275. goto Loop;
  276. }
  277. else if (isSameString(cparse, txtSitemapProperties)) {
  278. cparse.SetGlobal(TRUE);
  279. }
  280. }
  281. }
  282. else if ((cb = CompareSz(psz, txtEndObject))) {
  283. //////////////////// End Node /////////////////////////////////////////////
  284. if (!cparse.IsGlobal()) {
  285. if (m_fIndex) {
  286. if (!cparse.m_pSiteUrl->m_fUrlSpecified) {
  287. // BUGBUG: nag the author -- entry without a URL
  288. psz += cb;
  289. goto Loop;
  290. }
  291. cparse.SaveUrlEntry();
  292. if (cparse.pszText && cparse.cUrls) {
  293. AddEntry(&cparse);
  294. }
  295. else {
  296. #if (defined(HHCTRL) || defined(HHA))
  297. cparse.pszText = StrDup(GetStringResource(IDSHHA_INVALID_KEYWORD));
  298. AddEntry(&cparse);
  299. #endif
  300. // we ignore the entry entirely in hhctrl.ocx
  301. }
  302. cparse.Clear();
  303. cparse.level = (BYTE)curLevel;
  304. }
  305. else {
  306. if (cparse.m_pSiteUrl->m_fUrlSpecified)
  307. cparse.SaveUrlEntry();
  308. AddEntry(&cparse);
  309. }
  310. }
  311. else {
  312. cparse.SetGlobal(FALSE);
  313. //#ifdef HHCTRL // having this conditional for HHCTRL causes IT declarations to not be present in HHW until the info type tab is visited
  314. // bug 4762
  315. if (IsNonEmpty(m_pszHHIFile)) {
  316. cszMergeFile = cparse.m_cszValue.psz;
  317. fMergePending = TRUE;
  318. m_pszHHIFile = NULL; // so we don't merge twice
  319. }
  320. //#endif
  321. }
  322. psz += cb;
  323. goto Loop;
  324. }
  325. else if (isSameString(psz, txtSitemap) ||
  326. isSameString(psz, txtSitemap1) ||
  327. isSameString(psz, txtSitemap2)) {
  328. fSiteMap = TRUE;
  329. psz = FindCharacter(&ainput, &cszLine, psz, '>');
  330. if (!psz)
  331. goto FlushAndExit;
  332. else if (!*psz)
  333. continue;
  334. }
  335. // Global properties?
  336. else if ((cb = CompareSz(psz, txtBeginObject))) {
  337. psz = GetType(&ainput, &cszLine, psz + cb, cparse);
  338. if (!psz) {
  339. if (!ainput.getline(&cszLine))
  340. goto FlushAndExit;
  341. psz = GetType(&ainput, &cszLine, psz + cb, cparse);
  342. if (!psz)
  343. goto FlushAndExit;
  344. }
  345. if (isSameString(cparse, txtSitemapProperties)) {
  346. cparse.SetGlobal(TRUE);
  347. goto Loop;
  348. }
  349. else {
  350. // ******** Check for Merge (include another file) *******
  351. /*
  352. * This is an object that appears outside of a list
  353. * item. If it's a merge tag, then extract the merge
  354. * information. Otherwise, ignore it.
  355. */
  356. psz = strstr(psz, txtEndTag);
  357. if (psz)
  358. psz = FirstNonSpace(psz + 1);
  359. for (;;) {
  360. if (!psz) {
  361. if (!ainput.getline(&cszLine))
  362. goto FlushAndExit;
  363. psz = FirstNonSpace(cszLine.psz);
  364. }
  365. if ( !psz || !*psz) {
  366. psz = NULL; // so we'll read the next line
  367. continue; // ignore blank lines
  368. }
  369. if (*psz == '<') {
  370. if ((cb = CompareSz(psz, txtEndObject))) {
  371. psz += cb;
  372. goto Loop;
  373. }
  374. else if ((cb = CompareSz(psz, txtParam))) {
  375. psz = FindDblQuote(&ainput, &cszLine,
  376. psz + cb);
  377. if (!psz)
  378. goto FlushAndExit;
  379. PSTR pszParamType = psz;
  380. psz = GetValue(&ainput, &cszLine,
  381. psz, cparse);
  382. if (!psz)
  383. goto FlushAndExit;
  384. if (isSameString(pszParamType, txtParamMerge)) {
  385. #if (!defined(HHCTRL) && !defined(HHA))
  386. cszMergeFile = GetStringResource(IDS_INCLUDED_FILE);
  387. cszMergeFile += cparse.m_cszValue.psz;
  388. cparse.pszText = StrDup(cszMergeFile);
  389. cparse.fInclude = TRUE;
  390. cparse.iImage = IMAGE_CLOSED_FOLDER;
  391. cparse.level = curLevel;
  392. AddEntry(&cparse);
  393. #elif defined(HHA)
  394. if (stristr(cparse.m_cszValue.psz, ".CHM")) {
  395. cparse.pszText = StrDup(cparse.m_cszValue.psz);
  396. cparse.fInclude = TRUE;
  397. cparse.iImage = IMAGE_CLOSED_FOLDER;
  398. cparse.level = curLevel;
  399. AddEntry(&cparse);
  400. }
  401. else {
  402. cszMergeFile = cparse.m_cszValue.psz;
  403. fMergePending = TRUE;
  404. }
  405. #else
  406. cszMergeFile = cparse.m_cszValue.psz;
  407. fMergePending = TRUE;
  408. #endif
  409. }
  410. }
  411. }
  412. }
  413. }
  414. }
  415. else if (isSameString(psz, txtBeginHref)) {
  416. // Skip over all of HREF
  417. for (;;) {
  418. psz = strstr(psz, txtEndTag);
  419. if (psz) {
  420. if (strncmp(psz, txtEndHref, (int)strlen(txtEndHref)) == 0)
  421. break;
  422. psz = stristr(psz, txtEndHref);
  423. }
  424. if (!psz) {
  425. if (!ainput.getline(&cszLine))
  426. goto FlushAndExit;
  427. psz = cszLine.psz;
  428. }
  429. else
  430. break;
  431. }
  432. psz = FindCharacter(&ainput, &cszLine, psz, '>');
  433. goto Loop;
  434. }
  435. else {
  436. // Ignore whatever it is
  437. psz = FindCharacter(&ainput, &cszLine, psz, '>');
  438. goto Loop;
  439. }
  440. }
  441. if (fSiteMap) {
  442. // In sitemaps, we only care about what appears inside angle
  443. // brackets.
  444. for(;;) {
  445. psz = StrChr(psz, '<');
  446. if (!psz) {
  447. if (!ainput.getline(&cszLine)) {
  448. psz = ""; // so Loop processing works
  449. break;
  450. }
  451. psz = cszLine.psz;
  452. }
  453. else
  454. break;
  455. }
  456. goto Loop;
  457. }
  458. }
  459. # ifdef NOTYET
  460. // populate subsets
  461. if ( ptblSubSets )
  462. {
  463. if ( !m_pSubSets )
  464. m_pSubSets = new CSubSets(m_itTables.m_itSize, ptblSubSets, this, TRUE);
  465. delete ptblSubSets;
  466. }
  467. #endif
  468. if (!fIndex) {
  469. // Now determine what is a book -- anything without a child is a topic
  470. curLevel = 0;
  471. int pos;
  472. for (pos = 1; pos < endpos - 1; pos++) {
  473. SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
  474. if (pSiteMapEntry->level > curLevel + 1)
  475. pSiteMapEntry->level = curLevel + 1;
  476. curLevel = pSiteMapEntry->level;
  477. if (pSiteMapEntry->cUrls == 0)
  478. continue; // if there is no URL, then it's a book
  479. #ifdef _DEBUG
  480. SITEMAP_ENTRY* pSiteMapEntryNext = GetSiteMapEntry(pos + 1);
  481. #endif
  482. if (pSiteMapEntry->level >= GetSiteMapEntry(pos + 1)->level)
  483. pSiteMapEntry->SetTopic(TRUE);
  484. }
  485. // You can never end with a book
  486. if (endpos > 1)
  487. GetSiteMapEntry(endpos - 1)->SetTopic(TRUE);
  488. }
  489. return TRUE;
  490. FlushAndExit:
  491. return FALSE;
  492. }
  493. BOOL CSiteMap::ParseSiteMapParam(CParseSitemap* pcparse, PCSTR pszParamType, CTable *ptblSubSets)
  494. {
  495. int iLastType = 0;
  496. // Deal with any escape sequences starting with '&'
  497. ReplaceEscapes(*pcparse, (PSTR) *pcparse, ESCAPE_ENTITY);
  498. if (pcparse->IsGlobal()) {
  499. int cb;
  500. // WARNING! Check for txtParamTypeDesc BEFORE the check for txtParamType
  501. // (because it's a substring search).
  502. #ifdef NOTYET
  503. // parse Subset Declarations
  504. if ( isSameString( pszParamType, txtParamSSInclusive ) ||
  505. isSameString( pszParamType, txtParamSSExclusive))
  506. {
  507. if( !ptblSubSets )
  508. ptblSubsets = new CTable(16 * 1024);
  509. ptblSubSets->AddString(*pcparse);
  510. }else
  511. #endif
  512. // parse Information Types Declarations
  513. if (isSameString(pszParamType, txtParamTypeExclusive)
  514. #ifndef HHCTRL
  515. || isSameString(pszParamType, txtSaveTypeExclusive)
  516. #endif
  517. ) {
  518. if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
  519. iLastType = GetITIndex( *pcparse );
  520. AddToCategory( iLastType );
  521. return TRUE;
  522. }else
  523. {
  524. iLastType = AddTypeName(*pcparse);
  525. AddExclusiveIT( iLastType );
  526. AddToCategory( iLastType );
  527. return TRUE;
  528. }
  529. }
  530. else if (isSameString(pszParamType, txtParamTypeHidden)
  531. #ifndef HHCTRL
  532. || isSameString(pszParamType, txtSaveTypeHidden)
  533. #endif
  534. ) {
  535. if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
  536. iLastType = GetITIndex( *pcparse );
  537. AddToCategory( iLastType );
  538. return TRUE;
  539. }else
  540. {
  541. iLastType = AddTypeName(*pcparse);
  542. AddHiddenIT( iLastType );
  543. AddToCategory( iLastType );
  544. return TRUE;
  545. }
  546. }
  547. else if ((cb = CompareSz(pszParamType, txtParamTypeDesc))
  548. #ifndef HHCTRL
  549. || isSameString(pszParamType, txtSaveTypeDesc)
  550. #endif
  551. ) {
  552. if (!m_itTables.m_ptblInfoTypeDescriptions)
  553. return TRUE; // BUGBUG: nag author about description before type
  554. // add a blank description to infotype description, description not provided for last infotype
  555. while (m_itTables.m_ptblInfoTypes->CountStrings() > m_itTables.m_ptblInfoTypeDescriptions->CountStrings()+1)
  556. m_itTables.m_ptblInfoTypeDescriptions->AddString("");
  557. if ( m_itTables.m_ptblInfoTypes->CountStrings() != m_itTables.m_ptblInfoTypeDescriptions->CountStrings() )
  558. m_itTables.m_ptblInfoTypeDescriptions->AddString(*pcparse);
  559. return TRUE;
  560. } // this matches anything that begins with "type"
  561. else if (isSameString(pszParamType, txtParamType)
  562. #ifndef HHCTRL
  563. || isSameString(pszParamType, txtSaveType)
  564. #endif
  565. ) {
  566. if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
  567. iLastType = GetITIndex( *pcparse );
  568. AddToCategory( iLastType );
  569. return TRUE;
  570. }
  571. else
  572. {
  573. iLastType = AddTypeName(*pcparse);
  574. AddToCategory( iLastType );
  575. return TRUE;
  576. }
  577. }
  578. // WARNING! Check for txtParamCategoryDesc BEFORE the check for txtParamCategory
  579. // (because it's a substring search).
  580. else if ((cb = CompareSz(pszParamType, txtParamCategoryDesc))) {
  581. if (!m_itTables.m_ptblCatDescription)
  582. return TRUE; // BUGBUG: nag author about description before type
  583. // add a blank description to category description, description not provided for last Category
  584. while (m_itTables.m_ptblCategories->CountStrings() > m_itTables.m_ptblCatDescription->CountStrings()+1)
  585. m_itTables.m_ptblCatDescription->AddString("");
  586. m_itTables.m_ptblCatDescription->AddString(*pcparse);
  587. return TRUE;
  588. }
  589. else if (isSameString(pszParamType, txtParamCategory)) {
  590. if (m_itTables.m_ptblCategories && m_itTables.m_ptblCategories->IsStringInTable(*pcparse)) {
  591. // BUGBUG: we should nag the help author
  592. return TRUE;
  593. }
  594. if (!m_itTables.m_ptblCategories)
  595. {
  596. m_itTables.m_ptblCategories = new CTable(16 * 1024);
  597. m_itTables.m_ptblCatDescription = new CTable(16 * 1024);
  598. }
  599. m_itTables.m_ptblCategories->AddString(*pcparse);
  600. return TRUE;
  601. }
  602. else
  603. if (isSameString(pszParamType, txtParamFrame)) {
  604. if (!IsFrameDefined()) // can't override in a sitemap file
  605. SetFrameName(*pcparse);
  606. return TRUE;
  607. }
  608. else if (isSameString(pszParamType, txtParamWindow)) {
  609. if (!IsWindowDefined())
  610. SetWindowName(*pcparse);
  611. return TRUE;
  612. }
  613. else if (isSameString(pszParamType, txtImageType)) {
  614. if (isSameString(*pcparse, txtFolderType))
  615. m_fFolderImages = TRUE;
  616. }
  617. else if (isSameString(pszParamType, txtImageList)) {
  618. m_pszImageList = StrDup(*pcparse);
  619. return TRUE;
  620. }
  621. else if (isSameString(pszParamType, txtQueryType)) {
  622. m_fPromotForInfoTypes = TRUE;
  623. return TRUE;
  624. }
  625. else if (isSameString(pszParamType, txtBackGround)) {
  626. m_clrBackground = Atoi(*pcparse);
  627. return TRUE;
  628. }
  629. else if (isSameString(pszParamType, txtBackGroundImage)) {
  630. m_pszBackBitmap = StrDup(*pcparse);
  631. return TRUE;
  632. }
  633. else if (isSameString(pszParamType, txtForeGround)) {
  634. m_clrForeground = Atoi(*pcparse);
  635. return TRUE;
  636. }
  637. else if (isSameString(pszParamType, txtFont)) {
  638. m_pszFont = StrDup(*pcparse);
  639. return TRUE;
  640. }
  641. else if (isSameString(pszParamType, txtNumberImages)) {
  642. m_cImages = Atoi(*pcparse);
  643. return TRUE;
  644. }
  645. else if (isSameString(pszParamType, txtColorMask)) {
  646. m_clrMask = Atoi(*pcparse);
  647. return TRUE;
  648. }
  649. else if (isSameString(pszParamType, txtImageWidth)) {
  650. m_cImageWidth = Atoi(*pcparse);
  651. return TRUE;
  652. }
  653. else if (isSameString(pszParamType, txtWindowStyles) &&
  654. m_tvStyles == (DWORD) -1) {
  655. m_tvStyles = Atoi(*pcparse);
  656. return TRUE;
  657. }
  658. else if (isSameString(pszParamType, txtExWindowStyles)) {
  659. m_exStyles = Atoi(*pcparse);
  660. return TRUE;
  661. }
  662. #if (!defined(HHCTRL) && !defined(HHA))
  663. else if (isSameString(pszParamType, txtAutoGenerated)) {
  664. m_fAutoGenerated = YesNo(*pcparse);
  665. return TRUE;
  666. }
  667. #endif
  668. return FALSE;
  669. }
  670. if (m_fIndex) {
  671. if (isSameString(pszParamType, txtParamSectionTitle) ||
  672. isSameString(pszParamType, txtParamName)) {
  673. if (!pcparse->pszText)
  674. pcparse->pszText = StrDup(*pcparse);
  675. else {
  676. if (pcparse->m_pSiteUrl->m_pUrl->pszTitle) {
  677. if (pcparse->m_pSiteUrl->m_fUrlSpecified)
  678. pcparse->SaveUrlEntry();
  679. else
  680. FreeMemory(pcparse->pszText, -1);
  681. }
  682. pcparse->AddTitle(*pcparse);
  683. }
  684. return TRUE;
  685. }
  686. else if (isSameString(pszParamType, txtParamKeyword)) {
  687. // BUGBUG: check for duplicates first!
  688. pcparse->pszText = StrDup(*pcparse);
  689. return TRUE;
  690. }
  691. }
  692. else { // not an Index
  693. if (isSameString(pszParamType, txtParamName)) {
  694. if (pcparse->m_pSiteUrl->m_fUrlSpecified)
  695. pcparse->SaveUrlEntry();
  696. // BUGBUG: deal with duplicate names being specified
  697. pcparse->pszText = StrDup(*pcparse);
  698. return TRUE;
  699. }
  700. }
  701. if (isSameString(pszParamType, txtParamLocal)) {
  702. if (pcparse->m_pSiteUrl->m_fUrlSpecified) {
  703. // save previous URL entry
  704. pcparse->SaveUrlEntry();
  705. }
  706. URL url = AddUrl(*pcparse);
  707. if (pcparse->m_pSiteUrl->m_pUrl->urlSecondary == url)
  708. return TRUE; // ignore duplicate URLs for primary and secondary
  709. pcparse->m_pSiteUrl->m_pUrl->urlPrimary = url;
  710. pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
  711. return TRUE;
  712. }
  713. else if (isSameString(pszParamType, txtParamUrl) || isSameString(pszParamType, txtParamSecondary)) {
  714. if (pcparse->m_pSiteUrl->m_fUrlSpecified && pcparse->m_pSiteUrl->m_pUrl->urlSecondary) {
  715. // save previous URL entry
  716. pcparse->SaveUrlEntry();
  717. }
  718. URL url = AddUrl(*pcparse);
  719. if (pcparse->m_pSiteUrl->m_pUrl->urlPrimary == url)
  720. return TRUE; // ignore duplicate URLs for primary and secondary
  721. pcparse->m_pSiteUrl->m_pUrl->urlSecondary = url;
  722. pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
  723. return TRUE;
  724. }
  725. else if (isSameString(pszParamType, txtParamType) ||
  726. isSameString(pszParamType, txtParamTypeExclusive) ||
  727. isSameString(pszParamType, txtParamTypeHidden)) {
  728. if (pcparse->m_pSiteUrl->m_fUrlSpecified)
  729. // save previous URL entry
  730. pcparse->SaveUrlEntry();
  731. if (m_itTables.m_ptblInfoTypes)
  732. {
  733. INFOTYPE iType = GetInfoType(*pcparse);
  734. if (iType == (INFOTYPE) -1)
  735. iType = 0;
  736. else
  737. AddIT(iType, pcparse->m_pSiteUrl->m_pUrl->ainfoTypes );
  738. }
  739. return TRUE;
  740. }
  741. else if (isSameString(pszParamType, txtParamNew)) {
  742. pcparse->fNew = TRUE;
  743. return TRUE;
  744. }
  745. else if (isSameString(pszParamType, txtParamImageNumber)) {
  746. pcparse->iImage = (BYTE) Atoi(*pcparse);
  747. return TRUE;
  748. }
  749. else if (isSameString(pszParamType, txtParamDisplay)) {
  750. if (isSameString(*pcparse, txtNo))
  751. pcparse->fNoDisplay = TRUE;
  752. return TRUE;
  753. }
  754. else if (isSameString(pszParamType, txtParamFrame)) {
  755. SetEntryFrame(pcparse, *pcparse);
  756. return TRUE;
  757. }
  758. else if (isSameString(pszParamType, txtParamWindow)) {
  759. SetEntryWindow(pcparse, *pcparse);
  760. return TRUE;
  761. }
  762. else if (isSameString(pszParamType, txtSeeAlso)) {
  763. pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
  764. pcparse->fSeeAlso = TRUE;
  765. pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
  766. return TRUE;
  767. }
  768. else if (isSameString(pszParamType, txtSendEvent)) {
  769. pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
  770. pcparse->SaveUrlEntry();
  771. pcparse->fSendEvent = TRUE;
  772. return TRUE;
  773. }
  774. else if (isSameString(pszParamType, txtSendMessage)) {
  775. pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
  776. pcparse->SaveUrlEntry();
  777. pcparse->fSendMessage = TRUE;
  778. return TRUE;
  779. }
  780. #if (!defined(HHCTRL) && !defined(HHA))
  781. else if (isSameString(pszParamType, txtParamComment)) {
  782. pcparse->pszComment = StrDup(*pcparse);
  783. return TRUE;
  784. }
  785. #endif
  786. return FALSE;
  787. }
  788. URL CSiteMap::AddUrl(PCSTR pszUrl)
  789. {
  790. if (IsEmptyString(pszUrl))
  791. return NULL;
  792. #if (defined(HHCTRL) || defined(HHA))
  793. if (!IsEmptyString(m_pszBase) && !StrChr(pszUrl, ':')) {
  794. char szPath[INTERNET_MAX_URL_LENGTH];
  795. strcpy(szPath, m_pszBase);
  796. strcat(szPath, pszUrl);
  797. return (URL) StrDup(szPath);
  798. }
  799. #endif
  800. PCSTR psz = FirstNonSpace(pszUrl);
  801. return (URL) StrDup(psz?psz:"");
  802. }
  803. void CSiteMap::AddToCategory( int iLastType )
  804. {
  805. // Add the info type to the last category defined; if there is a Category
  806. if ( m_itTables.m_ptblCategories )
  807. {
  808. int posCat = m_itTables.m_ptblCategories->CountStrings();
  809. if (posCat <= 0 )
  810. return;
  811. AddITtoCategory( posCat-1, iLastType);
  812. }
  813. }
  814. int CompareSz(PCSTR psz, PCSTR pszSub)
  815. {
  816. int cb;
  817. if (IsSamePrefix(psz, pszSub, cb = (int)strlen(pszSub)))
  818. return cb;
  819. else
  820. return 0;
  821. }
  822. void CParseSitemap::AddTitle(PCSTR psz)
  823. {
  824. if (m_pSiteUrl->m_pUrl->pszTitle)
  825. m_pSiteMap->FreeMemory(m_pSiteUrl->m_pUrl->pszTitle, -1);
  826. m_pSiteUrl->m_pUrl->pszTitle = m_pSiteMap->StrDup(psz);
  827. }
  828. void CSiteEntryUrl::SaveUrlEntry(CSiteMap* pSiteMap, SITEMAP_ENTRY* pSiteMapEntry)
  829. {
  830. SITE_ENTRY_URL* pNewUrls = (SITE_ENTRY_URL*) pSiteMap->TableMalloc(
  831. sizeof(SITE_ENTRY_URL) * (pSiteMapEntry->cUrls + 1));
  832. if (pSiteMapEntry->cUrls) {
  833. ASSERT(pSiteMapEntry->pUrls);
  834. memcpy(pNewUrls, pSiteMapEntry->pUrls,
  835. sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls);
  836. pSiteMap->FreeMemory((PCSTR) pSiteMapEntry->pUrls,
  837. sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls);
  838. }
  839. memcpy((PBYTE) pNewUrls + sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls,
  840. m_pUrl, sizeof(SITE_ENTRY_URL));
  841. pSiteMapEntry->cUrls++;
  842. pSiteMapEntry->pUrls = pNewUrls;
  843. if (!pSiteMap->AreAnyInfoTypesDefined(pSiteMapEntry))
  844. pSiteMapEntry->fShowToEveryOne = TRUE;
  845. ZeroMemory(m_pUrl, sizeof(SITE_ENTRY_URL));
  846. m_pUrl->ainfoTypes = (INFOTYPE*)lcCalloc( pSiteMap->InfoTypeSize() );
  847. m_fUrlSpecified = FALSE;
  848. }
  849. /***************************************************************************
  850. FUNCTION: HashFromSz
  851. PURPOSE: Convert a string into a hash representation
  852. PARAMETERS:
  853. pszKey
  854. RETURNS: Hash number
  855. COMMENTS:
  856. Shamelessly stolen from the WinHelp code, since after 6 years
  857. of use by up to 1 million help authors, there were no reports
  858. of collisions.
  859. MODIFICATION DATES:
  860. 10-Aug-1996 [ralphw] Stolen from WinHelp, removed special-case
  861. hash characters
  862. ***************************************************************************/
  863. // This constant defines the alphabet size for our hash function.
  864. static const HASH MAX_CHARS = 43;
  865. HASH WINAPI HashFromSz(PCSTR pszKey)
  866. {
  867. HASH hash = 0;
  868. int cch = (int)strlen(pszKey);
  869. for (int ich = 0; ich < cch; ++ich) {
  870. // treat '/' and '\' as the same
  871. if (pszKey[ich] == '/')
  872. hash = (hash * MAX_CHARS) + ('\\' - '0');
  873. else if (pszKey[ich] <= 'Z')
  874. hash = (hash * MAX_CHARS) + (pszKey[ich] - '0');
  875. else
  876. hash = (hash * MAX_CHARS) + (pszKey[ich] - '0' - ('a' - 'A'));
  877. }
  878. /*
  879. * Since the value 0 is reserved as a nil value, if any context
  880. * string actually hashes to this value, we just move it.
  881. */
  882. return (hash == 0 ? 0 + 1 : hash);
  883. }
  884. int CSiteMap::AddName(PCSTR psz)
  885. {
  886. if (IsEmptyString(psz))
  887. return 0;
  888. psz = FirstNonSpace(psz);
  889. HASH hash = HashFromSz(psz);
  890. if (!m_ptblStrings)
  891. m_ptblStrings = new CTable(16 * 1024);
  892. int pos = m_ptblStrings->IsHashInTable(hash);
  893. if (pos > 0)
  894. return pos;
  895. else {
  896. m_ptblStrings->AddString(hash, psz);
  897. return m_ptblStrings->CountStrings();
  898. }
  899. }
  900. PSTR FindCharacter(CAInput* pinput, CStr* pcsz, PSTR psz, char ch)
  901. {
  902. for(;;) {
  903. psz = StrChr(psz, ch);
  904. if (!psz) {
  905. if (!pinput)
  906. return NULL;
  907. if (!pinput->getline(pcsz))
  908. return NULL;
  909. psz = pcsz->psz;
  910. }
  911. else
  912. break;
  913. }
  914. return FirstNonSpace(psz + 1);
  915. }
  916. PSTR FindDblQuote(CAInput* pinput, CStr* pcsz, PSTR psz)
  917. {
  918. for(;;) {
  919. psz = StrChr(psz, '\042');
  920. if (!psz) {
  921. if (!pinput->getline(pcsz))
  922. return NULL;
  923. psz = pcsz->psz;
  924. }
  925. else
  926. break;
  927. }
  928. return FirstNonSpace(psz + 1);
  929. }
  930. /***************************************************************************
  931. FUNCTION: GetValue
  932. PURPOSE: Copy the value of a param type into pszValue, and return
  933. a pointer to the first character after the closing angle
  934. bracket
  935. PARAMETERS:
  936. pinput pointer to current CInput file
  937. pcsz CStr to read new line into
  938. psz position in current line
  939. pcszValue CStr to receive value
  940. pszPrefix prefix to look for
  941. RETURNS:
  942. COMMENTS:
  943. MODIFICATION DATES:
  944. 24-Aug-1996 [ralphw]
  945. ***************************************************************************/
  946. PSTR GetValue(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue)
  947. {
  948. // Skip past ending quote of parameter type
  949. psz = FindDblQuote(pinput, pcsz, psz);
  950. if (!psz)
  951. return NULL;
  952. if (!isSameString(psz, txtValue)) {
  953. psz = stristr(psz, txtValue);
  954. if (!psz) {
  955. if (!pinput->getline(pcsz))
  956. return NULL;
  957. psz = stristr(pcsz->psz, txtValue);
  958. if (!psz)
  959. return NULL;
  960. }
  961. }
  962. // Now find opening quote of the value
  963. psz = FindDblQuote(pinput, pcsz, psz);
  964. if (!psz)
  965. return NULL;
  966. if (!pcszValue->psz)
  967. pcszValue->psz = (PSTR) lcMalloc(256);
  968. PSTR pszDst = pcszValue->psz;
  969. PSTR pszEnd = pszDst + lcSize(pcszValue->psz);
  970. while (*psz != '\042') {
  971. if (!*psz) {
  972. if (!pinput->getline(pcsz))
  973. return NULL;
  974. psz = pcsz->psz;
  975. continue;
  976. }
  977. *pszDst++ = *psz++;
  978. if (pszDst >= pszEnd) {
  979. /*
  980. * Our destination buffer is too small, so increase it by
  981. * 128 bytes.
  982. */
  983. int offset = (int)(pszDst - pcszValue->psz);
  984. pcszValue->ReSize((int)(pszEnd - pcszValue->psz) + 128);
  985. pszDst = pcszValue->psz + offset;
  986. pszEnd = pcszValue->psz + pcszValue->SizeAlloc();
  987. lcHeapCheck();
  988. }
  989. }
  990. *pszDst = '\0';
  991. return FindCharacter(pinput, pcsz, psz, '>');
  992. }
  993. PSTR GetType(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue)
  994. {
  995. psz = FirstNonSpace(psz);
  996. ASSERT(strlen(txtType) == sizeof(txtType) - 1); // make sure the compiler doesn't mess this up
  997. if (IsSamePrefix(psz, txtType, sizeof(txtType) - 1)) {
  998. psz = stristr(psz, txtType);
  999. if (!psz) {
  1000. if (!pinput->getline(pcsz))
  1001. return NULL;
  1002. psz = stristr(pcsz->psz, txtType);
  1003. if (!psz)
  1004. return NULL;
  1005. }
  1006. }
  1007. // Now find opening quote of the value
  1008. psz = FindDblQuote(pinput, pcsz, psz);
  1009. if (!psz)
  1010. return NULL;
  1011. if (!pcszValue->psz)
  1012. pcszValue->psz = (PSTR) lcMalloc(256);
  1013. PSTR pszDst = *pcszValue;
  1014. PSTR pszEnd = pszDst + lcSize(pszDst);
  1015. while (*psz != '\042') {
  1016. if (!*psz) {
  1017. if (!pinput->getline(pcsz))
  1018. return NULL;
  1019. psz = pcsz->psz;
  1020. continue;
  1021. }
  1022. *pszDst++ = *psz++;
  1023. if (pszDst >= pszEnd) {
  1024. /*
  1025. * Our input buffer is too small, so increase it by
  1026. * 128 bytes.
  1027. */
  1028. int offset = (int)(pszDst - pcsz->psz);
  1029. pcsz->ReSize((int)(pszEnd - pcsz->psz) + 128);
  1030. pszDst = pcsz->psz + offset;
  1031. pszEnd = pcsz->psz + pcsz->SizeAlloc();
  1032. lcHeapCheck();
  1033. }
  1034. }
  1035. *pszDst = '\0';
  1036. return FindCharacter(pinput, pcsz, psz, '>');
  1037. }
  1038. // This is called from the code that parses the sitemap in the information type section.
  1039. // Information types found outside of the declaration section are NOT added to the
  1040. // information types declared. So we don't have to worry about increasing the size of
  1041. // SITE_ENTRY_URLs after they have been defined. At least in this routine. We will have to
  1042. // deal with increasing the size of SITE_ENTRY_URLs when adding information types.
  1043. int CSiteMap::AddTypeName(PCSTR pszTypeName)
  1044. {
  1045. ASSERT(!IsEmptyString(pszTypeName));
  1046. if (!m_itTables.m_ptblInfoTypes) {
  1047. m_itTables.m_ptblInfoTypes = new CTable(16 * 1024);
  1048. ASSERT(!m_itTables.m_ptblInfoTypeDescriptions);
  1049. m_itTables.m_ptblInfoTypeDescriptions = new CTable(64 * 1024);
  1050. }
  1051. ASSERT(m_itTables.m_ptblInfoTypes);
  1052. /*
  1053. * If we have an Information type, but the table counts don't match,
  1054. * then we didn't get a description for the last type, so we add a blank
  1055. * description to keep the tables in sync.
  1056. */
  1057. while (m_itTables.m_ptblInfoTypes->CountStrings() > m_itTables.m_ptblInfoTypeDescriptions->CountStrings())
  1058. m_itTables.m_ptblInfoTypeDescriptions->AddString("");
  1059. /*
  1060. A category and type is specified as:
  1061. category::type name
  1062. */
  1063. CStr cszCategory;
  1064. CStr cszType;
  1065. int category = 0;
  1066. PCSTR pszCat = strstr(pszTypeName, "::");
  1067. if (pszCat) { // separate category name from type name
  1068. cszType = pszCat + 2; // make a local copy
  1069. cszCategory = pszTypeName;
  1070. cszCategory.psz[pszCat - pszTypeName] = '\0';
  1071. if (!m_itTables.m_ptblCategories) {
  1072. m_itTables.m_ptblCategories = new CTable(16 * 1024);
  1073. }
  1074. category = m_itTables.m_ptblCategories->IsStringInTable(cszCategory);
  1075. if (!category)
  1076. category = m_itTables.m_ptblCategories->AddString(cszCategory);
  1077. pszTypeName = cszType.psz;
  1078. }
  1079. int pos = m_itTables.m_ptblInfoTypes->IsStringInTable(pszTypeName);
  1080. if (pos <= 0) {
  1081. if ( (m_itTables.m_cTypes > 0) && ((m_itTables.m_cTypes+1) % 32 == 0) )
  1082. ReSizeIT(); // increase by one DWORD
  1083. pos = m_itTables.m_ptblInfoTypes->AddString(pszTypeName);
  1084. m_itTables.m_cTypes++;
  1085. int offset = 0;
  1086. int type = pos;
  1087. while (type > 32) {
  1088. offset++;
  1089. type -= 32;
  1090. }
  1091. INFOTYPE* pInfoType = m_pInfoTypes + offset;
  1092. *pInfoType |= (1 << type);
  1093. }
  1094. category--; // zero offset
  1095. if ( category >=0 )
  1096. AddITtoCategory(category, pos );
  1097. #if 0
  1098. /*
  1099. * If we have more then 32 information types, then we need to be certain
  1100. * the size of the SITE_ENTRY_URL* structure allocated for Sitemap Entries
  1101. * is large enough.
  1102. */
  1103. // BUGBUG: we need to deal with the situation where an information type
  1104. // gets specified AFTER a sitemap entry has been specified.
  1105. if (pos > m_pSiteUrl->m_cMaxTypes) {
  1106. m_cUrlEntry = sizeof(SITE_ENTRY_URL) + pos / sizeof(UINT);
  1107. m_pSiteUrl->m_pUrl = (SITE_ENTRY_URL*) lcReAlloc(m_pSiteUrl->m_pUrl, m_cUrlEntry);
  1108. m_pSiteUrl->m_cMaxTypes += 32;
  1109. m_cInfoTypeOffsets++;
  1110. }
  1111. if ( pos % 32 == 0 )
  1112. {
  1113. // Increase the Categories
  1114. for(int i=0; i<m_itTables.m_max_categories; i++)
  1115. m_itTables.m_aCategories[i].pInfoType = (INFOTYPE*)lcReAlloc(m_itTables.m_aCategories[i].pInfoType,
  1116. InfoTypeSize());
  1117. // Increase the Exclusive and Hidden IT fields.
  1118. m_itTables.m_pExclusive = (INFOTYPE*) lcReAlloc(m_itTables.m_pExclusive,
  1119. InfoTypeSize() );
  1120. m_itTables.m_pHidden = (INFOTYPE*) lcReAlloc(m_itTables.m_pHidden,
  1121. InfoTypeSize() );
  1122. }
  1123. #endif
  1124. return pos;
  1125. }
  1126. BOOL CSiteMap::AreAnyInfoTypesDefined(SITEMAP_ENTRY* pSiteMapEntry)
  1127. {
  1128. INFOTYPE *pIT;
  1129. SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
  1130. for (int iUrl = 0; iUrl < pSiteMapEntry->cUrls; iUrl++)
  1131. {
  1132. pIT = pUrl->ainfoTypes;
  1133. for (int i=0; i < InfoTypeSize()/4; i++)
  1134. {
  1135. if (*pIT)
  1136. return TRUE; // an info type was found
  1137. else
  1138. pIT++;
  1139. }
  1140. pUrl = NextUrlEntry(pUrl);
  1141. }
  1142. return FALSE;
  1143. }
  1144. /***************************************************************************
  1145. FUNCTION: CSiteMap::AreTheseInfoTypesDefined
  1146. PURPOSE: Find out if the specified INFOTYPES are defined
  1147. PARAMETERS:
  1148. pSiteMapEntry
  1149. types -- bit flag mask
  1150. offset -- offset into ainfoTypes
  1151. RETURNS:
  1152. A pointer to the first SITE_ENTRY_URL structure containing at
  1153. least one of the requested information types.
  1154. COMMENTS:
  1155. 32 Information Types may be checked on each call. This will check
  1156. every URL defined for the current Sitemap entry, and return
  1157. TRUE if there is any match.
  1158. If you needed to find out if information type number 33 was
  1159. defined, you would call this with types set to 1, and offset to 1
  1160. (offset determines which set of 32 information types to look at).
  1161. MODIFICATION DATES:
  1162. 25-Jan-1997 [ralphw]
  1163. ***************************************************************************/
  1164. SITE_ENTRY_URL* CSiteMap::AreTheseInfoTypesDefined(SITEMAP_ENTRY* pSiteMapEntry,
  1165. INFOTYPE types, int offset) const
  1166. {
  1167. ASSERT((UINT) offset <= m_itTables.m_cTypes / sizeof(INFOTYPE));
  1168. SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
  1169. if (!pUrl)
  1170. return NULL;
  1171. for (int iUrl = 0; iUrl < pSiteMapEntry->cUrls; iUrl++)
  1172. {
  1173. if ( *(pUrl->ainfoTypes+offset) & types )
  1174. return pUrl;
  1175. pUrl = NextUrlEntry(pUrl);
  1176. }
  1177. return NULL;
  1178. }
  1179. // This includes all memory for URL names and sitemap entries
  1180. const int MAX_POINTERS = (1024 * 1024); // 1 meg, 262,144 strings
  1181. const int MAX_STRINGS = (25 * 1024 * 1024) - 4096L; // 25 megs
  1182. CSiteMap::CSiteMap(int cMaxEntries) : CTable((cMaxEntries ? (cMaxEntries * 256) : MAX_STRINGS))
  1183. {
  1184. // Can't clear memory, because of our base class
  1185. m_fTypeCopy = FALSE;
  1186. m_fSaveIT = TRUE;
  1187. m_pszSitemapFile = NULL;
  1188. m_pTypicalInfoTypes = NULL;
  1189. m_fIndex = FALSE;
  1190. m_pszBase = NULL;
  1191. m_pszImageList = NULL;
  1192. m_cImages = 0;
  1193. m_pszFont = NULL;
  1194. m_fFolderImages = FALSE;
  1195. m_fPromotForInfoTypes = FALSE;
  1196. m_pszBackBitmap = NULL;
  1197. m_fAutoGenerated = FALSE;
  1198. m_ptblStrings = NULL;
  1199. m_pszFrameName = NULL;
  1200. m_pszWindowName = NULL;
  1201. m_pszHHIFile = NULL;
  1202. ZeroMemory(&m_itTables, sizeof(INFOTYPE_TABLES));
  1203. m_itTables.m_max_categories = MAX_CATEGORIES;
  1204. m_itTables.m_aCategories = (CATEGORY_TYPE*) lcMalloc(MAX_CATEGORIES*sizeof(CATEGORY_TYPE) );
  1205. m_itTables.m_cTypes = 0;
  1206. m_itTables.m_cITSize = 1; // Initially allocate one DWORD to hold info type bits
  1207. for(int i=0; i< MAX_CATEGORIES; i++)
  1208. {
  1209. m_itTables.m_aCategories[i].pInfoType = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE) );
  1210. memset(m_itTables.m_aCategories[i].pInfoType, '\0', InfoTypeSize() );
  1211. m_itTables.m_aCategories[i].c_Types = 0;
  1212. }
  1213. m_itTables.m_pExclusive = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE ) );
  1214. m_itTables.m_pHidden = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE) );
  1215. m_clrBackground = (COLORREF) -1;
  1216. m_clrForeground = (COLORREF) -1;
  1217. m_exStyles = (DWORD) -1;
  1218. m_tvStyles = (DWORD) -1;
  1219. m_clrMask = 0xFFFFFF;
  1220. m_cImageWidth = 20;
  1221. m_pInfoTypes = (INFOTYPE*) lcCalloc(sizeof(INFOTYPE) );
  1222. m_pTypicalInfoTypes = (INFOTYPE*) lcCalloc( sizeof(INFOTYPE) );
  1223. // By default, select all information types
  1224. memset(m_pInfoTypes, 0xFF, sizeof(INFOTYPE) );
  1225. #ifdef HHCTRL
  1226. #ifndef HHA
  1227. m_CodePage = (UINT)-1;
  1228. #endif
  1229. #endif
  1230. }
  1231. CSiteMap::~CSiteMap()
  1232. {
  1233. for (int pos = 1; pos < endpos - 1; pos++)
  1234. {
  1235. SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
  1236. if ( pSiteMapEntry && pSiteMapEntry->pUrls && pSiteMapEntry->pUrls->ainfoTypes )
  1237. lcFree(pSiteMapEntry->pUrls->ainfoTypes);
  1238. }
  1239. if (m_ptblStrings)
  1240. delete m_ptblStrings;
  1241. if (!m_fTypeCopy) {
  1242. if (m_itTables.m_ptblInfoTypes)
  1243. delete m_itTables.m_ptblInfoTypes;
  1244. if (m_itTables.m_ptblInfoTypeDescriptions)
  1245. delete m_itTables.m_ptblInfoTypeDescriptions;
  1246. if (m_itTables.m_ptblCategories)
  1247. delete m_itTables.m_ptblCategories;
  1248. if (m_itTables.m_ptblCatDescription)
  1249. delete m_itTables.m_ptblCatDescription;
  1250. }
  1251. for (int i=0; i< m_itTables.m_max_categories; i++)
  1252. lcFree( m_itTables.m_aCategories[i].pInfoType);
  1253. lcFree (m_itTables.m_aCategories);
  1254. lcFree (m_itTables.m_pHidden);
  1255. lcFree (m_itTables.m_pExclusive);
  1256. lcFree (m_pInfoTypes);
  1257. lcFree (m_pTypicalInfoTypes);
  1258. }
  1259. void CSiteMap::ReSizeURLIT(int Size)
  1260. {
  1261. int oldSize = InfoTypeSize();
  1262. if ( Size == 0 )
  1263. m_itTables.m_cITSize++;
  1264. else
  1265. m_itTables.m_cITSize= Size;
  1266. //Increase each sitemap entry URL infotype
  1267. int cEntries = Count();
  1268. INFOTYPE *pIT;
  1269. for (int i=1; i<=cEntries; i++)
  1270. {
  1271. SITEMAP_ENTRY *pSE = GetSiteMapEntry(i);
  1272. SITE_ENTRY_URL *pSEURL = pSE->pUrls;
  1273. for(int j=0; j<pSE->cUrls; j++)
  1274. {
  1275. pSEURL = pSEURL+j;
  1276. pIT = (INFOTYPE*) lcCalloc( InfoTypeSize() );
  1277. memcpy(pIT, pSEURL->ainfoTypes, oldSize);
  1278. lcFree( pSEURL->ainfoTypes );
  1279. pSEURL->ainfoTypes = pIT;
  1280. }
  1281. }
  1282. SizeIT( oldSize );
  1283. }
  1284. void CSiteMap::ReSizeIT(int Size)
  1285. {
  1286. int oldSize = InfoTypeSize();
  1287. if ( Size == 0 )
  1288. m_itTables.m_cITSize++; // increase by one
  1289. else
  1290. m_itTables.m_cITSize = Size;
  1291. SizeIT(oldSize);
  1292. }
  1293. void CSiteMap::SizeIT(int oldSize)
  1294. {
  1295. // Increase each category
  1296. INFOTYPE * pIT;
  1297. for(int i=0; i<m_itTables.m_max_categories; i++)
  1298. {
  1299. pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
  1300. memcpy(pIT, m_itTables.m_aCategories[i].pInfoType, oldSize);
  1301. lcFree(m_itTables.m_aCategories[i].pInfoType);
  1302. m_itTables.m_aCategories[i].pInfoType = pIT;
  1303. }
  1304. pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
  1305. memcpy(pIT, m_itTables.m_pExclusive, oldSize);
  1306. lcFree(m_itTables.m_pExclusive);
  1307. m_itTables.m_pExclusive = pIT;
  1308. pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
  1309. memcpy(pIT, m_itTables.m_pHidden, oldSize);
  1310. lcFree(m_itTables.m_pHidden);
  1311. m_itTables.m_pHidden = pIT;
  1312. pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
  1313. memcpy(pIT, m_pInfoTypes, oldSize);
  1314. lcFree(m_pInfoTypes);
  1315. m_pInfoTypes = pIT;
  1316. pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
  1317. memcpy(pIT, m_pTypicalInfoTypes, oldSize);
  1318. lcFree(m_pTypicalInfoTypes);
  1319. m_pTypicalInfoTypes = pIT;
  1320. }
  1321. void CSiteMap::CopyCat(INFOTYPE_TABLES *Dst_itTables, const INFOTYPE_TABLES * Src_itTables)
  1322. {
  1323. // copy the categories table
  1324. Dst_itTables->m_max_categories = Src_itTables->m_max_categories;
  1325. if ( Dst_itTables->m_max_categories > MAX_CATEGORIES )
  1326. Dst_itTables->m_aCategories = (CATEGORY_TYPE *)lcReAlloc(Dst_itTables->m_aCategories,
  1327. Dst_itTables->m_max_categories * sizeof(CATEGORY_TYPE) );
  1328. for(int i=0; i<Dst_itTables->m_max_categories; i++)
  1329. {
  1330. if ( Dst_itTables->m_aCategories[i].pInfoType )
  1331. lcFree(Dst_itTables->m_aCategories[i].pInfoType);
  1332. Dst_itTables->m_aCategories[i].pInfoType = (INFOTYPE*) lcCalloc( InfoTypeSize());
  1333. if ( Src_itTables->m_aCategories[i].c_Types > 0 )
  1334. {
  1335. memcpy(Dst_itTables->m_aCategories[i].pInfoType,
  1336. Src_itTables->m_aCategories[i].pInfoType,
  1337. InfoTypeSize() );
  1338. Dst_itTables->m_aCategories[i].c_Types = Src_itTables->m_aCategories[i].c_Types;
  1339. }
  1340. else
  1341. {
  1342. Dst_itTables->m_aCategories[i].c_Types = 0;
  1343. }
  1344. }
  1345. }
  1346. // Check all the categories to see if this type is a member of any of them, return TRUE on first occurrence
  1347. BOOL CSiteMap::IsInACategory( int type ) const
  1348. {
  1349. for (int i=0; i<HowManyCategories(); i++ )
  1350. {
  1351. int offset;
  1352. INFOTYPE *pIT;
  1353. offset = type / 32;
  1354. ASSERT ( m_itTables.m_aCategories[i].pInfoType );
  1355. pIT = m_itTables.m_aCategories[i].pInfoType + offset;
  1356. if ( *pIT & (1<<(type-(offset*32))) )
  1357. return TRUE;
  1358. }
  1359. return FALSE;
  1360. }
  1361. int CSiteMap::GetInfoType(PCSTR pszTypeName)
  1362. {
  1363. int type;
  1364. CStr cszCat = pszTypeName;
  1365. ASSERT(!IsEmptyString(pszTypeName));
  1366. /*
  1367. A category and type is specified as:
  1368. category::type name
  1369. */
  1370. PSTR pszCat = strstr(cszCat.psz, "::");
  1371. if ( !pszCat )
  1372. {
  1373. pszCat = StrChr(cszCat.psz, ':');
  1374. if (pszCat != NULL)
  1375. {
  1376. *pszCat = '\0';
  1377. pszCat++; // step over the :
  1378. }
  1379. }
  1380. else
  1381. {
  1382. *pszCat = '\0';
  1383. pszCat+=2; // step over the ::
  1384. }
  1385. if ( pszCat == NULL )
  1386. return GetITIndex(pszTypeName); // there is not category.
  1387. else
  1388. {
  1389. int cat = GetCatPosition( cszCat.psz );
  1390. if (cat <= 0)
  1391. return -1;
  1392. type = GetFirstCategoryType( cat-1 );
  1393. while( type != -1 )
  1394. {
  1395. if ( strcmp( pszCat, GetInfoTypeName(type) ) == 0 )
  1396. return type;
  1397. type = GetNextITinCategory();
  1398. }
  1399. }
  1400. return -1;
  1401. }
  1402. // Reads the user's current favorites to create nodes
  1403. void CSiteMap::CreateFavorites(int level)
  1404. {
  1405. HRESULT hr;
  1406. LPITEMIDLIST pidl;
  1407. char szFavoritesPath[MAX_PATH];
  1408. hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
  1409. if (SUCCEEDED(hr)) {
  1410. BOOL fResult = SHGetPathFromIDList(pidl, szFavoritesPath);
  1411. // SHFree(pidl); // BUGBUG: this function doesn't exist!!!
  1412. if (!fResult)
  1413. return; // BUGBUG: nag the author
  1414. }
  1415. else
  1416. return; // BUGBUG: nag the author
  1417. AddTrailingBackslash(szFavoritesPath);
  1418. CStr cszSearch(szFavoritesPath);
  1419. cszSearch += "*.*";
  1420. CTable tblFolders;
  1421. CTable tblFiles;
  1422. WIN32_FIND_DATA wfd;
  1423. HANDLE hFind = FindFirstFile(cszSearch, &wfd);
  1424. if (hFind != INVALID_HANDLE_VALUE) {
  1425. do {
  1426. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1427. if (wfd.cFileName[0] != '.') // ignore . and ..
  1428. tblFolders.AddString(wfd.cFileName);
  1429. }
  1430. else
  1431. tblFiles.AddString(wfd.cFileName);
  1432. } while (FindNextFile(hFind, &wfd));
  1433. FindClose(hFind);
  1434. }
  1435. // Did we get at least one entry?
  1436. if (tblFolders.CountStrings() || tblFiles.CountStrings()) {
  1437. SITEMAP_ENTRY SiteMapEntry;
  1438. ZERO_STRUCTURE(SiteMapEntry);
  1439. // Add the top level book called Favorites
  1440. SiteMapEntry.level = level++;
  1441. SiteMapEntry.pszText = StrDup(GetStringResource(IDS_BROWSER_FAVORITES));
  1442. AddEntry(&SiteMapEntry);
  1443. tblFolders.SortTablei(); // BUGBUG: set lcide first
  1444. for (int pos = 1; pos <= tblFolders.CountStrings(); pos++)
  1445. AddFavoriteNodes(szFavoritesPath, tblFolders.GetPointer(pos), level);
  1446. tblFiles.SortTablei(); // BUGBUG: set lcid first
  1447. for (pos = 1; pos <= tblFiles.CountStrings(); pos++) {
  1448. char szUrl[MAX_PATH * 4];
  1449. char szPath[MAX_PATH];
  1450. strcpy(szPath, szFavoritesPath);
  1451. AddTrailingBackslash(szPath);
  1452. strcat(szPath, tblFiles.GetPointer(pos));
  1453. if (GetPrivateProfileString("InternetShortcut", "URL", "",
  1454. szUrl, sizeof(szUrl), szPath) > 0 && szUrl[0]) {
  1455. CStr cszName(tblFiles.GetPointer(pos));
  1456. PSTR pszExtension = StrRChr(cszName, '.');
  1457. if (pszExtension) {
  1458. *pszExtension = '\0';
  1459. SiteMapEntry.level = (BYTE)level;
  1460. SiteMapEntry.pszText = StrDup(cszName);
  1461. CSiteEntryUrl curl( InfoTypeSize() );
  1462. curl.m_pUrl->urlPrimary = AddUrl(szUrl);
  1463. SiteMapEntry.pUrls = curl.m_pUrl;
  1464. SiteMapEntry.SetTopic(TRUE);
  1465. AddEntry(&SiteMapEntry);
  1466. }
  1467. }
  1468. }
  1469. }
  1470. }
  1471. void CSiteMap::AddFavoriteNodes(PCSTR pszRoot, PCSTR pszNewFolder, int level)
  1472. {
  1473. CTable tblFolders;
  1474. CTable tblFiles;
  1475. char szPath[MAX_PATH];
  1476. strcpy(szPath, pszRoot);
  1477. AddTrailingBackslash(szPath);
  1478. strcat(szPath, pszNewFolder);
  1479. CStr cszRoot(szPath); // save in case we need to recurse
  1480. AddTrailingBackslash(szPath);
  1481. strcat(szPath, "*.*");
  1482. WIN32_FIND_DATA wfd;
  1483. HANDLE hFind = FindFirstFile(szPath, &wfd);
  1484. if (hFind != INVALID_HANDLE_VALUE) {
  1485. do {
  1486. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1487. if (wfd.cFileName[0] != '.') // ignore . and ..
  1488. tblFolders.AddString(wfd.cFileName);
  1489. }
  1490. else
  1491. tblFiles.AddString(wfd.cFileName);
  1492. } while (FindNextFile(hFind, &wfd));
  1493. FindClose(hFind);
  1494. }
  1495. // Did we get at least one entry?
  1496. if (tblFolders.CountStrings() || tblFiles.CountStrings()) {
  1497. SITEMAP_ENTRY SiteMapEntry;
  1498. ZERO_STRUCTURE(SiteMapEntry);
  1499. SiteMapEntry.level = level++;
  1500. SiteMapEntry.pszText = StrDup(pszNewFolder);
  1501. AddEntry(&SiteMapEntry);
  1502. tblFolders.SortTablei(); // BUGBUG: set lcid first
  1503. // Handle all nested folders
  1504. for (int pos = 1; pos <= tblFolders.CountStrings(); pos++)
  1505. AddFavoriteNodes(cszRoot, tblFolders.GetPointer(pos), level);
  1506. tblFiles.SortTablei(); // BUGBUG: set lcide first
  1507. for (pos = 1; pos <= tblFiles.CountStrings(); pos++) {
  1508. char szUrl[MAX_PATH * 4];
  1509. strcpy(szPath, cszRoot);
  1510. AddTrailingBackslash(szPath);
  1511. strcat(szPath, tblFiles.GetPointer(pos));
  1512. if (GetPrivateProfileString("InternetShortcut", "URL", "",
  1513. szUrl, sizeof(szUrl), szPath) > 0 && szUrl[0]) {
  1514. CStr cszName(tblFiles.GetPointer(pos));
  1515. PSTR pszExtension = StrRChr(cszName, '.');
  1516. if (pszExtension) {
  1517. *pszExtension = '\0';
  1518. SiteMapEntry.level = (BYTE)level;
  1519. SiteMapEntry.pszText = StrDup(cszName);
  1520. CSiteEntryUrl curl( InfoTypeSize() );
  1521. curl.m_pUrl->urlPrimary = AddUrl(szUrl);
  1522. SiteMapEntry.pUrls = curl.m_pUrl;
  1523. SiteMapEntry.SetTopic(TRUE);
  1524. AddEntry(&SiteMapEntry);
  1525. }
  1526. }
  1527. }
  1528. }
  1529. }
  1530. int CSiteMap::GetImageNumber(SITEMAP_ENTRY* pSiteMapEntry) const
  1531. {
  1532. int image = pSiteMapEntry->GetImageIndex();
  1533. if (image == 0) {
  1534. if (pSiteMapEntry->IsTopic()) {
  1535. image = pSiteMapEntry->fNew ?
  1536. IMAGE_HELP_TOPIC_NEW : IMAGE_HELP_TOPIC;
  1537. if (m_fFolderImages)
  1538. image+= 2; // switch to standard topic images
  1539. }
  1540. else {
  1541. image = pSiteMapEntry->fNew ? IMAGE_OPEN_BOOK_NEW : IMAGE_OPEN_BOOK;
  1542. if (m_fFolderImages)
  1543. image += 4; // switch to standard books
  1544. }
  1545. }
  1546. if (m_cImages && image > m_cImages) {
  1547. // BUGBUG: if this really happens, nag the author
  1548. image = IMAGE_CLOSED_BOOK;
  1549. }
  1550. return image;
  1551. }
  1552. BOOL CSiteMap::IsEntryInCurTypeList(SITEMAP_ENTRY* pSiteMapEntry) const
  1553. {
  1554. int cTypes = m_itTables.m_ptblInfoTypes->CountStrings();
  1555. if (cTypes < 32) {
  1556. return AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[0], 0) != NULL;
  1557. }
  1558. else {
  1559. for (int i = 0; cTypes > 32; i++) {
  1560. if (AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[i], i))
  1561. return TRUE;
  1562. cTypes -= 32;
  1563. }
  1564. return AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[i], i) != NULL;
  1565. }
  1566. }
  1567. typedef struct tagEntityMap
  1568. {
  1569. PCSTR pszName;
  1570. int ch;
  1571. } ENTITYMAP, * PENTITYMAP;
  1572. // ENTITY TABLE SWIPED FROM IE
  1573. const ENTITYMAP rgEntities[] =
  1574. {
  1575. "AElig", '\306', // capital AE diphthong (ligature)
  1576. "Aacute", '\301', // capital A, acute accent
  1577. "Acirc", '\302', // capital A, circumflex accent
  1578. "Agrave", '\300', // capital A, grave accent
  1579. "Aring", '\305', // capital A, ring
  1580. "Atilde", '\303', // capital A, tilde
  1581. "Auml", '\304', // capital A, dieresis or umlaut mark
  1582. "Ccedil", '\307', // capital C, cedilla
  1583. "Dstrok", '\320', // capital Eth, Icelandic
  1584. "ETH", '\320', // capital Eth, Icelandic
  1585. "Eacute", '\311', // capital E, acute accent
  1586. "Ecirc", '\312', // capital E, circumflex accent
  1587. "Egrave", '\310', // capital E, grave accent
  1588. "Euml", '\313', // capital E, dieresis or umlaut mark
  1589. "Iacute", '\315', // capital I, acute accent
  1590. "Icirc", '\316', // capital I, circumflex accent
  1591. "Igrave", '\314', // capital I, grave accent
  1592. "Iuml", '\317', // capital I, dieresis or umlaut mark
  1593. "Ntilde", '\321', // capital N, tilde
  1594. "Oacute", '\323', // capital O, acute accent
  1595. "Ocirc", '\324', // capital O, circumflex accent
  1596. "Ograve", '\322', // capital O, grave accent
  1597. "Oslash", '\330', // capital O, slash
  1598. "Otilde", '\325', // capital O, tilde
  1599. "Ouml", '\326', // capital O, dieresis or umlaut mark
  1600. "THORN", '\336', // capital THORN, Icelandic
  1601. "Uacute", '\332', // capital U, acute accent
  1602. "Ucirc", '\333', // capital U, circumflex accent
  1603. "Ugrave", '\331', // capital U, grave accent
  1604. "Uuml", '\334', // capital U, dieresis or umlaut mark
  1605. "Yacute", '\335', // capital Y, acute accent
  1606. "aacute", '\341', // small a, acute accent
  1607. "acirc", '\342', // small a, circumflex accent
  1608. "acute", '\264', // acute accent
  1609. "aelig", '\346', // small ae diphthong (ligature)
  1610. "agrave", '\340', // small a, grave accent
  1611. "amp", '\046', // ampersand
  1612. "aring", '\345', // small a, ring
  1613. "atilde", '\343', // small a, tilde
  1614. "auml", '\344', // small a, dieresis or umlaut mark
  1615. "brkbar", '\246', // broken vertical bar
  1616. "brvbar", '\246', // broken vertical bar
  1617. "ccedil", '\347', // small c, cedilla
  1618. "cedil", '\270', // cedilla
  1619. "cent", '\242', // small c, cent
  1620. "copy", '\251', // copyright symbol (proposed 2.0)
  1621. "curren", '\244', // currency symbol
  1622. "deg", '\260', // degree sign
  1623. "die", '\250', // umlaut (dieresis)
  1624. "divide", '\367', // divide sign
  1625. "eacute", '\351', // small e, acute accent
  1626. "ecirc", '\352', // small e, circumflex accent
  1627. "egrave", '\350', // small e, grave accent
  1628. "eth", '\360', // small eth, Icelandic
  1629. "euml", '\353', // small e, dieresis or umlaut mark
  1630. "frac12", '\275', // fraction 1/2
  1631. "frac14", '\274', // fraction 1/4
  1632. "frac34", '\276', // fraction 3/4*/
  1633. "gt", '\076', // greater than
  1634. "hibar", '\257', // macron accent
  1635. "iacute", '\355', // small i, acute accent
  1636. "icirc", '\356', // small i, circumflex accent
  1637. "iexcl", '\241', // inverted exclamation
  1638. "igrave", '\354', // small i, grave accent
  1639. "iquest", '\277', // inverted question mark
  1640. "iuml", '\357', // small i, dieresis or umlaut mark
  1641. "laquo", '\253', // left angle quote
  1642. "lt", '\074', // less than
  1643. "macr", '\257', // macron accent
  1644. "micro", '\265', // micro sign
  1645. "middot", '\267', // middle dot
  1646. "nbsp", '\240', // non-breaking space (proposed 2.0)
  1647. "not", '\254', // not sign
  1648. "ntilde", '\361', // small n, tilde
  1649. "oacute", '\363', // small o, acute accent
  1650. "ocirc", '\364', // small o, circumflex accent
  1651. "ograve", '\362', // small o, grave accent
  1652. "ordf", '\252', // feminine ordinal
  1653. "ordm", '\272', // masculine ordinal
  1654. "oslash", '\370', // small o, slash
  1655. "otilde", '\365', // small o, tilde
  1656. "ouml", '\366', // small o, dieresis or umlaut mark
  1657. "para", '\266', // paragraph sign
  1658. "plusmn", '\261', // plus minus
  1659. "pound", '\243', // pound sterling
  1660. "quot", '"', // double quote
  1661. "raquo", '\273', // right angle quote
  1662. "reg", '\256', // registered trademark (proposed 2.0)
  1663. "sect", '\247', // section sign
  1664. "shy", '\255', // soft hyphen (proposed 2.0)
  1665. "sup1", '\271', // superscript 1
  1666. "sup2", '\262', // superscript 2
  1667. "sup3", '\263', // superscript 3
  1668. "szlig", '\337', // small sharp s, German (sz ligature)
  1669. "thorn", '\376', // small thorn, Icelandic
  1670. "times", '\327', // times sign
  1671. "trade", '\231', // trademark sign
  1672. "uacute", '\372', // small u, acute accent
  1673. "ucirc", '\373', // small u, circumflex accent
  1674. "ugrave", '\371', // small u, grave accent
  1675. "uml", '\250', // umlaut (dieresis)
  1676. "uuml", '\374', // small u, dieresis or umlaut mark
  1677. "yacute", '\375', // small y, acute accent
  1678. "yen", '\245', // yen
  1679. "yuml", '\377', // small y, dieresis or umlaut mark
  1680. 0, 0
  1681. };
  1682. BOOL ReplaceEscapes(PCSTR pszSrc, PSTR pszDst, int flags)
  1683. {
  1684. if (IsEmptyString(pszSrc))
  1685. return FALSE;
  1686. ASSERT(pszDst);
  1687. if ((flags & ESCAPE_URL)) {
  1688. if (StrChr(pszSrc, '%'))
  1689. goto CheckForEscape;
  1690. }
  1691. if ((flags & ESCAPE_C)) {
  1692. if (StrChr(pszSrc, '\\'))
  1693. goto CheckForEscape;
  1694. }
  1695. if ((flags & ESCAPE_ENTITY)) {
  1696. if (StrChr(pszSrc, '&'))
  1697. goto CheckForEscape;
  1698. }
  1699. // If we get here, there are no escape sequences, so copy the string and
  1700. // return.
  1701. if (pszDst != pszSrc)
  1702. strcpy(pszDst, pszSrc);
  1703. return FALSE; // nothing changed
  1704. CheckForEscape:
  1705. #ifdef _DEBUG
  1706. PSTR pszOrgDst = pszDst;
  1707. int cbSource = (int)strlen(pszSrc);
  1708. #endif
  1709. while (*pszSrc) {
  1710. if (IsDBCSLeadByte(*pszSrc))
  1711. {
  1712. if (pszSrc[1])
  1713. {
  1714. *pszDst++ = *pszSrc++;
  1715. *pszDst++ = *pszSrc++;
  1716. }
  1717. else
  1718. {
  1719. // leadbyte followed by 0; invalid!
  1720. *pszDst++ = '?';
  1721. break;
  1722. }
  1723. }
  1724. else if ((flags & ESCAPE_URL) && *pszSrc == '%')
  1725. {
  1726. // URL style hex digits
  1727. get_hex:
  1728. int val;
  1729. pszSrc++;
  1730. if (IsDigit(*pszSrc))
  1731. val = *pszSrc++ - '0';
  1732. else if (*pszSrc >= 'a' && *pszSrc <= 'f')
  1733. val = *pszSrc++ - 'a' + 10;
  1734. else if (*pszSrc >= 'A' && *pszSrc <= 'F')
  1735. val = *pszSrc++ - 'A' + 10;
  1736. if (IsDigit(*pszSrc))
  1737. val = val * 16 + *pszSrc++ - '0';
  1738. else if (*pszSrc >= 'a' && *pszSrc <= 'f')
  1739. val = val * 16 + *pszSrc++ - 'a' + 10;
  1740. else if (*pszSrc >= 'A' && *pszSrc <= 'F')
  1741. val = val * 16 + *pszSrc++ - 'A' + 10;
  1742. if (val)
  1743. {
  1744. *pszDst++ = (CHAR)val;
  1745. }
  1746. }
  1747. else if ((flags & ESCAPE_C) && *pszSrc == '\\')
  1748. {
  1749. // C style escape
  1750. switch (*++pszSrc)
  1751. {
  1752. case 'n':
  1753. *pszDst++ = '\n';
  1754. pszSrc++;
  1755. break;
  1756. case 'r':
  1757. *pszDst++ = '\r';
  1758. pszSrc++;
  1759. break;
  1760. case 't':
  1761. *pszDst++ = '\t';
  1762. pszSrc++;
  1763. break;
  1764. case '0':
  1765. case '1':
  1766. case '2':
  1767. case '3':
  1768. case '4':
  1769. case '5':
  1770. case '6':
  1771. case '7':
  1772. // octal digits
  1773. {
  1774. int val;
  1775. if (*pszSrc >= '0' && *pszSrc <= '7')
  1776. val = *pszSrc++ - '0';
  1777. if (*pszSrc >= '0' && *pszSrc <= '7')
  1778. val = val * 8 + *pszSrc++ - '0';
  1779. if (*pszSrc >= '0' && *pszSrc <= '7')
  1780. val = val * 8 + *pszSrc++ - '0';
  1781. if (val)
  1782. *pszDst++ = (CHAR)val;
  1783. }
  1784. break;
  1785. case 'x':
  1786. case 'X':
  1787. // hex digits
  1788. goto get_hex;
  1789. break;
  1790. case 0:
  1791. break;
  1792. default:
  1793. *pszDst++ = *pszSrc++;
  1794. break;
  1795. }
  1796. }
  1797. else if ( (flags & ESCAPE_ENTITY) && *pszSrc == '&' && *(pszSrc+1) != ' ' )
  1798. {
  1799. pszSrc++;
  1800. if (*pszSrc == '#')
  1801. {
  1802. // SGML/HTML character entity (decimal)
  1803. pszSrc++;
  1804. for (int val = 0; *pszSrc && *pszSrc != ';' && *pszSrc != ' '; pszSrc++)
  1805. {
  1806. if (*pszSrc >= '0' && *pszSrc <= '9')
  1807. val = val * 10 + *pszSrc - '0';
  1808. else
  1809. {
  1810. while (*pszSrc && *pszSrc != ';' && *pszSrc != ' ')
  1811. pszSrc++;
  1812. break;
  1813. }
  1814. }
  1815. if( *pszSrc == ';' )
  1816. pszSrc++;
  1817. if (val) {
  1818. *pszDst++ = (CHAR)val;
  1819. }
  1820. }
  1821. else if (*pszSrc)
  1822. {
  1823. char szEntityName[256];
  1824. int count = 0;
  1825. // extra code was added below to handle the case where an & appears without
  1826. // an entity name (which is an error in the HTML). This avoids overunning
  1827. // the szEntityName buffer.
  1828. //
  1829. for (PSTR p = szEntityName; *pszSrc && *pszSrc != ';' && *pszSrc != ' ' && count < sizeof(szEntityName);)
  1830. {
  1831. *p++ = *pszSrc++;
  1832. count++;
  1833. }
  1834. *p = 0;
  1835. if (*pszSrc == ';')
  1836. pszSrc++;
  1837. for (int i = 0; rgEntities[i].pszName; i++)
  1838. {
  1839. if (!strcmp(szEntityName, rgEntities[i].pszName)) {
  1840. if (rgEntities[i].ch) {
  1841. *pszDst++ = (CHAR)rgEntities[i].ch;
  1842. }
  1843. break;
  1844. }
  1845. }
  1846. if (!rgEntities[i].pszName) {
  1847. // illegal entity name, put in a block character
  1848. *pszDst++ = '?';
  1849. }
  1850. }
  1851. }
  1852. else {
  1853. // just your usual character...
  1854. *pszDst++ = *pszSrc++;
  1855. }
  1856. }
  1857. *pszDst = 0;
  1858. ASSERT(pszDst - pszOrgDst <= cbSource);
  1859. return TRUE;
  1860. }
  1861. #ifndef HHCTRL
  1862. void STDCALL ConvertToEscapes(PCSTR pszSrc, CStr* pcszDst)
  1863. {
  1864. int cbAlloc = pcszDst->SizeAlloc();
  1865. if (!cbAlloc)
  1866. pcszDst->ReSize(cbAlloc = (strlen(pszSrc) + 128));
  1867. int dstPos = 0;
  1868. if (!pszSrc) {
  1869. *pcszDst = "";
  1870. return;
  1871. }
  1872. int cbSrc = strlen(pszSrc);
  1873. while (*pszSrc) {
  1874. if( IsDBCSLeadByte(*pszSrc) )
  1875. {
  1876. pcszDst->psz[dstPos++] = *pszSrc++;
  1877. if( pszSrc )
  1878. pcszDst->psz[dstPos++] = *pszSrc++;
  1879. }
  1880. else {
  1881. for (int i = 0; rgEntities[i].pszName; i++) {
  1882. if (*pszSrc == rgEntities[i].ch) {
  1883. if ((size_t) cbAlloc - dstPos <= strlen(rgEntities[i].pszName) + 2)
  1884. pcszDst->ReSize(cbAlloc += 128);
  1885. pcszDst->psz[dstPos++] = '&';
  1886. strcpy(pcszDst->psz + dstPos, rgEntities[i].pszName);
  1887. strcat(pcszDst->psz, ";");
  1888. dstPos += strlen(rgEntities[i].pszName) + 1;
  1889. pszSrc++;
  1890. break;
  1891. }
  1892. }
  1893. if (!rgEntities[i].pszName)
  1894. pcszDst->psz[dstPos++] = *pszSrc++;
  1895. }
  1896. if (cbAlloc <= dstPos)
  1897. pcszDst->ReSize(cbAlloc += 128);
  1898. }
  1899. pcszDst->psz[dstPos] = '\0';
  1900. }
  1901. #endif
  1902. #ifdef HHCTRL
  1903. BOOL CAInput::Add(PCSTR pszFile)
  1904. {
  1905. m_ainput[++m_curInput].pin = new CInput(pszFile);
  1906. m_ainput[m_curInput].pszBaseName = lcStrDup(pszFile);
  1907. if (!m_ainput[m_curInput].pin->isInitialized()) {
  1908. Remove();
  1909. return FALSE;
  1910. }
  1911. // Strip basename down to the path
  1912. PSTR pszFilePortion = (PSTR) FindFilePortion(m_ainput[m_curInput].pszBaseName);
  1913. if (pszFilePortion)
  1914. *pszFilePortion = '\0';
  1915. ConvertBackSlashToForwardSlash(m_ainput[m_curInput].pszBaseName);
  1916. return TRUE;
  1917. }
  1918. #endif
  1919. ////////////////////////////////// non-HHCTRL code //////////////////////////////////
  1920. #ifndef HHCTRL
  1921. const int MAX_PARAM = 4096;
  1922. #pragma warning(disable:4125) // decimal digit terminates octal escape sequence
  1923. static const char txtSiteMapVersion[] = "<!-- Sitemap 1.0 -->";
  1924. static const char txtStringParam[] = "<param name=\042%s\042 value=\042%s\042>";
  1925. static const char txtSSConvString[] = "<param name=\042%s\042 value=\042%s:%s:%s\042>";
  1926. static const char txtYes[] = "Yes";
  1927. static const char txtDecimalParam[] = "<param name=\042%s\042 value=\042%u\042>";
  1928. static const char txtHexParam[] = "<param name=\042%s\042 value=\0420x%x\042>";
  1929. __inline void PadOutput(COutput* pout, int level) {
  1930. for (int i = 0; i < level; i++)
  1931. pout->outchar('\t');
  1932. }
  1933. BOOL CSiteMap::SaveSiteMap(PCSTR pszPathName, BOOL fIndex)
  1934. {
  1935. COutput output(pszPathName);
  1936. if (!output.isFileOpen()) {
  1937. // DO NOT USE MsgBox() as the parent window handle is invalid if we are closing
  1938. CStr csz(IDS_CANT_WRITE, pszPathName);
  1939. MessageBox(APP_WINDOW, csz, txtAppTitle, MB_OK | MB_ICONHAND);
  1940. return FALSE;
  1941. }
  1942. CStr cszTmp;
  1943. CMem memParam(MAX_PARAM);
  1944. PSTR pszParam = memParam.psz; // for notational convenience
  1945. output.outstring(GetStringResource(IDSHHA_HTML_NEW_FILE1));
  1946. output.outstring_eol(txtSiteMapVersion);
  1947. output.outstring_eol("</HEAD><BODY>");
  1948. // Write out any global properties
  1949. if ( IsFrameDefined() ||
  1950. IsWindowDefined() ||
  1951. m_itTables.m_ptblInfoTypes ||
  1952. m_itTables.m_ptblCategories ||
  1953. m_fFolderImages ||
  1954. m_pszImageList ||
  1955. m_fAutoGenerated ||
  1956. IsNonEmpty(m_pszFont) ||
  1957. IsNonEmpty(m_pszHHIFile) ||
  1958. m_clrBackground != (COLORREF) -1 ||
  1959. m_clrForeground != (COLORREF) -1 ||
  1960. m_exStyles != (DWORD) -1 ||
  1961. m_tvStyles != (DWORD) -1) {
  1962. output.outstring_eol("<OBJECT type=\042text/site properties\042>");
  1963. if (m_fAutoGenerated) {
  1964. wsprintf(pszParam, txtStringParam, txtAutoGenerated,
  1965. txtYes);
  1966. ASSERT(strlen(pszParam) < MAX_PARAM);
  1967. output.outchar('\t');
  1968. output.outstring_eol(pszParam);
  1969. }
  1970. if (IsFrameDefined()) {
  1971. ConvertToEscapes(GetFrameName(), &cszTmp);
  1972. wsprintf(pszParam, txtStringParam, txtParamFrame, cszTmp);
  1973. ASSERT(strlen(pszParam) < MAX_PARAM);
  1974. output.outchar('\t');
  1975. output.outstring_eol(pszParam);
  1976. }
  1977. if (IsWindowDefined()) {
  1978. ConvertToEscapes(GetWindowName(), &cszTmp);
  1979. wsprintf(pszParam, txtStringParam, txtParamWindow, cszTmp);
  1980. ASSERT(strlen(pszParam) < MAX_PARAM);
  1981. output.outchar('\t');
  1982. output.outstring_eol(pszParam);
  1983. }
  1984. /*
  1985. * REVIEW: we should eliminate Information Types which haven't
  1986. * actually been used.
  1987. */
  1988. // output the entire list of info types to disk, without regard to their inclusion
  1989. // in a category. We may have ITs that are not members of a category.
  1990. if ( m_fSaveIT && m_itTables.m_cTypes )
  1991. {
  1992. for(int pos=1; pos<=m_itTables.m_cTypes; pos++)
  1993. {
  1994. ConvertToEscapes(m_itTables.m_ptblInfoTypes->GetPointer(pos), &cszTmp);
  1995. if ( HowManyCategories() > 0 )
  1996. {
  1997. if ( IsExclusive(pos) ) // An Exclusive IT
  1998. wsprintf( pszParam, txtStringParam, txtSaveTypeExclusive, cszTmp);
  1999. else if ( IsHidden(pos) ) // A Hidden IT
  2000. wsprintf( pszParam, txtStringParam, txtSaveTypeHidden, cszTmp);
  2001. else // A regular IT
  2002. wsprintf(pszParam, txtStringParam, txtSaveType, cszTmp);
  2003. }
  2004. else
  2005. {
  2006. if ( IsExclusive(pos) ) // An Exclusive IT
  2007. wsprintf( pszParam, txtStringParam, txtParamTypeExclusive, cszTmp);
  2008. else if ( IsHidden(pos) ) // A Hidden IT
  2009. wsprintf( pszParam, txtStringParam, txtParamTypeHidden, cszTmp);
  2010. else // A regular IT
  2011. wsprintf(pszParam, txtStringParam, txtParamType, cszTmp);
  2012. }
  2013. ASSERT(strlen(pszParam) < MAX_PARAM);
  2014. output.outchar('\t');
  2015. output.outstring_eol(pszParam);
  2016. ConvertToEscapes(m_itTables.m_ptblInfoTypeDescriptions->GetPointer(pos), &cszTmp);
  2017. if (!IsEmptyString(cszTmp))
  2018. {
  2019. if (StrChr(cszTmp, '&'))
  2020. {
  2021. cszTmp = cszTmp;
  2022. cszTmp.AddAmpersandEscape();
  2023. cszTmp = cszTmp.psz;
  2024. }
  2025. if ( HowManyCategories() > 0)
  2026. wsprintf(pszParam, txtStringParam, txtSaveTypeDesc, cszTmp);
  2027. else
  2028. wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
  2029. ASSERT(strlen(pszParam) < MAX_PARAM);
  2030. output.outchar('\t');
  2031. output.outstring_eol(pszParam);
  2032. }
  2033. else
  2034. {
  2035. CStr cszTemp(" ");
  2036. cszTmp = cszTemp.psz;
  2037. if ( HowManyCategories() > 0)
  2038. wsprintf(pszParam, txtStringParam, txtSaveTypeDesc, cszTmp);
  2039. else
  2040. wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
  2041. ASSERT(strlen(pszParam) < MAX_PARAM);
  2042. output.outchar('\t');
  2043. output.outstring_eol(pszParam);
  2044. }
  2045. }
  2046. }
  2047. //Output Categories and the info types, that are members of each category, to disk.
  2048. if (m_fSaveIT && m_itTables.m_ptblCategories && m_itTables.m_ptblCategories->CountStrings() )
  2049. {
  2050. for(int posCat=1; posCat<=m_itTables.m_ptblCategories->CountStrings(); posCat++)
  2051. {
  2052. if ( IsCatDeleted( posCat ) )
  2053. continue;
  2054. ConvertToEscapes(GetCategoryString(posCat), &cszTmp);
  2055. if (cszTmp.IsNonEmpty())
  2056. {
  2057. wsprintf(pszParam, txtStringParam, txtParamCategory, cszTmp);
  2058. ASSERT(strlen(pszParam) < MAX_PARAM);
  2059. output.outchar('\t');
  2060. output.outstring_eol(pszParam);
  2061. ConvertToEscapes(m_itTables.m_ptblCatDescription->GetPointer(posCat), &cszTmp);
  2062. if (!IsEmptyString(cszTmp))
  2063. {
  2064. if (StrChr(cszTmp, '&'))
  2065. {
  2066. cszTmp = cszTmp;
  2067. cszTmp.AddAmpersandEscape();
  2068. cszTmp = cszTmp.psz;
  2069. }
  2070. wsprintf(pszParam, txtStringParam, txtParamCategoryDesc, cszTmp);
  2071. ASSERT(strlen(pszParam) < MAX_PARAM);
  2072. output.outchar('\t');
  2073. output.outstring_eol(pszParam);
  2074. }
  2075. else
  2076. {
  2077. CStr cszTemp(" ");
  2078. cszTmp = cszTemp.psz;
  2079. wsprintf(pszParam, txtStringParam, txtParamCategoryDesc, cszTmp);
  2080. ASSERT(strlen(pszParam) < MAX_PARAM);
  2081. output.outchar('\t');
  2082. output.outstring_eol(pszParam);
  2083. }
  2084. }
  2085. int posType = GetFirstCategoryType(posCat-1);
  2086. // for(int j = 1; j <= m_itTables.m_aCategories[posCat-1].c_Types; j++)
  2087. while( posType != -1 )
  2088. {
  2089. ConvertToEscapes(GetInfoTypeName(posType), &cszTmp);
  2090. if ( IsExclusive( posType ) )
  2091. wsprintf( pszParam, txtStringParam, txtParamTypeExclusive, cszTmp);
  2092. else
  2093. if ( IsHidden(posType) ) // A Hidden IT
  2094. wsprintf( pszParam, txtStringParam, txtParamTypeHidden, cszTmp);
  2095. else // A regular IT
  2096. wsprintf(pszParam, txtStringParam, txtParamType, cszTmp);
  2097. ASSERT(strlen(pszParam) < MAX_PARAM);
  2098. output.outchar('\t');
  2099. output.outstring_eol(pszParam);
  2100. ConvertToEscapes(m_itTables.m_ptblInfoTypeDescriptions->GetPointer(posType), &cszTmp);
  2101. if (cszTmp.IsNonEmpty())
  2102. {
  2103. if (StrChr(cszTmp, '&'))
  2104. {
  2105. cszTmp = cszTmp;
  2106. cszTmp.AddAmpersandEscape();
  2107. cszTmp = cszTmp.psz;
  2108. }
  2109. wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
  2110. ASSERT(strlen(pszParam) < MAX_PARAM);
  2111. output.outchar('\t');
  2112. output.outstring_eol(pszParam);
  2113. }
  2114. else
  2115. {
  2116. CStr cszTemp(" ");
  2117. cszTmp = cszTemp.psz;
  2118. wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
  2119. ASSERT(strlen(pszParam) < MAX_PARAM);
  2120. output.outchar('\t');
  2121. output.outstring_eol(pszParam);
  2122. }
  2123. posType = GetNextITinCategory();
  2124. } // for each IT in a category
  2125. } // for each category
  2126. } // if there are categories.
  2127. #ifdef NOTYET
  2128. // OutPut the SubSet Declarations.
  2129. CStr cszTemp;
  2130. for(int i=0; i<m_pSubSets->HowManySubSets(); i++)
  2131. {
  2132. CSubSet * cur_subset = m_pSubSets->GetSubSet(i);
  2133. if ( cur_subset == NULL )
  2134. continue;
  2135. // output the Inclusive IT's in the subset
  2136. int type = cur_subset->GetFirstIncITinSubSet();
  2137. while ( type != -1 )
  2138. {
  2139. wsprintf(pszParam, txtSSConvString, txtParamSSInclusive, txtSSInclusive
  2140. cur_subset->m_cszSubSetName.psz,
  2141. cur_subset->m_pIT->m_itTables.m_ptblInfoTypes->GetPointer(type) );
  2142. ASSERT(strlen(pszParam) < MAX_PARAM);
  2143. output.outchar('\t');
  2144. output.outstring_eol(pszParam);
  2145. type = cur_subset->GetNextIncITinSubSet();
  2146. }
  2147. // output the Exclusive IT's of the subset
  2148. type = cur_subset->GetFirstExcITinSubSet();
  2149. while( type != -1 )
  2150. {
  2151. wsprintf(pszParam, txtSSConvString, txtParamSSExclusive, txtSSExclusive
  2152. cur_subset->m_cszSubSetName.psz,
  2153. cur_subset->m_pIT->m_itTables.m_ptblInfoTypes->GetPointer(type) );
  2154. ASSERT(strlen(pszParam) < MAX_PARAM);
  2155. output.outchar('\t');
  2156. output.outstring_eol(pszParam);
  2157. type = cur_subset->GetNextExcITinSubSet();
  2158. }
  2159. } // End OutPut SubSets
  2160. #endif
  2161. if (m_pszImageList && m_cImageWidth) {
  2162. ConvertToEscapes(m_pszImageList, &cszTmp);
  2163. wsprintf(pszParam, txtStringParam, txtImageList, cszTmp);
  2164. ASSERT(strlen(pszParam) < MAX_PARAM);
  2165. output.outchar('\t');
  2166. output.outstring_eol(pszParam);
  2167. wsprintf(pszParam, txtDecimalParam, txtImageWidth, m_cImageWidth);
  2168. ASSERT(strlen(pszParam) < MAX_PARAM);
  2169. output.outchar('\t');
  2170. output.outstring_eol(pszParam);
  2171. if (m_clrMask != 0xFFFFFF) {
  2172. wsprintf(pszParam, txtHexParam, txtColorMask, m_clrMask);
  2173. ASSERT(strlen(pszParam) < MAX_PARAM);
  2174. output.outchar('\t');
  2175. output.outstring_eol(pszParam);
  2176. }
  2177. }
  2178. if (m_clrBackground != (DWORD) -1) {
  2179. wsprintf(pszParam, txtHexParam, txtBackGround, m_clrBackground);
  2180. ASSERT(strlen(pszParam) < MAX_PARAM);
  2181. output.outchar('\t');
  2182. output.outstring_eol(pszParam);
  2183. }
  2184. if (m_clrForeground != (DWORD) -1) {
  2185. wsprintf(pszParam, txtHexParam, txtForeGround, m_clrForeground);
  2186. ASSERT(strlen(pszParam) < MAX_PARAM);
  2187. output.outchar('\t');
  2188. output.outstring_eol(pszParam);
  2189. }
  2190. if (m_exStyles != (DWORD) -1) {
  2191. wsprintf(pszParam, txtHexParam, txtExWindowStyles, m_exStyles);
  2192. ASSERT(strlen(pszParam) < MAX_PARAM);
  2193. output.outchar('\t');
  2194. output.outstring_eol(pszParam);
  2195. }
  2196. if (m_tvStyles != (DWORD) -1) {
  2197. wsprintf(pszParam, txtHexParam, txtWindowStyles, m_tvStyles);
  2198. ASSERT(strlen(pszParam) < MAX_PARAM);
  2199. output.outchar('\t');
  2200. output.outstring_eol(pszParam);
  2201. }
  2202. if (m_fFolderImages) {
  2203. wsprintf(pszParam, txtStringParam, txtImageType, txtFolderType);
  2204. ASSERT(strlen(pszParam) < MAX_PARAM);
  2205. output.outchar('\t');
  2206. output.outstring_eol(pszParam);
  2207. }
  2208. if (IsNonEmpty(m_pszFont)) {
  2209. ConvertToEscapes(m_pszFont, &cszTmp);
  2210. wsprintf(pszParam, txtStringParam, txtFont, cszTmp);
  2211. output.outstring_eol(pszParam);
  2212. }
  2213. if (IsNonEmpty(m_pszHHIFile)) {
  2214. wsprintf(pszParam, txtStringParam, txtParamHHI, m_pszHHIFile);
  2215. output.outstring_eol(pszParam);
  2216. }
  2217. output.outstring_eol(txtEndObject);
  2218. }
  2219. // Write out the actual entries
  2220. output.outstring_eol(txtBeginList);
  2221. int curLevel = 1;
  2222. for (int pos = 1; pos <= CountStrings(); pos++) {
  2223. SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
  2224. ASSERT(pSiteMapEntry->pszText);
  2225. if (!pSiteMapEntry->pszText) // should never happen, but I'm paranoid...
  2226. continue;
  2227. // If level is greater, begin list item
  2228. while (pSiteMapEntry->level > curLevel) {
  2229. PadOutput(&output, curLevel);
  2230. output.outstring_eol(txtBeginList);
  2231. curLevel++;
  2232. }
  2233. // While level is lower, end lists
  2234. while (pSiteMapEntry->level < curLevel) {
  2235. curLevel--;
  2236. PadOutput(&output, curLevel);
  2237. output.outstring_eol(txtEndList);
  2238. }
  2239. PadOutput(&output, curLevel);
  2240. if (!pSiteMapEntry->fInclude)
  2241. output.outstring("<LI> ");
  2242. output.outstring_eol("<OBJECT type=\042text/sitemap\042>");
  2243. if (pSiteMapEntry->fInclude) {
  2244. PadOutput(&output, curLevel + 1);
  2245. output.outstring("<param name=\042Merge\042 value=\042");
  2246. ConvertToEscapes(pSiteMapEntry->pszText + strlen(GetStringResource(IDS_INCLUDED_FILE)), &cszTmp);
  2247. output.outstring(cszTmp);
  2248. output.outstring_eol("\042>\r\n");
  2249. PadOutput(&output, curLevel + 1);
  2250. output.outstring_eol(txtEndObject);
  2251. continue;
  2252. }
  2253. ConvertToEscapes(pSiteMapEntry->pszText, &cszTmp);
  2254. wsprintf(pszParam, txtStringParam, txtParamName, cszTmp);
  2255. ASSERT(strlen(pszParam) < MAX_PARAM);
  2256. PadOutput(&output, curLevel + 1);
  2257. output.outstring_eol(pszParam);
  2258. OutputDefaultSiteMapEntry(&output, pSiteMapEntry, curLevel, fIndex);
  2259. PadOutput(&output, curLevel + 1);
  2260. output.outstring_eol(txtEndObject);
  2261. #if 0
  2262. /*
  2263. * We need to add an HREF to keep down-level sitemap readers happy
  2264. * (makes the .hhc file readable in a browser). We pick the first
  2265. * URL specified and use that.
  2266. */
  2267. for (int i = 0; i < pSiteMapEntry->cTypes; i++) {
  2268. if ( pSiteMapEntry->aSiteInfoTypes[i].urlNumber > 0 &&
  2269. pSiteMapEntry->aSiteInfoTypes[i].infoNumber > 0) {
  2270. wsprintf(pszParam, "<A HREF=\042%s\042>%s</A>",
  2271. m_ptoc->GetUrlString((pSiteMapEntry->aSiteInfoTypes[i].urlNumber),
  2272. pSiteMapEntry->pszText);
  2273. ASSERT(strlen(pszParam) < MAX_PARAM);
  2274. PadOutput(&output, curLevel + 1);
  2275. output.outstring_eol(pszParam);
  2276. break;
  2277. }
  2278. }
  2279. #endif
  2280. }
  2281. while (curLevel > 1) {
  2282. curLevel--;
  2283. PadOutput(&output, curLevel);
  2284. output.outstring_eol(txtEndList);
  2285. }
  2286. output.outstring_eol(txtEndList);
  2287. output.outstring_eol("</BODY></HTML>");
  2288. return TRUE;
  2289. }
  2290. void CSiteMap::OutputDefaultSiteMapEntry(COutput* pout, SITEMAP_ENTRY* pSiteMapEntry,
  2291. int curLevel, BOOL fIndex)
  2292. {
  2293. CMem memParam(8 * 1024);
  2294. PSTR pszParam = memParam.psz; // for notational convenience
  2295. SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
  2296. int cTypes = HowManyInfoTypes();
  2297. for (int i = 0; i < pSiteMapEntry->cUrls; i++) {
  2298. if (!IsEmptyString(pUrl->pszTitle)) {
  2299. wsprintf(pszParam, txtStringParam, txtParamName, pUrl->pszTitle);
  2300. ASSERT(strlen(pszParam) < MAX_PARAM);
  2301. PadOutput(pout, curLevel + 1);
  2302. pout->outstring_eol(pszParam);
  2303. }
  2304. if (cTypes) {
  2305. int bitflag = 1 << 1;
  2306. int offset = 0;
  2307. CSiteMapEntry sitemapentry;
  2308. sitemapentry.cUrls = 1;
  2309. sitemapentry.pUrls = pUrl;
  2310. for (int infotype = 1; infotype <= cTypes; infotype++) {
  2311. if (AreTheseInfoTypesDefined(&sitemapentry, bitflag, offset)) {
  2312. CStr csz;
  2313. for (int l = 0; l < HowManyCategories(); l++) {
  2314. if( m_itTables.m_aCategories[l].c_Types <= 0)
  2315. break;
  2316. if( IsITinCategory( l, infotype) )
  2317. {
  2318. csz = GetCategoryString(l+1);
  2319. csz += "::";
  2320. break;
  2321. }
  2322. }
  2323. csz += GetInfoTypeName(infotype);
  2324. wsprintf(pszParam, txtStringParam, txtParamType, csz.psz);
  2325. ASSERT(strlen(pszParam) < MAX_PARAM);
  2326. PadOutput(pout, curLevel + 1);
  2327. pout->outstring_eol(pszParam);
  2328. }
  2329. bitflag = bitflag << 1;
  2330. if (!bitflag) { // wrap around, so switch offsets
  2331. offset++;
  2332. bitflag = 1;
  2333. }
  2334. }
  2335. }
  2336. if (pUrl->urlPrimary) {
  2337. if (pSiteMapEntry->fSeeAlso) {
  2338. wsprintf(pszParam, txtStringParam, txtSeeAlso, GetUrlString(pUrl->urlPrimary));
  2339. ASSERT(strlen(pszParam) < MAX_PARAM);
  2340. PadOutput(pout, curLevel + 1);
  2341. pout->outstring_eol(pszParam);
  2342. break; // only one URL if See Also entry
  2343. }
  2344. wsprintf(pszParam, txtStringParam, txtParamLocal,
  2345. GetUrlString(pUrl->urlPrimary));
  2346. ASSERT(strlen(pszParam) < MAX_PARAM);
  2347. PadOutput(pout, curLevel + 1);
  2348. pout->outstring_eol(pszParam);
  2349. }
  2350. if (pUrl->urlSecondary) {
  2351. wsprintf(pszParam, txtStringParam, txtParamUrl,
  2352. GetUrlString(pUrl->urlSecondary));
  2353. ASSERT(strlen(pszParam) < MAX_PARAM);
  2354. PadOutput(pout, curLevel + 1);
  2355. pout->outstring_eol(pszParam);
  2356. }
  2357. pUrl = NextUrlEntry(pUrl);
  2358. }
  2359. if (pSiteMapEntry->iFrameName) {
  2360. wsprintf(pszParam, txtStringParam, txtParamFrame,
  2361. GetName(pSiteMapEntry->iFrameName));
  2362. ASSERT(strlen(pszParam) < MAX_PARAM);
  2363. PadOutput(pout, curLevel + 1);
  2364. pout->outstring_eol(pszParam);
  2365. }
  2366. if (pSiteMapEntry->iWindowName) {
  2367. wsprintf(pszParam, txtStringParam, txtParamWindow,
  2368. GetName(pSiteMapEntry->iWindowName));
  2369. ASSERT(strlen(pszParam) < MAX_PARAM);
  2370. PadOutput(pout, curLevel + 1);
  2371. pout->outstring_eol(pszParam);
  2372. }
  2373. if (pSiteMapEntry->pszComment) {
  2374. wsprintf(pszParam, txtStringParam, txtParamComment, pSiteMapEntry->pszComment);
  2375. ASSERT(strlen(pszParam) < MAX_PARAM);
  2376. PadOutput(pout, curLevel + 1);
  2377. pout->outstring_eol(pszParam);
  2378. }
  2379. if (pSiteMapEntry->fNew) {
  2380. wsprintf(pszParam, txtDecimalParam, txtParamNew, 1);
  2381. ASSERT(strlen(pszParam) < MAX_PARAM);
  2382. PadOutput(pout, curLevel + 1);
  2383. pout->outstring_eol(pszParam);
  2384. }
  2385. if (pSiteMapEntry->iImage) {
  2386. wsprintf(pszParam, txtDecimalParam, txtParamImageNumber,
  2387. pSiteMapEntry->iImage);
  2388. ASSERT(strlen(pszParam) < MAX_PARAM);
  2389. PadOutput(pout, curLevel + 1);
  2390. pout->outstring_eol(pszParam);
  2391. }
  2392. if (pSiteMapEntry->fNoDisplay) {
  2393. wsprintf(pszParam, txtStringParam, txtParamDisplay, txtNo);
  2394. ASSERT(strlen(pszParam) < MAX_PARAM);
  2395. PadOutput(pout, curLevel + 1);
  2396. pout->outstring_eol(pszParam);
  2397. }
  2398. }
  2399. #endif // HHCTRL