|
|
//*********************************************************************************************************************************************
//
// File: collect.cpp
// Author: Donald Drake
// Purpose: Implements classes to support collections
#include "header.h"
#include "string.h"
#ifdef HHCTRL
#include "parserhh.h"
#include "toc.h"
#else
#include "stdio.h"
#include "windows.h"
#include "parser.h"
extern DWORD GetTitleVersion(const CHAR *szFileName); extern LANGID GetLangId(const CHAR *szFileName); #endif
#include "collect.h"
// Use CRT version in hhsetup
// Instance count checking:
AUTO_CLASS_COUNT_CHECK(CFolder); AUTO_CLASS_COUNT_CHECK(CTitle);
#ifndef HHCTRL
#define Atoi atoi
#undef _splitpath
#endif
char gszColReg[MAX_PATH]; WCHAR *CreateUnicodeFromAnsi(LPSTR psz);
class CAnsi { public: char *m_pszChar; CAnsi(WCHAR *); ~CAnsi(); operator CHAR *() { return (CHAR *) m_pszChar; } };
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions
DWORD AllocSetValue(const CHAR *value, CHAR **dest) { if (*dest) delete [] *dest;
// REVIEW: confirm that len gets optimized out of existence
int len = (int)strlen(value) + 1;
*dest = new CHAR[len];
if (*dest == NULL) return F_MEMORY;
strcpy(*dest, value); return F_OK; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPointerList implementation
void foo(void) {
}
void CPointerList::RemoveAll() { LISTITEM *p;
while (m_pHead) { p = m_pHead->Next; delete m_pHead; m_pHead = p; } }
CPointerList::~CPointerList() { RemoveAll(); }
LISTITEM *CPointerList::Add(void *p) { LISTITEM *pItem = new LISTITEM;
if (pItem) { pItem->pItem = p; pItem->Next = m_pHead; m_pHead = pItem; return pItem; } return NULL; }
LISTITEM *CPointerList::First() { return m_pHead; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CColList implementation
CColList::CColList() { m_dwColNo = 0; m_szFileName = NULL; m_pNext = NULL; }
void CColList::SetFileName(CHAR *sz) { if (sz) AllocSetValue(sz, &m_szFileName); }
CColList::~CColList() { if (m_szFileName) delete m_szFileName; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CCollection implementation
CCollection::CCollection() { m_bRemoved = FALSE; m_pwcSampleLocation = NULL; m_pwcMasterCHM = NULL; m_bFailNoFile = FALSE; m_bDirty = FALSE; m_szSampleLocation = NULL; m_szFileName = NULL; m_pwcFileName = NULL; m_szMasterCHM = NULL; m_pFirstTitle = NULL; m_pTitleTail = NULL; m_pColListHead = NULL; m_pColListTail = NULL; m_pLocationTail = NULL; m_pFirstLocation = NULL; m_pRootFolder = NULL; m_locationnum = 0; m_dwNextColNo = 1; m_dwColNo = 0; m_dwTitleRefCount = 0; m_dwRef = 0; m_dwVersion = 0; m_bFindMergedChms = FALSE; for (int i = 0; i < MAX_LEVELS; i++) m_pParents[i] = NULL;
m_dwCurLevel = 0; m_dwLastLevel = 0; m_bConfirmTitles = FALSE; m_MasterLangId = ENGLANGID; gszColReg[0] = NULL; #ifdef HHSETUP
CoInitialize(NULL); #endif
}
CCollection::~CCollection() { Close(); #ifdef HHSETUP
CoUninitialize(); #endif
}
DWORD CCollection::Release() { if (m_dwRef == 0) return 0; m_dwRef--; return m_dwRef; }
void CCollection::DeleteChildren(CFolder **p) { if (!p || !(*p)) return;
CFolder *pChild, *pNext; if (pChild = (*p)->GetFirstChildFolder()) DeleteChildren(&pChild); pNext = (*p)->GetNextFolder(); delete (*p); *p = NULL; do { if (pNext) DeleteChildren(&pNext); } while (pNext && (pNext = pNext->GetNextFolder())); }
void CCollection::SetSampleLocation(const CHAR *sz) { if (!sz) return; Dirty(); AllocSetValue(sz, &m_szSampleLocation); }
CHAR *CCollection::GetSampleLocation() { return m_szSampleLocation; }
BOOL CCollection::GetMasterCHM(CHAR **szName, LANGID *pLang) { *pLang = m_MasterLangId; *szName = m_szMasterCHM; if (m_szMasterCHM == NULL) return FALSE; return ((strlen(m_szMasterCHM) ? TRUE : FALSE)); }
void CCollection::SetMasterCHM(const CHAR *sz, LANGID lang) { if (!sz) return; Dirty(); m_MasterLangId = lang; AllocSetValue(sz, &m_szMasterCHM); }
// Opens and loads the contents of the file into data structures
DWORD CCollection::Open(const CHAR * FileName) { DWORD dw; BOOL bOld = FALSE; BOOL bTryAgain = FALSE; if (m_pRootFolder == NULL) { m_pRootFolder = new CFolder; if (m_pRootFolder == NULL) return F_MEMORY; m_pParents[0] = m_pRootFolder; }
CHAR szBuffer[MAX_PATH]; const CHAR *sz = szBuffer; BOOL bNewPath; HHGetGlobalCollectionPathname(szBuffer, sizeof(szBuffer), &bNewPath);
dw = ParseFile(sz);
#ifdef HHCTRL // hhsetup should only be concerned about the good location for this file
if (dw == F_NOFILE && bNewPath) { // try windows dir for backward compatibity
try_again: bNewPath=FALSE; HHGetOldGlobalCollectionPathname(szBuffer, sizeof(szBuffer)); dw = ParseFile(sz); bOld = TRUE; } #endif
if (dw != F_OK && dw != F_NOFILE) return dw;
if (dw == F_NOFILE && m_bFailNoFile) return F_NOFILE;
// save the hhcolreg file and path for save calls...
strcpy(gszColReg, sz);
if (bNewPath && m_dwNextColNo < STARTINGCOLNO) m_dwNextColNo += STARTINGCOLNO;
if (FileName) dw = ParseFile(FileName);
if (dw != F_OK && dw != F_NOFILE) return dw;
if (dw == F_NOFILE && m_bFailNoFile) return F_NOFILE;
// now that we moved the file, if we did not get any titles found for the collection at runtime
// and we have not looked at the old hhcolreg location let try it.
#ifdef HHCTRL // runtime only, I really hate this
if (m_RefTitles.First() == NULL && bOld == FALSE && bTryAgain == FALSE) { Close(); ConfirmTitles(); m_bFailNoFile = TRUE; bTryAgain = TRUE; if (m_pRootFolder == NULL) { m_pRootFolder = new CFolder; if (m_pRootFolder == NULL) return F_MEMORY; m_pParents[0] = m_pRootFolder; } goto try_again; }
// did we find any titles that matched
if (m_RefTitles.First() == NULL) { return F_REFERENCED; } #endif
dw = AllocSetValue(FileName, &m_szFileName);
m_bDirty = FALSE;
CColList *pCol;
if ((pCol = FindCollection(m_szFileName)) == NULL) { // collection has never been added
pCol = AddCollection(); pCol->SetFileName(m_szFileName); #ifdef HHCTRL
if (m_dwColNo) pCol->SetColNo(m_dwColNo); else { pCol->SetColNo(m_dwNextColNo); m_dwNextColNo++; if (bNewPath && m_dwNextColNo < STARTINGCOLNO) m_dwNextColNo += STARTINGCOLNO; } #else
pCol->SetColNo(m_dwNextColNo); m_dwNextColNo++; if (bNewPath && m_dwNextColNo < STARTINGCOLNO) m_dwNextColNo += STARTINGCOLNO; #endif
m_bDirty = TRUE; } m_dwColNo = pCol->GetColNo();
return dw; }
CColList * CCollection::FindCollection(CHAR *szFileName) { CColList *p = m_pColListHead; while (p) { if (stricmp(p->GetFileName(), szFileName) == 0) return p; p = p->GetNext(); } return NULL; }
CColList * CCollection::AddCollection() {
CColList *newCol = new CColList; if (!newCol) { return NULL; }
if (m_pColListHead == NULL) { m_pColListHead = newCol; } else { m_pColListTail->SetNext(newCol); } m_pColListTail = newCol; return newCol; }
void CCollection::RemoveCollectionEntry(CHAR *szFileName) { CColList *p = m_pColListHead; CColList *pPrev = NULL; while (p) { if (stricmp(p->GetFileName(), szFileName) == 0) { if (pPrev) { pPrev->SetNext(p->GetNext()); } else { m_pColListHead = p->GetNext(); } if (m_pColListTail == p) m_pColListTail = pPrev; delete p; break; } pPrev = p; p = p->GetNext(); } }
DWORD CCollection::AllocCopyValue(CParseXML *parser, CHAR *token, CHAR **dest) { CHAR *sz;
if (!parser || !token || !dest) return F_NULL;
sz = parser->GetValue(token); if (*dest) delete [] *dest;
int len = (int)strlen(sz) + 1;
*dest = new CHAR[len]; if (*dest == NULL) return F_MEMORY;
strcpy(*dest, sz); return F_OK; }
DWORD CCollection::ParseFile(const CHAR *FileName) { CParseXML parser; CHAR *token; CHAR *sz; DWORD dw;
if (!FileName) return F_NULL;
if ((dw = parser.Start(FileName)) != F_OK) return dw;
for (token = parser.GetToken(); token;) { if (token[0] == '/') { dw = m_Strings.GetTail(&sz); if (dw != F_OK) { parser.End(); return dw; } if (strcmp(sz, &token[1]) != 0) { parser.End(); delete sz; return F_TAGMISSMATCH; } delete sz; if (strcmp(token, "/Folder") == 0) m_dwCurLevel--; token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "XML") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Collections") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Collection") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } if ((dw = HandleCollectionEntry(&parser, token)) != F_OK) { parser.End(); return dw; } continue; } else if (stricmp(parser.GetFirstWord(token), "HTMLHelpCollection") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } if ((dw = HandleCollection(&parser, token)) != F_OK) { parser.End(); return dw; } continue; } else if (stricmp(parser.GetFirstWord(token), "NextCollectionId") == 0) { m_dwNextColNo = atoi(parser.GetValue(token)); token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Folders") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Folder") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } if ((dw = HandleFolder(&parser, token)) != F_OK) { parser.End(); return dw; } continue; } else if (stricmp(parser.GetFirstWord(token), "HTMLHelpDocInfo") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Locations") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (stricmp(parser.GetFirstWord(token), "Location") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } if ((dw = HandleLocation(&parser, token)) != F_OK) { parser.End(); return dw; } continue; } else if (strcmp(parser.GetFirstWord(token), "DocCompilations") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); continue; } else if (strcmp(parser.GetFirstWord(token), "DocCompilation") == 0) { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } if ((dw = HandleTitle(&parser, token)) != F_OK) { parser.End(); return dw; } continue; } else { dw = m_Strings.AddTail(parser.GetFirstWord(token)); if (dw != F_OK) { parser.End(); return dw; } token = parser.GetToken(); } }
// make sure all tags have been popped
dw = F_OK; while (m_Strings.GetTail(&sz) == F_OK) { delete sz; dw = F_MISSINGENDTAG; } parser.End(); return dw; } DWORD CCollection::HandleCollectionEntry(CParseXML *parser, CHAR *token) { if (!parser || !token) return F_NULL;
CColList *newCol = AddCollection(); if (!newCol) { return F_MEMORY; }
while (TRUE) { token = parser->GetToken(); if (stricmp(parser->GetFirstWord(token), "colname") == 0) { newCol->SetFileName(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "colnum") == 0) { newCol->SetColNo( atoi(parser->GetValue(token))); } else break; } return F_OK; }
DWORD CCollection::HandleCollection(CParseXML *parser, CHAR *token) { if (!parser || !token) return F_NULL;
while (TRUE) { token = parser->GetToken(); if (stricmp(parser->GetFirstWord(token), "homepage") == 0) { // need to be backward compatable with this tag
} else if (stricmp(parser->GetFirstWord(token), "masterchm") == 0) { SetMasterCHM( parser->GetValue(token), ENGLANGID); } else if (stricmp(parser->GetFirstWord(token), "samplelocation") == 0) { SetSampleLocation( parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "masterlangid") == 0) { m_MasterLangId = (LANGID)atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "refcount") == 0) { m_dwRef = atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "version") == 0) { m_dwVersion = atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "showhomepage") == 0) { // need to be backward compatable with this tag
} else if (stricmp(parser->GetFirstWord(token), "findmergedchms") == 0) { m_bFindMergedChms = atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "CollectionNum") == 0) { m_dwColNo = atoi(parser->GetValue(token)); } else break; } return F_OK; }
DWORD CCollection::HandleFolder(CParseXML *parser, CHAR *token) { if (!parser || !token) return F_NULL; CFolder *newFolder = new CFolder; if (newFolder == NULL) return F_MEMORY;
m_dwCurLevel++; while (TRUE) { token = parser->GetToken();
if (stricmp(parser->GetFirstWord(token), "TitleString") == 0) { newFolder->SetTitle(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "FolderOrder") == 0) { newFolder->SetOrder(atoi(parser->GetValue(token))); } else if (stricmp(parser->GetFirstWord(token), "LangId") == 0) { newFolder->SetLanguage((LANGID)atoi(parser->GetValue(token))); } else break; }
CHAR *pTitle; pTitle = newFolder->GetTitle(); if (pTitle && pTitle[0] == '=') { if (CheckTitleRef(pTitle, newFolder->GetLanguage()) != F_OK) { delete newFolder; return F_OK; } AddRefedTitle(newFolder); }
m_pParents[m_dwCurLevel - 1]->AddChildFolder(newFolder); m_pParents[m_dwCurLevel] = newFolder;
return F_OK; }
DWORD CCollection::AddRefedTitle(CFolder *pFolder) { m_dwTitleRefCount++; m_RefTitles.Add(pFolder); return F_OK; }
DWORD CCollection::HandleLocation(CParseXML *parser, CHAR *token) { if (!parser || !token) return F_NULL; CLocation *newLocation = NewLocation();
if (newLocation == NULL) return F_MEMORY;
newLocation->m_ColNum = 0; while (TRUE) { token = parser->GetToken(); if (stricmp(parser->GetFirstWord(token), "LocName") == 0) { newLocation->SetId(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "TitleString") == 0) { newLocation->SetTitle(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "LocPath") == 0) { newLocation->SetPath(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "Volume") == 0) { newLocation->SetVolume(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "LocColNum") == 0) { newLocation->m_ColNum = atoi(parser->GetValue(token)); } else break; }
return F_OK; }
DWORD CCollection::HandleTitle(CParseXML *parser, CHAR *token) {
if (!parser || !token) return F_NULL;
LOCATIONHISTORY *pNew; CTitle *newTitle = NewTitle(); DWORD dw;
CHAR *pSampleLocation = NULL; BOOL bMerge = FALSE;
if (newTitle == NULL) return F_MEMORY;
while (TRUE) { token = parser->GetToken(); if (stricmp(parser->GetFirstWord(token), "DocCompId") == 0) { newTitle->SetId(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "TitleString") == 0) { // no longer do anything with titlestring but need to support for backward compatiblity
continue; } else if (stricmp(parser->GetFirstWord(token), "TitleSampleLocation") == 0) { if (newTitle->m_pTail == NULL) { // old style global.col, save this for the locations to follow
AllocCopyValue(parser, token, &pSampleLocation); } else if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->SampleLocation))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "DocCompLanguage") == 0) { newTitle->SetLanguage((LANGID)atoi(parser->GetValue(token))); } else if (stricmp(parser->GetFirstWord(token), "SupportsMerge") == 0) { if (newTitle->m_pTail == NULL) { // old style global.col, save this for the locations to follow
bMerge = (BOOL)atoi(parser->GetValue(token)); } else newTitle->m_pTail->bSupportsMerge = (BOOL)atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "LocationHistory") == 0) { pNew = newTitle->NewLocationHistory();
if (pNew == NULL) return F_MEMORY;
if (pSampleLocation) if ((dw = AllocSetValue(pSampleLocation, &(newTitle->m_pTail->SampleLocation))) != F_OK) return dw;
newTitle->m_pTail->bSupportsMerge = bMerge;
dw = m_Strings.AddTail(parser->GetFirstWord(token)); if (dw != F_OK) { return dw; } } else if (stricmp(parser->GetFirstWord(token), "/LocationHistory") == 0) { CHAR *sz; dw = m_Strings.GetTail(&sz); if (dw != F_OK) { return dw; }
if (strcmp(sz, &token[1]) != 0) { delete sz; return F_TAGMISSMATCH; } delete sz; } else if (stricmp(parser->GetFirstWord(token), "TitleLocation") == 0) { if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->FileName))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "QueryLocation") == 0) { if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->QueryFileName))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "TitleQueryLocation") == 0) { if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->QueryLocation))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "IndexLocation") == 0) { if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->IndexFileName))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "LocationRef") == 0) { if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->LocationId))) != F_OK) return dw; } else if (stricmp(parser->GetFirstWord(token), "Version") == 0) { newTitle->m_pTail->Version = atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "LastPromptedVersion") == 0) { newTitle->m_pTail->LastPromptedVersion = atoi(parser->GetValue(token)); } else if (stricmp(parser->GetFirstWord(token), "ColNum") == 0) { newTitle->m_pTail->CollectionNumber = atoi(parser->GetValue(token)); } else break; }
if (pSampleLocation) delete pSampleLocation;
return F_OK; }
// Saves any changes made to the internal data structures to the file.
DWORD CCollection::Save() { CHAR szBuffer[MAX_LINE_LEN]; DWORD dwWritten;
#ifdef HHSETUP // only hhsetup needs to rewrite the users .col file
// don't want the control to add any new tags to old
// collections, which would break uninstall and update
// if no root folders delete the collection file
if (m_bRemoved == TRUE) { DeleteFile(m_szFileName); m_bRemoved = FALSE; } else { if ((m_fh = CreateFile(m_szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) { return F_NOFILE; }
strcpy(szBuffer, "<XML>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// write out collection information
strcpy(szBuffer, "<HTMLHelpCollection>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<masterchm value=\"%s\"/>\r\n", (m_szMasterCHM ? m_szMasterCHM : "")); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<masterlangid value=%d/>\r\n", m_MasterLangId); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<samplelocation value=\"%s\"/>\r\n", (m_szSampleLocation ? m_szSampleLocation : "")); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<collectionnum value=%d/>\r\n", m_dwColNo); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<refcount value=%d/>\r\n", m_dwRef); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<version value=%d/>\r\n", m_dwVersion); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<findmergedchms value=%d/>\r\n", m_bFindMergedChms); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// write out folders
strcpy(szBuffer,"<Folders>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } m_dwCurLevel = 0;
if (WriteFolders(&m_pRootFolder) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// close tags
strcpy(szBuffer, "</Folders>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
strcpy(szBuffer, "</HTMLHelpCollection>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
strcpy(szBuffer, "</XML>\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
CloseHandle(m_fh); }
#endif
// save the global titles and locations
// open collection file
if ((m_fh = CreateFile(gszColReg, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) { return F_NOFILE; }
// write out XML tag
strcpy(szBuffer, "<XML>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
strcpy(szBuffer, "<HTMLHelpDocInfo>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
wsprintf(szBuffer, "<NextCollectionId value=%d/>\r\n", m_dwNextColNo); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// write out the collection list
strcpy(szBuffer, "<Collections>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
CColList *pCol = m_pColListHead;
while (pCol) { strcpy(szBuffer, "<Collection>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<ColNum value=%d/>\r\n", pCol->GetColNo()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<ColName value=\"%s\"/>\r\n", (pCol->GetFileName() ? pCol->GetFileName() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "</Collection>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
pCol = pCol->GetNext(); } strcpy(szBuffer, "</Collections>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// write out the locations
strcpy(szBuffer, "<Locations>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
CLocation *p = FirstLocation();
while (p) { strcpy(szBuffer, "<Location>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<LocColNum value=%d/>\r\n", p->m_ColNum); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<LocName value=\"%s\"/>\r\n", (p->GetId() ? p->GetId() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<TitleString value=\"%s\"/>\r\n", (p->GetTitle() ? p->GetTitle() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<LocPath value=\"%s\"/>\r\n", (p->GetPath() ? p->GetPath() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<Volume value=\"%s\"/>\r\n", (p->GetVolume() ? p->GetVolume() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "</Location>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
p = p->GetNextLocation(); } strcpy(szBuffer, "</Locations>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
// write out the titles
strcpy(szBuffer, "<DocCompilations>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
CTitle *pTitle = GetFirstTitle(); LOCATIONHISTORY *pHist; while (pTitle) { strcpy(szBuffer, "<DocCompilation>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<DocCompId value=\"%s\"/>\r\n", (pTitle->GetId() ? pTitle->GetId() : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t<DocCompLanguage value=%d/>\r\n", pTitle->GetLanguage()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; }
pHist = pTitle->m_pHead;
while (pHist) { strcpy(szBuffer, "\t<LocationHistory>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<ColNum value=%d/>\r\n", pHist->CollectionNumber); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<TitleLocation value=\"%s\"/>\r\n", (pHist->FileName ? pHist->FileName : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<IndexLocation value=\"%s\"/>\r\n", (pHist->IndexFileName ? pHist->IndexFileName : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<QueryLocation value=\"%s\"/>\r\n", (pHist->QueryFileName ? pHist->QueryFileName : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<LocationRef value=\"%s\"/>\r\n", (pHist->LocationId ? pHist->LocationId : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<Version value=%ld/>\r\n", pHist->Version); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<LastPromptedVersion value=%ld/>\r\n", pHist->LastPromptedVersion); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<TitleSampleLocation value=\"%s\"/>\r\n", (pHist->SampleLocation ? pHist->SampleLocation : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<TitleQueryLocation value=\"%s\"/>\r\n", (pHist->QueryLocation ? pHist->QueryLocation : "")); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t<SupportsMerge value=%d/>\r\n", pHist->bSupportsMerge); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\t</LocationHistory>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } pHist = pHist->pNext; } strcpy(szBuffer, "</DocCompilation>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } pTitle = pTitle->GetNextTitle(); }
strcpy(szBuffer, "</DocCompilations>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "</HTMLHelpDocInfo>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer,"</XML>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } if (CloseHandle(m_fh) == FALSE) return F_CLOSE;
// make sure we can open this file for read
if ((m_fh = CreateFile(gszColReg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) { return F_EXISTCHECK; }
if (CloseHandle(m_fh) == FALSE) return F_CLOSE;
return F_OK; }
BOOL CCollection::WriteFolders(CFolder **p) { BOOL b = TRUE; if (!p || !(*p)) return FALSE;
CFolder *pChild;
pChild = (*p)->GetFirstChildFolder();
if (pChild) b = WriteFolder(&pChild);
delete *p; *p = NULL; return b; }
BOOL CCollection::WriteFolder(CFolder **p) { if (!p || !(*p)) return FALSE;
CHAR szBuffer[MAX_LINE_LEN]; DWORD dwWritten;
CFolder *pChild, *pNext; DWORD i; // write this folder
// tab over the indent level
strcpy(szBuffer, "\t"); for (i = 0; i < m_dwCurLevel; i++) { if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } } strcpy(szBuffer, "<Folder>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; }
strcpy(szBuffer, "\t"); for (i = 0; i < m_dwCurLevel+1; i++) { if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } } wsprintf(szBuffer, "<TitleString value=\"%s\"/>\r\n", (*p)->GetTitle()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; }
strcpy(szBuffer, "\t"); for (i = 0; i < m_dwCurLevel+1; i++) { if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } }
wsprintf(szBuffer, "<FolderOrder value=%d/>\r\n", (*p)->GetOrder()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; }
CHAR *pTitle = (*p)->GetTitle(); if (pTitle[0] == '=') { strcpy(szBuffer, "\t"); for (i = 0; i < m_dwCurLevel+1; i++) { if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } } wsprintf(szBuffer, "<LangId value=%d/>\r\n", (*p)->GetLanguage()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } }
m_dwCurLevel++; if (pChild = (*p)->GetFirstChildFolder()) { if (WriteFolder(&pChild) == FALSE) return FALSE; } if (m_dwCurLevel) m_dwCurLevel--;
strcpy(szBuffer, "\t"); for (i = 0; i < m_dwCurLevel; i++) { if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; } } strcpy(szBuffer, "</Folder>\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { return FALSE; }
pNext = (*p)->GetNextFolder(); delete (*p); *p = NULL; do { if (pNext) { if (WriteFolder(&pNext) == FALSE) return FALSE; } } while (pNext && (pNext = pNext->GetNextFolder())); return TRUE; }
DWORD CCollection::Close() { m_locationnum = 0; gszColReg[0] = NULL; m_dwNextColNo = 1; m_dwColNo = 0; m_dwTitleRefCount = 0; m_dwRef = 0; m_dwVersion = 0; for (int i = 0; i < MAX_LEVELS; i++) m_pParents[i] = NULL; m_dwCurLevel = 0; m_dwLastLevel = 0; m_bConfirmTitles = FALSE; m_MasterLangId = ENGLANGID; m_bFindMergedChms = FALSE; m_Strings.RemoveAll();
if (m_szFileName) { delete m_szFileName; m_szFileName = NULL; }
if (m_pwcFileName) { delete m_pwcFileName; m_pwcFileName = NULL; }
if (m_szMasterCHM) { delete m_szMasterCHM; m_szMasterCHM = NULL; }
if (m_pwcMasterCHM) { delete m_pwcMasterCHM; m_pwcMasterCHM = NULL; }
if (m_szSampleLocation) { delete m_szSampleLocation; m_szSampleLocation = NULL; }
// clean up col list
CColList *pCol, *pColNext; for (pCol = m_pColListHead; pCol; pCol = pColNext) { pColNext = pCol->GetNext(); delete pCol; }
m_pColListHead = NULL; m_pColListTail = NULL;
// clean up locations
CLocation *p, *pNext; for (p = m_pFirstLocation; p; p=pNext) { pNext = p->GetNextLocation(); delete p; }
m_pFirstLocation=NULL; m_pLocationTail = NULL; // clean up titles
CTitle *pTitle, *pNextTitle; for (pTitle = m_pFirstTitle; pTitle; pTitle=pNextTitle) { pNextTitle = pTitle->GetNextTitle(); delete pTitle; }
m_pFirstTitle = NULL; m_pTitleTail = NULL; // clean up folder
if (m_pRootFolder) { DeleteChildren(&m_pRootFolder); } m_pRootFolder = NULL; return F_OK; }
// Returns the first title
CTitle * CCollection::GetFirstTitle() { return m_pFirstTitle; }
// Locates a title based on id
CTitle * CCollection::FindTitle(const CHAR * Id, LANGID LangId) { if (!Id) return NULL;
CTitle *p;
p = m_pFirstTitle;
while (p) { if (stricmp(p->GetId(), Id) == 0 && (LangId == 0 || p->GetLanguage() == LangId)) // Ignore LangId if its zero.
{ return p; } p = p->GetNextTitle(); } return NULL; }
#ifdef HHCTRL
// Try multiple LangIds before failing
CTitle * CCollection::FindTitleNonExact(const CHAR * Id, LANGID DesiredLangId) { CTitle* pTitle = NULL ;
CLanguageEnum* pEnum = _Module.m_Language.GetEnumerator(DesiredLangId) ; ASSERT(pEnum) ; LANGID langid = pEnum->start() ; while (langid != c_LANGID_ENUM_EOF) { pTitle = FindTitle(Id, langid); if (pTitle) { break ; //Found It!
}
langid = pEnum->next() ; }
// Cleanup.
if (pEnum) { delete pEnum ; }
return pTitle; } #endif // #ifdef HHCTRL
// Returns the first location
CLocation* CCollection::FirstLocation() { return m_pFirstLocation; }
// Finds a location based on a name
CLocation * CCollection::FindLocation(const CHAR * Id, UINT* puiVolumeOrder ) { if (!Id) return NULL;
CLocation *p;
p = m_pFirstLocation;
if( puiVolumeOrder ) *puiVolumeOrder = 0;
while (p) { if( puiVolumeOrder ) *puiVolumeOrder = (*puiVolumeOrder)+1;
if (stricmp(p->GetId(), Id) == 0 && (p->m_ColNum == m_dwColNo|| p->m_ColNum == 0)) return p; p = p->GetNextLocation(); } return NULL; }
DWORD CCollection::CheckTitleRef(const CHAR *pId, const LANGID Lang) { if (m_bConfirmTitles == FALSE) return F_OK;
if (pId[0] != '=') return F_OK;
CTitle *pTitle; if ((pTitle = FindTitle(&pId[1], Lang)) == NULL) return F_NOTITLE;
LOCATIONHISTORY *p;
p = pTitle->m_pHead;
while (p) { if (p->CollectionNumber == GetColNo()) return F_OK; p = p->pNext; }
return F_NOTITLE; }
//Adds a new folder to the top level of the table of contents, with the given name and order and returns a pointer to that folder object. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
CFolder * CCollection::AddFolder(const CHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId) { if (!szName) { if (pDWORD) *pDWORD = F_NULL; return NULL; }
if (CheckTitleRef(szName, LangId) != F_OK) { if (pDWORD) *pDWORD = F_NOTITLE; return NULL; }
CFolder *pNew;
pNew = new CFolder;
DWORD dwrc = F_OK;
if (pNew) { pNew->SetTitle(szName); pNew->SetOrder(Order); pNew->SetLanguage(LangId); dwrc = m_pRootFolder->AddChildFolder(pNew);
if (dwrc != F_OK) { if (pDWORD) *pDWORD = dwrc; delete pNew; return NULL; }
Dirty(); return pNew; }
if (pDWORD) *pDWORD = F_MEMORY; return NULL; }
CTitle * CCollection::NewTitle() { CTitle *newTitle = new CTitle; if (newTitle == NULL) return NULL;
if (m_pFirstTitle == NULL) { m_pFirstTitle = newTitle; } else { m_pTitleTail->SetNextTitle(newTitle); } m_pTitleTail = newTitle;
return newTitle; }
// Adds a title based on the provided information. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
// Note: you must add or find a CLocation object or pass null to indication no location is in use (local file).
CTitle * CCollection::AddTitle(const CHAR * Id, const CHAR * FileName, const CHAR * IndexFile, const CHAR * Query, const CHAR *SampleLocation, LANGID Lang, UINT uiFlags, CLocation *pLocation, DWORD *pDWORD, BOOL bSupportsMerge, const CHAR *QueryLocation) { if (!Id || !FileName || !IndexFile) return NULL; DWORD dwrc;
CTitle *pTitle;
// check if the title exist
if (pTitle = FindTitle(Id, Lang)) { // add location
dwrc = pTitle->AddLocationHistory(m_dwColNo, FileName, IndexFile, Query, pLocation, SampleLocation, QueryLocation, bSupportsMerge); if (pDWORD) *pDWORD = dwrc; } else { // just add the title then
pTitle = NewTitle(); if (pTitle == NULL) { if (pDWORD) *pDWORD = F_MEMORY; return NULL; } pTitle->SetId(Id); pTitle->SetLanguage(Lang); dwrc = pTitle->AddLocationHistory(m_dwColNo, FileName, IndexFile, Query, pLocation, SampleLocation, QueryLocation, bSupportsMerge); if (pDWORD) *pDWORD = dwrc; } Dirty(); return pTitle; }
CLocation * CCollection::NewLocation() { CLocation *p = new CLocation; if (!p) { return NULL; } if (m_pFirstLocation == NULL) { m_pFirstLocation = p; } else { m_pLocationTail->SetNextLocation(p); } m_pLocationTail = p; return p; }
// Adds location based on the given information. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
CLocation * CCollection::AddLocation(const CHAR * Title, const CHAR * Path, const CHAR * Id, const CHAR * Volume, DWORD *pDWORD) { if (!Title || !Path || !Id || !Volume) return NULL;
CLocation *p;
p = FindLocation(Id);
// if not found then add new location entry
if (!p) p = NewLocation();
if (!p) { if (pDWORD) *pDWORD = F_MEMORY; return NULL; }
p->SetTitle(Title); p->SetPath(Path); p->SetId(Id); p->SetVolume(Volume); p->m_ColNum = m_dwColNo; if (pDWORD) *pDWORD = F_OK; Dirty(); return p; }
// removing objects
DWORD CCollection::DeleteFolder(CFolder *pDelete) {
if (!pDelete) return F_NULL;
CFolder *pParent; CFolder *pPrev = NULL; CFolder *p;
if ((pParent = pDelete->GetParent()) == NULL) return F_NOPARENT;
p = pParent->GetFirstChildFolder();
while (p) { if (p == pDelete) { // is this the head
if (!pPrev) { pParent->SetFirstChildFolder(p->GetNextFolder()); } else { // fixup the list
pPrev->SetNextFolder(p->GetNextFolder()); }
DeleteChildren(&pDelete); Dirty(); return F_OK;
} pPrev = p; p = p->GetNextFolder(); }
return F_NOTFOUND; }
DWORD CCollection::DeleteTitle(CTitle *pDelete) { if (!pDelete) return F_NULL; // remove all location history entries for this collection
LOCATIONHISTORY *pHist, *pHistPrev; pHistPrev = NULL; pHist = pDelete->m_pHead;
while (pHist) { if (pHist->CollectionNumber == m_dwColNo) { // head
if (pHist == pDelete->m_pHead) { // and tail
if (pHist == pDelete->m_pTail) { pDelete->m_pHead = NULL; pDelete->m_pTail = NULL; DeleteLocalFiles(pHist, pDelete); delete pHist; break; } pDelete->m_pHead = pHist->pNext; DeleteLocalFiles(pHist, pDelete); delete pHist; pHist = pDelete->m_pHead; pHistPrev = NULL; continue; }
// tail
if (pHist == pDelete->m_pTail) { pDelete->m_pTail = pHistPrev; if (pHistPrev) pHistPrev->pNext = NULL; DeleteLocalFiles(pHist, pDelete); delete pHist; break; }
pHistPrev->pNext = pHist->pNext; DeleteLocalFiles(pHist, pDelete); delete pHist; pHist = pHistPrev->pNext; } else { pHistPrev = pHist; pHist = pHist->pNext; } } Dirty();
// if no history remains remove the title
if (pDelete->m_pHead != NULL) return F_OK;
CTitle *p, *pPrev;
p = m_pFirstTitle; pPrev = NULL;
if (p== NULL) return F_NOTFOUND;
while (p) { if (p == pDelete) { // is this the head
if (!pPrev) { m_pFirstTitle = p->GetNextTitle(); } // is this the tail
else if (p == m_pTitleTail) { m_pTitleTail = pPrev; pPrev->SetNextTitle(p->GetNextTitle()); } else { // fixup the list
pPrev->SetNextTitle(p->GetNextTitle()); }
delete p; return F_OK; } pPrev = p; p = p->GetNextTitle(); } return F_NOTFOUND; }
void CCollection::DeleteLocalFiles(LOCATIONHISTORY *pThisHist, CTitle *pTitle) { if (m_bRemoveLocalFiles == FALSE) return;
LOCATIONHISTORY *pHist; pHist = pTitle->m_pHead;
// if the chm or chi is in use don't delete
while (pHist) { if (strcmp(pHist->FileName, pThisHist->FileName) == 0) return; if (strcmp(pHist->IndexFileName, pThisHist->IndexFileName) == 0) return; pHist = pHist->pNext; }
// if these are local files delete them
char drive[_MAX_DRIVE+1]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT];
_splitpath( pThisHist->FileName, drive, dir, fname, ext );
if(drive[1] == ':') { drive[2] = '\\'; drive[3] = 0; }
if (GetDriveType(drive) == DRIVE_FIXED) { // delete the title
if (DeleteFile(pThisHist->FileName) == FALSE) m_bAllFilesDeleted = FALSE; // could need to check for and delete samples stuff here
}
// if files are different
if (strcmp(pThisHist->IndexFileName, pThisHist->FileName)) { _splitpath( pThisHist->IndexFileName, drive, dir, fname, ext );
if(drive[1] == ':') { drive[2] = '\\'; drive[3] = 0; }
if (GetDriveType(drive) == DRIVE_FIXED) { // delete the index
if (DeleteFile(pThisHist->IndexFileName) == FALSE) m_bAllFilesDeleted = FALSE; // could need to check for and delete samples stuff here
} } }
// only used from HHSETUP
LANGID CCollection::GetLangId(const CHAR *szFileName) { #ifdef HHSETUP
return ::GetLangId(szFileName); #else
return 0; #endif
}
DWORD CCollection::DeleteLocation(CLocation *pDelete) { if (!pDelete) return F_NULL; CLocation *p, *pPrev;
p = m_pFirstLocation; pPrev = NULL;
if (p== NULL) return F_NOTFOUND;
while (p) { if (p == pDelete) { // is this the head
if (!pPrev) { m_pFirstLocation = p->GetNextLocation(); } // is this the tail
else if (p == m_pLocationTail) { m_pLocationTail = pPrev; pPrev->SetNextLocation(NULL); } else { // fixup the list
pPrev->SetNextLocation(p->GetNextLocation()); }
delete p; Dirty(); return F_OK; } pPrev = p; p = p->GetNextLocation(); } return F_NOTFOUND; }
DWORD CCollection::RemoveCollection(BOOL bRemoveLocalFiles) { // if release returns a positive ref count then don't delete
if (Release()) return F_OK;
m_bRemoveLocalFiles = bRemoveLocalFiles; m_bAllFilesDeleted = TRUE; m_bRemoved = TRUE;
CTitle *pT = GetFirstTitle(); CTitle *pNext; while (pT) { pNext = pT->GetNextTitle(); DeleteTitle(pT); pT = pNext; }
// delete locations for this collection
CLocation *pL = FirstLocation(); CLocation *pNextLoc;
while (pL) { pNextLoc = pL->GetNextLocation(); if (pL->m_ColNum == m_dwColNo) DeleteLocation(pL); pL = pNextLoc; } RemoveCollectionEntry(m_szFileName);
Dirty(); if (m_bRemoveLocalFiles == TRUE && m_bAllFilesDeleted == FALSE) return F_DELETE; return F_OK; }
void CCollection::DeleteFolders(CFolder **p) { CFolder *pChild, *pNext; if (pChild = (*p)->GetFirstChildFolder()) DeleteFolders(&pChild); pNext = (*p)->GetNextFolder();
// check if this is a title
const CHAR *pTitle = (*p)->GetTitle();
if (pTitle && pTitle[0] == '=') // if so delete it.
{ CTitle *pT;
pT = FindTitle(&pTitle[1], (*p)->GetLanguage()); if (pT) DeleteTitle(pT); }
delete (*p); *p = NULL; do { if (pNext) DeleteFolders(&pNext); } while (pNext && (pNext = pNext->GetNextFolder())); }
// Merges the currently installed titles for the collection into the specified filename (path determined internally)
BOOL CCollection::MergeKeywords(CHAR * pwzFilename ) { return FALSE; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CFolder implementation
CFolder::CFolder() { Title = NULL; pwcTitle = NULL; Order = 0; LangId = ENGLANGID; pNext = NULL; pKid = NULL; pParent = NULL; iLevel = 0; f_HasHash = 0; f_IsOrphan = 1; // Assume the worst.
}
CFolder::~CFolder() { if (Title) delete Title; if(pwcTitle) delete pwcTitle; }
void CFolder::SetTitle(const CHAR *sz) { AllocSetValue(sz, &Title); }
void CFolder::SetExTitlePtr(CExTitle* pTitle) { CFolder* pTmp;
pExTitle = pTitle; f_IsOrphan = 0;
pTmp = pParent; while ( pTmp ) { pTmp->f_IsOrphan = 0; pTmp = pTmp->pParent; } }
void CFolder::SetOrder(DWORD newOrder) { Order = newOrder; }
DWORD CFolder::GetOrder() { return Order; }
// Returns the next sibling folder given a folder entry
CFolder * CFolder::GetNextFolder() { return pNext; }
// Returns the first child of a given folder if it exists
CFolder * CFolder::GetFirstChildFolder() { return pKid; }
CFolder * CFolder::AddChildFolder(const CHAR *szName, DWORD Order, DWORD *pError, LANGID LangId) { CFolder *pFolder = new CFolder;
if (pFolder == NULL) return NULL;
pFolder->SetTitle(szName); pFolder->SetOrder(Order); pFolder->SetLanguage(LangId);
DWORD dwrc = AddChildFolder(pFolder); if (pError) *pError = dwrc; return pFolder; }
DWORD CFolder::AddChildFolder(CFolder *newFolder) { CFolder* pTmp; newFolder->SetParent(this); if (pKid == NULL) { pKid = newFolder; } else { if (newFolder->GetOrder() < pKid->GetOrder()) { // make this the first child
newFolder->pNext = pKid; pKid = newFolder; } else { // search for an insertion point
CFolder *pNext = pKid->pNext; CFolder *pPrev = pKid; while (pNext) { if (newFolder->GetOrder() < pNext->GetOrder()) { newFolder->pNext = pNext; break; } pPrev = pNext; pNext = pNext->pNext; } pPrev->pNext = newFolder; } } //
// Setup members to facilitate subsetting...
//
if ( newFolder->Title && newFolder->Title[0] == '=' ) { newFolder->f_HasHash = 1; //
// Leaf nodes will be rendered as open books in the subset dialog.
//
newFolder->f_A_Open = 1; newFolder->f_F_Open = 1; } pTmp = newFolder->pParent; while ( pTmp ) { newFolder->iLevel++; pTmp = pTmp->pParent; } newFolder->iLevel--; return F_OK; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CTitle implementation
void CTitle::SetId(const CHAR *sz) { AllocSetValue(sz, &Id); }
void CTitle::SetLanguage(LANGID l) { Language = l; }
CHAR *CTitle::GetId() { return Id; }
LANGID CTitle::GetLanguage() { return Language; }
LOCATIONHISTORY *CTitle::NewLocationHistory() { LOCATIONHISTORY *p;
p = new LOCATIONHISTORY;
if (p == NULL) return NULL;
p->SampleLocation = NULL; p->QueryLocation = NULL; p->FileName = NULL; p->IndexFileName = NULL; p->QueryFileName = NULL; p->LocationId = NULL; p->Version = 0; p->LastPromptedVersion = 0; p->bSupportsMerge = FALSE; p->pNext = NULL;
if (m_pHead == NULL) { m_pHead = p; } else { m_pTail->pNext = p; } m_pTail = p;
return p; }
DWORD CTitle::AddLocationHistory(DWORD ColNo, const CHAR *FileName, const CHAR *IndexFile, const CHAR *Query, const CLocation *pLocation, const CHAR *SampleLocation, const CHAR *QueryLocation, BOOL bSupportsMerge) { LOCATIONHISTORY *p; // get version information
DWORD dwNewVersion; #ifdef HHSETUP
if (IndexFile) dwNewVersion = GetTitleVersion(IndexFile); else if (FileName) dwNewVersion = GetTitleVersion(FileName); else dwNewVersion = 0; #else
dwNewVersion = 0; #endif
// see of any current entries match is new one if so update the existing item.
if (m_pHead) { p = m_pHead;
while (p) { if (p->CollectionNumber == ColNo && ((FileName == NULL && p->FileName[0] == NULL) || (FileName &&strcmp(p->FileName, FileName) == 0)) && ((IndexFile == NULL && p->IndexFileName[0] == NULL) || (IndexFile &&strcmp(p->IndexFileName, IndexFile) == 0)) && ((Query == NULL && p->QueryFileName[0] == NULL) || (Query &&strcmp(p->QueryFileName, Query) == 0)) && ((SampleLocation == NULL && p->SampleLocation[0] == NULL) || (SampleLocation &&strcmp(p->SampleLocation, SampleLocation) == 0)) && ((QueryLocation == NULL && p->QueryLocation[0] == NULL) || (QueryLocation &&strcmp(p->QueryLocation, QueryLocation) == 0)) && p->bSupportsMerge == bSupportsMerge) { if (pLocation && strcmp(pLocation->GetId(), p->LocationId) != 0) { p = p->pNext; continue; } // everything matches just update the version number
p->Version = dwNewVersion; return F_OK; } p = p->pNext; } }
// see if we already have this version if so update to location
if (m_pHead) { p = m_pHead;
while (p) { if (p->Version == dwNewVersion && p->CollectionNumber == ColNo) { // same version update location
p->bSupportsMerge = bSupportsMerge; if (FileName) AllocSetValue(FileName, &p->FileName); else p->FileName = NULL;
if (IndexFile) AllocSetValue(IndexFile, &p->IndexFileName); else p->IndexFileName = NULL;
if (SampleLocation) AllocSetValue(SampleLocation, &p->SampleLocation); else p->SampleLocation = NULL;
if (QueryLocation) AllocSetValue(QueryLocation, &p->QueryLocation); else p->QueryLocation = NULL;
if (Query) AllocSetValue(Query, &p->QueryFileName); else p->QueryFileName = NULL;
if (pLocation) AllocSetValue(pLocation->GetId() , &p->LocationId); else p->LocationId = NULL;
return F_OK; } p = p->pNext; } }
p = NewLocationHistory();
if (p == NULL) return F_MEMORY;
p->Version = dwNewVersion; p->CollectionNumber = ColNo; p->bSupportsMerge = bSupportsMerge; if (FileName) AllocSetValue(FileName, &p->FileName); if (IndexFile) AllocSetValue(IndexFile, &p->IndexFileName); if (SampleLocation) AllocSetValue(SampleLocation, &p->SampleLocation); if (QueryLocation) AllocSetValue(QueryLocation, &p->QueryLocation); else AllocSetValue("", &p->QueryLocation);
if (Query) AllocSetValue(Query, &p->QueryFileName); else AllocSetValue("", &p->QueryFileName); if (pLocation) AllocSetValue(pLocation->GetId() , &p->LocationId);
return F_OK; }
LOCATIONHISTORY * CTitle::GetLocation(DWORD Index) { LOCATIONHISTORY *p;
p = m_pHead; for (DWORD i = 0; p && i < Index; i++) p++;
return p; }
CTitle* CTitle::GetNextTitle() { return NextTitle; }
CTitle::~CTitle() { if (Id) delete Id; if (pwcId) delete pwcId;
// clean up location history
LOCATIONHISTORY *p, *pNext; for (p = m_pHead; p; p=pNext) { pNext = p->pNext; if (p->FileName) delete p->FileName; if (p->IndexFileName) delete p->IndexFileName; if (p->QueryFileName) delete p->QueryFileName; if (p->LocationId) delete p->LocationId; if (p->SampleLocation) delete p->SampleLocation; if (p->QueryLocation) delete p->QueryLocation; delete p; } }
CTitle::CTitle() { Id = NULL; pwcId = NULL; Language = 0; NextTitle = NULL; m_pHead = NULL; m_pTail = NULL; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLocation implementation
// BUGBUG: 29-May-1997 [ralphw] This is a lot of code overhead to call
// functions that do nothing but return a value or exectue a single line
// of code. These should all be inlined, at least for the OCX version
// to cut down code size.
void CLocation::SetId(const CHAR *sz) { AllocSetValue(sz, &Id); }
void CLocation::SetTitle(const CHAR *sz) { AllocSetValue(sz, &Title); }
void CLocation::SetPath(const CHAR *sz) { AllocSetValue(sz, &Path); }
void CLocation::SetVolume(const CHAR *sz) { AllocSetValue(sz, &Volume); }
CHAR * CLocation::GetId() const { return Id; }
CHAR * CLocation::GetTitle() { return Title; }
CHAR * CLocation::GetPath() { return Path; }
CHAR * CLocation::GetVolume() { return Volume; }
// Returns the next location
CLocation * CLocation::GetNextLocation() { return NextLocation; }
// UNICODE APIs /////////////////////////////////////////////////////////////////////////////////////////////////
//
void CFolder::SetTitle(const WCHAR *pTitle) { CAnsi cszTemp((WCHAR *)pTitle); SetTitle((char *)cszTemp); }
const WCHAR * CFolder::GetTitleW() { if(pwcTitle) delete [] pwcTitle;
pwcTitle = CreateUnicodeFromAnsi(Title);
return pwcTitle; }
CFolder * CFolder::AddChildFolder(const WCHAR *szName, DWORD Order, DWORD *pError, LANGID LangId) { CAnsi cszTemp1((WCHAR *)szName); return AddChildFolder((CHAR *)cszTemp1,Order,pError,LangId); }
const WCHAR * CTitle::GetIdW() { if(pwcId) delete [] pwcId;
pwcId = CreateUnicodeFromAnsi(Id);
return pwcId; }
void CTitle::SetId(const WCHAR *pszId) { CAnsi cszTemp1((WCHAR *)pszId); SetId((CHAR *)cszTemp1); }
DWORD CTitle::AddLocationHistory(DWORD ColNo, const WCHAR *FileName, const WCHAR *IndexFile, const WCHAR *Query, const CLocation *pLocation, const WCHAR *Sample, const WCHAR *QueryLocation, BOOL bSupportsMerge) { CAnsi cszTemp1((WCHAR *)FileName); CAnsi cszTemp2((WCHAR *)IndexFile); CAnsi cszTemp3((WCHAR *)Query); CAnsi cszTemp4((WCHAR *)Sample); CAnsi cszTemp5((WCHAR *)QueryLocation); return AddLocationHistory(ColNo, (CHAR *)cszTemp1, (CHAR *)cszTemp2, (CHAR *)cszTemp3, pLocation, (CHAR *)cszTemp4, (CHAR *)cszTemp5, bSupportsMerge); }
void CLocation::SetId(const WCHAR *pwcTemp) { CAnsi cszTemp1((WCHAR *)pwcTemp); SetId((CHAR *)cszTemp1); }
void CLocation::SetTitle(const WCHAR *pwcTemp) { CAnsi cszTemp1((WCHAR *)pwcTemp); SetTitle((CHAR *)cszTemp1); }
void CLocation::SetPath(const WCHAR *pwcTemp) { CAnsi cszTemp1((WCHAR *)pwcTemp); SetPath((CHAR *)cszTemp1); }
void CLocation::SetVolume(const WCHAR *pwcTemp) { CAnsi cszTemp1((WCHAR *)pwcTemp); SetVolume((CHAR *)cszTemp1); }
const WCHAR * CLocation::GetIdW() { if(pwcId) delete [] pwcId;
pwcId = CreateUnicodeFromAnsi(Id);
return pwcId; }
const WCHAR * CLocation::GetTitleW() { if(pwcTitle) delete [] pwcTitle;
pwcTitle = CreateUnicodeFromAnsi(Title);
return pwcTitle; }
const WCHAR * CLocation::GetPathW() { if(pwcPath) delete [] pwcPath;
pwcPath = CreateUnicodeFromAnsi(Path);
return pwcPath; }
const WCHAR * CLocation::GetVolumeW() { if(pwcVolume) delete [] pwcVolume;
pwcVolume = CreateUnicodeFromAnsi(Volume);
return pwcVolume; }
DWORD CCollection::CheckTitleRef(const WCHAR *pId, const LANGID Lang) { CAnsi cszTemp1((WCHAR *)pId); return CheckTitleRef(cszTemp1, Lang); }
void CCollection::SetSampleLocation(const WCHAR *pwcItem1) { CAnsi cszTemp1((WCHAR *)pwcItem1); SetSampleLocation(cszTemp1); }
const WCHAR * CCollection::GetSampleLocationW() { if(m_pwcSampleLocation) delete [] m_pwcSampleLocation;
m_pwcSampleLocation = CreateUnicodeFromAnsi(m_szSampleLocation);
return m_pwcSampleLocation; }
void CCollection::SetMasterCHM(const WCHAR *szName, LANGID Lang) { CAnsi cszTemp1((WCHAR *)szName); SetMasterCHM(cszTemp1, Lang); }
BOOL CCollection::GetMasterCHM(WCHAR ** szName, LANGID *pLang) { *pLang = m_MasterLangId; *szName = NULL; if (m_szMasterCHM == NULL) return FALSE;
if(m_pwcMasterCHM) delete [] m_pwcMasterCHM;
m_pwcMasterCHM = CreateUnicodeFromAnsi(m_szMasterCHM);
*szName = m_pwcMasterCHM;
return ((strlen(m_szMasterCHM) ? TRUE : FALSE)); }
DWORD CCollection::Open(const WCHAR * FileName) { CAnsi cszTemp1((WCHAR *)FileName); return Open(cszTemp1); }
CTitle * CCollection::FindTitle(const WCHAR * Id, LANGID LangId) { CAnsi cszTemp1((WCHAR *)Id); return FindTitle(cszTemp1, LangId); }
CLocation * CCollection::FindLocation(const WCHAR * Name, UINT* puiVolumeOrder) { CAnsi cszTemp1((WCHAR *)Name); return FindLocation(cszTemp1,puiVolumeOrder); }
CFolder * CCollection::AddFolder(const WCHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId) { CAnsi cszTemp1((WCHAR *)szName); return AddFolder(cszTemp1, Order, pDWORD, LangId); }
CTitle * CCollection::AddTitle(const WCHAR * Id, const WCHAR * FileName, const WCHAR * IndexFile, const WCHAR * Query, const WCHAR *SampleLocation, LANGID Lang, UINT uiFlags, CLocation *pLocation, DWORD *pDWORD, BOOL bSupportsMerge, const WCHAR *QueryLocation) { CAnsi cszTemp1((WCHAR *)Id); CAnsi cszTemp2((WCHAR *)FileName); CAnsi cszTemp3((WCHAR *)IndexFile); CAnsi cszTemp4((WCHAR *)Query); CAnsi cszTemp5((WCHAR *)SampleLocation); CAnsi cszTemp6((WCHAR *)QueryLocation); return AddTitle(cszTemp1, cszTemp2, cszTemp3, cszTemp4,cszTemp5, Lang, uiFlags, pLocation, pDWORD, bSupportsMerge, cszTemp6); }
CLocation * CCollection::AddLocation(const WCHAR * Title, const WCHAR * Path, const WCHAR * Id, const WCHAR * Volume, DWORD *pDWORD) { CAnsi cszTemp1((WCHAR *)Title); CAnsi cszTemp2((WCHAR *)Path); CAnsi cszTemp3((WCHAR *)Id); CAnsi cszTemp4((WCHAR *)Volume); return AddLocation(cszTemp1, cszTemp2,cszTemp3,cszTemp4,pDWORD); }
BOOL CCollection::MergeKeywords(WCHAR * pwzFilename ) { CAnsi cszTemp1((WCHAR *)pwzFilename); return MergeKeywords(cszTemp1); }
const WCHAR *CCollection::GetCollectionFileNameW(void) { if(m_pwcFileName) delete [] m_pwcFileName;
m_pwcFileName = CreateUnicodeFromAnsi(m_szFileName);
return m_pwcFileName; }
LANGID CCollection::GetLangId(const WCHAR *FileName) { CAnsi cszTemp1((WCHAR *)FileName); return GetLangId(cszTemp1); }
WCHAR *CreateUnicodeFromAnsi(LPSTR psz) { LPWSTR pwsz; int i;
if(!psz) return NULL;
i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); if (i <= 0) return NULL;
pwsz = (LPWSTR) new WCHAR[i];
if (!pwsz) return NULL;
MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i * sizeof(WCHAR)); return pwsz; }
CAnsi::CAnsi(WCHAR *pwcString) { m_pszChar = NULL;
int i;
i = WideCharToMultiByte(CP_ACP, 0, pwcString, -1, NULL, 0, NULL, NULL);
if (i <= 0) return;
m_pszChar = (CHAR *) new CHAR[i];
WideCharToMultiByte(CP_ACP, 0, pwcString, -1, m_pszChar, i, NULL, NULL); m_pszChar[i - 1] = 0; }
CAnsi::~CAnsi() { if(m_pszChar) delete [] m_pszChar; }
#ifdef HHCTRL
//
// CSlotLookupTable implementation...
//
int FASTCALL CSlotLookupTable::ltqs_callback(const void *elem1, const void *elem2) { struct _slt* p1 = (struct _slt*)elem1; struct _slt* p2 = (struct _slt*)elem2;
if ( p1->hash > p2->hash ) return 1; else if ( p2->hash > p1->hash ) return -1; else return 1; }
CSlotLookupTable::CSlotLookupTable() { m_pSLT = NULL; m_uiTotalCnt = m_uiHashCnt = m_uiTotalAllocated = 0; }
CSlotLookupTable::~CSlotLookupTable() { if ( m_pSLT ) lcFree(m_pSLT); }
void CSlotLookupTable::AddValue(CFolder* pFolder) { if ( (m_uiTotalCnt && (!(m_uiTotalCnt % 8))) || (m_uiTotalAllocated == 0) ) { m_uiTotalAllocated += 8; m_pSLT = (struct _slt*)lcReAlloc(m_pSLT, sizeof(struct _slt) * m_uiTotalAllocated); } m_pSLT[m_uiTotalCnt].pCFolder = pFolder; if ( pFolder->f_HasHash ) { m_pSLT[m_uiTotalCnt].hash = pFolder->pExTitle->m_dwHash; m_uiHashCnt++; } else m_pSLT[m_uiTotalCnt].hash = (unsigned)(-1); m_uiTotalCnt++; }
void CSlotLookupTable::SortAndAssignSlots(void) { unsigned i;
// First, sort by hash.
//
qsort(m_pSLT, m_uiTotalCnt, sizeof(struct _slt), ltqs_callback); //
// Next, run through the table and assign the slots back to the CFolders.
//
for (i = 0; i < m_uiTotalCnt; i++) m_pSLT[i].pCFolder->dwSlot = i; }
CFolder* CSlotLookupTable::HashToCFolder(HASH hash) { if (! m_pSLT ) return NULL;
int mid,low = 0; int high = m_uiHashCnt - 1;
while ( low <= high ) { mid = ((low + high) / 2); if ( m_pSLT[mid].hash == hash ) return m_pSLT[mid].pCFolder; // Found it!
else if ( m_pSLT[mid].hash > hash ) high = mid - 1; else low = mid + 1; } return NULL; // Oh bad!
}
#endif
|