You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
14 KiB
469 lines
14 KiB
/*--------------------------------------------------------------------------*
|
|
*
|
|
* Microsoft Windows
|
|
* Copyright (C) Microsoft Corporation, 1992 - 1999
|
|
*
|
|
* File: strtable.h
|
|
*
|
|
* Contents: Interface file for CStringTable
|
|
*
|
|
* History: 25-Jun-98 jeffro Created
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
#ifndef STRTABLE_H
|
|
#define STRTABLE_H
|
|
#pragma once
|
|
|
|
#include <exception> // for class exception
|
|
#include <string> // for string relational operators
|
|
#include "guidhelp.h" // for GUID relational operators
|
|
#include "stgio.h"
|
|
#include "strings.h"
|
|
|
|
|
|
#ifdef DBG
|
|
#define DECLARE_DIAGNOSITICS() \
|
|
public: void Dump() const;
|
|
#else
|
|
#define DECLARE_DIAGNOSITICS() \
|
|
public: void Dump() const {}
|
|
#endif
|
|
|
|
|
|
#ifdef DBG
|
|
extern CTraceTag tagStringTable;
|
|
#endif // DBG
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* IdentifierRange should be private to CIdentifierPool, but
|
|
* compiler bugs prevent it.
|
|
*/
|
|
template<class T>
|
|
class IdentifierRange
|
|
{
|
|
public:
|
|
IdentifierRange(T idMin_ = T(), T idMax_ = T())
|
|
: idMin (idMin_), idMax (idMax_)
|
|
{ ASSERT (idMin <= idMax); }
|
|
|
|
bool operator== (const IdentifierRange<T>& other) const
|
|
{ return ((idMin == other.idMin) && (idMax == other.idMax)); }
|
|
|
|
bool operator!= (const IdentifierRange<T>& other) const
|
|
{ return (!(*this == other.idMin)); }
|
|
|
|
T idMin;
|
|
T idMax;
|
|
};
|
|
|
|
|
|
template<class T = int>
|
|
class CIdentifierPool : public CXMLObject
|
|
{
|
|
public:
|
|
typedef IdentifierRange<T> Range;
|
|
typedef std::list<Range> RangeList;
|
|
|
|
private:
|
|
#if _MSC_VER > 1300
|
|
template <class U>
|
|
friend IStream& operator>> (IStream& stm, CIdentifierPool<U>& pool);
|
|
template <class U>
|
|
friend IStream& operator<< (IStream& stm, const CIdentifierPool<U>& pool);
|
|
#else
|
|
// VC7 bug - doesn't handle template friends properly. By luck, this works.
|
|
friend IStream& operator>> (IStream& stm, CIdentifierPool<T>& pool);
|
|
friend IStream& operator<< (IStream& stm, const CIdentifierPool<T>& pool);
|
|
#endif
|
|
virtual void Persist(CPersistor &persistor);
|
|
DEFINE_XML_TYPE(XML_TAG_IDENTIFIER_POOL);
|
|
|
|
SC ScInvertRangeList (RangeList& rlInvert) const;
|
|
|
|
#ifdef DBG
|
|
void DumpRangeList (const RangeList& l) const;
|
|
#endif
|
|
|
|
public:
|
|
DECLARE_DIAGNOSITICS();
|
|
|
|
CIdentifierPool (T idMin, T idMax);
|
|
CIdentifierPool (IStream& stm);
|
|
T Reserve();
|
|
bool Release(T idRelease);
|
|
bool IsValid () const;
|
|
bool IsRangeListValid (const RangeList& rl) const;
|
|
SC ScGenerate (const RangeList& rlUsedIDs);
|
|
|
|
static bool AddToRangeList (RangeList& rl, const Range& rangeToAdd);
|
|
static bool AddToRangeList (RangeList& rl, T idAdd);
|
|
|
|
class pool_exhausted : public exception
|
|
{
|
|
public:
|
|
pool_exhausted(const char *_S = "pool exhausted") _THROW0()
|
|
: exception(_S) {}
|
|
virtual ~pool_exhausted() _THROW0()
|
|
{}
|
|
};
|
|
|
|
private:
|
|
RangeList m_AvailableIDs;
|
|
RangeList m_StaleIDs;
|
|
T m_idAbsoluteMin;
|
|
T m_idAbsoluteMax;
|
|
T m_idNextAvailable;
|
|
};
|
|
|
|
|
|
typedef CIdentifierPool<MMC_STRING_ID> CStringIDPool;
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* CEntry and CStoredEntry should be private to CStringTable,
|
|
* but compiler bugs prevent it.
|
|
*/
|
|
|
|
/*
|
|
* represents a string table entry in memory
|
|
*/
|
|
class CEntry : public CXMLObject
|
|
{
|
|
friend class CStringTable;
|
|
friend class CStringEnumerator;
|
|
friend struct CompareEntriesByID;
|
|
friend struct CompareEntriesByString;
|
|
friend struct IdentifierReleaser;
|
|
|
|
friend IStream& operator>> (IStream& stm, CEntry& entry);
|
|
friend IStream& operator<< (IStream& stm, const CEntry& entry);
|
|
|
|
public:
|
|
DECLARE_DIAGNOSITICS();
|
|
|
|
CEntry () : m_id(0), m_cRefs(0) {}
|
|
|
|
CEntry (const std::wstring& str, MMC_STRING_ID id)
|
|
: m_str(str), m_id(id), m_cRefs(0)
|
|
{}
|
|
virtual LPCTSTR GetXMLType() {return XML_TAG_STRING_TABLE_STRING;}
|
|
virtual void Persist(CPersistor& persistor);
|
|
|
|
private:
|
|
/*
|
|
* This ctor is only used by CStringTable when reconstructing
|
|
* the entry from a file.
|
|
*/
|
|
CEntry (const std::wstring& str, MMC_STRING_ID id, DWORD cRefs)
|
|
: m_str(str) , m_id(id), m_cRefs(cRefs)
|
|
{}
|
|
|
|
private:
|
|
bool operator< (const LPCWSTR psz) const
|
|
{ return (m_str < psz); }
|
|
|
|
bool operator< (const CEntry& other) const
|
|
{ return (m_str < other.m_str); }
|
|
|
|
bool operator== (const LPCWSTR psz) const
|
|
{ return (m_str == psz); }
|
|
|
|
bool operator== (const CEntry& other) const
|
|
{ return (m_str == other.m_str); }
|
|
|
|
//private:
|
|
public: // temp!
|
|
std::wstring m_str;
|
|
MMC_STRING_ID m_id;
|
|
DWORD m_cRefs;
|
|
};
|
|
|
|
|
|
struct CompareEntriesByID :
|
|
public std::binary_function<const CEntry&, const CEntry&, bool>
|
|
{
|
|
bool operator() (const CEntry& entry1, const CEntry& entry2) const
|
|
{ return (entry1.m_id < entry2.m_id); }
|
|
};
|
|
|
|
struct CompareEntriesByString :
|
|
public std::binary_function<const CEntry&, const CEntry&, bool>
|
|
{
|
|
bool operator() (const CEntry& entry1, const CEntry& entry2) const
|
|
{ return (entry1 < entry2); }
|
|
};
|
|
|
|
struct IdentifierReleaser :
|
|
public std::unary_function<CEntry&, bool>
|
|
{
|
|
IdentifierReleaser (CStringIDPool& pool) : m_pool (pool) {}
|
|
|
|
bool operator() (CEntry& entry) const
|
|
{ return (m_pool.Release (entry.m_id)); }
|
|
|
|
private:
|
|
CStringIDPool& m_pool;
|
|
};
|
|
|
|
|
|
/*
|
|
* Because the string and ID indexes map their keys to CEntry
|
|
* pointers, we must use a collection that doesn't move its
|
|
* elements once they're inserted. The only STL collection
|
|
* that meets this requirement is a list.
|
|
*/
|
|
typedef std::list<CEntry> EntryList;
|
|
|
|
typedef XMLListCollectionWrap<EntryList> CStringTable_base;
|
|
class CStringTable : public CStringTable_base
|
|
{
|
|
friend IStream& operator>> (IStream& stm, CStringTable& entry);
|
|
friend IStream& operator<< (IStream& stm, const CStringTable& entry);
|
|
|
|
public:
|
|
DECLARE_DIAGNOSITICS();
|
|
|
|
CStringTable (CStringIDPool* pIDPool);
|
|
CStringTable (CStringIDPool* pIDPool, IStream& stm);
|
|
~CStringTable ();
|
|
|
|
CStringTable (const CStringTable& other);
|
|
CStringTable& operator= (const CStringTable& other);
|
|
|
|
/*
|
|
* IStringTable methods. Note that object doesn't implement
|
|
* IStringTable, because IUnknown isn't implemented.
|
|
*/
|
|
STDMETHOD(AddString) (LPCOLESTR pszAdd, MMC_STRING_ID* pID);
|
|
STDMETHOD(GetString) (MMC_STRING_ID id, ULONG cchBuffer, LPOLESTR lpBuffer, ULONG* pcchOut) const;
|
|
STDMETHOD(GetStringLength) (MMC_STRING_ID id, ULONG* pcchString) const;
|
|
STDMETHOD(DeleteString) (MMC_STRING_ID id);
|
|
STDMETHOD(DeleteAllStrings) ();
|
|
STDMETHOD(FindString) (LPCOLESTR pszFind, MMC_STRING_ID* pID) const;
|
|
STDMETHOD(Enumerate) (IEnumString** ppEnum) const;
|
|
|
|
size_t size() const
|
|
{ return (m_Entries.size()); }
|
|
|
|
virtual void Persist(CPersistor& persistor)
|
|
{
|
|
CStringTable_base::Persist(persistor);
|
|
if (persistor.IsLoading())
|
|
IndexAllEntries ();
|
|
}
|
|
|
|
SC ScCollectInUseIDs (CStringIDPool::RangeList& l) const;
|
|
|
|
|
|
private:
|
|
|
|
void IndexAllEntries ()
|
|
{ IndexEntries (m_Entries.begin(), m_Entries.end()); }
|
|
|
|
void IndexEntries (EntryList::iterator first, EntryList::iterator last)
|
|
{
|
|
for (; first != last; ++first)
|
|
IndexEntry (first);
|
|
}
|
|
|
|
void IndexEntry (EntryList::iterator);
|
|
|
|
typedef std::map<std::wstring, EntryList::iterator> StringToEntryMap;
|
|
typedef std::map<MMC_STRING_ID, EntryList::iterator> IDToEntryMap;
|
|
|
|
EntryList::iterator LookupEntryByString (const std::wstring&) const;
|
|
EntryList::iterator LookupEntryByID (MMC_STRING_ID) const;
|
|
EntryList::iterator FindInsertionPointForEntry (const CEntry& entry) const;
|
|
|
|
|
|
#ifdef DBG
|
|
static void AssertValid (const CStringTable* pTable);
|
|
#define ASSERT_VALID_(p) do { AssertValid(p); } while(0)
|
|
#else
|
|
#define ASSERT_VALID_(p) ((void) 0)
|
|
#endif
|
|
|
|
|
|
private:
|
|
EntryList m_Entries;
|
|
StringToEntryMap m_StringIndex;
|
|
IDToEntryMap m_IDIndex;
|
|
CStringIDPool* m_pIDPool;
|
|
};
|
|
|
|
extern const CLSID CLSID_MMC;
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CLSIDToStringTableMap
|
|
*
|
|
*
|
|
* PURPOSE: stl::map derived class that maps snapin_clsid to stringtable
|
|
* and supports XML persistence of the map collection
|
|
*
|
|
* NOTE: Throws exceptions!
|
|
*+-------------------------------------------------------------------------*/
|
|
typedef std::map<CLSID, CStringTable> ST_base;
|
|
class CLSIDToStringTableMap : public XMLMapCollection<ST_base>
|
|
{
|
|
public:
|
|
// this method is provided as alternative to Persist, whic allows
|
|
// to cache parameter to be used to create new string tables
|
|
void PersistSelf(CStringIDPool *pIDPool, CPersistor& persistor)
|
|
{
|
|
m_pIDPersistPool = pIDPool;
|
|
persistor.Persist(*this, NULL);
|
|
}
|
|
protected:
|
|
// XML persistence implementation
|
|
virtual LPCTSTR GetXMLType() {return XML_TAG_STRING_TABLE_MAP;}
|
|
virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal)
|
|
{
|
|
CLSID key;
|
|
ZeroMemory(&key,sizeof(key));
|
|
persistKey.Persist(key);
|
|
|
|
CStringTable val(m_pIDPersistPool);
|
|
persistVal.Persist(val);
|
|
insert(ST_base::value_type(key,val));
|
|
}
|
|
private:
|
|
CStringIDPool *m_pIDPersistPool;
|
|
};
|
|
typedef CLSIDToStringTableMap::value_type TableMapValue;
|
|
|
|
class CMasterStringTable : public IStringTablePrivate, public CComObjectRoot, public CXMLObject
|
|
{
|
|
friend IStorage& operator>> (IStorage& stg, CMasterStringTable& mst);
|
|
friend IStorage& operator<< (IStorage& stg, const CMasterStringTable& mst);
|
|
|
|
public:
|
|
DECLARE_DIAGNOSITICS();
|
|
|
|
CMasterStringTable ();
|
|
~CMasterStringTable ();
|
|
|
|
|
|
public:
|
|
DEFINE_XML_TYPE(XML_TAG_MMC_STRING_TABLE);
|
|
virtual void Persist(CPersistor& persistor);
|
|
|
|
SC ScPurgeUnusedStrings();
|
|
|
|
public:
|
|
/*
|
|
* ATL COM map
|
|
*/
|
|
BEGIN_COM_MAP (CMasterStringTable)
|
|
COM_INTERFACE_ENTRY (IStringTablePrivate)
|
|
END_COM_MAP ()
|
|
|
|
/*
|
|
* IStringTablePrivate methods
|
|
*/
|
|
STDMETHOD(AddString) (LPCOLESTR pszAdd, MMC_STRING_ID* pID, const CLSID* pclsid);
|
|
STDMETHOD(GetString) (MMC_STRING_ID id, ULONG cchBuffer, LPOLESTR lpBuffer, ULONG* pcchOut, const CLSID* pclsid);
|
|
STDMETHOD(GetStringLength) (MMC_STRING_ID id, ULONG* pcchString, const CLSID* pclsid);
|
|
STDMETHOD(DeleteString) (MMC_STRING_ID id, const CLSID* pclsid);
|
|
STDMETHOD(DeleteAllStrings) (const CLSID* pclsid);
|
|
STDMETHOD(FindString) (LPCOLESTR pszFind, MMC_STRING_ID* pID, const CLSID* pclsid);
|
|
STDMETHOD(Enumerate) (IEnumString** ppEnum, const CLSID* pclsid);
|
|
|
|
/*
|
|
* Shorthand into IStringTablePrivate (simulating a default parameter)
|
|
*/
|
|
STDMETHOD(AddString) (LPCOLESTR pszAdd, MMC_STRING_ID* pID)
|
|
{ return (AddString (pszAdd, pID, &CLSID_MMC)); }
|
|
|
|
STDMETHOD(GetString) (MMC_STRING_ID id, ULONG cchBuffer, LPOLESTR lpBuffer, ULONG* pcchOut)
|
|
{ return (GetString (id, cchBuffer, lpBuffer, pcchOut, &CLSID_MMC)); }
|
|
|
|
STDMETHOD(GetStringLength) (MMC_STRING_ID id, ULONG* pcchString)
|
|
{ return (GetStringLength (id, pcchString, &CLSID_MMC)); }
|
|
|
|
STDMETHOD(DeleteString) (MMC_STRING_ID id)
|
|
{ return (DeleteString (id, &CLSID_MMC)); }
|
|
|
|
STDMETHOD(DeleteAllStrings) ()
|
|
{ return (DeleteAllStrings (&CLSID_MMC)); }
|
|
|
|
STDMETHOD(FindString) (LPCOLESTR pszFind, MMC_STRING_ID* pID)
|
|
{ return (FindString (pszFind, pID, &CLSID_MMC)); }
|
|
|
|
STDMETHOD(Enumerate) (IEnumString** ppEnum)
|
|
{ return (Enumerate (ppEnum, &CLSID_MMC)); }
|
|
|
|
|
|
private:
|
|
CStringTable* LookupStringTableByCLSID (const CLSID* pclsid) const;
|
|
SC ScGenerateIDPool ();
|
|
|
|
private:
|
|
CStringIDPool m_IDPool;
|
|
CLSIDToStringTableMap m_TableMap;
|
|
|
|
static const WCHAR s_pszIDPoolStream[];
|
|
static const WCHAR s_pszStringsStream[];
|
|
};
|
|
|
|
|
|
|
|
class CStringEnumerator : public IEnumString, public CComObjectRoot
|
|
{
|
|
public:
|
|
CStringEnumerator ();
|
|
~CStringEnumerator ();
|
|
|
|
public:
|
|
/*
|
|
* ATL COM map
|
|
*/
|
|
BEGIN_COM_MAP (CStringEnumerator)
|
|
COM_INTERFACE_ENTRY (IEnumString)
|
|
END_COM_MAP ()
|
|
|
|
/*
|
|
* IEnumString methods
|
|
*/
|
|
STDMETHOD(Next) (ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched);
|
|
STDMETHOD(Skip) (ULONG celt);
|
|
STDMETHOD(Reset) ();
|
|
STDMETHOD(Clone) (IEnumString **ppenum);
|
|
|
|
static HRESULT CreateInstanceWrapper (
|
|
CComObject<CStringEnumerator>** ppEnumObject,
|
|
IEnumString** ppEnumIface);
|
|
|
|
bool Init (const EntryList& entries);
|
|
|
|
private:
|
|
typedef std::vector<std::wstring> StringVector;
|
|
|
|
StringVector m_Strings;
|
|
size_t m_cStrings;
|
|
size_t m_nCurrentIndex;
|
|
};
|
|
|
|
|
|
IStorage& operator>> (IStorage& stg, CMasterStringTable& mst);
|
|
IStorage& operator<< (IStorage& stg, const CMasterStringTable& mst);
|
|
IStorage& operator>> (IStorage& stg, CComObject<CMasterStringTable>& mst);
|
|
IStorage& operator<< (IStorage& stg, const CComObject<CMasterStringTable>& mst);
|
|
|
|
IStream& operator>> (IStream& stm, CStringTable& st);
|
|
IStream& operator<< (IStream& stm, const CStringTable& st);
|
|
IStream& operator>> (IStream& stm, CEntry& entry);
|
|
IStream& operator<< (IStream& stm, const CEntry& entry);
|
|
|
|
template<class T>
|
|
IStream& operator>> (IStream& stm, CIdentifierPool<T>& pool);
|
|
template<class T>
|
|
IStream& operator<< (IStream& stm, const CIdentifierPool<T>& pool);
|
|
|
|
|
|
#include "strtable.inl"
|
|
|
|
#endif /* STRTABLE_H */
|