mac_pref_file.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:15k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: mac_pref_file.cpp,v 1.2.32.3 2004/07/09 01:47:27 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "platform/mac/mac_pref_file.h"
  50. #ifndef _MAC_UNIX
  51. #include "filespecutils.h"
  52. #endif
  53. CMacPrefFile*
  54. CMacPrefFile::CreatePrefSystemObject( CFStringRef appIDStringRef, 
  55. CFStringRef userNameRef, CFStringRef hostNameRef ) // static
  56. {
  57. HX_RESULT res = HXR_FAIL;
  58. CMacPrefFileCFPref* pObj = new CMacPrefFileCFPref;
  59. check_nonnull( pObj );
  60. if ( pObj )
  61. {
  62. pObj->SetPrefsID( appIDStringRef, userNameRef, hostNameRef );
  63. res = HXR_OK;
  64. }
  65. return (CMacPrefFile*) pObj;
  66. }
  67. #ifndef _MAC_UNIX
  68. CMacPrefFile*
  69. CMacPrefFile::CreatePrefXMLObject( CHXFileSpecifier& fileSpec, CFStringRef appIDStringRef, const char* pProductName ) // static
  70. {
  71. HX_RESULT res = HXR_FAIL;
  72. CMacPrefFileXML* pObj = new CMacPrefFileXML;
  73. check_nonnull( pObj );
  74. if ( pObj )
  75. {
  76. pObj->SetPrefsFileSpec( fileSpec, appIDStringRef, pProductName );
  77. res = HXR_OK;
  78. }
  79. return (CMacPrefFile*) pObj;
  80. }
  81. #endif // _MAC_UNIX
  82. #pragma mark -
  83. //////////////////////////////////////////////////////////////////////////////////
  84. //
  85. // CMacPrefFileCFPref methods are just thin wrappers on CFPreferences functions
  86. //
  87. CMacPrefFileCFPref::CMacPrefFileCFPref()
  88. : m_PrefsAppIDNameRef( NULL ),
  89.   m_UserNameRef( NULL ),
  90.   m_HostNameRef( NULL ),
  91.   m_bInitialized( false )
  92. {
  93. }
  94. CMacPrefFileCFPref::~CMacPrefFileCFPref()
  95. {
  96. Destroy();
  97. }
  98. void 
  99. CMacPrefFileCFPref::SetPrefsID( CFStringRef appIDStringRef, CFStringRef userNameRef, CFStringRef hostNameRef )
  100. {
  101. require_nonnull_void_return( appIDStringRef );
  102. require_nonnull_void_return( userNameRef );
  103. require_nonnull_void_return( hostNameRef );
  104. Destroy();
  105. m_PrefsAppIDNameRef = appIDStringRef;
  106. m_UserNameRef = userNameRef;
  107. m_HostNameRef = hostNameRef;
  108. ::CFRetain( (CFStringRef) m_PrefsAppIDNameRef );
  109. ::CFRetain( (CFStringRef) m_UserNameRef );
  110. ::CFRetain( (CFStringRef) m_HostNameRef );
  111. m_bInitialized = true;
  112. }
  113. void
  114. CMacPrefFileCFPref::Destroy()
  115. {
  116. if ( m_PrefsAppIDNameRef ) ::CFRelease( (CFStringRef) m_PrefsAppIDNameRef );
  117. if ( m_UserNameRef )  ::CFRelease( (CFStringRef) m_UserNameRef );
  118. if ( m_HostNameRef )  ::CFRelease( (CFStringRef) m_HostNameRef );
  119. m_bInitialized = false;
  120. }
  121. CFPropertyListRef
  122. CMacPrefFileCFPref::CopyValue( CFStringRef key )
  123. {
  124. require_return( m_bInitialized, NULL );
  125. return ::CFPreferencesCopyValue(key, m_PrefsAppIDNameRef, m_UserNameRef, m_HostNameRef );
  126. }
  127. void
  128. CMacPrefFileCFPref::SetValue( CFStringRef key, CFPropertyListRef value )
  129. {
  130. require_void_return( m_bInitialized );
  131. ::CFPreferencesSetValue( key, value, m_PrefsAppIDNameRef, m_UserNameRef, m_HostNameRef );
  132. }
  133. CFArrayRef
  134. CMacPrefFileCFPref::CopyKeyList( void )
  135. {
  136. require_return( m_bInitialized, NULL );
  137. return ::CFPreferencesCopyKeyList( m_PrefsAppIDNameRef, m_UserNameRef, m_HostNameRef );
  138. }
  139. void
  140. CMacPrefFileCFPref::Synchronize( void )
  141. {
  142. require_void_return( m_bInitialized );
  143. ::CFPreferencesSynchronize( m_PrefsAppIDNameRef, m_UserNameRef, m_HostNameRef );
  144. }
  145. #pragma mark -
  146. #ifndef _MAC_UNIX
  147. //////////////////////////////////////////////////////////////////////////////////
  148. //
  149. // CMacPrefFileXML methods keep the prefs in a dictionary stores as XML in a file
  150. //
  151. /*  Coherence strategy
  152.     
  153.     Because this object is implemented in a static library and included by multiple
  154.     shared libraries, we have to take care that our data (m_DictRef) doesn't
  155.     become stale compared to other instances data.
  156.     
  157.     The strategy we'll use to ensure coherence is:
  158.     - A "coherence value" is a 32-bit non-zero seed that we store via CFPreferences in user prefs
  159.       every time we write out the preferences.  We don't really care if the seed
  160.       is remembered across runs; it just needs to be the same for all running instances
  161.       of this object.  CFPreferences acts as a global cache for the app, so the 
  162.       seed is independent of the object instance and library.
  163.       
  164.     - For every get, if the object's seed doesn't match the seed stored in the user preferences,
  165.       we'll re-load the dictionary from the file prior to reading the caller's key's value.
  166.       
  167.     - For every set, we'll read the pref first to ensure that our dictionary is up-to-date
  168.       and to avoid saving the new set value if it's the same as the old value. If necessary, we'll
  169.       save the new value in our dictionary and write out the XML file, and increment and save
  170.       in CFPreferences our new seed. 
  171.       
  172.  */
  173.     
  174. CMacPrefFileXML::CMacPrefFileXML()
  175. {
  176. CFIndex noItems = 0;
  177. m_DictRef = ::CFDictionaryCreateMutable( kCFAllocatorDefault, noItems,
  178. &kCFTypeDictionaryKeyCallBacks,
  179. &kCFTypeDictionaryValueCallBacks );
  180. check_nonnull( m_DictRef );
  181. m_CoherenceSeed = 0;
  182. }
  183. CMacPrefFileXML::~CMacPrefFileXML()
  184. {
  185. if ( m_DictRef )
  186. {
  187. ::CFRelease( m_DictRef );
  188. }
  189. }
  190. void 
  191. CMacPrefFileXML::SetPrefsFileSpec( const CHXFileSpecifier& fileSpec, CFStringRef appIDStringRef, const char* pProductName )
  192. {
  193. check( fileSpec.IsSet() );
  194. require_nonnull_void_return( appIDStringRef );
  195. m_FileSpec = fileSpec;
  196. m_cfsPrefsAppIDNameRef = appIDStringRef;
  197. ::CFRetain( m_cfsPrefsAppIDNameRef );
  198. // the coherence key is the pref key where we save the new coherence seed value after each
  199. // write; it's something like "UpdateSync"
  200. m_cfsCoherenceKey = CHXString( pProductName ) + "Sync";
  201. UpdateDictFromFile( true ); // true -> always read from file
  202. }
  203. CFPropertyListRef
  204. CMacPrefFileXML::CopyValue( CFStringRef key )
  205. {
  206. require_nonnull_return( m_DictRef, NULL );
  207. UpdateDictFromFile( false ); // reads m_DictRect from the file if necessary, false -> only if necessary
  208. CFPropertyListRef value = ::CFDictionaryGetValue( m_DictRef, key );
  209. if ( value )
  210. {
  211. ::CFRetain( value );
  212. }
  213. return value;
  214. }
  215. void
  216. CMacPrefFileXML::SetValue( CFStringRef key, CFPropertyListRef value )
  217. {
  218. require_nonnull_void_return( m_DictRef );
  219. // Because of the expense of saving the dict to disk with each write to maintain
  220. // coherence, we want to set and save the value only if it differs from what's
  221. // currently in the dict.
  222. // We have to use CopyValue to get the value out of the dict because
  223. // CopyValue will ensure the dict is synced with what's been saved to the
  224. // file.
  225. CFPropertyListRef oldValue = CopyValue( key );
  226. if ( oldValue == NULL && value == NULL )
  227. {
  228. // both unset, so do nothing
  229. }
  230. else if ( oldValue && value 
  231. && ( kCFCompareEqualTo == ::CFStringCompare( (CFStringRef) oldValue, (CFStringRef) value, (CFStringCompareFlags) 0 ) ) )
  232. {
  233. // both set to the same thing, so do nothing
  234. }
  235. else
  236. {
  237. // change or remove the value in the dictionary
  238. if (value)
  239. {
  240. ::CFDictionarySetValue( m_DictRef, key, value );
  241. }
  242. else
  243. {
  244. ::CFDictionaryRemoveValue( m_DictRef, key );
  245. }
  246. // write immediately to maintain coherence
  247. WriteToFile();
  248. }
  249. if ( oldValue )
  250. {
  251. ::CFRelease( oldValue );
  252. }
  253. }
  254. CFArrayRef
  255. CMacPrefFileXML::CopyKeyList( void )
  256. {
  257. require_return( m_DictRef, NULL );
  258. UpdateDictFromFile( false ); // reads m_DictRect from the file if necessary, false -> only if necessary
  259. CFIndex noItems = 0;
  260. // we'll build an array of keys by calling CopyKeyListProc repeatedly
  261. CFMutableArrayRef arrayRef = ::CFArrayCreateMutable( kCFAllocatorDefault,
  262. noItems, &kCFTypeArrayCallBacks );
  263. if ( arrayRef )
  264. {
  265. ::CFDictionaryApplyFunction( m_DictRef, CMacPrefFileXML::CopyKeyListProc, (void*) arrayRef );
  266. }
  267. return arrayRef;
  268. }
  269. void
  270. CMacPrefFileXML::CopyKeyListProc( const void *key, const void *value, void *context )
  271. {
  272. check_nonnull( context );
  273. ::CFArrayAppendValue( (CFMutableArrayRef) context, key );
  274. }
  275. void
  276. CMacPrefFileXML::Synchronize( void )
  277. {
  278. // we always write out from SetPref, so all we need to do to sync is read in if necessary
  279. UpdateDictFromFile( false ); // false -> read file only if necessary
  280. }
  281. void
  282. CMacPrefFileXML::WriteToFile( void )
  283. {
  284. require_nonnull_void_return( m_DictRef );
  285. require_void_return( m_FileSpec.IsSet() );
  286. // increment and save our coherence seed value; don't let it be zero since
  287. // that's the value of the member variable when the object is first initialized
  288. m_CoherenceSeed++;
  289. if ( !m_CoherenceSeed )
  290. {
  291. m_CoherenceSeed++;
  292. }
  293. CFNumberRef cfnValue = ::CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &m_CoherenceSeed );
  294. check_nonnull( cfnValue );
  295. if ( cfnValue )
  296. {
  297. ::CFPreferencesSetValue(m_cfsCoherenceKey, cfnValue, m_cfsPrefsAppIDNameRef, kCFPreferencesCurrentUser, kCFPreferencesAnyHost );
  298. ::CFRelease( cfnValue );
  299. cfnValue = NULL;
  300. }
  301. // write the dictionary out to the file
  302. CFDataRef  xmlData = NULL;
  303. CFURLRef  fileURL = NULL;
  304. CHXString strPosixPath;
  305. CFStringRef posixPathString = NULL;
  306. OSStatus  err;
  307. Boolean bSuccess;
  308. const Boolean  kIsntADir = false;
  309. // we have to use a path in case the file doesn't exist yet, since
  310. // we can't get an FSRef for a file that doesn't exist
  311. strPosixPath = m_FileSpec.GetPOSIXPath();
  312. posixPathString = ::CFStringCreateWithCString( kCFAllocatorDefault, (const char *) strPosixPath,
  313. ::CFStringGetSystemEncoding() );
  314. require_nonnull( posixPathString, Bail );
  315. fileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, posixPathString, kCFURLPOSIXPathStyle, kIsntADir );
  316. require_nonnull( fileURL, Bail );
  317. xmlData = ::CFPropertyListCreateXMLData( kCFAllocatorDefault, m_DictRef );
  318. require_nonnull( xmlData, Bail );
  319. bSuccess = ::CFURLWriteDataAndPropertiesToResource( fileURL, xmlData, NULL, &err );
  320. check( bSuccess );
  321. Bail:
  322. if ( fileURL )  ::CFRelease( fileURL );
  323. if ( xmlData )  ::CFRelease( xmlData );
  324. if ( posixPathString )  ::CFRelease( posixPathString );
  325. }
  326. void
  327. CMacPrefFileXML::UpdateDictFromFile( Boolean forceReadFromFile )
  328. {
  329. require_nonnull_void_return( m_DictRef );
  330. require_void_return( m_FileSpec.IsSet() );
  331. // check if the coherence seed value matches the one saved in prefs; if not,
  332. // re-fill the dict from the file, and set our coherence seed to the saved
  333. // one
  334. SInt32 coherenceValue = GetGlobalCoherenceSeed();
  335. if ( ( coherenceValue != m_CoherenceSeed ) || forceReadFromFile )
  336. {
  337. ReadFromFile();
  338. m_CoherenceSeed = coherenceValue;
  339. }
  340.      return;
  341. }
  342. SInt32
  343. CMacPrefFileXML::GetGlobalCoherenceSeed()
  344. {
  345. SInt32 coherenceValue = 0;
  346. CFNumberRef cfnValue = (CFNumberRef) ::CFPreferencesCopyValue(m_cfsCoherenceKey, m_cfsPrefsAppIDNameRef, kCFPreferencesCurrentUser, kCFPreferencesAnyHost );
  347. if ( cfnValue )
  348. {
  349. check( ::CFGetTypeID( cfnValue ) == ::CFNumberGetTypeID() );
  350. Boolean bSuccess = ::CFNumberGetValue( cfnValue, kCFNumberSInt32Type, &coherenceValue );
  351. check( bSuccess );
  352. }
  353. return coherenceValue;
  354. }
  355. void
  356. CMacPrefFileXML::ReadFromFile( void )
  357. {
  358. require_nonnull_void_return( m_DictRef );
  359. require_void_return( m_FileSpec.IsSet() );
  360. CFDataRef  xmlData = NULL;
  361. CFPropertyListRef  props = NULL;
  362. CFURLRef  fileURL = NULL;
  363. CFStringRef errString = NULL;
  364. FSRef fileRef;
  365. OSStatus  err;
  366. Boolean bSuccess;
  367. ::CFDictionaryRemoveAllValues( m_DictRef );
  368. require_quiet( CHXFileSpecUtils::FileExists( m_FileSpec ), Bail );
  369. fileRef = ( FSRef ) m_FileSpec;
  370. fileURL = ::CFURLCreateFromFSRef( kCFAllocatorDefault, &fileRef );
  371. require_nonnull( fileURL, Bail );
  372. // read the XML file
  373. //
  374. // the nils are for retrieving property info; could we just use those
  375. // and skip the call to CFPropertyListCreateFromXMLData?
  376. bSuccess = ::CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault,
  377. fileURL, &xmlData, nil, nil, &err );
  378. require( bSuccess, Bail );
  379. // make a dictionary from the XML
  380. props = ::CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
  381. xmlData, kCFPropertyListMutableContainersAndLeaves, &errString );
  382. require( ::CFGetTypeID( props ) == ::CFDictionaryGetTypeID(), Bail );
  383. ::CFRelease( m_DictRef );
  384. m_DictRef = (CFMutableDictionaryRef) props;
  385. ::CFRetain( m_DictRef ); // the release below is kept for error-handlign cleanup
  386. Bail:
  387. if ( fileURL )  ::CFRelease( fileURL );
  388. if ( xmlData )  ::CFRelease( xmlData );
  389. if ( props )  ::CFRelease( props );
  390. if ( errString ) ::CFRelease( errString );
  391. }
  392. #endif // _MAC_UNIX