chxliteprefs.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:17k
源码类别:

Symbian

开发平台:

C/C++

  1. #include "chxliteprefs.h"
  2. #include "hlxclib/fcntl.h"
  3. #include "chxdataf.h"
  4. #include "hxslist.h"
  5. #include "hxstring.h"
  6. #include "hxdir.h"
  7. #include "hxccf.h"
  8. #include "ihxpckts.h"
  9. #include <ctype.h>
  10. #include "hlxclib/stdlib.h"
  11. #include "pathutil.h"
  12. #include "hxthread.h"
  13. BEGIN_INTERFACE_LIST(CHXLitePrefs)
  14.     INTERFACE_LIST_ENTRY_SIMPLE(IHXPreferences)
  15.     INTERFACE_LIST_ENTRY_SIMPLE(IHXPreferences3)
  16. END_INTERFACE_LIST
  17. // for keeping track of a pref value
  18. class Pref
  19. {
  20. public:
  21.     Pref(const char* pStr): m_bChanged(FALSE), m_strValue(pStr){}
  22.     BOOL HasChanged() const { return m_bChanged;}
  23.     void SetChanged(BOOL bChanged) { m_bChanged = bChanged;}
  24.     void SetValue(const char* pStr) { m_strValue = pStr;}
  25.     
  26.     const char* Buffer() const { return m_strValue;}
  27.     UINT32 Size() const {return m_strValue.GetLength() + 1;}
  28. private:
  29.     BOOL    m_bChanged;
  30.     CHXString m_strValue;
  31. };
  32. // helpers local to this module
  33. namespace LitePrefs
  34. {
  35. void ClearPrefs(CHXMapStringToOb* pPrefs);
  36. CHXDataFile* OpenPrefFile(const char* pPath, UINT16 mode);
  37. HX_RESULT WritePrefFile(const char* pPath, CHXStringList& shadows, const CHXMapStringToOb& prefs);
  38. HX_RESULT WritePrefs(const CHXMapStringToOb* pPrefs, const char* pPath);
  39. HX_RESULT ReadPrefs(const char* pPath,
  40.       CHXMapStringToOb* pPrefs);
  41. HX_RESULT ParsePrefs(CHXDataFile* pFile,
  42.        CHXMapStringToOb* pPrefs,
  43.        CHXStringList* pShadows);
  44. HX_RESULT StorePref(CHXMapStringToOb* pPrefs,
  45.       const char* pName,
  46.       const char* pValue,
  47.       BOOL bChanged = TRUE);
  48. HX_RESULT RetrievePref(IHXCommonClassFactory* pFactory,
  49.  const CHXMapStringToOb* pPrefs,
  50.  const char* pName,
  51.  REF(IHXBuffer*) pValue);
  52. void FindNewOrAlteredPrefs(const CHXMapStringToOb& memPrefs, 
  53.                   const CHXMapStringToOb& origPrefs, 
  54.                   CHXMapStringToOb& prefsOut);
  55. BOOL SkipToken(char*& pos, INT32& nCount, char term);
  56. BOOL ParseToken(char*& pos, INT32& nCount, char term, CHXString& token);
  57. CHXString GetBasePath(const CHXString& strPath);
  58. }
  59. //
  60. // get base path part of full filename path (strip off filename)
  61. //
  62. inline
  63. CHXString LitePrefs::GetBasePath(const CHXString& strPath)
  64. {
  65.     CHXString strBase;
  66.     INT32 idxSep = strPath.ReverseFind(OS_SEPARATOR_CHAR);
  67.     if( idxSep != -1 )
  68.     {
  69.         strBase = strPath.Left(idxSep + 1);
  70.     }
  71.     return strBase;
  72. }
  73. //
  74. // go through current prefs (in memory) and determine which entries
  75. // are: a) set in a shadow but now have a different value; or b) not
  76. // in a shadow to begin with
  77. //
  78. inline void
  79. LitePrefs::FindNewOrAlteredPrefs(const CHXMapStringToOb& memPrefs, 
  80.                   const CHXMapStringToOb& origPrefs, 
  81.                   CHXMapStringToOb& prefsOut)
  82. {
  83.     // for each current pref setting (cast away const to work around deficiency in map inteface)...
  84.     CHXMapStringToOb& memPrefs_ = (CHXMapStringToOb&)memPrefs;
  85.     CHXMapStringToOb::Iterator iterEnd = memPrefs_.End();
  86.     for(CHXMapStringToOb::Iterator iter = memPrefs_.Begin(); iter != iterEnd; ++iter)
  87.     {
  88.         Pref* pPref = (Pref*)*iter;
  89.         const char* pKey = iter.get_key();
  90.         HX_ASSERT(pPref);
  91.         HX_ASSERT(pKey);
  92.     
  93.         // transfer this pref if is new or altered
  94.         if( pPref->HasChanged() || (0 != origPrefs.Lookup(pKey)) )
  95.         {
  96.             prefsOut.SetAt(pKey, pPref);
  97.         }
  98.     }
  99. }
  100. //
  101. // Prefs are read from primary file, then shadows. Settings in primary file override
  102. // those in shadows (which are essentially defaults). Therefore the first value that 
  103. // is found for a given pref is the value that remains in effect.
  104. //
  105. HX_RESULT 
  106. LitePrefs::ReadPrefs(const char* pPath,
  107. CHXMapStringToOb* pPrefs)
  108. {
  109.     HX_RESULT res = HXR_FAIL;
  110.     CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_RDONLY);
  111.     if (pFile)
  112.     {
  113.         CHXStringList shadows;
  114.         res = LitePrefs::ParsePrefs(pFile, pPrefs, &shadows);
  115.         pFile->Close();
  116.         // use base path from current pref file to locate regerenced shadow file
  117.         CHXString strBase = LitePrefs::GetBasePath(pPath);
  118.     
  119.         LISTPOSITION i = shadows.GetHeadPosition();
  120.         while(i)
  121.         {
  122.     const CHXString& strShadowFile = *((CHXString*) shadows.GetNext(i));
  123.             CHXString strPath = HXPathUtil::CombinePath(strBase, strShadowFile);
  124.     res = LitePrefs::ReadPrefs(strPath, pPrefs);
  125.         }
  126.     
  127.         HX_DELETE(pFile);
  128.     }
  129.     return res;
  130. }
  131. // helper
  132. CHXDataFile*
  133. LitePrefs::OpenPrefFile(const char* pPath, UINT16 mode)
  134. {
  135.     CHXDataFile* pFile = CHXDataFile::Construct();
  136.     if (pFile)
  137.     {
  138. HX_RESULT res = pFile->Open(pPath, mode, TRUE);
  139. if (FAILED(res))
  140. {
  141.             HX_DELETE(pFile);
  142. }
  143.     }
  144.     return pFile;
  145. }
  146. //
  147. // write out the given file in our pref file format
  148. //
  149. HX_RESULT
  150. LitePrefs::WritePrefFile(const char* pPath, CHXStringList& shadows, const CHXMapStringToOb& prefs)
  151. {
  152.     HX_RESULT hr = HXR_FAIL;
  153.     CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_WRONLY | O_CREAT | O_TRUNC);
  154.     if (pFile)
  155.     {
  156.         //
  157.         // write the shadow pref file references
  158.         //
  159.         LISTPOSITION j = shadows.GetHeadPosition();
  160.         while(j)
  161. {
  162.     const CHXString& fileName = *((CHXString*) shadows.GetNext(j));
  163.     // format shadow, write to file
  164.     pFile->Write("[", 1);
  165.     pFile->Write(fileName, fileName.GetLength());
  166.     pFile->Write("]n", 2);
  167. }
  168.         //
  169.         // write out preference name/value entries
  170.         //
  171.         // cast away const to work around deficiency in map interface...
  172.         CHXMapStringToOb& prefs_ = (CHXMapStringToOb&)prefs;
  173.         CHXMapStringToOb::Iterator iterEnd = prefs_.End();
  174.         for(CHXMapStringToOb::Iterator iter = prefs_.Begin(); iter != iterEnd; ++iter)
  175.         {
  176.             const char* pPrefKey = iter.get_key();
  177.             Pref* pPref = (Pref*)*iter;
  178.             
  179.     pFile->Write(pPrefKey, strlen(pPrefKey));
  180.     pFile->Write("=", 1);
  181.     if (pPref->Size() > 1)
  182.     {
  183. // don't write the null terminator
  184. pFile->Write(pPref->Buffer(), pPref->Size()-1);
  185.     }
  186.     
  187.     pFile->Write("n", 1);
  188. }
  189.         HX_DELETE(pFile);
  190.         hr = HXR_OK;
  191.     }
  192.     return hr;
  193. }
  194. HX_RESULT
  195. LitePrefs::WritePrefs(const CHXMapStringToOb* pPrefs, const char* pPath)
  196. {
  197.     HX_RESULT res = HXR_FAIL;
  198.     CHXDataFile* pFile = LitePrefs::OpenPrefFile(pPath, O_RDONLY);
  199.     if (pFile)
  200.     {
  201. // read current preference settings from files
  202. CHXStringList shadows;
  203. CHXMapStringToOb origPrefs;
  204. res = LitePrefs::ParsePrefs(pFile, &origPrefs, &shadows);
  205.         HX_DELETE(pFile);
  206. if (SUCCEEDED(res))
  207. {
  208.             // determine altered or new preferences
  209.             CHXMapStringToOb newPrefs;
  210.             FindNewOrAlteredPrefs(*pPrefs, origPrefs, newPrefs);
  211.             // write out the prefs with our up-to-date values
  212.             LitePrefs::WritePrefFile(pPath, shadows, newPrefs);
  213. }
  214.         
  215. LitePrefs::ClearPrefs(&origPrefs);
  216.     }
  217.     return res;
  218. }
  219. HX_RESULT 
  220. LitePrefs::StorePref(CHXMapStringToOb* pPrefs,
  221. const char* pName,
  222. const char* pValue,
  223. BOOL bChanged)
  224. {
  225.     Pref* pPref = NULL;
  226.     if (pPrefs->Lookup(pName, (void*&)pPref))
  227.     {
  228.         // update existing pref
  229.         pPref->SetValue(pValue);
  230.     }
  231.     else
  232.     {   
  233.         // create and add new pref
  234.         pPref = new Pref(pValue);
  235.         if(!pPref)
  236.         {
  237.             return HXR_OUTOFMEMORY;
  238.         }
  239.         pPrefs->SetAt(pName, pPref);
  240.     }
  241.     
  242.     pPref->SetChanged(bChanged);
  243.     return HXR_OK;
  244. }
  245. HX_RESULT
  246. LitePrefs::ParsePrefs(CHXDataFile* pFile,
  247.  CHXMapStringToOb* pPrefs,
  248.  CHXStringList* pShadows)
  249. {
  250.     HX_ASSERT(pFile && pPrefs && pShadows);
  251.     #define BUF_SZ 0x0400 // read file in 1k chunks
  252.     ParseState eState = eParsingWhiteSpace;
  253.     INT32 nCount = 0;
  254.     CHXString strBuf;
  255.     char* pos = 0;
  256.     char* buf = strBuf.GetBuffer(BUF_SZ);
  257.     CHXString sName;
  258.     CHXString sValue;
  259.     for (;;)
  260.     {
  261. // read more data
  262. if (nCount == 0)
  263. {
  264.     nCount = (INT32)pFile->Read(buf, BUF_SZ);
  265.     if (nCount <= 0)
  266.             {
  267.                 // end of file
  268. break;
  269.             }
  270.     pos = buf;
  271. }
  272.         switch(eState)
  273.         {
  274.         case eParsingValue:
  275.         {
  276.             if (LitePrefs::ParseToken(pos, nCount, 'n', sValue))
  277.             {
  278.                 eState = eParsingWhiteSpace;
  279.             
  280.                 // don't add this name value if name already exists in prefs
  281.                 if(0 ==  pPrefs->Lookup(sName))
  282.                 {
  283.                     HX_RESULT res = LitePrefs::StorePref(pPrefs, sName, sValue, FALSE);
  284.                     if (FAILED(res))
  285.                     {
  286.                         return res;
  287.                     }
  288.                 }
  289.                 sName.Empty();
  290.                 sValue.Empty();
  291.             }
  292.             
  293.         }
  294.         break;
  295.         case eParsingComment:
  296.         {
  297.             // skip to end of line
  298.             if (LitePrefs::SkipToken(pos, nCount, 'n'))
  299.             {
  300.                 eState = eParsingWhiteSpace;
  301.             }
  302.         }
  303.         break;
  304.         case eParsingName:
  305.         {
  306.             // name is everything up to '='
  307.             if (LitePrefs::ParseToken(pos, nCount, '=', sName))
  308.             {
  309.                 eState = eParsingValue;
  310.             }
  311.         }
  312.         break;
  313.         case eParsingShadow:
  314.         {
  315.             // shadow reference is everything up to closing ']'
  316.             if (LitePrefs::ParseToken(pos, nCount, ']', sName))
  317.             {
  318.                 eState = eParsingComment;
  319.           
  320.                 // queue this up for parsing
  321.                 pShadows->AddTailString(sName);
  322.                 sName.Empty();
  323.             }
  324.         }
  325.         break;
  326.         case eParsingWhiteSpace:
  327.         {
  328.                 // we're looking for something to parse
  329.                 switch (*pos)
  330.                 {
  331.                     case '[':
  332.                     {
  333.                         eState = eParsingShadow;
  334.                     }
  335.                     break;
  336.                     case '#':
  337.                     case ';':
  338.                     {
  339.                         eState = eParsingComment;
  340.                     }
  341.                     break;
  342.                     default:
  343.                     {
  344.                         eState = eParsingName;
  345.                         sName = *pos; // don't lose this char
  346.                     }
  347.                 }
  348.                 ++pos;
  349.                 --nCount;
  350.         }
  351.         break;
  352.         default:
  353.             HX_ASSERT(false);
  354.             break;
  355.         }
  356.     }
  357.     return HXR_OK;
  358. }
  359. void
  360. LitePrefs::ClearPrefs(CHXMapStringToOb* pPrefs)
  361. {
  362.     POSITION pos = pPrefs->GetStartPosition();
  363.     while(pos != NULL)
  364.     {
  365.         Pref * pPref = NULL;
  366.         char * szPrefKey = NULL;
  367.         pPrefs->GetNextAssoc( pos, (const char*&) szPrefKey, (void*&) pPref );
  368.         HX_ASSERT(pPref);
  369.         delete pPref;
  370.     }
  371.     pPrefs->RemoveAll();
  372. }
  373. HX_RESULT 
  374. LitePrefs::RetrievePref(IHXCommonClassFactory* pFactory,
  375.    const CHXMapStringToOb* pPrefs,
  376.    const char* pName,
  377.    REF(IHXBuffer*) pValue)
  378. {
  379.     HX_RESULT res = HXR_FAIL;
  380.     Pref* pPref = NULL;
  381.     if (pPrefs->Lookup(pName, (void*&)pPref))
  382.     {
  383. res = pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pValue);
  384. if (SUCCEEDED(res))
  385. {
  386.     res = pValue->Set((const UCHAR*)pPref->Buffer(), 
  387.    pPref->Size());
  388. }
  389.     }
  390.     return res;
  391. }
  392. BOOL
  393. LitePrefs::SkipToken(char*& pos, INT32& nCount, char term)
  394. {
  395.     BOOL bRet = FALSE;
  396.     while (*pos != term && nCount != 0)
  397.     {
  398.         ++pos;
  399.         --nCount;
  400.     }
  401.     if( nCount != 0 )
  402.     {
  403.         // skip term
  404.         ++pos;
  405.         --nCount;
  406.         bRet = TRUE;
  407.     }
  408.     return bRet;
  409. }
  410. BOOL
  411. LitePrefs::ParseToken(char*& pos, INT32& nCount, char term, CHXString& token)
  412. {
  413.     BOOL bRet = FALSE;
  414.     while (*pos != term && nCount != 0)
  415.     {
  416.         token += *pos;
  417.         ++pos;
  418.         --nCount;
  419.     }
  420.     if( nCount != 0 )
  421.     {
  422.         // skip term
  423.         ++pos;
  424.         --nCount;
  425.         // trim white space around token
  426.         token.TrimLeft();
  427.         token.TrimRight();
  428.         bRet = TRUE;
  429.     }
  430.     return bRet;
  431. }
  432. //
  433. // class CHXLitePrefs
  434. //
  435. CHXLitePrefs::CHXLitePrefs(const char* pRootPath)
  436. : m_pMutex(NULL)
  437. , m_pFactory(NULL)
  438. , m_pScheduler(NULL)
  439. , m_hCallback((CallbackHandle)NULL)
  440. , m_strRootPath(pRootPath)
  441. , m_bAutoCommit(true)
  442. {
  443. #ifdef THREADS_SUPPORTED
  444.     HXMutex::MakeMutex(m_pMutex);
  445. #else
  446.     HXMutex::MakeStubMutex(m_pMutex);
  447. #endif
  448.     m_prefs.SetCaseSensitive(FALSE);
  449. }
  450. CHXLitePrefs::~CHXLitePrefs()
  451. {
  452.     Close();
  453. }
  454. inline
  455. CHXString CHXLitePrefs::GetFullPath(const CHXString& strFileName)
  456. {
  457.     return HXPathUtil::CombinePath(m_strRootPath, strFileName);
  458. }
  459. void
  460. CHXLitePrefs::Close()
  461. {
  462. #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
  463.     // remove pending callback
  464.     if (m_hCallback)
  465.     {
  466. m_pScheduler->Remove(m_hCallback);
  467.         m_hCallback = (CallbackHandle)NULL;
  468.     }
  469. #endif // (HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
  470.     // commit changes
  471.     Commit();
  472.     // cleanup
  473.     LitePrefs::ClearPrefs(&m_prefs);
  474.     HX_RELEASE(m_pFactory);
  475.     HX_RELEASE(m_pScheduler);
  476.     HX_DELETE(m_pMutex);
  477. }
  478. // IHXPreferences
  479. STDMETHODIMP
  480. CHXLitePrefs::ReadPref(const char* pName, REF(IHXBuffer*) pValue)
  481. {
  482.     HX_RESULT res = HXR_FAIL;
  483.     if (pName && m_pFactory)
  484.     {
  485. m_pMutex->Lock();
  486. res = LitePrefs::RetrievePref(m_pFactory, &m_prefs, pName, pValue);
  487. m_pMutex->Unlock();
  488.     }
  489.     return res;
  490. }
  491. STDMETHODIMP
  492. CHXLitePrefs::SetAutoCommit(bool bAutoCommit)
  493. {
  494.     // if false, client must explicitly call Commit() to save changes after write
  495.     m_bAutoCommit = bAutoCommit;
  496.     return HXR_OK;
  497. }
  498. void
  499. CHXLitePrefs::PossiblyCommitPrefChange()
  500. {
  501.     if (m_bAutoCommit)
  502.     {
  503. #if defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)      
  504.         HX_VERIFY(SUCCEEDED(Commit()));
  505. #else
  506.         // schedule a callback and commit the changes
  507.         // so that multiple WritePref calls result in only one write to file
  508. if (!m_hCallback && m_pScheduler)
  509. {
  510.     m_hCallback = m_pScheduler->RelativeEnter(this, 0);
  511.     HX_ASSERT(m_hCallback);
  512. }
  513. else if (!m_pScheduler)
  514. {
  515.     // lame... no scheduler!
  516.     HX_VERIFY(SUCCEEDED(Commit()));
  517. }
  518. #endif
  519.     }
  520. }
  521. STDMETHODIMP
  522. CHXLitePrefs::WritePref(const char* pName, IHXBuffer* pValue)
  523. {
  524.     HX_RESULT res = HXR_FAIL;
  525.     if (pName && pValue)
  526.     {
  527. m_pMutex->Lock();
  528. res = LitePrefs::StorePref(&m_prefs, pName, (const char*)pValue->GetBuffer());
  529.         if(SUCCEEDED(res))
  530.         {
  531.             PossiblyCommitPrefChange();
  532.         }
  533.         m_pMutex->Unlock();
  534.     }
  535.     return res;
  536. }
  537. // IHXPreferences3
  538. STDMETHODIMP
  539. CHXLitePrefs::Open(const char* pCompanyName,
  540.    const char* pProductName,
  541.    ULONG32 nProdMajorVer,
  542.    ULONG32 nProdMinorVer)
  543. {
  544.     HX_RESULT res = HXR_INVALID_PARAMETER;
  545.     if (pProductName)
  546.     {
  547.         m_strFileName.Format("%s_%lu_%lu.cfg",pProductName, nProdMajorVer, nProdMinorVer); 
  548. LitePrefs::ClearPrefs(&m_prefs);
  549.     
  550.         CHXString strPath = GetFullPath(m_strFileName);
  551.         res = LitePrefs::ReadPrefs(strPath, &m_prefs);
  552.     }
  553.     return res;
  554. }
  555. STDMETHODIMP
  556. CHXLitePrefs::OpenShared(const char* pCompanyName)
  557. {
  558.     return HXR_NOTIMPL; //Open(pCompanyName, "Shared", 0, 0);
  559. }
  560. STDMETHODIMP
  561. CHXLitePrefs::DeletePref(const char* pPrefKey)
  562. {
  563.     HX_RESULT hr = HXR_FAIL;
  564.     Pref* pPref = NULL;
  565.     m_pMutex->Lock();
  566.     if (m_prefs.Lookup(pPrefKey, (void*&)pPref))
  567.     {
  568. // delete the pref
  569.         m_prefs.RemoveKey(pPrefKey);
  570. delete pPref;
  571.         PossiblyCommitPrefChange();
  572.         hr = HXR_OK;
  573.     }
  574.     m_pMutex->Unlock();
  575.     return hr;
  576. }
  577. //
  578. // Restore primary pref file so it contains no pref
  579. // settings (and update current prefs accordingly) 
  580. //
  581. STDMETHODIMP
  582. CHXLitePrefs::ResetPrefs()
  583. {
  584.     m_pMutex->Lock();
  585.     // force re-write of file so only shadow references remain.
  586.     LitePrefs::ClearPrefs(&m_prefs);
  587.     Commit();
  588.     // re-build memory prefs (so default values from shadows are set)
  589.     CHXString strPrimaryFilePath = GetFullPath(m_strFileName);
  590.     HX_RESULT hr = LitePrefs::ReadPrefs(strPrimaryFilePath, &m_prefs);
  591.     m_pMutex->Lock();
  592.     return hr;
  593. }
  594. STDMETHODIMP
  595. CHXLitePrefs::SetContext(IUnknown* pContext)
  596. {
  597.     HX_RESULT res = HXR_FAIL;
  598.     if (!m_pFactory && pContext)
  599.     {
  600. res = pContext->QueryInterface(IID_IHXCommonClassFactory,
  601.        (void**)&m_pFactory);
  602. HX_ASSERT(SUCCEEDED(res));
  603. #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
  604. res = pContext->QueryInterface(IID_IHXScheduler,
  605.        (void**)&m_pScheduler);
  606. HX_ASSERT(SUCCEEDED(res));
  607. #endif // (HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
  608.     }
  609.     return res;
  610. }
  611. STDMETHODIMP
  612. CHXLitePrefs::Commit()
  613. {
  614.     HX_RESULT res = HXR_NOT_INITIALIZED;
  615.     
  616.     if (m_strFileName)
  617.     {
  618. m_pMutex->Lock();
  619.         CHXString strPath = GetFullPath(m_strFileName);
  620. res = LitePrefs::WritePrefs(&m_prefs, strPath);
  621. m_pMutex->Unlock();
  622.     }
  623.     return res;
  624. }
  625. // IHXCallback
  626. #if !defined(HELIX_CONFIG_LITEPREFS_SLUGGISH_OUT)
  627. STDMETHODIMP
  628. CHXLitePrefs::Func()
  629. {
  630.     m_hCallback = (CallbackHandle)NULL;
  631.     HX_VERIFY(SUCCEEDED(Commit()));
  632.     return HXR_OK;
  633. }
  634. #endif