//********************************************************************************************************************************************* // // 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, "\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\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, "\r\n", m_MasterLangId); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\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, "\r\n", m_dwColNo); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\r\n", m_dwRef); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\r\n", m_dwVersion); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\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,"\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\r\n"); if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\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, "\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\r\n", pCol->GetColNo()); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } pCol = pCol->GetNext(); } strcpy(szBuffer, "\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, "\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\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\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\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\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\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } p = p->GetNextLocation(); } strcpy(szBuffer, "\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, "\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, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\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\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\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } wsprintf(szBuffer, "\t\t\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\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\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\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\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\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\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\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\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\r\n", pHist->bSupportsMerge); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\t\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } pHist = pHist->pNext; } strcpy(szBuffer, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } pTitle = pTitle->GetNextTitle(); } strcpy(szBuffer, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer, "\r\n"); if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE) { CloseHandle(m_fh); return F_WRITE; } strcpy(szBuffer,"\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, "\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, "\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, "\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, "\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, "\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