📄 chxliteprefs.cpp
字号:
#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 ';':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -