480 lines
15 KiB
C
480 lines
15 KiB
C
|
//*********************************************************************************************************************************************
|
||
|
//
|
||
|
// File: collect.h
|
||
|
// Author: Donald Drake
|
||
|
// Purpose: Defines classes to support titles, collections, locations and folders
|
||
|
|
||
|
#ifndef _COLLECT_H
|
||
|
#define _COLLECT_H
|
||
|
|
||
|
#undef CLASS_IMPORT_EXPORT
|
||
|
#ifdef HHCTRL // define this only when building the HHCtrl DLL
|
||
|
#define CLASS_IMPORT_EXPORT /**/
|
||
|
#else
|
||
|
#ifdef HHSETUP // define this only when building the HHSetup DLL
|
||
|
#define CLASS_IMPORT_EXPORT __declspec( dllexport )
|
||
|
#else
|
||
|
#define CLASS_IMPORT_EXPORT __declspec( dllimport )
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef HHCTRL
|
||
|
|
||
|
#undef COUNT
|
||
|
#define COUNT(x)
|
||
|
|
||
|
#undef MI_COUNT
|
||
|
#define MI_COUNT(x)
|
||
|
|
||
|
#undef SI_COUNT
|
||
|
#define SI_COUNT(x)
|
||
|
|
||
|
#undef MI2_COUNT
|
||
|
#define MI2_COUNT(x)
|
||
|
|
||
|
#undef AUTO_CLASS_COUNT_CHECK
|
||
|
#define AUTO_CLASS_COUNT_CHECK(x)
|
||
|
|
||
|
#undef CHECK_CLASS_COUNT
|
||
|
#define CHECK_CLASS_COUNT(x)
|
||
|
|
||
|
#undef DUMP_CLASS_COUNT
|
||
|
#define DUMP_CLASS_COUNT(x)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef HHCTRL
|
||
|
#include "parserhh.h"
|
||
|
#else
|
||
|
#include "parser.h"
|
||
|
#endif
|
||
|
|
||
|
#define F_MSDN 0x0001
|
||
|
#define F_TITLELOCAL 0x0002
|
||
|
#define F_INDEXLOCAL 0x0004
|
||
|
#define STARTINGCOLNO 10000
|
||
|
|
||
|
#define ENGLANGID 1033
|
||
|
|
||
|
#define MAX_LEVELS 100
|
||
|
|
||
|
typedef struct LocationHistory {
|
||
|
CHAR * SampleLocation;
|
||
|
CHAR * FileName;
|
||
|
CHAR * IndexFileName;
|
||
|
CHAR * QueryFileName;
|
||
|
CHAR * LocationId;
|
||
|
DWORD CollectionNumber;
|
||
|
DWORD Version;
|
||
|
DWORD LastPromptedVersion;
|
||
|
BOOL bSupportsMerge;
|
||
|
LocationHistory *pNext;
|
||
|
CHAR * QueryLocation;
|
||
|
} LOCATIONHISTORY;
|
||
|
|
||
|
DWORD CLASS_IMPORT_EXPORT AllocSetValue(const CHAR *value, CHAR **dest);
|
||
|
|
||
|
// forward declarations
|
||
|
class CLocation;
|
||
|
class CTitle;
|
||
|
class CCollection;
|
||
|
class CFolder;
|
||
|
class CSlotLookupTable;
|
||
|
class CExTitle;
|
||
|
class CColList;
|
||
|
|
||
|
typedef struct ListItem {
|
||
|
void *pItem;
|
||
|
ListItem *Next;
|
||
|
} LISTITEM;
|
||
|
|
||
|
class CLASS_IMPORT_EXPORT CPointerList {
|
||
|
private:
|
||
|
LISTITEM *m_pHead;
|
||
|
|
||
|
public:
|
||
|
CPointerList()
|
||
|
{
|
||
|
m_pHead = NULL;
|
||
|
}
|
||
|
|
||
|
~CPointerList();
|
||
|
void RemoveAll();
|
||
|
LISTITEM *Add(void *);
|
||
|
LISTITEM *First();
|
||
|
LISTITEM *Next(LISTITEM *p) { return p->Next; }
|
||
|
};
|
||
|
|
||
|
#ifdef HHCTRL // define this only when building the HHCtrl DLL
|
||
|
|
||
|
//
|
||
|
// <mc>
|
||
|
// This lookup table will facilitate a quick translation of a "slot" number into a CFolder* as well as a
|
||
|
// HASH value into a CFolder*. This will be done using two DWORDS per CFolder object, one for the HASH value
|
||
|
// and one for the CFolder*. After ALL the CFolders for a given collection have been created and this lookup
|
||
|
// table is fully populated the SortAndAssignSlots() member will be called. This will sort the table by HASH
|
||
|
// value and will assign the slot values back to the CFolders according to the sorted order. This will make
|
||
|
// slot --> CFolder* lookup a simple array index and will also allow us to use a bsearch for the
|
||
|
// HASH --> CFolder* lookup. Note that only leaf level CFolders have useful hash values, for the non leaf
|
||
|
// CFolders we will assign a hash of -1, these items in the table will then appear at the end of the table
|
||
|
// and will not interfear with a bsearch operation when translating a hash into a pSLT.
|
||
|
// </mc>
|
||
|
//
|
||
|
class CSlotLookupTable
|
||
|
{
|
||
|
public:
|
||
|
CSlotLookupTable();
|
||
|
~CSlotLookupTable();
|
||
|
|
||
|
static int FASTCALL ltqs_callback(const void *elem1, const void *elem2);
|
||
|
void AddValue(CFolder* pFolder);
|
||
|
void SortAndAssignSlots(void);
|
||
|
CFolder* HashToCFolder(HASH hash);
|
||
|
|
||
|
CFolder* SlotToCFolder(DWORD dwSlot)
|
||
|
{
|
||
|
if ( dwSlot > 0 && dwSlot <= m_uiTotalCnt ) // Slot 0 reserved for error case.
|
||
|
return m_pSLT[dwSlot].pCFolder;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
struct _slt
|
||
|
{
|
||
|
HASH hash;
|
||
|
CFolder* pCFolder;
|
||
|
};
|
||
|
|
||
|
struct _slt* m_pSLT;
|
||
|
unsigned m_uiTotalAllocated;
|
||
|
unsigned m_uiTotalCnt;
|
||
|
unsigned m_uiHashCnt;
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
class CLASS_IMPORT_EXPORT CFolder SI_COUNT(CFolder)
|
||
|
{
|
||
|
private:
|
||
|
CHAR *Title; // name of the folder
|
||
|
WCHAR *pwcTitle;
|
||
|
DWORD Order;
|
||
|
LANGID LangId;
|
||
|
DWORD dwSlot;
|
||
|
CExTitle* pExTitle;
|
||
|
CFolder *pNext, *pKid, *pParent;
|
||
|
//
|
||
|
// This DWORD value is being added to support .CHM level subsetting.
|
||
|
//
|
||
|
WORD iLevel;
|
||
|
WORD f_Filter: 1; // render into filter LB.
|
||
|
WORD f_Available: 1; // render into Available LB.
|
||
|
WORD f_F_Open: 1; // Expanded or closed ?
|
||
|
WORD f_A_Open: 1; // Expanded or closed ?
|
||
|
WORD f_HasHash: 1; // Does Node have a prefix hash ?
|
||
|
WORD f_IsOrphan: 1; // Is this node an orphane ?
|
||
|
WORD f_IsVisable: 1; // Indicates membership in the currently selected TOC subset.
|
||
|
|
||
|
public:
|
||
|
CFolder();
|
||
|
~CFolder();
|
||
|
BOOL bIsVisable() { return (BOOL)f_IsVisable; }
|
||
|
void SetTitle(const CHAR *);
|
||
|
void SetTitle(const WCHAR *);
|
||
|
void SetExTitlePtr(CExTitle* pTitle);
|
||
|
CHAR *GetTitle() { return Title; }
|
||
|
const WCHAR *GetTitleW();
|
||
|
void SetLanguage(LANGID Id) { LangId = Id; }
|
||
|
LANGID GetLanguage() { return LangId; }
|
||
|
void SetOrder(DWORD);
|
||
|
DWORD GetOrder();
|
||
|
// Returns the next sibling folder given a folder entry
|
||
|
CFolder * GetNextFolder();
|
||
|
void SetNextFolder(CFolder *p) { pNext = p; }
|
||
|
// Returns the first child of a given folder if it exists
|
||
|
CFolder * GetFirstChildFolder();
|
||
|
void SetFirstChildFolder(CFolder *p) { pKid = p; }
|
||
|
// Add a new folder as child of a given folder
|
||
|
CFolder * AddChildFolder(const CHAR *szName, DWORD Order, DWORD *pError, LANGID LangId = ENGLANGID);
|
||
|
CFolder * AddChildFolder(const WCHAR *szName, DWORD Order, DWORD *pError, LANGID LangId = ENGLANGID);
|
||
|
DWORD AddChildFolder(CFolder *newFolder);
|
||
|
void SetParent(CFolder *p) { pParent = p; }
|
||
|
CFolder * GetParent() { return pParent; }
|
||
|
|
||
|
friend class CSlotLookupTable;
|
||
|
friend class CDefineSS;
|
||
|
friend class CStructuralSubset;
|
||
|
|
||
|
};
|
||
|
|
||
|
class CLASS_IMPORT_EXPORT CCollection SI_COUNT(CCollection)
|
||
|
{
|
||
|
public:
|
||
|
CCollection();
|
||
|
~CCollection();
|
||
|
void ConfirmTitles() { m_bConfirmTitles = TRUE; }
|
||
|
void SetSampleLocation(const CHAR *);
|
||
|
CHAR *GetSampleLocation();
|
||
|
void SetMasterCHM(const CHAR *szName, LANGID Lang);
|
||
|
BOOL GetMasterCHM(CHAR ** szName, LANGID *Lang);
|
||
|
// Opens and loads the contents of the file into data structures
|
||
|
DWORD Open(const CHAR * FileName);
|
||
|
void SetSampleLocation(const WCHAR *);
|
||
|
void SetFindMergedCHMS(BOOL bFind) { m_bFindMergedChms = bFind; }
|
||
|
BOOL GetFindMergedCHMS() { return m_bFindMergedChms; }
|
||
|
const WCHAR *GetSampleLocationW();
|
||
|
void SetMasterCHM(const WCHAR *szName, LANGID Lang);
|
||
|
BOOL GetMasterCHM(WCHAR ** szName, LANGID *Lang);
|
||
|
// Opens and loads the contents of the file into data structures
|
||
|
DWORD Open(const WCHAR * FileName);
|
||
|
// Saves any changes made to the internal data structures to the file.
|
||
|
DWORD Save();
|
||
|
DWORD Close();
|
||
|
|
||
|
void AddRef() { m_dwRef++; }
|
||
|
|
||
|
DWORD GetVersion() { return m_dwVersion; }
|
||
|
void SetVersion(DWORD dw) { m_dwVersion = dw; }
|
||
|
// navigating the collection
|
||
|
// Returns the first folder in the collection
|
||
|
CFolder * GetRootFolder() { return m_pRootFolder; }
|
||
|
CFolder * GetVisableRootFolder() { return m_pRootFolder->GetFirstChildFolder(); } // Returns the visable root.
|
||
|
// Returns the first title
|
||
|
CTitle * GetFirstTitle();
|
||
|
// Locates a title based on id
|
||
|
CTitle * FindTitle(const CHAR * Id, LANGID LangId = ENGLANGID);
|
||
|
CTitle * FindTitle(const WCHAR * Id, LANGID LangId = ENGLANGID);
|
||
|
// Try multiple LangIds, before failing.
|
||
|
#ifdef HHCTRL
|
||
|
CTitle * FindTitleNonExact(const CHAR * Id, LANGID LangId) ;
|
||
|
#endif // #ifdef HHCTRL
|
||
|
|
||
|
|
||
|
// Returns the first location
|
||
|
CLocation* FirstLocation();
|
||
|
// Finds a location based on a name
|
||
|
CLocation * FindLocation(const CHAR * Name, UINT* puiVolumeOrder = NULL );
|
||
|
|
||
|
// collection entry management
|
||
|
CColList * FindCollection(CHAR *szFileName);
|
||
|
CColList * AddCollection();
|
||
|
void RemoveCollectionEntry(CHAR *szFileName);
|
||
|
|
||
|
//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 * AddFolder(const CHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId = ENGLANGID);
|
||
|
|
||
|
DWORD DeleteFolder(CFolder *);
|
||
|
//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 * 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 = FALSE, const CHAR *QueryLocation = NULL);
|
||
|
|
||
|
|
||
|
// 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 * AddLocation(const CHAR * Title, const CHAR * Path, const CHAR * Id, const CHAR * Volume, DWORD *pDWORD);
|
||
|
|
||
|
CLocation * FindLocation(const WCHAR * Name, UINT* puiVolumeOrder = NULL );
|
||
|
CFolder * AddFolder(const WCHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId = ENGLANGID);
|
||
|
CTitle * 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 = FALSE, const WCHAR *QueryLocation = NULL);
|
||
|
CLocation * AddLocation(const WCHAR * Title, const WCHAR * Path, const WCHAR * Id, const WCHAR * Volume, DWORD *pDWORD);
|
||
|
|
||
|
DWORD RemoveCollection(BOOL bRemoveLocalFiles = FALSE);
|
||
|
|
||
|
DWORD GetRefTitleCount() { return m_dwTitleRefCount; }
|
||
|
// Merges the currently installed titles for the collection into the specified filename (path determined internally)
|
||
|
BOOL MergeKeywords(CHAR * pwzFilename );
|
||
|
BOOL MergeKeywords(WCHAR * pwzFilename );
|
||
|
DWORD GetColNo() { return m_dwColNo; }
|
||
|
PCSTR GetCollectionFileName(void) { return m_szFileName; }
|
||
|
const WCHAR *GetCollectionFileNameW(void);
|
||
|
BOOL IsDirty() { return m_bDirty;}
|
||
|
void IncrementRefTitleCount() { m_dwTitleRefCount++; }
|
||
|
void DecrementRefTitleCount() { m_dwTitleRefCount--; }
|
||
|
void Dirty() { m_bDirty = TRUE; }
|
||
|
|
||
|
LANGID GetLangId(const CHAR *FileName);
|
||
|
LANGID GetLangId(const WCHAR *FileName);
|
||
|
private: // functions
|
||
|
|
||
|
DWORD AddRefedTitle(CFolder *pFolder);
|
||
|
// removing objects
|
||
|
DWORD DeleteTitle(CTitle *);
|
||
|
void DeleteLocalFiles(LOCATIONHISTORY *pHist, CTitle *pTitle);
|
||
|
DWORD DeleteLocation(CLocation *);
|
||
|
|
||
|
DWORD CheckTitleRef(const CHAR *pId, const LANGID Lang);
|
||
|
DWORD CheckTitleRef(const WCHAR *pId, const LANGID Lang);
|
||
|
DWORD ParseFile(const CHAR *FileName);
|
||
|
DWORD HandleCollection(CParseXML *parser, CHAR *sz);
|
||
|
DWORD HandleCollectionEntry(CParseXML *parser, CHAR *sz);
|
||
|
DWORD HandleFolder(CParseXML *parser, CHAR *token);
|
||
|
DWORD HandleLocation(CParseXML *parser, CHAR *token);
|
||
|
DWORD HandleTitle(CParseXML *parser, CHAR *token);
|
||
|
void DeleteChildren(CFolder **p);
|
||
|
void DeleteFolders(CFolder **p);
|
||
|
BOOL WriteFolders(CFolder **p);
|
||
|
BOOL WriteFolder(CFolder **p);
|
||
|
DWORD AllocCopyValue(CParseXML *parser, CHAR *token, CHAR **dest);
|
||
|
CTitle *NewTitle();
|
||
|
CLocation *NewLocation();
|
||
|
|
||
|
private:
|
||
|
BOOL m_bRemoveLocalFiles;
|
||
|
BOOL m_bRemoved;
|
||
|
DWORD Release();
|
||
|
CHAR * m_szFileName;
|
||
|
WCHAR * m_pwcFileName;
|
||
|
CHAR * m_szMasterCHM;
|
||
|
WCHAR * m_pwcMasterCHM;
|
||
|
CHAR * m_szSampleLocation;
|
||
|
WCHAR * m_pwcSampleLocation;
|
||
|
LANGID m_MasterLangId;
|
||
|
CTitle * m_pFirstTitle;
|
||
|
CTitle * m_pTitleTail;
|
||
|
CLocation * m_pFirstLocation;
|
||
|
CLocation * m_pLocationTail;
|
||
|
CFolder *m_pRootFolder;
|
||
|
DWORD m_locationnum;
|
||
|
CFIFOString m_Strings;
|
||
|
CFolder *m_pParents[MAX_LEVELS];
|
||
|
DWORD m_dwCurLevel;
|
||
|
DWORD m_dwLastLevel;
|
||
|
DWORD m_dwNextColNo;
|
||
|
DWORD m_dwColNo;
|
||
|
DWORD m_dwTitleRefCount;
|
||
|
BOOL m_bConfirmTitles;
|
||
|
BOOL m_bFindMergedChms;
|
||
|
DWORD m_dwRef;
|
||
|
DWORD m_dwVersion;
|
||
|
HANDLE m_fh;
|
||
|
BOOL m_bDirty;
|
||
|
CColList *m_pColListHead;
|
||
|
CColList *m_pColListTail;
|
||
|
public:
|
||
|
CPointerList m_RefTitles;
|
||
|
BOOL m_bFailNoFile;
|
||
|
BOOL m_bAllFilesDeleted;
|
||
|
};
|
||
|
|
||
|
class CColList
|
||
|
{
|
||
|
private:
|
||
|
DWORD m_dwColNo;
|
||
|
CHAR * m_szFileName;
|
||
|
CColList *m_pNext;
|
||
|
public:
|
||
|
CColList();
|
||
|
~CColList();
|
||
|
void SetColNo(DWORD dw) { m_dwColNo = dw; }
|
||
|
void SetFileName(CHAR *szFileName);
|
||
|
DWORD GetColNo() { return m_dwColNo; }
|
||
|
CHAR *GetFileName() { return m_szFileName; }
|
||
|
CColList *GetNext() { return m_pNext; }
|
||
|
void SetNext(CColList *p) { m_pNext = p; }
|
||
|
};
|
||
|
|
||
|
class CLASS_IMPORT_EXPORT CTitle SI_COUNT(CTitle)
|
||
|
{
|
||
|
private:
|
||
|
CHAR * Id; // Title identifier
|
||
|
WCHAR *pwcId;
|
||
|
LANGID Language; // language identifier
|
||
|
CTitle *NextTitle; // pointer to the next title
|
||
|
public:
|
||
|
LOCATIONHISTORY *m_pHead, *m_pTail;
|
||
|
void SetId(const CHAR *);
|
||
|
void SetId(const WCHAR *);
|
||
|
void SetLanguage(LANGID);
|
||
|
CHAR * GetId();
|
||
|
const WCHAR * GetIdW();
|
||
|
LANGID GetLanguage();
|
||
|
LOCATIONHISTORY *GetLocation(DWORD Index);
|
||
|
CTitle* GetNextTitle();
|
||
|
~CTitle();
|
||
|
CTitle();
|
||
|
LOCATIONHISTORY *NewLocationHistory();
|
||
|
DWORD AddLocationHistory(DWORD ColNo, const CHAR *FileName, const CHAR *IndexFile, const CHAR *Query, const CLocation *pLocation, const CHAR *Sample, const CHAR *QueryLocation, BOOL bSupportsMerge);
|
||
|
DWORD AddLocationHistory(DWORD ColNo, const WCHAR *FileName, const WCHAR *IndexFile, const WCHAR *Query, const CLocation *pLocation, const WCHAR *Sample, const WCHAR *QueryLocation, BOOL bSupportsMerge);
|
||
|
void SetNextTitle(CTitle *p) { NextTitle = p; }
|
||
|
};
|
||
|
|
||
|
class CLASS_IMPORT_EXPORT CLocation SI_COUNT(CLocation)
|
||
|
{
|
||
|
private:
|
||
|
CHAR * Id;
|
||
|
CHAR * Title; // Friendly name for the title
|
||
|
CHAR * Path; // location of the device
|
||
|
CHAR * Volume;
|
||
|
WCHAR * pwcId;
|
||
|
WCHAR * pwcTitle; // Friendly name for the title
|
||
|
WCHAR * pwcPath; // location of the device
|
||
|
WCHAR * pwcVolume;
|
||
|
CLocation *NextLocation; // pointer to the next location if it exists
|
||
|
public:
|
||
|
DWORD m_ColNum;
|
||
|
CLocation()
|
||
|
{
|
||
|
Id = NULL;
|
||
|
Title = NULL;
|
||
|
Path = NULL;
|
||
|
Volume = NULL;
|
||
|
NextLocation = NULL;
|
||
|
pwcId = NULL;
|
||
|
pwcTitle = NULL;
|
||
|
pwcPath = NULL;
|
||
|
pwcVolume = NULL;
|
||
|
}
|
||
|
|
||
|
~CLocation()
|
||
|
{
|
||
|
if (Id)
|
||
|
delete Id;
|
||
|
if (Title)
|
||
|
delete Title;
|
||
|
if (Path)
|
||
|
delete Path;
|
||
|
if (Volume)
|
||
|
delete Volume;
|
||
|
if (pwcId)
|
||
|
delete pwcId;
|
||
|
if (pwcTitle)
|
||
|
delete pwcTitle;
|
||
|
if (pwcPath)
|
||
|
delete pwcPath;
|
||
|
if (pwcVolume)
|
||
|
delete pwcVolume;
|
||
|
}
|
||
|
|
||
|
void SetNextLocation(CLocation *p) { NextLocation = p; }
|
||
|
void SetId(const CHAR *);
|
||
|
void SetTitle(const CHAR *);
|
||
|
void SetPath(const CHAR *);
|
||
|
void SetVolume(const CHAR *);
|
||
|
CHAR * GetId() const;
|
||
|
CHAR * GetTitle();
|
||
|
CHAR * GetPath();
|
||
|
CHAR * GetVolume();
|
||
|
void SetId(const WCHAR *);
|
||
|
void SetTitle(const WCHAR *);
|
||
|
void SetPath(const WCHAR *);
|
||
|
void SetVolume(const WCHAR *);
|
||
|
const WCHAR * GetIdW();
|
||
|
const WCHAR * GetTitleW();
|
||
|
const WCHAR * GetPathW();
|
||
|
const WCHAR * GetVolumeW();
|
||
|
|
||
|
// Returns the next location
|
||
|
CLocation *GetNextLocation();
|
||
|
};
|
||
|
#endif
|