chxliteprefs.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:17k
- #include "chxliteprefs.h"
- #include "hlxclib/fcntl.h"
- #include "chxdataf.h"
- #include "hxslist.h"
- #include "hxstring.h"
- #include "hxdir.h"
- #include "hxccf.h"
- #include "ihxpckts.h"
- #include <ctype.h>
- #include "hlxclib/stdlib.h"
- #include "pathutil.h"
- #include "hxthread.h"
- BEGIN_INTERFACE_LIST(CHXLitePrefs)
- INTERFACE_LIST_ENTRY_SIMPLE(IHXPreferences)
- INTERFACE_LIST_ENTRY_SIMPLE(IHXPreferences3)
- END_INTERFACE_LIST
- // for keeping track of a pref value
- class Pref
- {
- public:
- Pref(const char* pStr): m_bChanged(FALSE), m_strValue(pStr){}
- BOOL HasChanged() const { return m_bChanged;}
- void SetChanged(BOOL bChanged) { m_bChanged = bChanged;}
- void SetValue(const char* pStr) { m_strValue = pStr;}
-
- const char* Buffer() const { return m_strValue;}
- UINT32 Size() const {return m_strValue.GetLength() + 1;}
- private:
- BOOL m_bChanged;
- CHXString m_strValue;
- };
- // helpers local to this module
- namespace LitePrefs
- {
- void ClearPrefs(CHXMapStringToOb* pPrefs);
- CHXDataFile* OpenPrefFile(const char* pPath, UINT16 mode);
- HX_RESULT WritePrefFile(const char* pPath, CHXStringList& shadows, const CHXMapStringToOb& prefs);
- HX_RESULT WritePrefs(const CHXMapStringToOb* pPrefs, const char* pPath);
- HX_RESULT ReadPrefs(const char* pPath,
- CHXMapStringToOb* pPrefs);
- HX_RESULT ParsePrefs(CHXDataFile* pFile,
- CHXMapStringToOb* pPrefs,
- CHXStringList* pShadows);
- HX_RESULT StorePref(CHXMapStringToOb* pPrefs,
- const char* pName,
- const char* pValue,
- BOOL bChanged = TRUE);
- HX_RESULT RetrievePref(IHXCommonClassFactory* pFactory,
- const CHXMapStringToOb* pPrefs,
- const char* pName,
- REF(IHXBuffer*) pValue);
- void FindNewOrAlteredPrefs(const CHXMapStringToOb& memPrefs,
- const CHXMapStringToOb& origPrefs,
- CHXMapStringToOb& prefsOut);
- BOOL SkipToken(char*& pos, INT32& nCount, char term);
- BOOL ParseToken(char*& pos, INT32& nCount, char term, CHXString& token);
- CHXString GetBasePath(const CHXString& strPath);
- }
- //
- // get base path part of full filename path (strip off filename)
- //
- inline
- CHXString LitePrefs::GetBasePath(const CHXString& strPath)
- {
- CHXString strBase;
- INT32 idxSep = strPath.ReverseFind(OS_SEPARATOR_CHAR);
- if( idxSep != -1 )
- {
- strBase = strPath.Left(idxSep + 1);
- }
- return strBase;
- }
- //
- // go through current prefs (in memory) and determine which entries
- // are: a) set in a shadow but now have a different value; or b) not
- // in a shadow to begin with
- //
- inline void
- LitePrefs::FindNewOrAlteredPrefs(const CHXMapStringToOb& memPrefs,
- const CHXMapStringToOb& origPrefs,
- CHXMapStringToOb& prefsOut)
- {
- // for each current pref setting (cast away const to work around deficiency in map inteface)...
- CHXMapStringToOb& memPrefs_ = (CHXMapStringToOb&)memPrefs;
- CHXMapStringToOb::Iterator iterEnd = memPrefs_.End();
- for(CHXMapStringToOb::Iterator iter = memPrefs_.Begin(); iter != iterEnd; ++iter)
- {
- Pref* pPref = (Pref*)*iter;
- const char* pKey = iter.get_key();
- HX_ASSERT(pPref);
- HX_ASSERT(pKey);
-
- // transfer this pref if is new or altered
- if( pPref->HasChanged() || (0 != origPrefs.Lookup(pKey)) )
- {
- prefsOut.SetAt(pKey, pPref);
- }
- }
- }
- //
- // Prefs are read from primary file, then shadows. Settings in primary file override
- // those in shadows (which are essentially defaults). Therefore the first value that
- // is found for a given pref is the value that remains in effect.
- //
- HX_RESULT
- LitePrefs::ReadPrefs(const char* pPath,
- CHXMapStringToOb* pPrefs)
- {
- HX_RESULT res = HXR_FAIL;
- CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_RDONLY);
- if (pFile)
- {
- CHXStringList shadows;
- res = LitePrefs::ParsePrefs(pFile, pPrefs, &shadows);
- pFile->Close();
- // use base path from current pref file to locate regerenced shadow file
- CHXString strBase = LitePrefs::GetBasePath(pPath);
-
- LISTPOSITION i = shadows.GetHeadPosition();
- while(i)
- {
- const CHXString& strShadowFile = *((CHXString*) shadows.GetNext(i));
- CHXString strPath = HXPathUtil::CombinePath(strBase, strShadowFile);
- res = LitePrefs::ReadPrefs(strPath, pPrefs);
- }
-
- HX_DELETE(pFile);
- }
- return res;
- }
- // helper
- CHXDataFile*
- LitePrefs::OpenPrefFile(const char* pPath, UINT16 mode)
- {
- CHXDataFile* pFile = CHXDataFile::Construct();
- if (pFile)
- {
- HX_RESULT res = pFile->Open(pPath, mode, TRUE);
- if (FAILED(res))
- {
- HX_DELETE(pFile);
- }
- }
- return pFile;
- }
- //
- // write out the given file in our pref file format
- //
- HX_RESULT
- LitePrefs::WritePrefFile(const char* pPath, CHXStringList& shadows, const CHXMapStringToOb& prefs)
- {
- HX_RESULT hr = HXR_FAIL;
- CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_WRONLY | O_CREAT | O_TRUNC);
- if (pFile)
- {
- //
- // write the shadow pref file references
- //
- LISTPOSITION j = shadows.GetHeadPosition();
- while(j)
- {
- const CHXString& fileName = *((CHXString*) shadows.GetNext(j));
- // format shadow, write to file
- pFile->Write("[", 1);
- pFile->Write(fileName, fileName.GetLength());
- pFile->Write("]n", 2);
- }
- //
- // write out preference name/value entries
- //
- // cast away const to work around deficiency in map interface...
- CHXMapStringToOb& prefs_ = (CHXMapStringToOb&)prefs;
- CHXMapStringToOb::Iterator iterEnd = prefs_.End();
- for(CHXMapStringToOb::Iterator iter = prefs_.Begin(); iter != iterEnd; ++iter)
- {
- const char* pPrefKey = iter.get_key();
- Pref* pPref = (Pref*)*iter;
-
- pFile->Write(pPrefKey, strlen(pPrefKey));
- pFile->Write("=", 1);
- if (pPref->Size() > 1)
- {
- // don't write the null terminator
- pFile->Write(pPref->Buffer(), pPref->Size()-1);
- }
-
- pFile->Write("n", 1);
- }
- HX_DELETE(pFile);
- hr = HXR_OK;
- }
- return hr;
- }
- HX_RESULT
- LitePrefs::WritePrefs(const CHXMapStringToOb* pPrefs, const char* pPath)
- {
- HX_RESULT res = HXR_FAIL;
- CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_RDONLY);
- if (pFile)
- {
- // read current preference settings from files
- CHXStringList shadows;
- CHXMapStringToOb origPrefs;
- res = LitePrefs::ParsePrefs(pFile, &origPrefs, &shadows);
- HX_DELETE(pFile);
- if (SUCCEEDED(res))
- {
- // determine altered or new preferences
- CHXMapStringToOb newPrefs;
- FindNewOrAlteredPrefs(*pPrefs, origPrefs, newPrefs);
- // write out the prefs with our up-to-date values
- LitePrefs::WritePrefFile(pPath, shadows, newPrefs);
- }
-
- LitePrefs::ClearPrefs(&origPrefs);
- }
-
- return res;
- }
- HX_RESULT
- LitePrefs::StorePref(CHXMapStringToOb* pPrefs,
- const char* pName,
- const char* pValue,
- BOOL bChanged)
- {
- Pref* pPref = NULL;
- if (pPrefs->Lookup(pName, (void*&)pPref))
- {
- // update existing pref
- pPref->SetValue(pValue);
- }
- else
- {
- // create and add new pref
- pPref = new Pref(pValue);
- if(!pPref)
- {
- return HXR_OUTOFMEMORY;
- }
- pPrefs->SetAt(pName, pPref);
- }
-
- pPref->SetChanged(bChanged);
- return HXR_OK;
- }
- HX_RESULT
- LitePrefs::ParsePrefs(CHXDataFile* pFile,
- CHXMapStringToOb* pPrefs,
- CHXStringList* pShadows)
- {
- HX_ASSERT(pFile && pPrefs && pShadows);
- #define BUF_SZ 0x0400 // read file in 1k chunks
- ParseState eState = eParsingWhiteSpace;
- INT32 nCount = 0;
- CHXString strBuf;
- char* pos = 0;
- char* buf = strBuf.GetBuffer(BUF_SZ);
- CHXString sName;
- CHXString sValue;
- for (;;)
- {
- // read more data
- if (nCount == 0)
- {
- nCount = (INT32)pFile->Read(buf, BUF_SZ);
- if (nCount <= 0)
- {
- // end of file
- break;
- }
- pos = buf;
- }
- switch(eState)
- {
- case eParsingValue:
- {
- if (LitePrefs::ParseToken(pos, nCount, 'n', sValue))
- {
- eState = eParsingWhiteSpace;
-
- // don't add this name value if name already exists in prefs
- if(0 == pPrefs->Lookup(sName))
- {
- HX_RESULT res = LitePrefs::StorePref(pPrefs, sName, sValue, FALSE);
- if (FAILED(res))
- {
- return res;
- }
- }
- sName.Empty();
- sValue.Empty();
- }
-
- }
- break;
- case eParsingComment:
- {
- // skip to end of line
- if (LitePrefs::SkipToken(pos, nCount, 'n'))
- {
- eState = eParsingWhiteSpace;
- }
- }
- break;
- case eParsingName:
- {
- // name is everything up to '='
- if (LitePrefs::ParseToken(pos, nCount, '=', sName))
- {
- eState = eParsingValue;
- }
- }
- break;
- case eParsingShadow:
- {
- // shadow reference is everything up to closing ']'
- if (LitePrefs::ParseToken(pos, nCount, ']', sName))
- {
- eState = eParsingComment;
-
- // queue this up for parsing
- pShadows->AddTailString(sName);
- sName.Empty();
- }
- }
- break;
- case eParsingWhiteSpace:
- {
- // we're looking for something to parse
- switch (*pos)
- {
- case '[':
- {
- eState = eParsingShadow;
- }
- break;
- case '#':
- case ';':
- {
- eState = eParsingComment;
- }
- break;
- default:
- {
- eState = eParsingName;
- sName = *pos; // don't lose this char
- }
- }
- ++pos;
- --nCount;
- }
- break;
- default:
- HX_ASSERT(false);
- break;
- }
- }
- return HXR_OK;
- }
- void
- LitePrefs::ClearPrefs(CHXMapStringToOb* pPrefs)
- {
- POSITION pos = pPrefs->GetStartPosition();
- while(pos != NULL)
- {
- Pref * pPref = NULL;
- char * szPrefKey = NULL;
- pPrefs->GetNextAssoc( pos, (const char*&) szPrefKey, (void*&) pPref );
- HX_ASSERT(pPref);
- delete pPref;
- }
- pPrefs->RemoveAll();
- }
- HX_RESULT
- LitePrefs::RetrievePref(IHXCommonClassFactory* pFactory,
- const CHXMapStringToOb* pPrefs,
- const char* pName,
- REF(IHXBuffer*) pValue)
- {
- HX_RESULT res = HXR_FAIL;
- Pref* pPref = NULL;
- if (pPrefs->Lookup(pName, (void*&)pPref))
- {
- res = pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pValue);
- if (SUCCEEDED(res))
- {
- res = pValue->Set((const UCHAR*)pPref->Buffer(),
- pPref->Size());
- }
- }
- return res;
- }
- BOOL
- LitePrefs::SkipToken(char*& pos, INT32& nCount, char term)
- {
- BOOL bRet = FALSE;
- while (*pos != term && nCount != 0)
- {
- ++pos;
- --nCount;
- }
- if( nCount != 0 )
- {
- // skip term
- ++pos;
- --nCount;
- bRet = TRUE;
- }
- return bRet;
- }
- BOOL
- LitePrefs::ParseToken(char*& pos, INT32& nCount, char term, CHXString& token)
- {
- BOOL bRet = FALSE;
- while (*pos != term && nCount != 0)
- {
- token += *pos;
- ++pos;
- --nCount;
- }
- if( nCount != 0 )
- {
- // skip term
- ++pos;
- --nCount;
- // trim white space around token
- token.TrimLeft();
- token.TrimRight();
- bRet = TRUE;
- }
- return bRet;
- }
- //
- // class CHXLitePrefs
- //
- CHXLitePrefs::CHXLitePrefs(const char* pRootPath)
- : m_pMutex(NULL)
- , m_pFactory(NULL)
- , m_pScheduler(NULL)
- , m_hCallback((CallbackHandle)NULL)
- , m_strRootPath(pRootPath)
- , m_bAutoCommit(true)
- {
- #ifdef THREADS_SUPPORTED
- HXMutex::MakeMutex(m_pMutex);
- #else
- HXMutex::MakeStubMutex(m_pMutex);
- #endif
- m_prefs.SetCaseSensitive(FALSE);
- }
- CHXLitePrefs::~CHXLitePrefs()
- {
- Close();
- }
- inline
- CHXString CHXLitePrefs::GetFullPath(const CHXString& strFileName)
- {
- return HXPathUtil::CombinePath(m_strRootPath, strFileName);
- }
- void
- CHXLitePrefs::Close()
- {
- #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- // remove pending callback
- if (m_hCallback)
- {
- m_pScheduler->Remove(m_hCallback);
- m_hCallback = (CallbackHandle)NULL;
- }
- #endif // (HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- // commit changes
- Commit();
- // cleanup
- LitePrefs::ClearPrefs(&m_prefs);
- HX_RELEASE(m_pFactory);
- HX_RELEASE(m_pScheduler);
- HX_DELETE(m_pMutex);
- }
- // IHXPreferences
- STDMETHODIMP
- CHXLitePrefs::ReadPref(const char* pName, REF(IHXBuffer*) pValue)
- {
- HX_RESULT res = HXR_FAIL;
- if (pName && m_pFactory)
- {
- m_pMutex->Lock();
- res = LitePrefs::RetrievePref(m_pFactory, &m_prefs, pName, pValue);
- m_pMutex->Unlock();
- }
- return res;
- }
- STDMETHODIMP
- CHXLitePrefs::SetAutoCommit(bool bAutoCommit)
- {
- // if false, client must explicitly call Commit() to save changes after write
- m_bAutoCommit = bAutoCommit;
- return HXR_OK;
- }
- void
- CHXLitePrefs::PossiblyCommitPrefChange()
- {
- if (m_bAutoCommit)
- {
- #if defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- HX_VERIFY(SUCCEEDED(Commit()));
- #else
- // schedule a callback and commit the changes
- // so that multiple WritePref calls result in only one write to file
- if (!m_hCallback && m_pScheduler)
- {
- m_hCallback = m_pScheduler->RelativeEnter(this, 0);
- HX_ASSERT(m_hCallback);
- }
- else if (!m_pScheduler)
- {
- // lame... no scheduler!
- HX_VERIFY(SUCCEEDED(Commit()));
- }
- #endif
- }
- }
- STDMETHODIMP
- CHXLitePrefs::WritePref(const char* pName, IHXBuffer* pValue)
- {
- HX_RESULT res = HXR_FAIL;
- if (pName && pValue)
- {
- m_pMutex->Lock();
- res = LitePrefs::StorePref(&m_prefs, pName, (const char*)pValue->GetBuffer());
- if(SUCCEEDED(res))
- {
- PossiblyCommitPrefChange();
- }
- m_pMutex->Unlock();
- }
- return res;
- }
- // IHXPreferences3
- STDMETHODIMP
- CHXLitePrefs::Open(const char* pCompanyName,
- const char* pProductName,
- ULONG32 nProdMajorVer,
- ULONG32 nProdMinorVer)
- {
- HX_RESULT res = HXR_INVALID_PARAMETER;
- if (pProductName)
- {
- m_strFileName.Format("%s_%lu_%lu.cfg",pProductName, nProdMajorVer, nProdMinorVer);
- LitePrefs::ClearPrefs(&m_prefs);
-
- CHXString strPath = GetFullPath(m_strFileName);
- res = LitePrefs::ReadPrefs(strPath, &m_prefs);
- }
- return res;
- }
- STDMETHODIMP
- CHXLitePrefs::OpenShared(const char* pCompanyName)
- {
- return HXR_NOTIMPL; //Open(pCompanyName, "Shared", 0, 0);
- }
- STDMETHODIMP
- CHXLitePrefs::DeletePref(const char* pPrefKey)
- {
- HX_RESULT hr = HXR_FAIL;
- Pref* pPref = NULL;
- m_pMutex->Lock();
- if (m_prefs.Lookup(pPrefKey, (void*&)pPref))
- {
- // delete the pref
- m_prefs.RemoveKey(pPrefKey);
- delete pPref;
- PossiblyCommitPrefChange();
- hr = HXR_OK;
- }
- m_pMutex->Unlock();
- return hr;
- }
- //
- // Restore primary pref file so it contains no pref
- // settings (and update current prefs accordingly)
- //
- STDMETHODIMP
- CHXLitePrefs::ResetPrefs()
- {
- m_pMutex->Lock();
- // force re-write of file so only shadow references remain.
- LitePrefs::ClearPrefs(&m_prefs);
- Commit();
- // re-build memory prefs (so default values from shadows are set)
- CHXString strPrimaryFilePath = GetFullPath(m_strFileName);
- HX_RESULT hr = LitePrefs::ReadPrefs(strPrimaryFilePath, &m_prefs);
- m_pMutex->Lock();
- return hr;
- }
- STDMETHODIMP
- CHXLitePrefs::SetContext(IUnknown* pContext)
- {
- HX_RESULT res = HXR_FAIL;
- if (!m_pFactory && pContext)
- {
- res = pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pFactory);
- HX_ASSERT(SUCCEEDED(res));
- #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- res = pContext->QueryInterface(IID_IHXScheduler,
- (void**)&m_pScheduler);
- HX_ASSERT(SUCCEEDED(res));
- #endif // (HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- }
- return res;
- }
- STDMETHODIMP
- CHXLitePrefs::Commit()
- {
- HX_RESULT res = HXR_NOT_INITIALIZED;
-
- if (m_strFileName)
- {
- m_pMutex->Lock();
- CHXString strPath = GetFullPath(m_strFileName);
- res = LitePrefs::WritePrefs(&m_prefs, strPath);
- m_pMutex->Unlock();
- }
- return res;
- }
- // IHXCallback
- #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
- STDMETHODIMP
- CHXLitePrefs::Func()
- {
- m_hCallback = (CallbackHandle)NULL;
- HX_VERIFY(SUCCEEDED(Commit()));
- return HXR_OK;
- }
- #endif