windows-nt/Source/XPSP1/NT/enduser/stuff/hhctrl/sitemap.cpp

2718 lines
92 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
#include "header.h"
#include "sitemap.h"
#include <shlobj.h>
#include <wininet.h>
#ifndef HHCTRL
#include "hha_strtable.h"
#else
#include "hha_strtable.h"
#include "hhctrl.h"
#include "strtable.h"
#endif
#include "web.h"
#ifdef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__;
#endif
#ifndef _DEBUG
#pragma optimize("at", on)
#endif
#include "sitechar.cpp"
#ifndef HHCTRL
static const char txtSaveTypeHidden[] = "SaveHidden";
static const char txtSaveTypeExclusive[] = "SaveExclusive";
static const char txtSaveType[] = "SaveType";
static const char txtSaveTypeDesc[] = "SaveTypeDesc";
#endif
class CParseSitemap : public SITEMAP_ENTRY
{
public:
CParseSitemap(CSiteMap* pSiteMap) {
m_pSiteMap = pSiteMap;
Clear();
m_fGlobal = FALSE;
m_cMaxTitles = 50;
m_ppszTitles = (PCSTR*) lcCalloc(m_cMaxTitles * sizeof(PCSTR));
m_pSiteUrl = new CSiteEntryUrl(pSiteMap->InfoTypeSize());
}
~CParseSitemap() { lcFree(m_ppszTitles); delete m_pSiteUrl; }
BOOL IsGlobal(void) { return m_fGlobal; }
void SetGlobal(BOOL fSetting) { m_fGlobal = fSetting; }
void AddTitle(PCSTR psz);
PCSTR* m_ppszTitles;
int m_cMaxTitles;
CStr m_cszValue;
BOOL m_fGlobal;
CSiteMap* m_pSiteMap;
CSiteEntryUrl* m_pSiteUrl;
void SaveUrlEntry() { m_pSiteUrl->SaveUrlEntry(m_pSiteMap, this); }
operator CStr*() { return &m_cszValue; }
operator PSTR() { return m_cszValue.psz; }
operator PCSTR() const { return m_cszValue.psz; }
};
#ifndef _DEBUG
// REVIEW: check this from time to time to see if it is necessary...
#pragma optimize("a", on)
#endif
// Function prototypes
PSTR FindDblQuote(CAInput* painput, CStr* pcsz, PSTR psz);
PSTR GetValue(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue);
PSTR FindCharacter(CAInput* pinput, CStr* pcsz, PSTR psz, char ch);
PSTR GetType(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue);
#ifdef HHCTRL
#ifdef HHA
BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, CHtmlHelpControl* phhctrl )
#else
BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, CHtmlHelpControl* phhctrl, UINT CodePage )
#endif
#else
BOOL CSiteMap::ReadFromFile(PCSTR pszFileName, BOOL fIndex, PCSTR pszBaseFile)
#endif
{
#ifdef HHCTRL
#ifndef HHA
m_CodePage = CodePage;
#endif
#endif
CAInput ainput;
int curInput = 0;
if (!ainput.Add(pszFileName)) {
#ifdef HHCTRL
if (phhctrl)
phhctrl->AuthorMsg(IDS_CANT_OPEN, pszFileName);
SITEMAP_ENTRY* pSiteMapEntry = AddEntry();
ASSERT_COMMENT(!pSiteMapEntry->iFrameName &&
!pSiteMapEntry->iWindowName,
"Add() function not returning zero'd memory");
pSiteMapEntry->level = 1;
CStr cszLine(IDS_CANT_FIND_FILE, pszFileName);
pSiteMapEntry->pszText = StrDup(cszLine);
pSiteMapEntry->SetTopic(TRUE);
#else
MsgBox(IDS_CANT_OPEN, pszFileName);
#endif
return FALSE;
}
SetSiteMapFile(pszFileName);
m_fIndex = fIndex;
// We don't want the first file to have a basename
#if (defined(HHCTRL) || defined(HHA))
m_pszBase = ainput.GetBaseName();
*m_pszBase = '\0';
#endif
// used for indexes
CParseSitemap cparse(this);
CTable *ptblSubSets=NULL; // To hold any subset declarations.
int curLevel = 0;
CStr cszLine;
BOOL fSiteMap = FALSE;
BOOL fMergePending = FALSE; // TRUE if we need to include another file
CStr cszMergeFile; // file to merge into current
#ifdef _DEBUG
int cLoops = 0; // so we know when to set a breakpoint
#endif
for (;;) {
#ifdef _DEBUG
cLoops++;
// lcHeapCheck();
#endif
if (fMergePending) {
#if (defined(HHCTRL) || defined(HHA))
char szUrl[INTERNET_MAX_URL_LENGTH];
#endif
#ifdef HHA
// When compiling, find the full path to the file
strcpy(szUrl, cszMergeFile);
ConvertToFull(pszBaseFile, szUrl);
ainput.Add(szUrl);
{
#else
if (!ainput.Add(cszMergeFile)) {
#endif
#ifdef HHCTRL
if (ConvertToCacheFile(cszMergeFile, szUrl))
ainput.Add(szUrl);
else if (phhctrl && phhctrl->m_pWebBrowserApp) {
CStr cszUrl;
phhctrl->m_pWebBrowserApp->GetLocationURL(&cszUrl);
PSTR psz = (PSTR) FindFilePortion(cszUrl);
if (psz) {
*psz = '\0';
cszUrl += cszMergeFile;
if (ConvertToCacheFile(cszUrl, szUrl))
ainput.Add(szUrl);
}
}
#endif
}
fMergePending = FALSE;
#if (defined(HHCTRL) || defined(HHA))
m_pszBase = ainput.GetBaseName();
/*
* If we are in the same location as our parent, ignore the
* base name
*/
if (!IsEmptyString(m_pszBase)) {
CStr cszBase(m_pszBase);
CStr cszSitemap(GetSiteMapFile());
PSTR psz = (PSTR) FindFilePortion(cszSitemap);
ASSERT(psz);
if (psz)
*psz = '\0';
ConvertBackSlashToForwardSlash(cszBase);
ConvertBackSlashToForwardSlash(cszSitemap);
if (lstrcmpi(cszBase, cszSitemap) == 0)
m_pszBase = NULL;
}
#endif
}
if (curInput < 0)
break;
if (!ainput.getline(&cszLine)) {
if (!ainput.Remove()) {
if (m_fIndex)
return TRUE;
break; // we're all done.
}
/*
* Set parse to global so that if this was part of a merged
* file we won't rewrite the last item when an </OBJECT> is
* encountered.
*/
// 16-Dec-1997 [ralphw] Don't call SetGlobal -- it deletes the
// next folder
// cparse.SetGlobal(TRUE);
cparse.Clear();
#if (defined(HHCTRL) || defined(HHA))
m_pszBase = ainput.GetBaseName();
#endif
continue;
}
PSTR psz = FirstNonSpace(cszLine);
Loop:
if ( !psz || !*psz)
continue; // ignore blank lines
if (*psz == '<') {
int cb;
if ((cb = CompareSz(psz, txtParam))) {
psz = FindDblQuote(&ainput, &cszLine, psz + cb);
if (!psz)
goto FlushAndExit;
PSTR pszParamType = psz;
psz = GetValue(&ainput, &cszLine, psz, cparse);
if (!psz)
goto FlushAndExit;
if (ParseSiteMapParam(&cparse, pszParamType, ptblSubSets)) {
goto Loop;
}
else if (isSameString(pszParamType, txtParamHHI)) {
m_pszHHIFile = StrDup(cparse.m_cszValue.psz);
goto Loop;
}
else if (isSameString(pszParamType, txtParamMerge)) {
#if (!defined(HHCTRL) && !defined(HHA))
cszMergeFile = GetStringResource(IDS_INCLUDED_FILE);
cszMergeFile += cparse.m_cszValue.psz;
cparse.pszText = StrDup(cszMergeFile);
cparse.fInclude = TRUE;
cparse.iImage = IMAGE_CLOSED_FOLDER;
AddEntry(&cparse);
cparse.SetGlobal(TRUE); // so end object doesn't rewrite
#elif defined(HHA)
if (stristr(cparse.m_cszValue.psz, ".CHM")) {
cparse.pszText = StrDup(cparse.m_cszValue.psz);
cparse.fInclude = TRUE;
cparse.iImage = IMAGE_CLOSED_FOLDER;
AddEntry(&cparse);
}
else {
cszMergeFile = cparse.m_cszValue.psz;
fMergePending = TRUE;
}
#else
cszMergeFile = cparse.m_cszValue.psz;
fMergePending = TRUE;
#endif
goto Loop;
}
else if (!m_fIndex && isSameString(pszParamType, txtFavorites)) {
#if (defined(HHCTRL) || defined(HHA))
CreateFavorites();
goto Loop;
#endif
// REVIEW: how do we deal with this in HHW?
}
}
else if ((cb = CompareSz(psz, txtBeginList))) {
curLevel++;
psz = FirstNonSpace(psz + cb);
goto Loop;
}
else if ((cb = CompareSz(psz, txtEndList))) {
curLevel--;
psz = FirstNonSpace(psz + cb);
goto Loop;
}
else if ((cb = CompareSz(psz, txtBeginListItem))) {
psz = FindCharacter(&ainput, &cszLine, psz + cb, '>');
if (!psz)
goto FlushAndExit;
if ((cb = CompareSz(psz, txtBeginObject))) {
psz = GetType(&ainput, &cszLine, psz + cb, cparse);
if (!psz) {
if (!ainput.getline(&cszLine))
goto FlushAndExit;
psz = GetType(&ainput, &cszLine, cszLine, cparse);
if (!psz)
goto FlushAndExit;
}
//////////////////// New Node /////////////////////////////////////////////
if (isSameString(cparse, txtSiteMapObject)) {
// Create a new entry
cparse.Clear();
cparse.level = (BYTE)curLevel;
goto Loop;
}
else if (isSameString(cparse, txtSitemapProperties)) {
cparse.SetGlobal(TRUE);
}
}
}
else if ((cb = CompareSz(psz, txtEndObject))) {
//////////////////// End Node /////////////////////////////////////////////
if (!cparse.IsGlobal()) {
if (m_fIndex) {
if (!cparse.m_pSiteUrl->m_fUrlSpecified) {
// BUGBUG: nag the author -- entry without a URL
psz += cb;
goto Loop;
}
cparse.SaveUrlEntry();
if (cparse.pszText && cparse.cUrls) {
AddEntry(&cparse);
}
else {
#if (defined(HHCTRL) || defined(HHA))
cparse.pszText = StrDup(GetStringResource(IDSHHA_INVALID_KEYWORD));
AddEntry(&cparse);
#endif
// we ignore the entry entirely in hhctrl.ocx
}
cparse.Clear();
cparse.level = (BYTE)curLevel;
}
else {
if (cparse.m_pSiteUrl->m_fUrlSpecified)
cparse.SaveUrlEntry();
AddEntry(&cparse);
}
}
else {
cparse.SetGlobal(FALSE);
//#ifdef HHCTRL // having this conditional for HHCTRL causes IT declarations to not be present in HHW until the info type tab is visited
// bug 4762
if (IsNonEmpty(m_pszHHIFile)) {
cszMergeFile = cparse.m_cszValue.psz;
fMergePending = TRUE;
m_pszHHIFile = NULL; // so we don't merge twice
}
//#endif
}
psz += cb;
goto Loop;
}
else if (isSameString(psz, txtSitemap) ||
isSameString(psz, txtSitemap1) ||
isSameString(psz, txtSitemap2)) {
fSiteMap = TRUE;
psz = FindCharacter(&ainput, &cszLine, psz, '>');
if (!psz)
goto FlushAndExit;
else if (!*psz)
continue;
}
// Global properties?
else if ((cb = CompareSz(psz, txtBeginObject))) {
psz = GetType(&ainput, &cszLine, psz + cb, cparse);
if (!psz) {
if (!ainput.getline(&cszLine))
goto FlushAndExit;
psz = GetType(&ainput, &cszLine, psz + cb, cparse);
if (!psz)
goto FlushAndExit;
}
if (isSameString(cparse, txtSitemapProperties)) {
cparse.SetGlobal(TRUE);
goto Loop;
}
else {
// ******** Check for Merge (include another file) *******
/*
* This is an object that appears outside of a list
* item. If it's a merge tag, then extract the merge
* information. Otherwise, ignore it.
*/
psz = strstr(psz, txtEndTag);
if (psz)
psz = FirstNonSpace(psz + 1);
for (;;) {
if (!psz) {
if (!ainput.getline(&cszLine))
goto FlushAndExit;
psz = FirstNonSpace(cszLine.psz);
}
if ( !psz || !*psz) {
psz = NULL; // so we'll read the next line
continue; // ignore blank lines
}
if (*psz == '<') {
if ((cb = CompareSz(psz, txtEndObject))) {
psz += cb;
goto Loop;
}
else if ((cb = CompareSz(psz, txtParam))) {
psz = FindDblQuote(&ainput, &cszLine,
psz + cb);
if (!psz)
goto FlushAndExit;
PSTR pszParamType = psz;
psz = GetValue(&ainput, &cszLine,
psz, cparse);
if (!psz)
goto FlushAndExit;
if (isSameString(pszParamType, txtParamMerge)) {
#if (!defined(HHCTRL) && !defined(HHA))
cszMergeFile = GetStringResource(IDS_INCLUDED_FILE);
cszMergeFile += cparse.m_cszValue.psz;
cparse.pszText = StrDup(cszMergeFile);
cparse.fInclude = TRUE;
cparse.iImage = IMAGE_CLOSED_FOLDER;
cparse.level = curLevel;
AddEntry(&cparse);
#elif defined(HHA)
if (stristr(cparse.m_cszValue.psz, ".CHM")) {
cparse.pszText = StrDup(cparse.m_cszValue.psz);
cparse.fInclude = TRUE;
cparse.iImage = IMAGE_CLOSED_FOLDER;
cparse.level = curLevel;
AddEntry(&cparse);
}
else {
cszMergeFile = cparse.m_cszValue.psz;
fMergePending = TRUE;
}
#else
cszMergeFile = cparse.m_cszValue.psz;
fMergePending = TRUE;
#endif
}
}
}
}
}
}
else if (isSameString(psz, txtBeginHref)) {
// Skip over all of HREF
for (;;) {
psz = strstr(psz, txtEndTag);
if (psz) {
if (strncmp(psz, txtEndHref, (int)strlen(txtEndHref)) == 0)
break;
psz = stristr(psz, txtEndHref);
}
if (!psz) {
if (!ainput.getline(&cszLine))
goto FlushAndExit;
psz = cszLine.psz;
}
else
break;
}
psz = FindCharacter(&ainput, &cszLine, psz, '>');
goto Loop;
}
else {
// Ignore whatever it is
psz = FindCharacter(&ainput, &cszLine, psz, '>');
goto Loop;
}
}
if (fSiteMap) {
// In sitemaps, we only care about what appears inside angle
// brackets.
for(;;) {
psz = StrChr(psz, '<');
if (!psz) {
if (!ainput.getline(&cszLine)) {
psz = ""; // so Loop processing works
break;
}
psz = cszLine.psz;
}
else
break;
}
goto Loop;
}
}
# ifdef NOTYET
// populate subsets
if ( ptblSubSets )
{
if ( !m_pSubSets )
m_pSubSets = new CSubSets(m_itTables.m_itSize, ptblSubSets, this, TRUE);
delete ptblSubSets;
}
#endif
if (!fIndex) {
// Now determine what is a book -- anything without a child is a topic
curLevel = 0;
int pos;
for (pos = 1; pos < endpos - 1; pos++) {
SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
if (pSiteMapEntry->level > curLevel + 1)
pSiteMapEntry->level = curLevel + 1;
curLevel = pSiteMapEntry->level;
if (pSiteMapEntry->cUrls == 0)
continue; // if there is no URL, then it's a book
#ifdef _DEBUG
SITEMAP_ENTRY* pSiteMapEntryNext = GetSiteMapEntry(pos + 1);
#endif
if (pSiteMapEntry->level >= GetSiteMapEntry(pos + 1)->level)
pSiteMapEntry->SetTopic(TRUE);
}
// You can never end with a book
if (endpos > 1)
GetSiteMapEntry(endpos - 1)->SetTopic(TRUE);
}
return TRUE;
FlushAndExit:
return FALSE;
}
BOOL CSiteMap::ParseSiteMapParam(CParseSitemap* pcparse, PCSTR pszParamType, CTable *ptblSubSets)
{
int iLastType = 0;
// Deal with any escape sequences starting with '&'
ReplaceEscapes(*pcparse, (PSTR) *pcparse, ESCAPE_ENTITY);
if (pcparse->IsGlobal()) {
int cb;
// WARNING! Check for txtParamTypeDesc BEFORE the check for txtParamType
// (because it's a substring search).
#ifdef NOTYET
// parse Subset Declarations
if ( isSameString( pszParamType, txtParamSSInclusive ) ||
isSameString( pszParamType, txtParamSSExclusive))
{
if( !ptblSubSets )
ptblSubsets = new CTable(16 * 1024);
ptblSubSets->AddString(*pcparse);
}else
#endif
// parse Information Types Declarations
if (isSameString(pszParamType, txtParamTypeExclusive)
#ifndef HHCTRL
|| isSameString(pszParamType, txtSaveTypeExclusive)
#endif
) {
if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
iLastType = GetITIndex( *pcparse );
AddToCategory( iLastType );
return TRUE;
}else
{
iLastType = AddTypeName(*pcparse);
AddExclusiveIT( iLastType );
AddToCategory( iLastType );
return TRUE;
}
}
else if (isSameString(pszParamType, txtParamTypeHidden)
#ifndef HHCTRL
|| isSameString(pszParamType, txtSaveTypeHidden)
#endif
) {
if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
iLastType = GetITIndex( *pcparse );
AddToCategory( iLastType );
return TRUE;
}else
{
iLastType = AddTypeName(*pcparse);
AddHiddenIT( iLastType );
AddToCategory( iLastType );
return TRUE;
}
}
else if ((cb = CompareSz(pszParamType, txtParamTypeDesc))
#ifndef HHCTRL
|| isSameString(pszParamType, txtSaveTypeDesc)
#endif
) {
if (!m_itTables.m_ptblInfoTypeDescriptions)
return TRUE; // BUGBUG: nag author about description before type
// add a blank description to infotype description, description not provided for last infotype
while (m_itTables.m_ptblInfoTypes->CountStrings() > m_itTables.m_ptblInfoTypeDescriptions->CountStrings()+1)
m_itTables.m_ptblInfoTypeDescriptions->AddString("");
if ( m_itTables.m_ptblInfoTypes->CountStrings() != m_itTables.m_ptblInfoTypeDescriptions->CountStrings() )
m_itTables.m_ptblInfoTypeDescriptions->AddString(*pcparse);
return TRUE;
} // this matches anything that begins with "type"
else if (isSameString(pszParamType, txtParamType)
#ifndef HHCTRL
|| isSameString(pszParamType, txtSaveType)
#endif
) {
if (m_itTables.m_ptblInfoTypes && m_itTables.m_ptblInfoTypes->IsStringInTable(*pcparse)) {
iLastType = GetITIndex( *pcparse );
AddToCategory( iLastType );
return TRUE;
}
else
{
iLastType = AddTypeName(*pcparse);
AddToCategory( iLastType );
return TRUE;
}
}
// WARNING! Check for txtParamCategoryDesc BEFORE the check for txtParamCategory
// (because it's a substring search).
else if ((cb = CompareSz(pszParamType, txtParamCategoryDesc))) {
if (!m_itTables.m_ptblCatDescription)
return TRUE; // BUGBUG: nag author about description before type
// add a blank description to category description, description not provided for last Category
while (m_itTables.m_ptblCategories->CountStrings() > m_itTables.m_ptblCatDescription->CountStrings()+1)
m_itTables.m_ptblCatDescription->AddString("");
m_itTables.m_ptblCatDescription->AddString(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtParamCategory)) {
if (m_itTables.m_ptblCategories && m_itTables.m_ptblCategories->IsStringInTable(*pcparse)) {
// BUGBUG: we should nag the help author
return TRUE;
}
if (!m_itTables.m_ptblCategories)
{
m_itTables.m_ptblCategories = new CTable(16 * 1024);
m_itTables.m_ptblCatDescription = new CTable(16 * 1024);
}
m_itTables.m_ptblCategories->AddString(*pcparse);
return TRUE;
}
else
if (isSameString(pszParamType, txtParamFrame)) {
if (!IsFrameDefined()) // can't override in a sitemap file
SetFrameName(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtParamWindow)) {
if (!IsWindowDefined())
SetWindowName(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtImageType)) {
if (isSameString(*pcparse, txtFolderType))
m_fFolderImages = TRUE;
}
else if (isSameString(pszParamType, txtImageList)) {
m_pszImageList = StrDup(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtQueryType)) {
m_fPromotForInfoTypes = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtBackGround)) {
m_clrBackground = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtBackGroundImage)) {
m_pszBackBitmap = StrDup(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtForeGround)) {
m_clrForeground = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtFont)) {
m_pszFont = StrDup(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtNumberImages)) {
m_cImages = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtColorMask)) {
m_clrMask = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtImageWidth)) {
m_cImageWidth = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtWindowStyles) &&
m_tvStyles == (DWORD) -1) {
m_tvStyles = Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtExWindowStyles)) {
m_exStyles = Atoi(*pcparse);
return TRUE;
}
#if (!defined(HHCTRL) && !defined(HHA))
else if (isSameString(pszParamType, txtAutoGenerated)) {
m_fAutoGenerated = YesNo(*pcparse);
return TRUE;
}
#endif
return FALSE;
}
if (m_fIndex) {
if (isSameString(pszParamType, txtParamSectionTitle) ||
isSameString(pszParamType, txtParamName)) {
if (!pcparse->pszText)
pcparse->pszText = StrDup(*pcparse);
else {
if (pcparse->m_pSiteUrl->m_pUrl->pszTitle) {
if (pcparse->m_pSiteUrl->m_fUrlSpecified)
pcparse->SaveUrlEntry();
else
FreeMemory(pcparse->pszText, -1);
}
pcparse->AddTitle(*pcparse);
}
return TRUE;
}
else if (isSameString(pszParamType, txtParamKeyword)) {
// BUGBUG: check for duplicates first!
pcparse->pszText = StrDup(*pcparse);
return TRUE;
}
}
else { // not an Index
if (isSameString(pszParamType, txtParamName)) {
if (pcparse->m_pSiteUrl->m_fUrlSpecified)
pcparse->SaveUrlEntry();
// BUGBUG: deal with duplicate names being specified
pcparse->pszText = StrDup(*pcparse);
return TRUE;
}
}
if (isSameString(pszParamType, txtParamLocal)) {
if (pcparse->m_pSiteUrl->m_fUrlSpecified) {
// save previous URL entry
pcparse->SaveUrlEntry();
}
URL url = AddUrl(*pcparse);
if (pcparse->m_pSiteUrl->m_pUrl->urlSecondary == url)
return TRUE; // ignore duplicate URLs for primary and secondary
pcparse->m_pSiteUrl->m_pUrl->urlPrimary = url;
pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtParamUrl) || isSameString(pszParamType, txtParamSecondary)) {
if (pcparse->m_pSiteUrl->m_fUrlSpecified && pcparse->m_pSiteUrl->m_pUrl->urlSecondary) {
// save previous URL entry
pcparse->SaveUrlEntry();
}
URL url = AddUrl(*pcparse);
if (pcparse->m_pSiteUrl->m_pUrl->urlPrimary == url)
return TRUE; // ignore duplicate URLs for primary and secondary
pcparse->m_pSiteUrl->m_pUrl->urlSecondary = url;
pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtParamType) ||
isSameString(pszParamType, txtParamTypeExclusive) ||
isSameString(pszParamType, txtParamTypeHidden)) {
if (pcparse->m_pSiteUrl->m_fUrlSpecified)
// save previous URL entry
pcparse->SaveUrlEntry();
if (m_itTables.m_ptblInfoTypes)
{
INFOTYPE iType = GetInfoType(*pcparse);
if (iType == (INFOTYPE) -1)
iType = 0;
else
AddIT(iType, pcparse->m_pSiteUrl->m_pUrl->ainfoTypes );
}
return TRUE;
}
else if (isSameString(pszParamType, txtParamNew)) {
pcparse->fNew = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtParamImageNumber)) {
pcparse->iImage = (BYTE) Atoi(*pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtParamDisplay)) {
if (isSameString(*pcparse, txtNo))
pcparse->fNoDisplay = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtParamFrame)) {
SetEntryFrame(pcparse, *pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtParamWindow)) {
SetEntryWindow(pcparse, *pcparse);
return TRUE;
}
else if (isSameString(pszParamType, txtSeeAlso)) {
pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
pcparse->fSeeAlso = TRUE;
pcparse->m_pSiteUrl->m_fUrlSpecified = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtSendEvent)) {
pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
pcparse->SaveUrlEntry();
pcparse->fSendEvent = TRUE;
return TRUE;
}
else if (isSameString(pszParamType, txtSendMessage)) {
pcparse->m_pSiteUrl->m_pUrl->urlPrimary = AddUrl(*pcparse);
pcparse->SaveUrlEntry();
pcparse->fSendMessage = TRUE;
return TRUE;
}
#if (!defined(HHCTRL) && !defined(HHA))
else if (isSameString(pszParamType, txtParamComment)) {
pcparse->pszComment = StrDup(*pcparse);
return TRUE;
}
#endif
return FALSE;
}
URL CSiteMap::AddUrl(PCSTR pszUrl)
{
if (IsEmptyString(pszUrl))
return NULL;
#if (defined(HHCTRL) || defined(HHA))
if (!IsEmptyString(m_pszBase) && !StrChr(pszUrl, ':')) {
char szPath[INTERNET_MAX_URL_LENGTH];
strcpy(szPath, m_pszBase);
strcat(szPath, pszUrl);
return (URL) StrDup(szPath);
}
#endif
PCSTR psz = FirstNonSpace(pszUrl);
return (URL) StrDup(psz?psz:"");
}
void CSiteMap::AddToCategory( int iLastType )
{
// Add the info type to the last category defined; if there is a Category
if ( m_itTables.m_ptblCategories )
{
int posCat = m_itTables.m_ptblCategories->CountStrings();
if (posCat <= 0 )
return;
AddITtoCategory( posCat-1, iLastType);
}
}
int CompareSz(PCSTR psz, PCSTR pszSub)
{
int cb;
if (IsSamePrefix(psz, pszSub, cb = (int)strlen(pszSub)))
return cb;
else
return 0;
}
void CParseSitemap::AddTitle(PCSTR psz)
{
if (m_pSiteUrl->m_pUrl->pszTitle)
m_pSiteMap->FreeMemory(m_pSiteUrl->m_pUrl->pszTitle, -1);
m_pSiteUrl->m_pUrl->pszTitle = m_pSiteMap->StrDup(psz);
}
void CSiteEntryUrl::SaveUrlEntry(CSiteMap* pSiteMap, SITEMAP_ENTRY* pSiteMapEntry)
{
SITE_ENTRY_URL* pNewUrls = (SITE_ENTRY_URL*) pSiteMap->TableMalloc(
sizeof(SITE_ENTRY_URL) * (pSiteMapEntry->cUrls + 1));
if (pSiteMapEntry->cUrls) {
ASSERT(pSiteMapEntry->pUrls);
memcpy(pNewUrls, pSiteMapEntry->pUrls,
sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls);
pSiteMap->FreeMemory((PCSTR) pSiteMapEntry->pUrls,
sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls);
}
memcpy((PBYTE) pNewUrls + sizeof(SITE_ENTRY_URL) * pSiteMapEntry->cUrls,
m_pUrl, sizeof(SITE_ENTRY_URL));
pSiteMapEntry->cUrls++;
pSiteMapEntry->pUrls = pNewUrls;
if (!pSiteMap->AreAnyInfoTypesDefined(pSiteMapEntry))
pSiteMapEntry->fShowToEveryOne = TRUE;
ZeroMemory(m_pUrl, sizeof(SITE_ENTRY_URL));
m_pUrl->ainfoTypes = (INFOTYPE*)lcCalloc( pSiteMap->InfoTypeSize() );
m_fUrlSpecified = FALSE;
}
/***************************************************************************
FUNCTION: HashFromSz
PURPOSE: Convert a string into a hash representation
PARAMETERS:
pszKey
RETURNS: Hash number
COMMENTS:
Shamelessly stolen from the WinHelp code, since after 6 years
of use by up to 1 million help authors, there were no reports
of collisions.
MODIFICATION DATES:
10-Aug-1996 [ralphw] Stolen from WinHelp, removed special-case
hash characters
***************************************************************************/
// This constant defines the alphabet size for our hash function.
static const HASH MAX_CHARS = 43;
HASH WINAPI HashFromSz(PCSTR pszKey)
{
HASH hash = 0;
int cch = (int)strlen(pszKey);
for (int ich = 0; ich < cch; ++ich) {
// treat '/' and '\' as the same
if (pszKey[ich] == '/')
hash = (hash * MAX_CHARS) + ('\\' - '0');
else if (pszKey[ich] <= 'Z')
hash = (hash * MAX_CHARS) + (pszKey[ich] - '0');
else
hash = (hash * MAX_CHARS) + (pszKey[ich] - '0' - ('a' - 'A'));
}
/*
* Since the value 0 is reserved as a nil value, if any context
* string actually hashes to this value, we just move it.
*/
return (hash == 0 ? 0 + 1 : hash);
}
int CSiteMap::AddName(PCSTR psz)
{
if (IsEmptyString(psz))
return 0;
psz = FirstNonSpace(psz);
HASH hash = HashFromSz(psz);
if (!m_ptblStrings)
m_ptblStrings = new CTable(16 * 1024);
int pos = m_ptblStrings->IsHashInTable(hash);
if (pos > 0)
return pos;
else {
m_ptblStrings->AddString(hash, psz);
return m_ptblStrings->CountStrings();
}
}
PSTR FindCharacter(CAInput* pinput, CStr* pcsz, PSTR psz, char ch)
{
for(;;) {
psz = StrChr(psz, ch);
if (!psz) {
if (!pinput)
return NULL;
if (!pinput->getline(pcsz))
return NULL;
psz = pcsz->psz;
}
else
break;
}
return FirstNonSpace(psz + 1);
}
PSTR FindDblQuote(CAInput* pinput, CStr* pcsz, PSTR psz)
{
for(;;) {
psz = StrChr(psz, '\042');
if (!psz) {
if (!pinput->getline(pcsz))
return NULL;
psz = pcsz->psz;
}
else
break;
}
return FirstNonSpace(psz + 1);
}
/***************************************************************************
FUNCTION: GetValue
PURPOSE: Copy the value of a param type into pszValue, and return
a pointer to the first character after the closing angle
bracket
PARAMETERS:
pinput pointer to current CInput file
pcsz CStr to read new line into
psz position in current line
pcszValue CStr to receive value
pszPrefix prefix to look for
RETURNS:
COMMENTS:
MODIFICATION DATES:
24-Aug-1996 [ralphw]
***************************************************************************/
PSTR GetValue(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue)
{
// Skip past ending quote of parameter type
psz = FindDblQuote(pinput, pcsz, psz);
if (!psz)
return NULL;
if (!isSameString(psz, txtValue)) {
psz = stristr(psz, txtValue);
if (!psz) {
if (!pinput->getline(pcsz))
return NULL;
psz = stristr(pcsz->psz, txtValue);
if (!psz)
return NULL;
}
}
// Now find opening quote of the value
psz = FindDblQuote(pinput, pcsz, psz);
if (!psz)
return NULL;
if (!pcszValue->psz)
pcszValue->psz = (PSTR) lcMalloc(256);
PSTR pszDst = pcszValue->psz;
PSTR pszEnd = pszDst + lcSize(pcszValue->psz);
while (*psz != '\042') {
if (!*psz) {
if (!pinput->getline(pcsz))
return NULL;
psz = pcsz->psz;
continue;
}
*pszDst++ = *psz++;
if (pszDst >= pszEnd) {
/*
* Our destination buffer is too small, so increase it by
* 128 bytes.
*/
int offset = (int)(pszDst - pcszValue->psz);
pcszValue->ReSize((int)(pszEnd - pcszValue->psz) + 128);
pszDst = pcszValue->psz + offset;
pszEnd = pcszValue->psz + pcszValue->SizeAlloc();
lcHeapCheck();
}
}
*pszDst = '\0';
return FindCharacter(pinput, pcsz, psz, '>');
}
PSTR GetType(CAInput* pinput, CStr* pcsz, PSTR psz, CStr* pcszValue)
{
psz = FirstNonSpace(psz);
ASSERT(strlen(txtType) == sizeof(txtType) - 1); // make sure the compiler doesn't mess this up
if (IsSamePrefix(psz, txtType, sizeof(txtType) - 1)) {
psz = stristr(psz, txtType);
if (!psz) {
if (!pinput->getline(pcsz))
return NULL;
psz = stristr(pcsz->psz, txtType);
if (!psz)
return NULL;
}
}
// Now find opening quote of the value
psz = FindDblQuote(pinput, pcsz, psz);
if (!psz)
return NULL;
if (!pcszValue->psz)
pcszValue->psz = (PSTR) lcMalloc(256);
PSTR pszDst = *pcszValue;
PSTR pszEnd = pszDst + lcSize(pszDst);
while (*psz != '\042') {
if (!*psz) {
if (!pinput->getline(pcsz))
return NULL;
psz = pcsz->psz;
continue;
}
*pszDst++ = *psz++;
if (pszDst >= pszEnd) {
/*
* Our input buffer is too small, so increase it by
* 128 bytes.
*/
int offset = (int)(pszDst - pcsz->psz);
pcsz->ReSize((int)(pszEnd - pcsz->psz) + 128);
pszDst = pcsz->psz + offset;
pszEnd = pcsz->psz + pcsz->SizeAlloc();
lcHeapCheck();
}
}
*pszDst = '\0';
return FindCharacter(pinput, pcsz, psz, '>');
}
// This is called from the code that parses the sitemap in the information type section.
// Information types found outside of the declaration section are NOT added to the
// information types declared. So we don't have to worry about increasing the size of
// SITE_ENTRY_URLs after they have been defined. At least in this routine. We will have to
// deal with increasing the size of SITE_ENTRY_URLs when adding information types.
int CSiteMap::AddTypeName(PCSTR pszTypeName)
{
ASSERT(!IsEmptyString(pszTypeName));
if (!m_itTables.m_ptblInfoTypes) {
m_itTables.m_ptblInfoTypes = new CTable(16 * 1024);
ASSERT(!m_itTables.m_ptblInfoTypeDescriptions);
m_itTables.m_ptblInfoTypeDescriptions = new CTable(64 * 1024);
}
ASSERT(m_itTables.m_ptblInfoTypes);
/*
* If we have an Information type, but the table counts don't match,
* then we didn't get a description for the last type, so we add a blank
* description to keep the tables in sync.
*/
while (m_itTables.m_ptblInfoTypes->CountStrings() > m_itTables.m_ptblInfoTypeDescriptions->CountStrings())
m_itTables.m_ptblInfoTypeDescriptions->AddString("");
/*
A category and type is specified as:
category::type name
*/
CStr cszCategory;
CStr cszType;
int category = 0;
PCSTR pszCat = strstr(pszTypeName, "::");
if (pszCat) { // separate category name from type name
cszType = pszCat + 2; // make a local copy
cszCategory = pszTypeName;
cszCategory.psz[pszCat - pszTypeName] = '\0';
if (!m_itTables.m_ptblCategories) {
m_itTables.m_ptblCategories = new CTable(16 * 1024);
}
category = m_itTables.m_ptblCategories->IsStringInTable(cszCategory);
if (!category)
category = m_itTables.m_ptblCategories->AddString(cszCategory);
pszTypeName = cszType.psz;
}
int pos = m_itTables.m_ptblInfoTypes->IsStringInTable(pszTypeName);
if (pos <= 0) {
if ( (m_itTables.m_cTypes > 0) && ((m_itTables.m_cTypes+1) % 32 == 0) )
ReSizeIT(); // increase by one DWORD
pos = m_itTables.m_ptblInfoTypes->AddString(pszTypeName);
m_itTables.m_cTypes++;
int offset = 0;
int type = pos;
while (type > 32) {
offset++;
type -= 32;
}
INFOTYPE* pInfoType = m_pInfoTypes + offset;
*pInfoType |= (1 << type);
}
category--; // zero offset
if ( category >=0 )
AddITtoCategory(category, pos );
#if 0
/*
* If we have more then 32 information types, then we need to be certain
* the size of the SITE_ENTRY_URL* structure allocated for Sitemap Entries
* is large enough.
*/
// BUGBUG: we need to deal with the situation where an information type
// gets specified AFTER a sitemap entry has been specified.
if (pos > m_pSiteUrl->m_cMaxTypes) {
m_cUrlEntry = sizeof(SITE_ENTRY_URL) + pos / sizeof(UINT);
m_pSiteUrl->m_pUrl = (SITE_ENTRY_URL*) lcReAlloc(m_pSiteUrl->m_pUrl, m_cUrlEntry);
m_pSiteUrl->m_cMaxTypes += 32;
m_cInfoTypeOffsets++;
}
if ( pos % 32 == 0 )
{
// Increase the Categories
for(int i=0; i<m_itTables.m_max_categories; i++)
m_itTables.m_aCategories[i].pInfoType = (INFOTYPE*)lcReAlloc(m_itTables.m_aCategories[i].pInfoType,
InfoTypeSize());
// Increase the Exclusive and Hidden IT fields.
m_itTables.m_pExclusive = (INFOTYPE*) lcReAlloc(m_itTables.m_pExclusive,
InfoTypeSize() );
m_itTables.m_pHidden = (INFOTYPE*) lcReAlloc(m_itTables.m_pHidden,
InfoTypeSize() );
}
#endif
return pos;
}
BOOL CSiteMap::AreAnyInfoTypesDefined(SITEMAP_ENTRY* pSiteMapEntry)
{
INFOTYPE *pIT;
SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
for (int iUrl = 0; iUrl < pSiteMapEntry->cUrls; iUrl++)
{
pIT = pUrl->ainfoTypes;
for (int i=0; i < InfoTypeSize()/4; i++)
{
if (*pIT)
return TRUE; // an info type was found
else
pIT++;
}
pUrl = NextUrlEntry(pUrl);
}
return FALSE;
}
/***************************************************************************
FUNCTION: CSiteMap::AreTheseInfoTypesDefined
PURPOSE: Find out if the specified INFOTYPES are defined
PARAMETERS:
pSiteMapEntry
types -- bit flag mask
offset -- offset into ainfoTypes
RETURNS:
A pointer to the first SITE_ENTRY_URL structure containing at
least one of the requested information types.
COMMENTS:
32 Information Types may be checked on each call. This will check
every URL defined for the current Sitemap entry, and return
TRUE if there is any match.
If you needed to find out if information type number 33 was
defined, you would call this with types set to 1, and offset to 1
(offset determines which set of 32 information types to look at).
MODIFICATION DATES:
25-Jan-1997 [ralphw]
***************************************************************************/
SITE_ENTRY_URL* CSiteMap::AreTheseInfoTypesDefined(SITEMAP_ENTRY* pSiteMapEntry,
INFOTYPE types, int offset) const
{
ASSERT((UINT) offset <= m_itTables.m_cTypes / sizeof(INFOTYPE));
SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
if (!pUrl)
return NULL;
for (int iUrl = 0; iUrl < pSiteMapEntry->cUrls; iUrl++)
{
if ( *(pUrl->ainfoTypes+offset) & types )
return pUrl;
pUrl = NextUrlEntry(pUrl);
}
return NULL;
}
// This includes all memory for URL names and sitemap entries
const int MAX_POINTERS = (1024 * 1024); // 1 meg, 262,144 strings
const int MAX_STRINGS = (25 * 1024 * 1024) - 4096L; // 25 megs
CSiteMap::CSiteMap(int cMaxEntries) : CTable((cMaxEntries ? (cMaxEntries * 256) : MAX_STRINGS))
{
// Can't clear memory, because of our base class
m_fTypeCopy = FALSE;
m_fSaveIT = TRUE;
m_pszSitemapFile = NULL;
m_pTypicalInfoTypes = NULL;
m_fIndex = FALSE;
m_pszBase = NULL;
m_pszImageList = NULL;
m_cImages = 0;
m_pszFont = NULL;
m_fFolderImages = FALSE;
m_fPromotForInfoTypes = FALSE;
m_pszBackBitmap = NULL;
m_fAutoGenerated = FALSE;
m_ptblStrings = NULL;
m_pszFrameName = NULL;
m_pszWindowName = NULL;
m_pszHHIFile = NULL;
ZeroMemory(&m_itTables, sizeof(INFOTYPE_TABLES));
m_itTables.m_max_categories = MAX_CATEGORIES;
m_itTables.m_aCategories = (CATEGORY_TYPE*) lcMalloc(MAX_CATEGORIES*sizeof(CATEGORY_TYPE) );
m_itTables.m_cTypes = 0;
m_itTables.m_cITSize = 1; // Initially allocate one DWORD to hold info type bits
for(int i=0; i< MAX_CATEGORIES; i++)
{
m_itTables.m_aCategories[i].pInfoType = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE) );
memset(m_itTables.m_aCategories[i].pInfoType, '\0', InfoTypeSize() );
m_itTables.m_aCategories[i].c_Types = 0;
}
m_itTables.m_pExclusive = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE ) );
m_itTables.m_pHidden = (INFOTYPE*)lcCalloc( sizeof(INFOTYPE) );
m_clrBackground = (COLORREF) -1;
m_clrForeground = (COLORREF) -1;
m_exStyles = (DWORD) -1;
m_tvStyles = (DWORD) -1;
m_clrMask = 0xFFFFFF;
m_cImageWidth = 20;
m_pInfoTypes = (INFOTYPE*) lcCalloc(sizeof(INFOTYPE) );
m_pTypicalInfoTypes = (INFOTYPE*) lcCalloc( sizeof(INFOTYPE) );
// By default, select all information types
memset(m_pInfoTypes, 0xFF, sizeof(INFOTYPE) );
#ifdef HHCTRL
#ifndef HHA
m_CodePage = (UINT)-1;
#endif
#endif
}
CSiteMap::~CSiteMap()
{
for (int pos = 1; pos < endpos - 1; pos++)
{
SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
if ( pSiteMapEntry && pSiteMapEntry->pUrls && pSiteMapEntry->pUrls->ainfoTypes )
lcFree(pSiteMapEntry->pUrls->ainfoTypes);
}
if (m_ptblStrings)
delete m_ptblStrings;
if (!m_fTypeCopy) {
if (m_itTables.m_ptblInfoTypes)
delete m_itTables.m_ptblInfoTypes;
if (m_itTables.m_ptblInfoTypeDescriptions)
delete m_itTables.m_ptblInfoTypeDescriptions;
if (m_itTables.m_ptblCategories)
delete m_itTables.m_ptblCategories;
if (m_itTables.m_ptblCatDescription)
delete m_itTables.m_ptblCatDescription;
}
for (int i=0; i< m_itTables.m_max_categories; i++)
lcFree( m_itTables.m_aCategories[i].pInfoType);
lcFree (m_itTables.m_aCategories);
lcFree (m_itTables.m_pHidden);
lcFree (m_itTables.m_pExclusive);
lcFree (m_pInfoTypes);
lcFree (m_pTypicalInfoTypes);
}
void CSiteMap::ReSizeURLIT(int Size)
{
int oldSize = InfoTypeSize();
if ( Size == 0 )
m_itTables.m_cITSize++;
else
m_itTables.m_cITSize= Size;
//Increase each sitemap entry URL infotype
int cEntries = Count();
INFOTYPE *pIT;
for (int i=1; i<=cEntries; i++)
{
SITEMAP_ENTRY *pSE = GetSiteMapEntry(i);
SITE_ENTRY_URL *pSEURL = pSE->pUrls;
for(int j=0; j<pSE->cUrls; j++)
{
pSEURL = pSEURL+j;
pIT = (INFOTYPE*) lcCalloc( InfoTypeSize() );
memcpy(pIT, pSEURL->ainfoTypes, oldSize);
lcFree( pSEURL->ainfoTypes );
pSEURL->ainfoTypes = pIT;
}
}
SizeIT( oldSize );
}
void CSiteMap::ReSizeIT(int Size)
{
int oldSize = InfoTypeSize();
if ( Size == 0 )
m_itTables.m_cITSize++; // increase by one
else
m_itTables.m_cITSize = Size;
SizeIT(oldSize);
}
void CSiteMap::SizeIT(int oldSize)
{
// Increase each category
INFOTYPE * pIT;
for(int i=0; i<m_itTables.m_max_categories; i++)
{
pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
memcpy(pIT, m_itTables.m_aCategories[i].pInfoType, oldSize);
lcFree(m_itTables.m_aCategories[i].pInfoType);
m_itTables.m_aCategories[i].pInfoType = pIT;
}
pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
memcpy(pIT, m_itTables.m_pExclusive, oldSize);
lcFree(m_itTables.m_pExclusive);
m_itTables.m_pExclusive = pIT;
pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
memcpy(pIT, m_itTables.m_pHidden, oldSize);
lcFree(m_itTables.m_pHidden);
m_itTables.m_pHidden = pIT;
pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
memcpy(pIT, m_pInfoTypes, oldSize);
lcFree(m_pInfoTypes);
m_pInfoTypes = pIT;
pIT = (INFOTYPE *) lcCalloc( InfoTypeSize() );
memcpy(pIT, m_pTypicalInfoTypes, oldSize);
lcFree(m_pTypicalInfoTypes);
m_pTypicalInfoTypes = pIT;
}
void CSiteMap::CopyCat(INFOTYPE_TABLES *Dst_itTables, const INFOTYPE_TABLES * Src_itTables)
{
// copy the categories table
Dst_itTables->m_max_categories = Src_itTables->m_max_categories;
if ( Dst_itTables->m_max_categories > MAX_CATEGORIES )
Dst_itTables->m_aCategories = (CATEGORY_TYPE *)lcReAlloc(Dst_itTables->m_aCategories,
Dst_itTables->m_max_categories * sizeof(CATEGORY_TYPE) );
for(int i=0; i<Dst_itTables->m_max_categories; i++)
{
if ( Dst_itTables->m_aCategories[i].pInfoType )
lcFree(Dst_itTables->m_aCategories[i].pInfoType);
Dst_itTables->m_aCategories[i].pInfoType = (INFOTYPE*) lcCalloc( InfoTypeSize());
if ( Src_itTables->m_aCategories[i].c_Types > 0 )
{
memcpy(Dst_itTables->m_aCategories[i].pInfoType,
Src_itTables->m_aCategories[i].pInfoType,
InfoTypeSize() );
Dst_itTables->m_aCategories[i].c_Types = Src_itTables->m_aCategories[i].c_Types;
}
else
{
Dst_itTables->m_aCategories[i].c_Types = 0;
}
}
}
// Check all the categories to see if this type is a member of any of them, return TRUE on first occurrence
BOOL CSiteMap::IsInACategory( int type ) const
{
for (int i=0; i<HowManyCategories(); i++ )
{
int offset;
INFOTYPE *pIT;
offset = type / 32;
ASSERT ( m_itTables.m_aCategories[i].pInfoType );
pIT = m_itTables.m_aCategories[i].pInfoType + offset;
if ( *pIT & (1<<(type-(offset*32))) )
return TRUE;
}
return FALSE;
}
int CSiteMap::GetInfoType(PCSTR pszTypeName)
{
int type;
CStr cszCat = pszTypeName;
ASSERT(!IsEmptyString(pszTypeName));
/*
A category and type is specified as:
category::type name
*/
PSTR pszCat = strstr(cszCat.psz, "::");
if ( !pszCat )
{
pszCat = StrChr(cszCat.psz, ':');
if (pszCat != NULL)
{
*pszCat = '\0';
pszCat++; // step over the :
}
}
else
{
*pszCat = '\0';
pszCat+=2; // step over the ::
}
if ( pszCat == NULL )
return GetITIndex(pszTypeName); // there is not category.
else
{
int cat = GetCatPosition( cszCat.psz );
if (cat <= 0)
return -1;
type = GetFirstCategoryType( cat-1 );
while( type != -1 )
{
if ( strcmp( pszCat, GetInfoTypeName(type) ) == 0 )
return type;
type = GetNextITinCategory();
}
}
return -1;
}
// Reads the user's current favorites to create nodes
void CSiteMap::CreateFavorites(int level)
{
HRESULT hr;
LPITEMIDLIST pidl;
char szFavoritesPath[MAX_PATH];
hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
if (SUCCEEDED(hr)) {
BOOL fResult = SHGetPathFromIDList(pidl, szFavoritesPath);
// SHFree(pidl); // BUGBUG: this function doesn't exist!!!
if (!fResult)
return; // BUGBUG: nag the author
}
else
return; // BUGBUG: nag the author
AddTrailingBackslash(szFavoritesPath);
CStr cszSearch(szFavoritesPath);
cszSearch += "*.*";
CTable tblFolders;
CTable tblFiles;
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(cszSearch, &wfd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (wfd.cFileName[0] != '.') // ignore . and ..
tblFolders.AddString(wfd.cFileName);
}
else
tblFiles.AddString(wfd.cFileName);
} while (FindNextFile(hFind, &wfd));
FindClose(hFind);
}
// Did we get at least one entry?
if (tblFolders.CountStrings() || tblFiles.CountStrings()) {
SITEMAP_ENTRY SiteMapEntry;
ZERO_STRUCTURE(SiteMapEntry);
// Add the top level book called Favorites
SiteMapEntry.level = level++;
SiteMapEntry.pszText = StrDup(GetStringResource(IDS_BROWSER_FAVORITES));
AddEntry(&SiteMapEntry);
tblFolders.SortTablei(); // BUGBUG: set lcide first
for (int pos = 1; pos <= tblFolders.CountStrings(); pos++)
AddFavoriteNodes(szFavoritesPath, tblFolders.GetPointer(pos), level);
tblFiles.SortTablei(); // BUGBUG: set lcid first
for (pos = 1; pos <= tblFiles.CountStrings(); pos++) {
char szUrl[MAX_PATH * 4];
char szPath[MAX_PATH];
strcpy(szPath, szFavoritesPath);
AddTrailingBackslash(szPath);
strcat(szPath, tblFiles.GetPointer(pos));
if (GetPrivateProfileString("InternetShortcut", "URL", "",
szUrl, sizeof(szUrl), szPath) > 0 && szUrl[0]) {
CStr cszName(tblFiles.GetPointer(pos));
PSTR pszExtension = StrRChr(cszName, '.');
if (pszExtension) {
*pszExtension = '\0';
SiteMapEntry.level = (BYTE)level;
SiteMapEntry.pszText = StrDup(cszName);
CSiteEntryUrl curl( InfoTypeSize() );
curl.m_pUrl->urlPrimary = AddUrl(szUrl);
SiteMapEntry.pUrls = curl.m_pUrl;
SiteMapEntry.SetTopic(TRUE);
AddEntry(&SiteMapEntry);
}
}
}
}
}
void CSiteMap::AddFavoriteNodes(PCSTR pszRoot, PCSTR pszNewFolder, int level)
{
CTable tblFolders;
CTable tblFiles;
char szPath[MAX_PATH];
strcpy(szPath, pszRoot);
AddTrailingBackslash(szPath);
strcat(szPath, pszNewFolder);
CStr cszRoot(szPath); // save in case we need to recurse
AddTrailingBackslash(szPath);
strcat(szPath, "*.*");
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(szPath, &wfd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (wfd.cFileName[0] != '.') // ignore . and ..
tblFolders.AddString(wfd.cFileName);
}
else
tblFiles.AddString(wfd.cFileName);
} while (FindNextFile(hFind, &wfd));
FindClose(hFind);
}
// Did we get at least one entry?
if (tblFolders.CountStrings() || tblFiles.CountStrings()) {
SITEMAP_ENTRY SiteMapEntry;
ZERO_STRUCTURE(SiteMapEntry);
SiteMapEntry.level = level++;
SiteMapEntry.pszText = StrDup(pszNewFolder);
AddEntry(&SiteMapEntry);
tblFolders.SortTablei(); // BUGBUG: set lcid first
// Handle all nested folders
for (int pos = 1; pos <= tblFolders.CountStrings(); pos++)
AddFavoriteNodes(cszRoot, tblFolders.GetPointer(pos), level);
tblFiles.SortTablei(); // BUGBUG: set lcide first
for (pos = 1; pos <= tblFiles.CountStrings(); pos++) {
char szUrl[MAX_PATH * 4];
strcpy(szPath, cszRoot);
AddTrailingBackslash(szPath);
strcat(szPath, tblFiles.GetPointer(pos));
if (GetPrivateProfileString("InternetShortcut", "URL", "",
szUrl, sizeof(szUrl), szPath) > 0 && szUrl[0]) {
CStr cszName(tblFiles.GetPointer(pos));
PSTR pszExtension = StrRChr(cszName, '.');
if (pszExtension) {
*pszExtension = '\0';
SiteMapEntry.level = (BYTE)level;
SiteMapEntry.pszText = StrDup(cszName);
CSiteEntryUrl curl( InfoTypeSize() );
curl.m_pUrl->urlPrimary = AddUrl(szUrl);
SiteMapEntry.pUrls = curl.m_pUrl;
SiteMapEntry.SetTopic(TRUE);
AddEntry(&SiteMapEntry);
}
}
}
}
}
int CSiteMap::GetImageNumber(SITEMAP_ENTRY* pSiteMapEntry) const
{
int image = pSiteMapEntry->GetImageIndex();
if (image == 0) {
if (pSiteMapEntry->IsTopic()) {
image = pSiteMapEntry->fNew ?
IMAGE_HELP_TOPIC_NEW : IMAGE_HELP_TOPIC;
if (m_fFolderImages)
image+= 2; // switch to standard topic images
}
else {
image = pSiteMapEntry->fNew ? IMAGE_OPEN_BOOK_NEW : IMAGE_OPEN_BOOK;
if (m_fFolderImages)
image += 4; // switch to standard books
}
}
if (m_cImages && image > m_cImages) {
// BUGBUG: if this really happens, nag the author
image = IMAGE_CLOSED_BOOK;
}
return image;
}
BOOL CSiteMap::IsEntryInCurTypeList(SITEMAP_ENTRY* pSiteMapEntry) const
{
int cTypes = m_itTables.m_ptblInfoTypes->CountStrings();
if (cTypes < 32) {
return AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[0], 0) != NULL;
}
else {
for (int i = 0; cTypes > 32; i++) {
if (AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[i], i))
return TRUE;
cTypes -= 32;
}
return AreTheseInfoTypesDefined(pSiteMapEntry, m_pInfoTypes[i], i) != NULL;
}
}
typedef struct tagEntityMap
{
PCSTR pszName;
int ch;
} ENTITYMAP, * PENTITYMAP;
// ENTITY TABLE SWIPED FROM IE
const ENTITYMAP rgEntities[] =
{
"AElig", '\306', // capital AE diphthong (ligature)
"Aacute", '\301', // capital A, acute accent
"Acirc", '\302', // capital A, circumflex accent
"Agrave", '\300', // capital A, grave accent
"Aring", '\305', // capital A, ring
"Atilde", '\303', // capital A, tilde
"Auml", '\304', // capital A, dieresis or umlaut mark
"Ccedil", '\307', // capital C, cedilla
"Dstrok", '\320', // capital Eth, Icelandic
"ETH", '\320', // capital Eth, Icelandic
"Eacute", '\311', // capital E, acute accent
"Ecirc", '\312', // capital E, circumflex accent
"Egrave", '\310', // capital E, grave accent
"Euml", '\313', // capital E, dieresis or umlaut mark
"Iacute", '\315', // capital I, acute accent
"Icirc", '\316', // capital I, circumflex accent
"Igrave", '\314', // capital I, grave accent
"Iuml", '\317', // capital I, dieresis or umlaut mark
"Ntilde", '\321', // capital N, tilde
"Oacute", '\323', // capital O, acute accent
"Ocirc", '\324', // capital O, circumflex accent
"Ograve", '\322', // capital O, grave accent
"Oslash", '\330', // capital O, slash
"Otilde", '\325', // capital O, tilde
"Ouml", '\326', // capital O, dieresis or umlaut mark
"THORN", '\336', // capital THORN, Icelandic
"Uacute", '\332', // capital U, acute accent
"Ucirc", '\333', // capital U, circumflex accent
"Ugrave", '\331', // capital U, grave accent
"Uuml", '\334', // capital U, dieresis or umlaut mark
"Yacute", '\335', // capital Y, acute accent
"aacute", '\341', // small a, acute accent
"acirc", '\342', // small a, circumflex accent
"acute", '\264', // acute accent
"aelig", '\346', // small ae diphthong (ligature)
"agrave", '\340', // small a, grave accent
"amp", '\046', // ampersand
"aring", '\345', // small a, ring
"atilde", '\343', // small a, tilde
"auml", '\344', // small a, dieresis or umlaut mark
"brkbar", '\246', // broken vertical bar
"brvbar", '\246', // broken vertical bar
"ccedil", '\347', // small c, cedilla
"cedil", '\270', // cedilla
"cent", '\242', // small c, cent
"copy", '\251', // copyright symbol (proposed 2.0)
"curren", '\244', // currency symbol
"deg", '\260', // degree sign
"die", '\250', // umlaut (dieresis)
"divide", '\367', // divide sign
"eacute", '\351', // small e, acute accent
"ecirc", '\352', // small e, circumflex accent
"egrave", '\350', // small e, grave accent
"eth", '\360', // small eth, Icelandic
"euml", '\353', // small e, dieresis or umlaut mark
"frac12", '\275', // fraction 1/2
"frac14", '\274', // fraction 1/4
"frac34", '\276', // fraction 3/4*/
"gt", '\076', // greater than
"hibar", '\257', // macron accent
"iacute", '\355', // small i, acute accent
"icirc", '\356', // small i, circumflex accent
"iexcl", '\241', // inverted exclamation
"igrave", '\354', // small i, grave accent
"iquest", '\277', // inverted question mark
"iuml", '\357', // small i, dieresis or umlaut mark
"laquo", '\253', // left angle quote
"lt", '\074', // less than
"macr", '\257', // macron accent
"micro", '\265', // micro sign
"middot", '\267', // middle dot
"nbsp", '\240', // non-breaking space (proposed 2.0)
"not", '\254', // not sign
"ntilde", '\361', // small n, tilde
"oacute", '\363', // small o, acute accent
"ocirc", '\364', // small o, circumflex accent
"ograve", '\362', // small o, grave accent
"ordf", '\252', // feminine ordinal
"ordm", '\272', // masculine ordinal
"oslash", '\370', // small o, slash
"otilde", '\365', // small o, tilde
"ouml", '\366', // small o, dieresis or umlaut mark
"para", '\266', // paragraph sign
"plusmn", '\261', // plus minus
"pound", '\243', // pound sterling
"quot", '"', // double quote
"raquo", '\273', // right angle quote
"reg", '\256', // registered trademark (proposed 2.0)
"sect", '\247', // section sign
"shy", '\255', // soft hyphen (proposed 2.0)
"sup1", '\271', // superscript 1
"sup2", '\262', // superscript 2
"sup3", '\263', // superscript 3
"szlig", '\337', // small sharp s, German (sz ligature)
"thorn", '\376', // small thorn, Icelandic
"times", '\327', // times sign
"trade", '\231', // trademark sign
"uacute", '\372', // small u, acute accent
"ucirc", '\373', // small u, circumflex accent
"ugrave", '\371', // small u, grave accent
"uml", '\250', // umlaut (dieresis)
"uuml", '\374', // small u, dieresis or umlaut mark
"yacute", '\375', // small y, acute accent
"yen", '\245', // yen
"yuml", '\377', // small y, dieresis or umlaut mark
0, 0
};
BOOL ReplaceEscapes(PCSTR pszSrc, PSTR pszDst, int flags)
{
if (IsEmptyString(pszSrc))
return FALSE;
ASSERT(pszDst);
if ((flags & ESCAPE_URL)) {
if (StrChr(pszSrc, '%'))
goto CheckForEscape;
}
if ((flags & ESCAPE_C)) {
if (StrChr(pszSrc, '\\'))
goto CheckForEscape;
}
if ((flags & ESCAPE_ENTITY)) {
if (StrChr(pszSrc, '&'))
goto CheckForEscape;
}
// If we get here, there are no escape sequences, so copy the string and
// return.
if (pszDst != pszSrc)
strcpy(pszDst, pszSrc);
return FALSE; // nothing changed
CheckForEscape:
#ifdef _DEBUG
PSTR pszOrgDst = pszDst;
int cbSource = (int)strlen(pszSrc);
#endif
while (*pszSrc) {
if (IsDBCSLeadByte(*pszSrc))
{
if (pszSrc[1])
{
*pszDst++ = *pszSrc++;
*pszDst++ = *pszSrc++;
}
else
{
// leadbyte followed by 0; invalid!
*pszDst++ = '?';
break;
}
}
else if ((flags & ESCAPE_URL) && *pszSrc == '%')
{
// URL style hex digits
get_hex:
int val;
pszSrc++;
if (IsDigit(*pszSrc))
val = *pszSrc++ - '0';
else if (*pszSrc >= 'a' && *pszSrc <= 'f')
val = *pszSrc++ - 'a' + 10;
else if (*pszSrc >= 'A' && *pszSrc <= 'F')
val = *pszSrc++ - 'A' + 10;
if (IsDigit(*pszSrc))
val = val * 16 + *pszSrc++ - '0';
else if (*pszSrc >= 'a' && *pszSrc <= 'f')
val = val * 16 + *pszSrc++ - 'a' + 10;
else if (*pszSrc >= 'A' && *pszSrc <= 'F')
val = val * 16 + *pszSrc++ - 'A' + 10;
if (val)
{
*pszDst++ = (CHAR)val;
}
}
else if ((flags & ESCAPE_C) && *pszSrc == '\\')
{
// C style escape
switch (*++pszSrc)
{
case 'n':
*pszDst++ = '\n';
pszSrc++;
break;
case 'r':
*pszDst++ = '\r';
pszSrc++;
break;
case 't':
*pszDst++ = '\t';
pszSrc++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
// octal digits
{
int val;
if (*pszSrc >= '0' && *pszSrc <= '7')
val = *pszSrc++ - '0';
if (*pszSrc >= '0' && *pszSrc <= '7')
val = val * 8 + *pszSrc++ - '0';
if (*pszSrc >= '0' && *pszSrc <= '7')
val = val * 8 + *pszSrc++ - '0';
if (val)
*pszDst++ = (CHAR)val;
}
break;
case 'x':
case 'X':
// hex digits
goto get_hex;
break;
case 0:
break;
default:
*pszDst++ = *pszSrc++;
break;
}
}
else if ( (flags & ESCAPE_ENTITY) && *pszSrc == '&' && *(pszSrc+1) != ' ' )
{
pszSrc++;
if (*pszSrc == '#')
{
// SGML/HTML character entity (decimal)
pszSrc++;
for (int val = 0; *pszSrc && *pszSrc != ';' && *pszSrc != ' '; pszSrc++)
{
if (*pszSrc >= '0' && *pszSrc <= '9')
val = val * 10 + *pszSrc - '0';
else
{
while (*pszSrc && *pszSrc != ';' && *pszSrc != ' ')
pszSrc++;
break;
}
}
if( *pszSrc == ';' )
pszSrc++;
if (val) {
*pszDst++ = (CHAR)val;
}
}
else if (*pszSrc)
{
char szEntityName[256];
int count = 0;
// extra code was added below to handle the case where an & appears without
// an entity name (which is an error in the HTML). This avoids overunning
// the szEntityName buffer.
//
for (PSTR p = szEntityName; *pszSrc && *pszSrc != ';' && *pszSrc != ' ' && count < sizeof(szEntityName);)
{
*p++ = *pszSrc++;
count++;
}
*p = 0;
if (*pszSrc == ';')
pszSrc++;
for (int i = 0; rgEntities[i].pszName; i++)
{
if (!strcmp(szEntityName, rgEntities[i].pszName)) {
if (rgEntities[i].ch) {
*pszDst++ = (CHAR)rgEntities[i].ch;
}
break;
}
}
if (!rgEntities[i].pszName) {
// illegal entity name, put in a block character
*pszDst++ = '?';
}
}
}
else {
// just your usual character...
*pszDst++ = *pszSrc++;
}
}
*pszDst = 0;
ASSERT(pszDst - pszOrgDst <= cbSource);
return TRUE;
}
#ifndef HHCTRL
void STDCALL ConvertToEscapes(PCSTR pszSrc, CStr* pcszDst)
{
int cbAlloc = pcszDst->SizeAlloc();
if (!cbAlloc)
pcszDst->ReSize(cbAlloc = (strlen(pszSrc) + 128));
int dstPos = 0;
if (!pszSrc) {
*pcszDst = "";
return;
}
int cbSrc = strlen(pszSrc);
while (*pszSrc) {
if( IsDBCSLeadByte(*pszSrc) )
{
pcszDst->psz[dstPos++] = *pszSrc++;
if( pszSrc )
pcszDst->psz[dstPos++] = *pszSrc++;
}
else {
for (int i = 0; rgEntities[i].pszName; i++) {
if (*pszSrc == rgEntities[i].ch) {
if ((size_t) cbAlloc - dstPos <= strlen(rgEntities[i].pszName) + 2)
pcszDst->ReSize(cbAlloc += 128);
pcszDst->psz[dstPos++] = '&';
strcpy(pcszDst->psz + dstPos, rgEntities[i].pszName);
strcat(pcszDst->psz, ";");
dstPos += strlen(rgEntities[i].pszName) + 1;
pszSrc++;
break;
}
}
if (!rgEntities[i].pszName)
pcszDst->psz[dstPos++] = *pszSrc++;
}
if (cbAlloc <= dstPos)
pcszDst->ReSize(cbAlloc += 128);
}
pcszDst->psz[dstPos] = '\0';
}
#endif
#ifdef HHCTRL
BOOL CAInput::Add(PCSTR pszFile)
{
m_ainput[++m_curInput].pin = new CInput(pszFile);
m_ainput[m_curInput].pszBaseName = lcStrDup(pszFile);
if (!m_ainput[m_curInput].pin->isInitialized()) {
Remove();
return FALSE;
}
// Strip basename down to the path
PSTR pszFilePortion = (PSTR) FindFilePortion(m_ainput[m_curInput].pszBaseName);
if (pszFilePortion)
*pszFilePortion = '\0';
ConvertBackSlashToForwardSlash(m_ainput[m_curInput].pszBaseName);
return TRUE;
}
#endif
////////////////////////////////// non-HHCTRL code //////////////////////////////////
#ifndef HHCTRL
const int MAX_PARAM = 4096;
#pragma warning(disable:4125) // decimal digit terminates octal escape sequence
static const char txtSiteMapVersion[] = "<!-- Sitemap 1.0 -->";
static const char txtStringParam[] = "<param name=\042%s\042 value=\042%s\042>";
static const char txtSSConvString[] = "<param name=\042%s\042 value=\042%s:%s:%s\042>";
static const char txtYes[] = "Yes";
static const char txtDecimalParam[] = "<param name=\042%s\042 value=\042%u\042>";
static const char txtHexParam[] = "<param name=\042%s\042 value=\0420x%x\042>";
__inline void PadOutput(COutput* pout, int level) {
for (int i = 0; i < level; i++)
pout->outchar('\t');
}
BOOL CSiteMap::SaveSiteMap(PCSTR pszPathName, BOOL fIndex)
{
COutput output(pszPathName);
if (!output.isFileOpen()) {
// DO NOT USE MsgBox() as the parent window handle is invalid if we are closing
CStr csz(IDS_CANT_WRITE, pszPathName);
MessageBox(APP_WINDOW, csz, txtAppTitle, MB_OK | MB_ICONHAND);
return FALSE;
}
CStr cszTmp;
CMem memParam(MAX_PARAM);
PSTR pszParam = memParam.psz; // for notational convenience
output.outstring(GetStringResource(IDSHHA_HTML_NEW_FILE1));
output.outstring_eol(txtSiteMapVersion);
output.outstring_eol("</HEAD><BODY>");
// Write out any global properties
if ( IsFrameDefined() ||
IsWindowDefined() ||
m_itTables.m_ptblInfoTypes ||
m_itTables.m_ptblCategories ||
m_fFolderImages ||
m_pszImageList ||
m_fAutoGenerated ||
IsNonEmpty(m_pszFont) ||
IsNonEmpty(m_pszHHIFile) ||
m_clrBackground != (COLORREF) -1 ||
m_clrForeground != (COLORREF) -1 ||
m_exStyles != (DWORD) -1 ||
m_tvStyles != (DWORD) -1) {
output.outstring_eol("<OBJECT type=\042text/site properties\042>");
if (m_fAutoGenerated) {
wsprintf(pszParam, txtStringParam, txtAutoGenerated,
txtYes);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (IsFrameDefined()) {
ConvertToEscapes(GetFrameName(), &cszTmp);
wsprintf(pszParam, txtStringParam, txtParamFrame, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (IsWindowDefined()) {
ConvertToEscapes(GetWindowName(), &cszTmp);
wsprintf(pszParam, txtStringParam, txtParamWindow, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
/*
* REVIEW: we should eliminate Information Types which haven't
* actually been used.
*/
// output the entire list of info types to disk, without regard to their inclusion
// in a category. We may have ITs that are not members of a category.
if ( m_fSaveIT && m_itTables.m_cTypes )
{
for(int pos=1; pos<=m_itTables.m_cTypes; pos++)
{
ConvertToEscapes(m_itTables.m_ptblInfoTypes->GetPointer(pos), &cszTmp);
if ( HowManyCategories() > 0 )
{
if ( IsExclusive(pos) ) // An Exclusive IT
wsprintf( pszParam, txtStringParam, txtSaveTypeExclusive, cszTmp);
else if ( IsHidden(pos) ) // A Hidden IT
wsprintf( pszParam, txtStringParam, txtSaveTypeHidden, cszTmp);
else // A regular IT
wsprintf(pszParam, txtStringParam, txtSaveType, cszTmp);
}
else
{
if ( IsExclusive(pos) ) // An Exclusive IT
wsprintf( pszParam, txtStringParam, txtParamTypeExclusive, cszTmp);
else if ( IsHidden(pos) ) // A Hidden IT
wsprintf( pszParam, txtStringParam, txtParamTypeHidden, cszTmp);
else // A regular IT
wsprintf(pszParam, txtStringParam, txtParamType, cszTmp);
}
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
ConvertToEscapes(m_itTables.m_ptblInfoTypeDescriptions->GetPointer(pos), &cszTmp);
if (!IsEmptyString(cszTmp))
{
if (StrChr(cszTmp, '&'))
{
cszTmp = cszTmp;
cszTmp.AddAmpersandEscape();
cszTmp = cszTmp.psz;
}
if ( HowManyCategories() > 0)
wsprintf(pszParam, txtStringParam, txtSaveTypeDesc, cszTmp);
else
wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
else
{
CStr cszTemp(" ");
cszTmp = cszTemp.psz;
if ( HowManyCategories() > 0)
wsprintf(pszParam, txtStringParam, txtSaveTypeDesc, cszTmp);
else
wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
}
}
//Output Categories and the info types, that are members of each category, to disk.
if (m_fSaveIT && m_itTables.m_ptblCategories && m_itTables.m_ptblCategories->CountStrings() )
{
for(int posCat=1; posCat<=m_itTables.m_ptblCategories->CountStrings(); posCat++)
{
if ( IsCatDeleted( posCat ) )
continue;
ConvertToEscapes(GetCategoryString(posCat), &cszTmp);
if (cszTmp.IsNonEmpty())
{
wsprintf(pszParam, txtStringParam, txtParamCategory, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
ConvertToEscapes(m_itTables.m_ptblCatDescription->GetPointer(posCat), &cszTmp);
if (!IsEmptyString(cszTmp))
{
if (StrChr(cszTmp, '&'))
{
cszTmp = cszTmp;
cszTmp.AddAmpersandEscape();
cszTmp = cszTmp.psz;
}
wsprintf(pszParam, txtStringParam, txtParamCategoryDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
else
{
CStr cszTemp(" ");
cszTmp = cszTemp.psz;
wsprintf(pszParam, txtStringParam, txtParamCategoryDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
}
int posType = GetFirstCategoryType(posCat-1);
// for(int j = 1; j <= m_itTables.m_aCategories[posCat-1].c_Types; j++)
while( posType != -1 )
{
ConvertToEscapes(GetInfoTypeName(posType), &cszTmp);
if ( IsExclusive( posType ) )
wsprintf( pszParam, txtStringParam, txtParamTypeExclusive, cszTmp);
else
if ( IsHidden(posType) ) // A Hidden IT
wsprintf( pszParam, txtStringParam, txtParamTypeHidden, cszTmp);
else // A regular IT
wsprintf(pszParam, txtStringParam, txtParamType, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
ConvertToEscapes(m_itTables.m_ptblInfoTypeDescriptions->GetPointer(posType), &cszTmp);
if (cszTmp.IsNonEmpty())
{
if (StrChr(cszTmp, '&'))
{
cszTmp = cszTmp;
cszTmp.AddAmpersandEscape();
cszTmp = cszTmp.psz;
}
wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
else
{
CStr cszTemp(" ");
cszTmp = cszTemp.psz;
wsprintf(pszParam, txtStringParam, txtParamTypeDesc, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
posType = GetNextITinCategory();
} // for each IT in a category
} // for each category
} // if there are categories.
#ifdef NOTYET
// OutPut the SubSet Declarations.
CStr cszTemp;
for(int i=0; i<m_pSubSets->HowManySubSets(); i++)
{
CSubSet * cur_subset = m_pSubSets->GetSubSet(i);
if ( cur_subset == NULL )
continue;
// output the Inclusive IT's in the subset
int type = cur_subset->GetFirstIncITinSubSet();
while ( type != -1 )
{
wsprintf(pszParam, txtSSConvString, txtParamSSInclusive, txtSSInclusive
cur_subset->m_cszSubSetName.psz,
cur_subset->m_pIT->m_itTables.m_ptblInfoTypes->GetPointer(type) );
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
type = cur_subset->GetNextIncITinSubSet();
}
// output the Exclusive IT's of the subset
type = cur_subset->GetFirstExcITinSubSet();
while( type != -1 )
{
wsprintf(pszParam, txtSSConvString, txtParamSSExclusive, txtSSExclusive
cur_subset->m_cszSubSetName.psz,
cur_subset->m_pIT->m_itTables.m_ptblInfoTypes->GetPointer(type) );
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
type = cur_subset->GetNextExcITinSubSet();
}
} // End OutPut SubSets
#endif
if (m_pszImageList && m_cImageWidth) {
ConvertToEscapes(m_pszImageList, &cszTmp);
wsprintf(pszParam, txtStringParam, txtImageList, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
wsprintf(pszParam, txtDecimalParam, txtImageWidth, m_cImageWidth);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
if (m_clrMask != 0xFFFFFF) {
wsprintf(pszParam, txtHexParam, txtColorMask, m_clrMask);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
}
if (m_clrBackground != (DWORD) -1) {
wsprintf(pszParam, txtHexParam, txtBackGround, m_clrBackground);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (m_clrForeground != (DWORD) -1) {
wsprintf(pszParam, txtHexParam, txtForeGround, m_clrForeground);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (m_exStyles != (DWORD) -1) {
wsprintf(pszParam, txtHexParam, txtExWindowStyles, m_exStyles);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (m_tvStyles != (DWORD) -1) {
wsprintf(pszParam, txtHexParam, txtWindowStyles, m_tvStyles);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (m_fFolderImages) {
wsprintf(pszParam, txtStringParam, txtImageType, txtFolderType);
ASSERT(strlen(pszParam) < MAX_PARAM);
output.outchar('\t');
output.outstring_eol(pszParam);
}
if (IsNonEmpty(m_pszFont)) {
ConvertToEscapes(m_pszFont, &cszTmp);
wsprintf(pszParam, txtStringParam, txtFont, cszTmp);
output.outstring_eol(pszParam);
}
if (IsNonEmpty(m_pszHHIFile)) {
wsprintf(pszParam, txtStringParam, txtParamHHI, m_pszHHIFile);
output.outstring_eol(pszParam);
}
output.outstring_eol(txtEndObject);
}
// Write out the actual entries
output.outstring_eol(txtBeginList);
int curLevel = 1;
for (int pos = 1; pos <= CountStrings(); pos++) {
SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
ASSERT(pSiteMapEntry->pszText);
if (!pSiteMapEntry->pszText) // should never happen, but I'm paranoid...
continue;
// If level is greater, begin list item
while (pSiteMapEntry->level > curLevel) {
PadOutput(&output, curLevel);
output.outstring_eol(txtBeginList);
curLevel++;
}
// While level is lower, end lists
while (pSiteMapEntry->level < curLevel) {
curLevel--;
PadOutput(&output, curLevel);
output.outstring_eol(txtEndList);
}
PadOutput(&output, curLevel);
if (!pSiteMapEntry->fInclude)
output.outstring("<LI> ");
output.outstring_eol("<OBJECT type=\042text/sitemap\042>");
if (pSiteMapEntry->fInclude) {
PadOutput(&output, curLevel + 1);
output.outstring("<param name=\042Merge\042 value=\042");
ConvertToEscapes(pSiteMapEntry->pszText + strlen(GetStringResource(IDS_INCLUDED_FILE)), &cszTmp);
output.outstring(cszTmp);
output.outstring_eol("\042>\r\n");
PadOutput(&output, curLevel + 1);
output.outstring_eol(txtEndObject);
continue;
}
ConvertToEscapes(pSiteMapEntry->pszText, &cszTmp);
wsprintf(pszParam, txtStringParam, txtParamName, cszTmp);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(&output, curLevel + 1);
output.outstring_eol(pszParam);
OutputDefaultSiteMapEntry(&output, pSiteMapEntry, curLevel, fIndex);
PadOutput(&output, curLevel + 1);
output.outstring_eol(txtEndObject);
#if 0
/*
* We need to add an HREF to keep down-level sitemap readers happy
* (makes the .hhc file readable in a browser). We pick the first
* URL specified and use that.
*/
for (int i = 0; i < pSiteMapEntry->cTypes; i++) {
if ( pSiteMapEntry->aSiteInfoTypes[i].urlNumber > 0 &&
pSiteMapEntry->aSiteInfoTypes[i].infoNumber > 0) {
wsprintf(pszParam, "<A HREF=\042%s\042>%s</A>",
m_ptoc->GetUrlString((pSiteMapEntry->aSiteInfoTypes[i].urlNumber),
pSiteMapEntry->pszText);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(&output, curLevel + 1);
output.outstring_eol(pszParam);
break;
}
}
#endif
}
while (curLevel > 1) {
curLevel--;
PadOutput(&output, curLevel);
output.outstring_eol(txtEndList);
}
output.outstring_eol(txtEndList);
output.outstring_eol("</BODY></HTML>");
return TRUE;
}
void CSiteMap::OutputDefaultSiteMapEntry(COutput* pout, SITEMAP_ENTRY* pSiteMapEntry,
int curLevel, BOOL fIndex)
{
CMem memParam(8 * 1024);
PSTR pszParam = memParam.psz; // for notational convenience
SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls;
int cTypes = HowManyInfoTypes();
for (int i = 0; i < pSiteMapEntry->cUrls; i++) {
if (!IsEmptyString(pUrl->pszTitle)) {
wsprintf(pszParam, txtStringParam, txtParamName, pUrl->pszTitle);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (cTypes) {
int bitflag = 1 << 1;
int offset = 0;
CSiteMapEntry sitemapentry;
sitemapentry.cUrls = 1;
sitemapentry.pUrls = pUrl;
for (int infotype = 1; infotype <= cTypes; infotype++) {
if (AreTheseInfoTypesDefined(&sitemapentry, bitflag, offset)) {
CStr csz;
for (int l = 0; l < HowManyCategories(); l++) {
if( m_itTables.m_aCategories[l].c_Types <= 0)
break;
if( IsITinCategory( l, infotype) )
{
csz = GetCategoryString(l+1);
csz += "::";
break;
}
}
csz += GetInfoTypeName(infotype);
wsprintf(pszParam, txtStringParam, txtParamType, csz.psz);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
bitflag = bitflag << 1;
if (!bitflag) { // wrap around, so switch offsets
offset++;
bitflag = 1;
}
}
}
if (pUrl->urlPrimary) {
if (pSiteMapEntry->fSeeAlso) {
wsprintf(pszParam, txtStringParam, txtSeeAlso, GetUrlString(pUrl->urlPrimary));
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
break; // only one URL if See Also entry
}
wsprintf(pszParam, txtStringParam, txtParamLocal,
GetUrlString(pUrl->urlPrimary));
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pUrl->urlSecondary) {
wsprintf(pszParam, txtStringParam, txtParamUrl,
GetUrlString(pUrl->urlSecondary));
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
pUrl = NextUrlEntry(pUrl);
}
if (pSiteMapEntry->iFrameName) {
wsprintf(pszParam, txtStringParam, txtParamFrame,
GetName(pSiteMapEntry->iFrameName));
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pSiteMapEntry->iWindowName) {
wsprintf(pszParam, txtStringParam, txtParamWindow,
GetName(pSiteMapEntry->iWindowName));
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pSiteMapEntry->pszComment) {
wsprintf(pszParam, txtStringParam, txtParamComment, pSiteMapEntry->pszComment);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pSiteMapEntry->fNew) {
wsprintf(pszParam, txtDecimalParam, txtParamNew, 1);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pSiteMapEntry->iImage) {
wsprintf(pszParam, txtDecimalParam, txtParamImageNumber,
pSiteMapEntry->iImage);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
if (pSiteMapEntry->fNoDisplay) {
wsprintf(pszParam, txtStringParam, txtParamDisplay, txtNo);
ASSERT(strlen(pszParam) < MAX_PARAM);
PadOutput(pout, curLevel + 1);
pout->outstring_eol(pszParam);
}
}
#endif // HHCTRL