mac_pref_cf.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 14k
Category:

Symbian

Development Platform:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "platform/mac/mac_pref_cf.h"
  36. #include "hxbuffer.h"
  37. #include "filespecutils.h"
  38. const char * kPrefPrefixSeparator = "\"; // backslash since no Windows programmer will use it inside of a key
  39. //  call open_pref() to automatically create the correct Macintosh specific preference object.
  40. CMacPref * CMacPref::open_pref(const char* pCompanyName, const char* pProductName, int nProdMajorVer, int nProdMinorVer, BOOL bCommon)
  41. {
  42.     return new CMacPref(pCompanyName, pProductName, nProdMajorVer, nProdMinorVer, bCommon);
  43. }
  44. //  Constructor NOTE: use open_pref() to create an instance of this class
  45. CMacPref::CMacPref(const char* pCompanyName, const char* pProductName, int nProdMajorVer, int nProdMinorVer, BOOL bCommon)
  46. {  
  47. CHXString strBundleID;
  48. CFStringRef userNameRef, hostNameRef;
  49. CHXCFString cfsPrefsBundleName;
  50. check(pCompanyName && *pCompanyName);
  51. check(pProductName && *pProductName);
  52. check(strcspn(pCompanyName, " .,;:/\!@#$%^&*()"") == strlen(pCompanyName)); // ensure there are no punctuation
  53. // prefs common among all users are "any user, current host"
  54. // prefs for just the current user are "current user, any host"
  55. userNameRef = bCommon ? kCFPreferencesAnyUser : kCFPreferencesCurrentUser;
  56. hostNameRef = bCommon ? kCFPreferencesCurrentHost : kCFPreferencesAnyHost;
  57. m_pPrefFile = NULL;
  58. m_strProductNamePrefix = pProductName;
  59. // Added support for overloading the preference file name.
  60. // If the HelixPreferenceFileID preferences exists in the main bundle's pref's, then use its value as the pref. filename.
  61. CFBundleRef mainBundleRef = NULL;
  62.         CFStringRef mainBundleID = NULL;
  63.         CFStringRef helixPrefFileID = NULL;
  64.         
  65.         mainBundleRef = CFBundleGetMainBundle();
  66.         
  67.         if (mainBundleRef)
  68.         {
  69.             // if previous step succeeded (failure possible with CFM app)
  70.             mainBundleID = CFBundleGetIdentifier( mainBundleRef );
  71.         }
  72.         
  73.         if (mainBundleID)
  74.         {
  75.             // if previous step succeeded
  76.             helixPrefFileID = ( CFStringRef ) CFPreferencesCopyAppValue( CFSTR( "HelixPreferenceFileID" ), mainBundleID );
  77.         }
  78.         
  79. if ( helixPrefFileID )
  80. {
  81. // Support mapping of helix product names to application specific values.
  82. m_pPrefFile = CMacPrefFile::CreatePrefSystemObject( helixPrefFileID, userNameRef, hostNameRef );
  83. CFDataRef helixPrefMapRef = ( CFDataRef ) CFPreferencesCopyAppValue( CFSTR( "HelixPrefMap" ), helixPrefFileID );
  84. if ( helixPrefMapRef )
  85. {
  86. CFStringRef errorString;
  87. CFDictionaryRef helixPrefMap = ( CFDictionaryRef ) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, helixPrefMapRef, kCFPropertyListImmutable, &errorString );
  88. if ( helixPrefMap )
  89. {
  90. CFStringRef key = CFStringCreateWithCString( kCFAllocatorDefault, m_strProductNamePrefix, kCFStringEncodingUTF8 );
  91. if ( key )
  92. {
  93. CFStringRef mappedPrefixName = ( CFStringRef ) CFDictionaryGetValue( helixPrefMap, key );
  94. if ( mappedPrefixName )
  95. {
  96. m_strProductNamePrefix = mappedPrefixName;
  97. }
  98. CFRelease( key );
  99. }
  100. CFRelease( helixPrefMap );
  101. }
  102. if ( errorString )
  103. {
  104. CFRelease( errorString );
  105. }
  106. CFRelease( helixPrefMapRef );
  107. }
  108. CFRelease( helixPrefFileID );
  109. }
  110. else
  111. {
  112. strBundleID.Format("com.%s.%s", pCompanyName, pProductName);
  113. cfsPrefsBundleName = strBundleID;
  114. m_pPrefFile = CMacPrefFile::CreatePrefSystemObject( cfsPrefsBundleName, userNameRef, hostNameRef );
  115. }
  116. // save the product name which becomes the prefix for each pref entry, like "RealMediaSDK"
  117. m_strProductNamePrefix += kPrefPrefixSeparator;
  118. check_nonnull(m_pPrefFile);
  119. if (bCommon)
  120. {
  121. HX_ASSERT(!"Using machine-wide prefs, which fails for non-admin users. Absolutely sure?");
  122. }
  123. }
  124. //  class destructor 
  125. CMacPref::~CMacPref (void)
  126. {
  127. commit_prefs(); // writes prefs to disk
  128. EndAllSubPrefs(); // frees up the stack of CHXStrings
  129. if (m_pPrefFile)
  130. {
  131. HX_DELETE(m_pPrefFile);
  132. }
  133. }
  134. HX_RESULT CMacPref::commit_prefs(void)
  135. {
  136. require_nonnull_return(m_pPrefFile, HXR_NOT_INITIALIZED);
  137. m_pPrefFile->Synchronize();
  138. // Boolean bSuccess = CFPreferencesAppSynchronize(m_cfsPrefsBundleName);
  139. //return bSuccess ? HXR_OK : HXR_FAIL;
  140. return HXR_OK;
  141. }
  142. void CMacPref::MakePrefKeyCF(const char *pPrefKey, CHXCFString& outCfsRealKey)
  143. {
  144. CHXString strKey;
  145. MakePrefKey(pPrefKey, strKey);
  146. outCfsRealKey = strKey;
  147. }
  148. void CMacPref::MakePrefKey(const char *pPrefKey, CHXString& outMadeKey)
  149. {
  150. CHXString strInKey;
  151. //check(strstr(pPrefKey, kPrefPrefixSeparator) == 0); // check that the separator isn't in a key
  152. // alas, the Core sometimes builds subprefs by lazily including backslashes
  153. strInKey = pPrefKey;
  154. // delete any leading separator at the beginning of the string
  155. if (strInKey.Find(kPrefPrefixSeparator) == 0)
  156. {
  157. strInKey = strInKey.Right(strInKey.GetLength() - strlen(kPrefPrefixSeparator));
  158. }
  159. // the full key is constructed as "Product/Subpref/Key"
  160. outMadeKey = m_strProductNamePrefix;
  161. if (m_strSubPrefPrefix.IsEmpty())
  162. {
  163. // no subpref prefix
  164. outMadeKey += strInKey;
  165. }
  166. else
  167. {
  168. // prepend with subpref prefix
  169. outMadeKey += m_strSubPrefPrefix;
  170. outMadeKey += strInKey;
  171. }
  172. }
  173. HX_RESULT CMacPref::MakeIHXBuffer(const char *pData, IHXBuffer*& pBuffer)
  174. {
  175. check_nonnull(pData);
  176. return CHXBuffer::FromCharArray(pData, &pBuffer);
  177. }
  178. //  read_pref reads the preference specified by Key to the Buffer.
  179. HX_RESULT CMacPref::read_pref(const char* pPrefKey, IHXBuffer*& pBuffer)
  180. {
  181. require_nonnull_return(m_pPrefFile, HXR_NOT_INITIALIZED);
  182. CHXCFString cfsKey;
  183. CHXCFString cfsPref;
  184. MakePrefKeyCF(pPrefKey, cfsKey);
  185. cfsPref = (CFStringRef) m_pPrefFile->CopyValue(cfsKey);
  186. if (cfsPref.IsSet())
  187. {
  188. CHXString str;
  189. str = cfsPref;
  190. return MakeIHXBuffer((const char *) str, pBuffer);
  191. }
  192. return HXR_FAIL;
  193. }
  194.  
  195. //  write_pref writes (saves) the preference specified by pPrefKey from the Buffer. 
  196. HX_RESULT CMacPref::write_pref(const char* pPrefKey, IHXBuffer* pBuffer)
  197. {   
  198. require_nonnull_return(m_pPrefFile, HXR_NOT_INITIALIZED);
  199. CHXCFString cfsKey;
  200. CHXCFString cfsValue((const char *) pBuffer->GetBuffer());
  201. MakePrefKeyCF(pPrefKey, cfsKey);
  202. // CFPreferences doesn't return an error for this...
  203. m_pPrefFile->SetValue(cfsKey, cfsValue);
  204. //::CFPreferencesSetValue(cfsKey, cfsValue, m_cfsPrefsBundleName, m_UserNameRef, m_HostNameRef);
  205. return HXR_OK;
  206. }
  207. //  delete_pref deletes the preference specified by Key from the Buffer.
  208. HX_RESULT CMacPref::delete_pref(const char* pPrefKey)
  209. {   
  210.     return remove_pref(pPrefKey);
  211. }
  212. HX_RESULT CMacPref::remove_pref(const char* pPrefKey)
  213. {
  214. // pPrefKey is either a key (in the current subpref) or a subpref branch name
  215. // (also in the current subpref)
  216. // try deleting that key directly
  217. RemoveSinglePrefInternal(pPrefKey);
  218. // now try deleting that key as a subpref subtree: we'll set to the subpref and
  219. // remove all keys inside of it
  220. if (pPrefKey && *pPrefKey)
  221. {
  222. const UINT32 kFirstKeyIndex = 0;
  223. CHXString strKey;
  224. const BOOL kReturnDeeperNestings = TRUE;
  225. BeginSubPref(pPrefKey);
  226. while (1)
  227. {
  228. HX_RESULT res = GetPrefKeyInternal(kFirstKeyIndex, kReturnDeeperNestings, strKey); // we want "sub/x" and "sub/x/y"
  229. if (FAILED(res)) break;
  230. RemoveSinglePrefInternal(strKey);
  231. }
  232. EndSubPref();
  233. }
  234. return HXR_OK;
  235. }
  236. void CMacPref::RemoveSinglePrefInternal(const char* pPrefKey)
  237. {
  238. require_nonnull_void_return(m_pPrefFile);
  239. const CFPropertyListRef kRemovePreference = NULL;
  240. CHXCFString cfsKey;
  241. MakePrefKeyCF(pPrefKey, cfsKey);
  242. m_pPrefFile->SetValue(cfsKey, kRemovePreference); // CFPrefs doesn't return an error for this
  243. }
  244. HX_RESULT CMacPref::remove_indexed_pref(const char* pPrefKey)
  245. {
  246. CHXString strKey;
  247. UINT16 index;
  248. IHXBuffer* pBuffer;
  249. HX_RESULT err;
  250. index = 1;
  251. while (1)
  252. {
  253. strKey.Format("%s%d", pPrefKey, index);
  254. // if there's one with this index, remove it
  255. pBuffer = nil;
  256. err = read_pref(strKey, pBuffer);
  257. HX_RELEASE(pBuffer);
  258. if (SUCCEEDED(err))
  259. {
  260. err = remove_pref(strKey);
  261. check_success(err);
  262. index++;
  263. }
  264. else
  265. {
  266. // no more keyN prefs here; we're done
  267. break;
  268. }
  269. }
  270. return HXR_OK;
  271. }
  272. HX_RESULT CMacPref::BeginSubPref(const char* szSubPref)
  273. {
  274. check(szSubPref && strlen(szSubPref));
  275. // if there was already a prefix, push it onto the stack to save it for later
  276. if (!m_strSubPrefPrefix.IsEmpty())
  277. {
  278. CHXString *pStrNew = new CHXString;
  279. check_nonnull(pStrNew);
  280. *pStrNew = (const char *) m_strSubPrefPrefix;
  281. m_arrSubKeyStack.Add(&pStrNew);
  282. }
  283. // now add the new subpref prefix part and a separator to the previous subpref prefix
  284. m_strSubPrefPrefix += szSubPref;
  285. m_strSubPrefPrefix += kPrefPrefixSeparator;
  286. return HXR_OK;
  287. }
  288. HX_RESULT CMacPref::EndSubPref()
  289. {
  290. require_return(!m_strSubPrefPrefix.IsEmpty(), HXR_FAIL);
  291. m_strSubPrefPrefix.Empty();
  292. if (!m_arrSubKeyStack.IsEmpty())
  293. {
  294. // we're nested in; pop an old prefix off the stack
  295. CHXString *pStrOld;
  296. HX_RESULT res = HXR_OK;
  297. pStrOld = (CHXString*)m_arrSubKeyStack.GetAt(m_arrSubKeyStack.GetSize()-1);
  298. m_arrSubKeyStack.RemoveAt(m_arrSubKeyStack.GetSize()-1);
  299. check_success(res);
  300. if (SUCCEEDED(res))
  301. {
  302. m_strSubPrefPrefix = (const char *) *pStrOld;
  303. delete pStrOld;
  304. }
  305. }
  306. return HXR_OK;
  307. }
  308. void CMacPref::EndAllSubPrefs()
  309. {
  310. while (!m_arrSubKeyStack.IsEmpty())
  311. {
  312. // get rid of those old CHxStrings
  313. EndSubPref();
  314. }
  315. m_strSubPrefPrefix.Empty();
  316. }
  317. HX_RESULT CMacPref::GetPrefKey(UINT32 nIndex,IHXBuffer*& pBuffer)
  318. {
  319. const BOOL kDontReturnDeeperNestings = FALSE;
  320. CHXString strKey;
  321. HX_RESULT res = GetPrefKeyInternal(nIndex, kDontReturnDeeperNestings, strKey);
  322. if ( SUCCEEDED( res ) )
  323. {
  324. res = MakeIHXBuffer((const char *) strKey, pBuffer);
  325. }
  326. return res;
  327. }
  328. HX_RESULT CMacPref::GetPrefKeyInternal(UINT32 nIndex, BOOL bReturnDeeperNestings, CHXString& outStrKey)
  329. {
  330. require_nonnull_return(m_pPrefFile, HXR_NOT_INITIALIZED);
  331. CFArrayRef cfArray;
  332. HX_RESULT res;
  333. res = HXR_FAIL;
  334. // Get the array of keys from our preferences file, step through the keys, and look for
  335. // any beginning with the current SubPref prefix.
  336. //
  337. // We only want to count and return keys with the matching SubPref prefix that are not 
  338. // nested more deeply.  For example, for the SubPref  'foo', we want to return 'fooa' 
  339. // and 'foob' but not 'fooxc'
  340. cfArray = m_pPrefFile->CopyKeyList();
  341. //cfArray = CFPreferencesCopyKeyList(m_cfsPrefsBundleName, m_UserNameRef, m_HostNameRef);
  342. if (cfArray)
  343. {
  344. CFIndex numArrayElements, nCountDown, idx;
  345. CHXString strCurrKey, strCurrKeyAfterPrefix, strActivePrefix;
  346. // make the current prefix including product name and any subpref
  347. MakePrefKey("", strActivePrefix);
  348. nCountDown = nIndex; // when nCountDown hits zero, we return the next appropriate key
  349. numArrayElements = CFArrayGetCount(cfArray);
  350. for (idx = 0; idx < numArrayElements; idx++)
  351. {
  352. CFStringRef cfsRef; // we're not using CHXCFString since we won't release these; they belong to the array
  353. cfsRef = (CFStringRef) CFArrayGetValueAtIndex(cfArray, idx);
  354. check_nonnull(cfsRef);
  355. if (cfsRef)
  356. {
  357. UINT32 prefixLen, keyLen;
  358. // convert this key to a CHXString
  359. strCurrKey = cfsRef;
  360. // if the left side of the key matches our current prefix,
  361. // then this counts
  362. prefixLen = strActivePrefix.GetLength();
  363. keyLen = strCurrKey.GetLength();
  364. // check that the prefix matches
  365. if (prefixLen == 0 || strActivePrefix == strCurrKey.Left( prefixLen ))
  366. {
  367. // check that this is not a key for a deeper subpref (if it is,
  368. // there will be another separator in the key string)
  369. strCurrKeyAfterPrefix = strCurrKey.Right(keyLen - prefixLen);
  370. if (bReturnDeeperNestings ||
  371. -1 == strCurrKeyAfterPrefix.Find(kPrefPrefixSeparator) )
  372. {
  373. if (nCountDown > 0)
  374. {
  375. nCountDown--;
  376. }
  377. else
  378. {
  379. // this is the one to return
  380. outStrKey = (const char*) strCurrKeyAfterPrefix;
  381. res = HXR_OK;
  382. // no need to look at others
  383. break;
  384. }
  385. }
  386. }
  387. }
  388. }
  389. CFRelease(cfArray);
  390. }
  391. return res;
  392. }