Back to index

lightning-sunbird  0.9+nobinonly
nsRegistry.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifdef MOZ_LOGGING
00039 #define FORCE_PR_LOG /* Allow logging in the release build */
00040 #endif
00041 
00042 #include "nsIGenericFactory.h"
00043 
00044 #include "nsRegistry.h"
00045 #include "nsIEnumerator.h"
00046 #include "nsDirectoryService.h"
00047 #include "nsDirectoryServiceDefs.h"
00048 #include "nsAppDirectoryServiceDefs.h"
00049 #include "NSReg.h"
00050 #include "prmem.h"
00051 #include "prlock.h"
00052 #include "prlog.h"
00053 #include "prprf.h"
00054 #include "nsCRT.h"
00055 #include "nsMemory.h"
00056 
00057 #include "nsCOMPtr.h"
00058 #include "nsILocalFile.h"
00059 #include "nsIServiceManager.h"
00060 #include "nsTextFormatter.h"
00061 
00062 #ifdef XP_BEOS
00063 #include <FindDirectory.h>
00064 #include <Path.h>
00065 #endif
00066 
00067 /* extra locking for the paranoid */
00068 /* #define EXTRA_THREADSAFE */
00069 #ifndef EXTRA_THREADSAFE
00070 #define PR_Lock(x)           (void)0
00071 #define PR_Unlock(x)         (void)0
00072 #endif
00073 
00074 // Logging of debug output
00075 extern NS_COM PRLogModuleInfo *nsComponentManagerLog;
00076 
00077 PRUnichar widestrFormat[] = { PRUnichar('%'),PRUnichar('s'),PRUnichar(0)};
00078 
00079 /*-------------------------------- nsRegistry ----------------------------------
00080 | This class implements the nsIRegistry interface using the functions          |
00081 | provided by libreg (as declared in mozilla/modules/libreg/include/NSReg.h).  |
00082 |                                                                              |
00083 | Since that interface is designed to match the libreg function, this class    |
00084 | is implemented with each member function being a simple wrapper for the      |
00085 | corresponding libreg function.                                               |
00086 |                                                                              |
00087 | #define EXTRA_THREADSAFE if you are worried about libreg thread safety.      |
00088 | It should not be necessary, but I'll leave in the code for the paranoid.     |
00089 ------------------------------------------------------------------------------*/
00090 
00091 #define NS_MOZILLA_DIR_PERMISSION 00700
00092 
00093 #include "nsRegistry.h"
00094 /*
00095 struct nsRegistry : public nsIRegistry {
00096     // This class implements the nsISupports interface functions.
00097     NS_DECL_ISUPPORTS
00098 
00099     // This class implements the nsIRegistry interface functions.
00100     NS_DECL_NSIREGISTRY
00101 
00102     // ctor/dtor
00103     nsRegistry();
00104 
00105 private:
00106     ~nsRegistry();
00107 
00108 protected:
00109     HREG   mReg; // Registry handle.
00110 #ifdef EXTRA_THREADSAFE
00111     PRLock *mregLock;    // libreg isn't threadsafe. Use locks to synchronize.
00112 #endif
00113     char *mCurRegFile;    // these are to prevent open from opening the registry again
00114     nsWellKnownRegistry mCurRegID;
00115 
00116     NS_IMETHOD Close();
00117 }; // nsRegistry
00118 */
00119 
00120 #include "nsIFactory.h"
00121 /*----------------------------- nsRegistryFactory ------------------------------
00122 | Class factory for nsRegistry objects.                                        |
00123 ------------------------------------------------------------------------------*/
00124 struct nsRegistryFactory : public nsIFactory {
00125     // This class implements the nsISupports interface functions.
00126     NS_DECL_ISUPPORTS
00127 
00128     // nsIFactory methods
00129     NS_IMETHOD CreateInstance(nsISupports *,const nsIID &,void **);
00130     NS_IMETHOD LockFactory(PRBool aLock);
00131 
00132     // ctor
00133     nsRegistryFactory();
00134 };
00135 
00136 
00137 /*--------------------------- nsRegSubtreeEnumerator ---------------------------
00138 | This class implements the nsIEnumerator interface and is used to implement   |
00139 | the nsRegistry EnumerateSubtrees and EnumerateAllSubtrees functions.         |
00140 ------------------------------------------------------------------------------*/
00141 struct nsRegSubtreeEnumerator : public nsIRegistryEnumerator {
00142     // This class implements the nsISupports interface functions.
00143     NS_DECL_ISUPPORTS
00144 
00145     // This class implements the nsIEnumerator interface functions.
00146     NS_DECL_NSIENUMERATOR
00147 
00148     // And our magic behind-the-back fast-path thing.
00149     NS_DECL_NSIREGISTRYENUMERATOR
00150 
00151     // ctor/dtor
00152     nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all );
00153     // virtual dtor since subclasses call our Release()
00154     virtual ~nsRegSubtreeEnumerator();
00155 
00156 protected:
00157     NS_IMETHOD advance(); // Implementation file; does appropriate NR_RegEnum call.
00158     HREG    mReg;   // Handle to registry we're affiliated with.
00159     RKEY    mKey;   // Base key being enumerated.
00160     char    mName[MAXREGPATHLEN]; // The name of the current key which is in mNext
00161     REGENUM mEnum;  // Corresponding libreg "enumerator".
00162     REGENUM mNext;  // Lookahead value.
00163     PRUint32  mStyle; // Style (indicates all or some);
00164     PRBool  mDone;  // Done flag.
00165 #ifdef EXTRA_THREADSAFE
00166     PRLock *mregLock;
00167 #endif
00168 }; // nsRegSubtreeEnumerator
00169 
00170 
00171 /*--------------------------- nsRegValueEnumerator -----------------------------
00172 | This class is a variation on nsRegSubtreeEnumerator that allocates           |
00173 | nsRegistryValue objects rather than nsRegistryNode objects.  It also         |
00174 | overrides certain functions to make sure the "value" oriented libreg         |
00175 | functions used rather than the subtree oriented ones.                        |
00176 ------------------------------------------------------------------------------*/
00177 struct nsRegValueEnumerator : public nsRegSubtreeEnumerator {
00178     // Override CurrentItem to allocate nsRegistryValue objects.
00179     NS_IMETHOD CurrentItem( nsISupports **result );
00180 
00181     // Override advance() to use proper NR_RegEnumEntries.
00182     NS_IMETHOD advance();
00183 
00184     // ctor/dtor
00185     nsRegValueEnumerator( HREG hReg, RKEY rKey );
00186 }; // nsRegValueEnumerator
00187 
00188 /*------------------------------ nsRegistryNode --------------------------------
00189 | This class implements the nsIRegistryNode interface.  Instances are         |
00190 | allocated by nsRegSubtreeEnumerator::CurrentItem.                           |
00191 ------------------------------------------------------------------------------*/
00192 struct nsRegistryNode : public nsIRegistryNode {
00193     // This class implements the nsISupports interface functions.
00194     NS_DECL_ISUPPORTS
00195 
00196     // This class implements the nsIRegistryNode interface functions.
00197     NS_DECL_NSIREGISTRYNODE
00198 
00199     // ctor
00200     nsRegistryNode( HREG hReg, char *name, RKEY childKey );
00201     
00202 private:
00203     ~nsRegistryNode();
00204 
00205 protected:
00206     HREG    mReg;  // Handle to registry this node is part of.
00207     char    mName[MAXREGPATHLEN]; // Buffer to hold name.
00208     RKEY    mChildKey;    // Key corresponding to mName
00209 #ifdef EXTRA_THREADSAFE
00210     PRLock *mregLock;
00211 #endif
00212 }; // nsRegistryNode
00213 
00214 
00215 /*------------------------------ nsRegistryValue -------------------------------
00216 | This class implements the nsIRegistryValue interface.  Instances are         |
00217 | allocated by nsRegValueEnumerator::CurrentItem.                              |
00218 ------------------------------------------------------------------------------*/
00219 struct nsRegistryValue : public nsIRegistryValue {
00220     // This class implements the nsISupports interface functions.
00221     NS_DECL_ISUPPORTS
00222 
00223     // This class implements the nsIRegistryValue interface functions.
00224     NS_DECL_NSIREGISTRYVALUE
00225 
00226     // ctor
00227     nsRegistryValue( HREG hReg, RKEY key, REGENUM slot );
00228 
00229 private:
00230     ~nsRegistryValue();
00231 
00232 protected:
00233     nsresult getInfo(); // Get registry info.
00234     HREG    mReg;  // Handle to registry this node is part of.
00235     RKEY    mKey;  // Key this node is under.
00236     REGENUM mEnum; // Copy of corresponding content of parent enumerator.
00237     REGINFO mInfo; // Value info.
00238     char    mName[MAXREGNAMELEN]; // Buffer to hold name.
00239     REGERR  mErr; // XXX This causes this class to be NON THREAD SAFE
00240 #ifdef EXTRA_THREADSAFE
00241     PRLock *mregLock;
00242 #endif
00243 }; // nsRegistryValue
00244 
00245 
00246 /*----------------------------- regerr2nsresult --------------------------------
00247 | This utility function maps a REGERR value to a corresponding nsresult        |
00248 | error code.                                                                  |
00249 ------------------------------------------------------------------------------*/
00250 static nsresult regerr2nsresult( REGERR err ) {
00251     nsresult rv = NS_ERROR_UNEXPECTED;
00252     switch( err ) {
00253         case REGERR_OK:
00254             rv = NS_OK;
00255             break;
00256 
00257         case REGERR_FAIL:
00258             rv = NS_ERROR_FAILURE;
00259             break;
00260 
00261         case REGERR_NOMORE:
00262             rv = NS_ERROR_REG_NO_MORE;
00263             break;
00264     
00265         case REGERR_NOFIND:
00266             rv = NS_ERROR_REG_NOT_FOUND;
00267             break;
00268     
00269         case REGERR_PARAM:
00270         case REGERR_BADTYPE:
00271         case REGERR_BADNAME:
00272             rv = NS_ERROR_INVALID_ARG;
00273             break;
00274     
00275         case REGERR_NOFILE:
00276             rv = NS_ERROR_REG_NOFILE;
00277             break;
00278     
00279         case REGERR_MEMORY:
00280             rv = NS_ERROR_OUT_OF_MEMORY;
00281             break;
00282     
00283         case REGERR_BUFTOOSMALL:
00284             rv = NS_ERROR_REG_BUFFER_TOO_SMALL;
00285             break;
00286     
00287         case REGERR_NAMETOOLONG:
00288             rv = NS_ERROR_REG_NAME_TOO_LONG;
00289             break;
00290     
00291         case REGERR_NOPATH:
00292             rv = NS_ERROR_REG_NO_PATH;
00293             break;
00294     
00295         case REGERR_READONLY:
00296             rv = NS_ERROR_REG_READ_ONLY;
00297             break;
00298     
00299         case REGERR_BADUTF8:
00300             rv = NS_ERROR_REG_BAD_UTF8;
00301             break;
00302     
00303     }
00304     return rv;
00305 }
00306 
00307 /*----------------------------- reginfo2DataType -------------------------------
00308 | This utility function converts the type field in the REGINFO structure to    |
00309 | the corresponding nsIRegistry::DataType value.                              |
00310 ------------------------------------------------------------------------------*/
00311 static void reginfo2DataType( const REGINFO &in, PRUint32 &out ) {
00312     // Transfer information, based on entry type.
00313     switch( in.entryType ) {
00314         case REGTYPE_ENTRY_STRING_UTF:
00315             out = nsIRegistry::String;
00316             //out.length = in.entryLength;
00317             break;
00318 
00319         case REGTYPE_ENTRY_INT32_ARRAY:
00320             out = nsIRegistry::Int32;
00321             // Convert length in bytes to array dimension.
00322             //out.length = in.entryLength / sizeof(PRInt32);
00323             break;
00324 
00325         case REGTYPE_ENTRY_BYTES:
00326             out = nsIRegistry::Bytes;
00327             //out.length = in.entryLength;
00328             break;
00329 
00330         case REGTYPE_ENTRY_FILE:
00331             out = nsIRegistry::File;
00332             //out.length = in.entryLength;
00333             break;
00334     }
00335 }
00336 
00337 /*----------------------------- reginfo2DataType -------------------------------
00338 | This utility function converts the length field in the REGINFO structure to  |
00339 | the proper units (if type==Int32 array, we divide by sizeof(PRInt32)).         |
00340 ------------------------------------------------------------------------------*/
00341 static void reginfo2Length( const REGINFO &in, PRUint32 &out ) {
00342     // Transfer information, based on entry type.
00343     switch( in.entryType ) {
00344         case REGTYPE_ENTRY_STRING_UTF:
00345             out = in.entryLength;
00346             break;
00347 
00348         case REGTYPE_ENTRY_INT32_ARRAY:
00349             // Convert length in bytes to array dimension.
00350             out = in.entryLength / sizeof(PRInt32);
00351             break;
00352 
00353         case REGTYPE_ENTRY_BYTES:
00354             out = in.entryLength;
00355             break;
00356 
00357         case REGTYPE_ENTRY_FILE:
00358             out = in.entryLength;
00359             break;
00360     }
00361 }
00362 
00363 /*------------------------ nsISupports Implementation --------------------------
00364 | This code generates the implementation of the nsISupports member functions   |
00365 | for each class implemented in this file.                                     |
00366 ------------------------------------------------------------------------------*/
00367 NS_IMPL_THREADSAFE_ISUPPORTS2(nsRegistry,  nsIRegistry, nsIRegistryGetter)
00368 NS_IMPL_ISUPPORTS2( nsRegSubtreeEnumerator, nsIEnumerator,
00369                     nsIRegistryEnumerator)
00370 NS_IMPL_ISUPPORTS1( nsRegistryNode,         nsIRegistryNode  )
00371 NS_IMPL_ISUPPORTS1( nsRegistryValue,        nsIRegistryValue )
00372 
00373 /*-------------------------- nsRegistry::nsRegistry ----------------------------
00374 | Vanilla nsRegistry constructor.                                              |
00375 ------------------------------------------------------------------------------*/
00376 nsRegistry::nsRegistry() 
00377     : mReg(0), mCurRegID(0) {
00378 #ifdef EXTRA_THREADSAFE
00379     mregLock = PR_NewLock();
00380 #endif
00381     NR_StartupRegistry();
00382     return;
00383 }
00384 
00385 /*------------------------- nsRegistry::~nsRegistry ----------------------------
00386 | The dtor closes the registry file(if open).                                  |
00387 ------------------------------------------------------------------------------*/
00388 nsRegistry::~nsRegistry() {
00389     if( mReg ) {
00390         Close();
00391     }
00392 #ifdef EXTRA_THREADSAFE
00393     if (mregLock) {
00394         PR_DestroyLock(mregLock);
00395     }
00396 #endif
00397     NR_ShutdownRegistry();
00398     return;
00399 }
00400 
00401 /*----------------------------- nsRegistry::Open -------------------------------
00402 | If the argument is null, delegate to OpenDefault, else open the registry     |
00403 | file.  We first check to see if a registry file is already open and close    |
00404 | it if so.                                                                    |
00405 ------------------------------------------------------------------------------*/
00406 NS_IMETHODIMP nsRegistry::Open( nsIFile *regFile ) {
00407     REGERR err = REGERR_OK;
00408 
00409     // Check for default.
00410     if( !regFile ) {
00411         return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry);
00412     }
00413 
00414     nsCAutoString regPath;
00415     nsresult rv = regFile->GetNativePath(regPath);
00416     if (NS_FAILED(rv)) return rv;
00417 
00418 #ifdef DEBUG_dp
00419     printf("nsRegistry: Opening registry %s\n", regPath.get());
00420 #endif /* DEBUG_dp */
00421    
00422     if (mCurRegID != nsIRegistry::None && mCurRegID != nsIRegistry::ApplicationCustomRegistry)
00423     {
00424         // Cant open another registry without closing explictly.
00425         return NS_ERROR_INVALID_ARG;
00426     }
00427 
00428     // Do we have an open registry ?
00429     if (mCurRegID != nsIRegistry::None)
00430     {
00431         PRBool equals;
00432         if (mCurRegFile && NS_SUCCEEDED(mCurRegFile->Equals(regFile, &equals)) && equals)
00433         {
00434             // The right one is already open
00435             return NS_OK;
00436         }
00437         else
00438         {
00439             // Opening a new registry without closing an already open one.
00440             // This is an error.
00441             return NS_ERROR_FAILURE;
00442         }
00443     }
00444 
00445     // Open specified registry.
00446     PR_Lock(mregLock);
00447     err = NR_RegOpen(NS_CONST_CAST(char*,regPath.get()), &mReg);
00448     PR_Unlock(mregLock);
00449 
00450     mCurRegID = nsIRegistry::ApplicationCustomRegistry;
00451 
00452     // No error checking for no mem. Trust me.
00453     if (NS_FAILED(regFile->Clone(getter_AddRefs(mCurRegFile))))
00454         mCurRegFile = nsnull; // not fatal
00455 
00456     // Convert the result.
00457     return regerr2nsresult( err );
00458 }
00459 
00460 static void
00461 EnsureDefaultRegistryDirectory() {
00462 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00463     // Create ~/.mozilla as that is the default place for the registry file
00464 
00465     /* The default registry on the unix system is $HOME/.mozilla/registry per
00466      * vr_findGlobalRegName(). vr_findRegFile() will create the registry file
00467      * if it doesn't exist. But it wont create directories.
00468      *
00469      * Hence we need to create the directory if it doesn't exist already.
00470      *
00471      * Why create it here as opposed to the app ?
00472      * ------------------------------------------
00473      * The app cannot create the directory in main() as most of the registry
00474      * and initialization happens due to use of static variables.
00475      * And we dont want to be dependent on the order in which
00476      * these static stuff happen.
00477      *
00478      * Permission for the $HOME/.mozilla will be Read,Write,Execute
00479      * for user only. Nothing to group and others.
00480      */
00481     char *home = getenv("HOME");
00482     if (home != NULL)
00483     {
00484         char dotMozillaDir[1024];
00485         PR_snprintf(dotMozillaDir, sizeof(dotMozillaDir),
00486                     "%s/" MOZ_USER_DIR, home);
00487         if (PR_Access(dotMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS)
00488         {
00489             PR_MkDir(dotMozillaDir, NS_MOZILLA_DIR_PERMISSION);
00490             PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
00491                    ("nsComponentManager: Creating Directory %s", dotMozillaDir));
00492         }
00493     }
00494 #endif /* XP_UNIX */
00495 
00496 #ifdef XP_BEOS
00497     BPath p;
00498     const char *settings = "/boot/home/config/settings";
00499     if(find_directory(B_USER_SETTINGS_DIRECTORY, &p) == B_OK)
00500         settings = p.Path();
00501     char settingsMozillaDir[1024];
00502     PR_snprintf(settingsMozillaDir, sizeof(settingsMozillaDir),
00503                 "%s/" MOZ_USER_DIR, settings);
00504     if (PR_Access(settingsMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
00505         PR_MkDir(settingsMozillaDir, NS_MOZILLA_DIR_PERMISSION);
00506         PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
00507                ("nsComponentManager: Creating Directory %s", settingsMozillaDir));
00508     }
00509 #endif
00510 }
00511 
00512 /*----------------------------- nsRegistry::OpenWellKnownRegistry --------------
00513 | Takes a registry id and maps that to a file name for opening. We first check |
00514 | to see if a registry file is already open and close  it if so.               |
00515 ------------------------------------------------------------------------------*/
00516 NS_IMETHODIMP nsRegistry::OpenWellKnownRegistry( nsWellKnownRegistry regid ) 
00517 {
00518     REGERR err = REGERR_OK;
00519 
00520     if (mCurRegID != nsIRegistry::None && mCurRegID != regid)
00521     {
00522         // Cant open another registry without closing explictly.
00523         return NS_ERROR_INVALID_ARG;
00524     }
00525 
00526     if (mCurRegID == regid)
00527     {
00528         // Already opened.
00529         return NS_OK;
00530     }
00531 
00532     nsresult rv;
00533     nsCOMPtr<nsIFile> registryLocation;
00534 
00535     PRBool foundReg = PR_FALSE;
00536     nsCAutoString regFile;
00537     
00538     switch ( (nsWellKnownRegistry) regid ) {
00539       case ApplicationComponentRegistry:
00540         NS_WARNING("ApplicationComponentRegistry is unsupported!");
00541         break;
00542       case ApplicationRegistry:
00543         {
00544             EnsureDefaultRegistryDirectory();
00545             nsCOMPtr<nsIProperties> directoryService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00546             if (NS_FAILED(rv)) return rv;
00547             directoryService->Get(NS_APP_APPLICATION_REGISTRY_FILE, NS_GET_IID(nsIFile), 
00548                                   getter_AddRefs(registryLocation));
00549 
00550             if (registryLocation)
00551             {
00552                 foundReg = PR_TRUE;
00553                 rv = registryLocation->GetNativePath(regFile);  // dougt fix...
00554                 // dveditz needs to fix his registry so that I can pass an
00555                 // nsIFile interface and not hack 
00556                 if (NS_FAILED(rv))
00557                   return rv;
00558             }
00559         }
00560         break;
00561 
00562       default:
00563         break;
00564     }
00565 
00566     if (foundReg == PR_FALSE) {
00567         return NS_ERROR_REG_BADTYPE;
00568     }
00569    
00570 #ifdef DEBUG_dp
00571     printf("nsRegistry: Opening std registry %s\n", regFile.get());
00572 #endif /* DEBUG_dp */
00573 
00574     PR_Lock(mregLock);
00575     err = NR_RegOpen(NS_CONST_CAST(char*, regFile.get()), &mReg );
00576     PR_Unlock(mregLock);
00577 
00578     // Store the registry that was opened for optimizing future opens.
00579     mCurRegID = regid;
00580 
00581     // Convert the result.
00582     return regerr2nsresult( err );
00583 }
00584 
00585 #if 0
00586 /*-------------------------- nsRegistry::OpenDefault ---------------------------
00587 | Open the "default" registry; in the case of this libreg-based implementation |
00588 | that is done by passing a null file name pointer to NR_RegOpen.              |
00589 ------------------------------------------------------------------------------*/
00590 NS_IMETHODIMP nsRegistry::OpenDefault() {
00591     return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry);
00592 }
00593 #endif
00594 
00595 /*----------------------------- nsRegistry::Close ------------------------------
00596 | Tests the mReg handle and if non-null, closes the registry via NR_RegClose.  |
00597 ------------------------------------------------------------------------------*/
00598 NS_IMETHODIMP nsRegistry::Close() {
00599     REGERR err = REGERR_OK;
00600     if( mReg ) {
00601         PR_Lock(mregLock);
00602         err = NR_RegClose( mReg );
00603         PR_Unlock(mregLock);
00604         mReg = 0;
00605         mCurRegFile = nsnull;
00606         mCurRegID = 0;
00607     }
00608     return regerr2nsresult( err );
00609 }
00610 
00611 /*----------------------------- nsRegistry::Flush ------------------------------
00612 | Flushes the registry via NR_RegFlush.                                        |
00613 ------------------------------------------------------------------------------*/
00614 NS_IMETHODIMP nsRegistry::Flush() {
00615     REGERR err = REGERR_FAIL;
00616     if( mReg ) {
00617         PR_Lock(mregLock);
00618         err = NR_RegFlush( mReg );
00619         PR_Unlock(mregLock);
00620     }
00621     return regerr2nsresult( err );
00622 }
00623 
00624 /*----------------------------- nsRegistry::IsOpen -----------------------------
00625 | Tests the mReg handle and returns whether the registry is open or not.       |
00626 ------------------------------------------------------------------------------*/
00627 NS_IMETHODIMP nsRegistry::IsOpen( PRBool *result ) {
00628     *result = ( mReg != 0 );
00629     return NS_OK;
00630 }
00631 
00632 
00633 /*--------------------------- nsRegistry::AddKey -------------------------------
00634 | Add a key into the registry or find an existing one.  This is generally used |
00635 | instead of GetKey unless it's an error for the key not to exist already      i
00636 ------------------------------------------------------------------------------*/
00637 NS_IMETHODIMP nsRegistry::AddKey( nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval)
00638 {
00639     if ( !keyname ) 
00640         return NS_ERROR_NULL_POINTER;
00641 
00642     return AddSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval );
00643 }
00644 
00645 /*--------------------------- nsRegistry::GetKey -------------------------------
00646 | returns the nsRegistryKey associated with a given node in the registry       |
00647 ------------------------------------------------------------------------------*/
00648 NS_IMETHODIMP nsRegistry::GetKey(nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval)
00649 {
00650     if ( !keyname || !_retval ) 
00651         return NS_ERROR_NULL_POINTER;
00652 
00653     return GetSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval );
00654 }
00655 
00656 /*--------------------------- nsRegistry::RemoveKey ----------------------------
00657 | Delete a key from the registry                                               |
00658 ------------------------------------------------------------------------------*/
00659 NS_IMETHODIMP nsRegistry::RemoveKey(nsRegistryKey baseKey, const PRUnichar *keyname)
00660 {
00661     if ( !keyname ) 
00662         return NS_ERROR_NULL_POINTER;
00663 
00664     return RemoveSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get() );
00665 }
00666 
00667 NS_IMETHODIMP nsRegistry::GetString(nsRegistryKey baseKey, const PRUnichar *valname, PRUnichar **_retval)
00668 {
00669     // Make sure caller gave us place for result.
00670     if ( !valname || !_retval )
00671         return NS_ERROR_NULL_POINTER;
00672 
00673     // initialize the return value
00674     *_retval = nsnull;
00675     nsXPIDLCString tmpstr;
00676 
00677     nsresult rv = GetStringUTF8( baseKey, NS_ConvertUCS2toUTF8(valname).get(), getter_Copies(tmpstr) );
00678 
00679     if (NS_SUCCEEDED(rv))
00680     {
00681         *_retval = nsTextFormatter::smprintf( widestrFormat, tmpstr.get() );
00682         if ( *_retval == nsnull )
00683             rv = NS_ERROR_OUT_OF_MEMORY;
00684     }
00685 
00686     return rv;
00687 }
00688 
00689 NS_IMETHODIMP nsRegistry::SetString(nsRegistryKey baseKey, const PRUnichar *valname, const PRUnichar *value)
00690 {
00691     if ( !valname || ! value )
00692         return NS_ERROR_NULL_POINTER;
00693 
00694     return SetStringUTF8( baseKey,
00695                           NS_ConvertUCS2toUTF8(valname).get(),
00696                           NS_ConvertUCS2toUTF8(value).get() );
00697 }
00698 
00699 /*--------------------------- nsRegistry::GetString ----------------------------
00700 | First, look for the entry using GetValueInfo.  If found, and it's a string,  |
00701 | allocate space for it and fetch the value.                                   |
00702 ------------------------------------------------------------------------------*/
00703 NS_IMETHODIMP nsRegistry::GetStringUTF8( nsRegistryKey baseKey, const char *path, char **result ) {
00704     nsresult rv = NS_OK;
00705     REGERR   err = REGERR_OK;
00706 
00707     // Make sure caller gave us place for result.
00708     if ( !result )
00709         return NS_ERROR_NULL_POINTER;
00710 
00711     char   regStr[MAXREGPATHLEN];
00712 
00713     // initialize the return value
00714     *result = 0;
00715 
00716     // Attempt to get string into our fixed buffer
00717     PR_Lock(mregLock);
00718     err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, regStr,
00719                                 sizeof(regStr) );
00720     PR_Unlock(mregLock);
00721 
00722     if ( err == REGERR_OK )
00723     {
00724         *result = nsCRT::strdup(regStr);
00725         if (!*result)
00726             rv = NS_ERROR_OUT_OF_MEMORY;
00727     }
00728     else if ( err == REGERR_BUFTOOSMALL ) 
00729     {
00730         // find the real size and malloc it
00731         PRUint32 length;
00732         rv = GetValueLength( baseKey, path, &length );
00733         // See if that worked.
00734         if( rv == NS_OK ) 
00735         {
00736             *result =(char*)nsMemory::Alloc( length + 1 );
00737             if( *result ) 
00738             {
00739                 // Get string from registry into result buffer.
00740                 PR_Lock(mregLock);
00741                 err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, *result, length+1 );
00742                 PR_Unlock(mregLock);
00743 
00744                 // Convert status.
00745                 rv = regerr2nsresult( err );
00746                 if ( rv != NS_OK )
00747                 {
00748                     // Didn't get result, free buffer
00749                     nsCRT::free( *result );
00750                     *result = 0;
00751                 }
00752             }
00753             else
00754             {
00755                 rv = NS_ERROR_OUT_OF_MEMORY;
00756             }
00757         }
00758     }
00759     else
00760     {
00761         // Convert status.
00762         rv = regerr2nsresult( err );
00763         NS_ASSERTION(NS_FAILED(rv), "returning success code on failure");
00764     }
00765 
00766    return rv;
00767 }
00768 
00769 NS_IMETHODIMP
00770 nsRegistry::GetStringUTF8IntoBuffer( nsRegistryKey baseKey, const char *path,
00771                                      char *buf, PRUint32 *length )
00772 {
00773     REGERR   err = REGERR_OK;
00774 
00775     // Attempt to get string into our fixed buffer
00776     PR_Lock(mregLock);
00777     err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, buf, *length );
00778     PR_Unlock(mregLock);
00779 
00780     // Convert status.
00781     nsresult rv = regerr2nsresult( err );
00782 
00783     if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) {
00784       // fill length with the actual length
00785       nsresult rv1 = GetValueLength( baseKey, path, length );
00786       if(NS_FAILED(rv1))
00787         return rv1;
00788     }
00789 
00790     return rv;
00791 }
00792 
00793 /*--------------------------- nsRegistry::SetString ----------------------------
00794 | Simply sets the registry contents using NR_RegSetEntryString.                |
00795 ------------------------------------------------------------------------------*/
00796 NS_IMETHODIMP nsRegistry::SetStringUTF8( nsRegistryKey baseKey, const char *path, const char *value ) {
00797     REGERR err = REGERR_OK;
00798     // Set the contents.
00799     PR_Lock(mregLock);
00800     err = NR_RegSetEntryString( mReg,(RKEY)baseKey,(char*)path,(char*)value );
00801     PR_Unlock(mregLock);
00802     // Convert result.
00803     return regerr2nsresult( err );
00804 }
00805 
00806 /*---------------------------- nsRegistry::GetBytesUTF8 ------------------------------
00807 | This function is just shorthand for fetching a char array.  We  |
00808 | implement it "manually" using NR_RegGetEntry                                 |
00809 ------------------------------------------------------------------------------*/
00810 NS_IMETHODIMP nsRegistry::GetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32* length, PRUint8** result) {
00811     nsresult rv = NS_OK;
00812     REGERR err = REGERR_OK;
00813     
00814     if ( !result )
00815         return NS_ERROR_NULL_POINTER;
00816 
00817     char   regStr[MAXREGPATHLEN];
00818 
00819     // initialize the return value
00820     *length = 0;
00821     *result = 0;
00822 
00823     // Get info about the requested entry.
00824     PRUint32 type;
00825     rv = GetValueType( baseKey, path, &type );
00826     // See if that worked.
00827     if( rv == NS_OK ) 
00828     {
00829             // Make sure the entry is an PRInt8 array.
00830         if( type == Bytes ) 
00831         {
00832             // Attempt to get string into our fixed buffer
00833             PR_Lock(mregLock);
00834             uint32 length2 = sizeof regStr;
00835             err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), regStr, &length2);
00836             PR_Unlock(mregLock);
00837 
00838             if ( err == REGERR_OK )
00839             {
00840                 *length = length2;
00841                 *result = (PRUint8*)(nsCRT::strdup(regStr));
00842                 if (!*result)
00843                 {
00844                     rv = NS_ERROR_OUT_OF_MEMORY;
00845                     *length = 0;
00846                 }
00847                 else
00848                 {
00849                     *length = length2;
00850                 }
00851             }
00852             else if ( err == REGERR_BUFTOOSMALL ) 
00853             {
00854             // find the real size and malloc it
00855                 rv = GetValueLength( baseKey, path, length );
00856                 // See if that worked.
00857                 if( rv == NS_OK ) 
00858                 {
00859                     *result = NS_REINTERPRET_CAST(PRUint8*,nsMemory::Alloc( *length ));
00860                     if( *result ) 
00861                     {
00862                         // Get bytes from registry into result field.
00863                         PR_Lock(mregLock);
00864                         length2 = *length;
00865                         err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), *result, &length2);
00866                         *length = length2;
00867                         PR_Unlock(mregLock);
00868                         // Convert status.
00869                         rv = regerr2nsresult( err );
00870                         if ( rv != NS_OK )
00871                         {
00872                             // Didn't get result, free buffer
00873                             nsCRT::free( NS_REINTERPRET_CAST(char*, *result) );
00874                             *result = 0;
00875                             *length = 0;
00876                         }
00877                     }
00878                     else
00879                     {
00880                         rv = NS_ERROR_OUT_OF_MEMORY;
00881                     }
00882                 }
00883             }
00884         } 
00885         else 
00886         {
00887             // They asked for the wrong type of value.
00888             rv = NS_ERROR_REG_BADTYPE;
00889         }
00890     }
00891     return rv;
00892 }
00893 
00894 NS_IMETHODIMP
00895 nsRegistry::GetBytesUTF8IntoBuffer( nsRegistryKey baseKey, const char *path,
00896                                     PRUint8 *buf, PRUint32* length )
00897 {
00898     REGERR err = REGERR_OK;
00899 
00900     // Get info about the requested entry.
00901     PRUint32 type;
00902     nsresult rv = GetValueType( baseKey, path, &type );
00903     // See if that worked.
00904     if(NS_FAILED(rv)) 
00905       return rv;
00906     // Make sure we are dealing with bytes
00907     if (type != Bytes)
00908       return NS_ERROR_REG_BADTYPE;
00909 
00910     // Attempt to get bytes into our fixed buffer
00911     PR_Lock(mregLock);
00912     err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path),
00913                           buf, (uint32 *)length );
00914     PR_Unlock(mregLock);
00915 
00916     rv = regerr2nsresult(rv);
00917 
00918     if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) {
00919       // fill length with the actual length
00920       nsresult rv1 = GetValueLength( baseKey, path, length );
00921       if(NS_FAILED(rv1))
00922         return rv1;
00923     }
00924 
00925 
00926     return rv;
00927 }
00928 
00929 /*---------------------------- nsRegistry::GetInt ------------------------------
00930 | This function is just shorthand for fetching a 1-element PRInt32 array.  We  |
00931 | implement it "manually" using NR_RegGetEntry                                 |
00932 ------------------------------------------------------------------------------*/
00933 NS_IMETHODIMP nsRegistry::GetInt( nsRegistryKey baseKey, const char *path, PRInt32 *result ) {
00934     nsresult rv = NS_OK;
00935     REGERR err = REGERR_OK;
00936 
00937     // Make sure caller gave us place for result.
00938     if( result ) {
00939         // Get info about the requested entry.
00940         PRUint32 type;
00941         rv = GetValueType( baseKey, path, &type );
00942         // See if that worked.
00943         if( rv == NS_OK ) {
00944             // Make sure the entry is an PRInt32 array.
00945             if( type == Int32 ) {
00946                 uint32 len = sizeof *result;
00947                 // Get int from registry into result field.
00948                 PR_Lock(mregLock);
00949                 err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path, result, &len );
00950                 PR_Unlock(mregLock);
00951                 // Convert status.
00952                 rv = regerr2nsresult( err );
00953             } else {
00954                 // They asked for the wrong type of value.
00955                 rv = NS_ERROR_REG_BADTYPE;
00956             }
00957         }
00958     } else {
00959         rv = NS_ERROR_NULL_POINTER;
00960     }
00961     return rv;
00962 }
00963 
00964 
00965 /*---------------------------- nsRegistry::GetLongLong--------------------------
00966 | This function is just shorthand for fetching a 1-element PRInt64 array.  We  |
00967 | implement it "manually" using NR_RegGetEntry                                 |
00968 ------------------------------------------------------------------------------*/
00969 NS_IMETHODIMP nsRegistry::GetLongLong( nsRegistryKey baseKey, const char *path, PRInt64 *result ) {
00970     REGERR err = REGERR_OK;
00971     
00972     PR_Lock(mregLock);
00973     
00974     uint32 length = sizeof(PRInt64);
00975     err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path,(void*)result,&length);
00976     
00977     PR_Unlock(mregLock);
00978     
00979     // Convert status.
00980     return regerr2nsresult( err );
00981 }
00982 /*---------------------------- nsRegistry::SetBytesUTF8 ------------------------------
00983 | Write out the value as a char array, using NR_RegSetEntry.      |
00984 ------------------------------------------------------------------------------*/
00985 NS_IMETHODIMP nsRegistry::SetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32 length, PRUint8* value) {
00986     REGERR err = REGERR_OK;
00987     // Set the contents.
00988     PR_Lock(mregLock);
00989     err = NR_RegSetEntry( mReg,
00990                 (RKEY)baseKey,
00991                 (char*)path,
00992                            REGTYPE_ENTRY_BYTES,
00993                            (char*)value,
00994                            length);
00995     PR_Unlock(mregLock);
00996     // Convert result.
00997     return regerr2nsresult( err );
00998 }
00999 
01000 /*---------------------------- nsRegistry::SetInt ------------------------------
01001 | Write out the value as a one-element PRInt32 array, using NR_RegSetEntry.      |
01002 ------------------------------------------------------------------------------*/
01003 NS_IMETHODIMP nsRegistry::SetInt( nsRegistryKey baseKey, const char *path, PRInt32 value ) {
01004     REGERR err = REGERR_OK;
01005     // Set the contents.
01006     PR_Lock(mregLock);
01007     err = NR_RegSetEntry( mReg,
01008                 (RKEY)baseKey,
01009                 (char*)path,
01010                            REGTYPE_ENTRY_INT32_ARRAY,
01011                            &value,
01012                            sizeof value );
01013     PR_Unlock(mregLock);
01014     // Convert result.
01015     return regerr2nsresult( err );
01016 }
01017 
01018 
01019 
01020 /*---------------------------- nsRegistry::SetLongLong---------------------------
01021 | Write out the value as a one-element PRInt64 array, using NR_RegSetEntry.      |
01022 ------------------------------------------------------------------------------*/
01023 NS_IMETHODIMP nsRegistry::SetLongLong( nsRegistryKey baseKey, const char *path, PRInt64* value ) {
01024     REGERR err = REGERR_OK;
01025     // Set the contents.
01026     PR_Lock(mregLock);
01027 
01028     err = NR_RegSetEntry( mReg,
01029                         (RKEY)baseKey,
01030                         (char*)path,
01031                         REGTYPE_ENTRY_BYTES,
01032                         (void*)value,
01033                         sizeof(PRInt64) );
01034 
01035     PR_Unlock(mregLock);
01036     // Convert result.
01037     return regerr2nsresult( err );
01038 }
01039 
01040 /*-------------------------- nsRegistry::AddSubtree ----------------------------
01041 | Add a new registry subkey with the specified name, using NR_RegAddKey.       |
01042 ------------------------------------------------------------------------------*/
01043 NS_IMETHODIMP nsRegistry::AddSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) {
01044     REGERR err = REGERR_OK;
01045     // Add the subkey.
01046     PR_Lock(mregLock);
01047     err = NR_RegAddKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result );
01048     PR_Unlock(mregLock);
01049     // Convert result.
01050     return regerr2nsresult( err );
01051 }
01052 
01053 /*-------------------------- nsRegistry::AddSubtreeRaw--------------------------
01054 | Add a new registry subkey with the specified name, using NR_RegAddKeyRaw     |
01055 ------------------------------------------------------------------------------*/
01056 NS_IMETHODIMP nsRegistry::AddSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) {
01057     REGERR err = REGERR_OK;
01058     // Add the subkey.
01059     PR_Lock(mregLock);
01060     err = NR_RegAddKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result );
01061     PR_Unlock(mregLock);
01062     // Convert result.
01063     return regerr2nsresult( err );
01064 }
01065 
01066 
01067 /*------------------------- nsRegistry::RemoveSubtree --------------------------
01068 | Deletes the subtree at a given location using NR_RegDeleteKey.               |
01069 ------------------------------------------------------------------------------*/
01070 NS_IMETHODIMP nsRegistry::RemoveSubtree( nsRegistryKey baseKey, const char *path ) {
01071     nsresult rv = NS_OK;
01072     REGERR err = REGERR_OK;
01073 
01074     // libreg doesn't delete keys if there are subkeys under the key
01075     // Hence we have to recurse through to delete the subtree
01076 
01077     RKEY key;
01078 
01079     PR_Lock(mregLock);
01080     err = NR_RegGetKey(mReg, baseKey, (char *)path, &key);
01081     PR_Unlock(mregLock);
01082     if (err != REGERR_OK)
01083     {
01084         rv = regerr2nsresult( err );
01085         return rv;
01086     }
01087 
01088     // Now recurse through and delete all keys under hierarchy
01089     
01090     char subkeyname[MAXREGPATHLEN+1];
01091     REGENUM state = 0;
01092     subkeyname[0] = '\0';
01093     while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, sizeof(subkeyname),
01094            REGENUM_NORMAL) == REGERR_OK)
01095     {
01096 #ifdef DEBUG_dp
01097         printf("...recursing into %s\n", subkeyname);
01098 #endif /* DEBUG_dp */
01099         // Even though this is not a "Raw" API the subkeys may still, in fact,
01100         // *be* raw. Since we're recursively deleting this will work either way.
01101         // If we were guaranteed none would be raw then a depth-first enumeration
01102         // would be much more efficient.
01103         err = RemoveSubtreeRaw(key, subkeyname);
01104         if (err != REGERR_OK) break;
01105     }
01106 
01107     // If success in deleting all subkeys, delete this key too
01108     if (err == REGERR_OK)
01109     {
01110 #ifdef DEBUG_dp
01111         printf("...deleting %s\n", path);
01112 #endif /* DEBUG_dp */
01113         PR_Lock(mregLock);
01114         err = NR_RegDeleteKey(mReg, baseKey, (char *)path);
01115         PR_Unlock(mregLock);
01116     }
01117 
01118     // Convert result.
01119       rv = regerr2nsresult( err );
01120     return rv;
01121 }
01122 
01123 
01124 /*------------------------- nsRegistry::RemoveSubtreeRaw -----------------------
01125 | Deletes the subtree at a given location using NR_RegDeleteKeyRaw             |
01126 ------------------------------------------------------------------------------*/
01127 NS_IMETHODIMP nsRegistry::RemoveSubtreeRaw( nsRegistryKey baseKey, const char *keyname ) {
01128     nsresult rv = NS_OK;
01129     REGERR err = REGERR_OK;
01130 
01131     // libreg doesn't delete keys if there are subkeys under the key
01132     // Hence we have to recurse through to delete the subtree
01133 
01134     RKEY key;
01135     char subkeyname[MAXREGPATHLEN+1];
01136     int n = sizeof(subkeyname);
01137     REGENUM state = 0;
01138 
01139     PR_Lock(mregLock);
01140     err = NR_RegGetKeyRaw(mReg, baseKey, (char *)keyname, &key);
01141     PR_Unlock(mregLock);
01142     if (err != REGERR_OK)
01143     {
01144         rv = regerr2nsresult( err );
01145         return rv;
01146     }
01147 
01148     // Now recurse through and delete all keys under hierarchy
01149     
01150     subkeyname[0] = '\0';
01151     while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, n, REGENUM_NORMAL) == REGERR_OK)
01152     {
01153 #ifdef DEBUG_dp
01154         printf("...recursing into %s\n", subkeyname);
01155 #endif /* DEBUG_dp */
01156         err = RemoveSubtreeRaw(key, subkeyname);
01157         if (err != REGERR_OK) break;
01158     }
01159 
01160     // If success in deleting all subkeys, delete this key too
01161     if (err == REGERR_OK)
01162     {
01163 #ifdef DEBUG_dp
01164         printf("...deleting %s\n", keyname);
01165 #endif /* DEBUG_dp */
01166         PR_Lock(mregLock);
01167         err = NR_RegDeleteKeyRaw(mReg, baseKey, (char *)keyname);
01168         PR_Unlock(mregLock);
01169     }
01170 
01171     // Convert result.
01172       rv = regerr2nsresult( err );
01173     return rv;
01174 }
01175 /*-------------------------- nsRegistry::GetSubtree ----------------------------
01176 | Returns a nsRegistryKey(RKEY) for a given key/path.  The key is           |
01177 | obtained using NR_RegGetKey.                                                 |
01178 ------------------------------------------------------------------------------*/
01179 NS_IMETHODIMP nsRegistry::GetSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) {
01180     nsresult rv = NS_OK;
01181     REGERR err = REGERR_OK;
01182     // Make sure we have a place for the result.
01183     if( result ) {
01184         // Get key.
01185         PR_Lock(mregLock);
01186         err = NR_RegGetKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result );
01187         PR_Unlock(mregLock);
01188         // Convert result.
01189         rv = regerr2nsresult( err );
01190     } else {
01191         rv = NS_ERROR_NULL_POINTER;
01192     }
01193     return rv;
01194 }
01195 
01196 /*-------------------------- nsRegistry::GetSubtreeRaw--------------------------
01197 | Returns a nsRegistryKey(RKEY) for a given key/path.  The key is           |
01198 | obtained using NR_RegGetKeyRaw.                                              |
01199 ------------------------------------------------------------------------------*/
01200 NS_IMETHODIMP nsRegistry::GetSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) {
01201     nsresult rv = NS_OK;
01202     REGERR err = REGERR_OK;
01203     // Make sure we have a place for the result.
01204     if( result ) {
01205         // Get key.
01206         PR_Lock(mregLock);
01207         err = NR_RegGetKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result );
01208         PR_Unlock(mregLock);
01209         // Convert result.
01210         rv = regerr2nsresult( err );
01211     } else {
01212         rv = NS_ERROR_NULL_POINTER;
01213     }
01214     return rv;
01215 }
01216 
01217 
01218 /*----------------------- nsRegistry::EnumerateSubtrees ------------------------
01219 | Allocate a nsRegSubtreeEnumerator object and return it to the caller.        |
01220 | We construct the enumerator using the registry handle from this registry     |
01221 | object, the user-specified registry key, and indicate that we don't want     |
01222 | to recurse down subtrees.  No libreg functions are invoked at this point     |
01223 |(that will happen when the enumerator member functions are called).          |
01224 ------------------------------------------------------------------------------*/
01225 NS_IMETHODIMP nsRegistry::EnumerateSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) {
01226     nsresult rv = NS_OK;
01227     // Make sure we have a place to put the result.
01228     if( result ) {
01229         *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_FALSE );
01230         // Check for success.
01231         if( *result ) {
01232             // Bump refcnt on behalf of caller.
01233           NS_ADDREF(*result);
01234         } else {
01235             // Unable to allocate space for the enumerator object.
01236             rv = NS_ERROR_OUT_OF_MEMORY;
01237         }
01238     } else {
01239         rv = NS_ERROR_NULL_POINTER;
01240     }
01241     return rv;
01242 }
01243 
01244 /*--------------------- nsRegistry::EnumerateAllSubtrees -----------------------
01245 | Same as EnumerateSubtrees but we pass PR_TRUE to request that the            |
01246 | enumerator object descend subtrees when it is used.                          |
01247 ------------------------------------------------------------------------------*/
01248 NS_IMETHODIMP nsRegistry::EnumerateAllSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) {
01249     nsresult rv = NS_OK;
01250     // Make sure we have a place to put the result.
01251     if( result ) {
01252         *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_TRUE );
01253         // Check for success.
01254         if( *result ) {
01255             // Bump refcnt on behalf of caller.
01256           NS_ADDREF(*result);
01257         } else {
01258             // Unable to allocate space for the enumerator object.
01259             rv = NS_ERROR_OUT_OF_MEMORY;
01260         }
01261     } else {
01262         rv = NS_ERROR_NULL_POINTER;
01263     }
01264     return rv;
01265 }
01266 
01267 /*------------------------- nsRegistry::GetValueType ---------------------------
01268 | Gets the type from the registry using the NR_GetEntryInfo libreg API.        |
01269 | The result is transferred to the PRUint32 value passed in (with conversion     |
01270 | to the appropriate nsIRegistry::DataType value).                             |
01271 ------------------------------------------------------------------------------*/
01272 NS_IMETHODIMP nsRegistry::GetValueType( nsRegistryKey baseKey, const char *path, PRUint32 *result ) {
01273     nsresult rv = NS_OK;
01274     REGERR err = REGERR_OK;
01275     // Make sure we have a place to put the result.
01276     if( result ) {
01277         // Get registry info into local structure.
01278         REGINFO info = { sizeof info, 0, 0 };
01279         PR_Lock(mregLock);
01280         err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info );
01281         PR_Unlock(mregLock);
01282         if( err == REGERR_OK ) {
01283             // Copy info to user's result value.
01284             reginfo2DataType( info, *result );
01285         } else {
01286             rv = regerr2nsresult( err );
01287         }
01288     } else {
01289         rv = NS_ERROR_NULL_POINTER;
01290     }
01291     return rv;
01292 }
01293 
01294 /*------------------------ nsRegistry::GetValueLength --------------------------
01295 | Gets the registry value info via NR_RegGetEntryInfo.  The length is          |
01296 | converted to the proper "units" via reginfo2Length.                          |
01297 ------------------------------------------------------------------------------*/
01298 NS_IMETHODIMP nsRegistry::GetValueLength( nsRegistryKey baseKey, const char *path, PRUint32 *result ) {
01299     nsresult rv = NS_OK;
01300     REGERR err = REGERR_OK;
01301     // Make sure we have a place to put the result.
01302     if( result ) {
01303         // Get registry info into local structure.
01304         REGINFO info = { sizeof info, 0, 0 };
01305         PR_Lock(mregLock);
01306         err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info );
01307         PR_Unlock(mregLock);
01308         if( err == REGERR_OK ) {
01309             // Copy info to user's result value.
01310             reginfo2Length( info, *result );
01311         } else {
01312             rv = regerr2nsresult( err );
01313         }
01314     } else {
01315         rv = NS_ERROR_NULL_POINTER;
01316     }
01317     return rv;
01318 }
01319 
01320 /*-------------------------- nsRegistry::DeleteValue ---------------------------
01321 | Remove the registry value with the specified name                            |
01322 ------------------------------------------------------------------------------*/
01323 NS_IMETHODIMP nsRegistry::DeleteValue( nsRegistryKey baseKey, const char *path)
01324 {
01325     REGERR err = REGERR_OK;
01326     // Delete the value
01327     PR_Lock(mregLock);
01328     err = NR_RegDeleteEntry( mReg,(RKEY)baseKey,(char*)path );
01329     PR_Unlock(mregLock);
01330     // Convert result.
01331     return regerr2nsresult( err );
01332 }
01333 
01334 /*------------------------ nsRegistry::EnumerateValues -------------------------
01335 | Allocates and returns an instance of nsRegValueEnumerator constructed in     |
01336 | a similar fashion as the nsRegSubtreeEnumerator is allocated/returned by     |
01337 | EnumerateSubtrees.                                                           |
01338 ------------------------------------------------------------------------------*/
01339 NS_IMETHODIMP nsRegistry::EnumerateValues( nsRegistryKey baseKey, nsIEnumerator **result ) {
01340     nsresult rv = NS_OK;
01341     // Make sure we have a place to put the result.
01342     if( result ) {
01343         *result = new nsRegValueEnumerator( mReg,(RKEY)baseKey );
01344         // Check for success.
01345         if( *result ) {
01346             // Bump refcnt on behalf of caller.
01347             NS_ADDREF(*result);
01348         } else {
01349             // Unable to allocate space for the enumerator object.
01350             rv = NS_ERROR_OUT_OF_MEMORY;
01351         }
01352     } else {
01353         rv = NS_ERROR_NULL_POINTER;
01354     }
01355     return rv;
01356 }
01357 
01358 /*---------------------- nsRegistry::GetCurrentUserName ------------------------
01359 | Simple wrapper for NR_RegGetUsername.                                        |
01360 ------------------------------------------------------------------------------*/
01361 NS_IMETHODIMP nsRegistry::GetCurrentUserName( char **result ) {
01362     nsresult rv = NS_OK;
01363     REGERR err = REGERR_OK;
01364     // Make sure we have a place to put the result.
01365     if( result ) {
01366         // Get the user name.
01367         PR_Lock(mregLock);
01368         err = NR_RegGetUsername( result );
01369         PR_Unlock(mregLock);
01370         // Convert the result.
01371         rv = regerr2nsresult( err );
01372     } else {
01373         rv = NS_ERROR_NULL_POINTER;
01374     }
01375     return rv;
01376 }
01377 
01378 /*---------------------- nsRegistry::SetCurrentUserName ------------------------
01379 | Simple wrapper for NR_RegSetUsername.                                        |
01380 ------------------------------------------------------------------------------*/
01381 NS_IMETHODIMP nsRegistry::SetCurrentUserName( const char *name ) {
01382     nsresult rv = NS_OK;
01383     REGERR err = REGERR_OK;
01384     // Set the user name.
01385     PR_Lock(mregLock);
01386     err = NR_RegSetUsername( name );
01387     PR_Unlock(mregLock);
01388     // Convert result.
01389     rv = regerr2nsresult( err );
01390     return rv;
01391 }
01392 
01393 /*----------------------------- nsRegistry::Pack -------------------------------
01394 | Simple wrapper for NR_RegPack.  We don't set up any callback.                |
01395 ------------------------------------------------------------------------------*/
01396 NS_IMETHODIMP nsRegistry::Pack() {
01397     nsresult rv = NS_OK;
01398     REGERR err = REGERR_OK;
01399     // Pack the registry.
01400     PR_Lock(mregLock);
01401     err = NR_RegPack( mReg, 0, 0 );
01402     PR_Unlock(mregLock);
01403     // Convert result.
01404     rv = regerr2nsresult( err );
01405     return rv;
01406 }
01407 
01408 /*----------------------------- nsRegistry::EscapeKey -------------------------------
01409 | Escape a binary key so that the registry works OK, since it expects UTF8
01410 | with no slashes or control characters.  This is probably better than raw.
01411 | If no escaping is required, then the method is successful and a null is
01412 | returned, indicating that the caller should use the original string.
01413 ------------------------------------------------------------------------------*/
01414 static const char sEscapeKeyHex[] = "0123456789abcdef0123456789ABCDEF";
01415 NS_IMETHODIMP nsRegistry::EscapeKey(PRUint8* key, PRUint32 termination, PRUint32* length, PRUint8** escaped)
01416 {
01417     nsresult rv = NS_OK;
01418     char* value = (char*)key;
01419     char* b = value;
01420     char* e = b + *length;
01421     int escapees = 0;
01422     while (b < e)    //    Count characters outside legal range or slash
01423     {
01424         int c = *b++;
01425         if (c <= ' '
01426             || c > '~'
01427             || c == '/'
01428             || c == '%')
01429         {
01430             escapees++;
01431         }
01432     }
01433     if (escapees == 0)    //    If no escapees, then no results
01434     {
01435         *length = 0;
01436         *escaped = nsnull;
01437         return NS_OK;
01438     }
01439     //    New length includes two extra chars for escapees.
01440     *length += escapees * 2;
01441     *escaped = (PRUint8*)nsMemory::Alloc(*length + termination);
01442     if (*escaped == nsnull)
01443     {
01444         *length = 0;
01445         *escaped = nsnull;
01446         return NS_ERROR_OUT_OF_MEMORY;
01447     }
01448     char* n = (char*)*escaped;
01449     b = value;
01450     while (escapees && b < e)
01451     {
01452         char c = *b++;
01453         if (c < ' '
01454             || c > '~'
01455             || c == '/'
01456             || c == '%')
01457         {
01458             *(n++) = '%';
01459             *(n++) = sEscapeKeyHex[ 0xF & (c >> 4) ];
01460             *(n++) = sEscapeKeyHex[ 0xF & c ];
01461             escapees--;
01462         }
01463         else
01464         {
01465             *(n++) = c;
01466         }
01467     }
01468     e += termination;
01469     if (b < e)
01470     {
01471         strncpy(n, b, e - b);
01472     }
01473     return rv;
01474 }
01475 
01476 /*----------------------------- nsRegistry::UnescapeKey -------------------------------
01477 | Unscape a binary key so that the registry works OK, since it expects UTF8
01478 | with no slashes or control characters.  This is probably better than raw.
01479 | If no escaping is required, then the method is successful and a null is
01480 | returned, indicating that the caller should use the original string.
01481 ------------------------------------------------------------------------------*/
01482 NS_IMETHODIMP nsRegistry::UnescapeKey(PRUint8* escaped, PRUint32 termination, PRUint32* length, PRUint8** key)
01483 {
01484     nsresult rv = NS_OK;
01485     char* value = (char*)escaped;
01486     char* b = value;
01487     char* e = b + *length;
01488     int escapees = 0;
01489     while (b < e)    //    Count characters outside legal range or slash
01490     {
01491         if (*b++ == '%')
01492         {
01493             escapees++;
01494         }
01495     }
01496     if (escapees == 0)    //    If no escapees, then no results
01497     {
01498         *length = 0;
01499         *key = nsnull;
01500         return NS_OK;
01501     }
01502     //    New length includes two extra chars for escapees.
01503     *length -= escapees * 2;
01504     *key = (PRUint8*)nsMemory::Alloc(*length + termination);
01505     if (*key == nsnull)
01506     {
01507         *length = 0;
01508         *key = nsnull;
01509         return NS_ERROR_OUT_OF_MEMORY;
01510     }
01511     char* n = (char*)*key;
01512     b = value;
01513     while (escapees && b < e)
01514     {
01515         char c = *(b++);
01516         if (c == '%')
01517         {
01518             if (e - b >= 2)
01519             {
01520                 const char* c1 = strchr(sEscapeKeyHex, *(b++));
01521                 const char* c2 = strchr(sEscapeKeyHex, *(b++));
01522                 if (c1 != nsnull
01523                     && c2 != nsnull)
01524                 {
01525                     *(n++) = ((c2 - sEscapeKeyHex) & 0xF)
01526                         | (((c1 - sEscapeKeyHex) & 0xF) << 4);
01527                 }
01528                 else
01529                 {
01530                     escapees = -1;
01531                 }
01532             }
01533             else
01534             {
01535                 escapees = -1;
01536             }
01537             escapees--;
01538         }
01539         else
01540         {
01541             *(n++) = c;
01542         }
01543     }
01544     if (escapees < 0)
01545     {
01546         nsMemory::Free(*key);
01547         *length = 0;
01548         *key = nsnull;
01549         return NS_ERROR_INVALID_ARG;
01550     }
01551     e += termination;
01552     if (b < e)
01553     {
01554         strncpy(n, b, e - b);
01555     }
01556     return rv;
01557 }
01558 
01559 
01560 /*-------------- nsRegistry::SetBufferSize-------------------------------------
01561 | Sets the size of the file used for the registry's buffer size.               |
01562 ------------------------------------------------------------------------------*/
01563 int nsRegistry::SetBufferSize( int bufsize )
01564 {
01565     int newSize;
01566     // set the file buffer size
01567     PR_Lock(mregLock);
01568     newSize = NR_RegSetBufferSize( mReg, bufsize );
01569     PR_Unlock(mregLock);
01570     return newSize;
01571 }
01572 
01573 
01574 /*-------------- nsRegSubtreeEnumerator::nsRegSubtreeEnumerator ----------------
01575 | The ctor simply stashes all the information that will be needed to enumerate |
01576 | the subkeys.                                                                 |
01577 ------------------------------------------------------------------------------*/
01578 nsRegSubtreeEnumerator::nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all )
01579     : mReg( hReg ), mKey( rKey ), mEnum( 0 ), mNext( 0 ),
01580       mStyle( all ? REGENUM_DESCEND : REGENUM_CHILDREN ), mDone( PR_FALSE ) {
01581 
01582     mName[0] = '\0';
01583 
01584 #ifdef EXTRA_THREADSAFE
01585     // Create a registry lock
01586     mregLock = PR_NewLock();
01587 #endif
01588     return;
01589 }
01590 
01591 nsRegSubtreeEnumerator::~nsRegSubtreeEnumerator()
01592 {
01593 #ifdef EXTRA_THREADSAFE
01594     if (mregLock) {
01595         PR_DestroyLock(mregLock);
01596     }
01597 #endif
01598 }
01599 
01600 /*----------------------- nsRegSubtreeEnumerator::First ------------------------
01601 | Set mEnum to 0; this will cause the next NR_RegEnum call to go to            |
01602 | the beginning.  We then do a Next() call in order to do a "lookahead" to     |
01603 | properly detect an empty list (i.e., set the mDone flag).                    |
01604 ------------------------------------------------------------------------------*/
01605 NS_IMETHODIMP
01606 nsRegSubtreeEnumerator::First() {
01607     nsresult rv = NS_OK;
01608     // Reset "done" flag.
01609     mDone = PR_FALSE;
01610     // Clear Name
01611     mName[0] = '\0';
01612     // Go to beginning.
01613     mEnum = mNext = 0;
01614     // Lookahead so mDone flag gets set for empty list.
01615     rv = Next();
01616     return rv;
01617 }
01618 
01619 /*----------------------- nsRegSubtreeEnumerator::Next -------------------------
01620 | First, we check if we've already advanced to the end by checking the  mDone  |
01621 | flag.                                                                        |
01622 |                                                                              |
01623 | We advance mEnum to the next enumeration value which is in the mNext         |
01624 | lookahead buffer.  We must then call advance to lookahead and properly set   |
01625 | the isDone flag.                                                             |
01626 ------------------------------------------------------------------------------*/
01627 NS_IMETHODIMP
01628 nsRegSubtreeEnumerator::Next() {
01629     nsresult rv = NS_OK;
01630     // Check for at end.
01631     if ( !mDone ) {
01632         // Advance to next spot.
01633         mEnum = mNext;
01634         // Lookahead so mDone is properly set (and to update mNext).
01635         rv = advance();
01636     } else {
01637         // Set result accordingly.
01638         rv = regerr2nsresult( REGERR_NOMORE );
01639     }
01640     return rv;
01641 }
01642 
01643 /*---------------------- nsRegSubtreeEnumerator::advance -----------------------
01644 | Advance mNext to next subkey using NR_RegEnumSubkeys.  We set mDone if       |
01645 | there are no more subkeys.                                                   |
01646 ------------------------------------------------------------------------------*/
01647 NS_IMETHODIMP nsRegSubtreeEnumerator::advance() {
01648     REGERR err = REGERR_OK;
01649     PR_Lock(mregLock);
01650     err = NR_RegEnumSubkeys( mReg, mKey, &mNext, mName, sizeof mName, mStyle );
01651     // See if we ran off end.
01652     if( err == REGERR_NOMORE ) {
01653         // Remember we've run off end.
01654         mDone = PR_TRUE;
01655     }
01656     PR_Unlock(mregLock);
01657     // Convert result.
01658     nsresult rv = regerr2nsresult( err );
01659     return rv;
01660 }
01661 
01662 /*-------------------- nsRegSubtreeEnumerator::CurrentItem ---------------------
01663 | Allocates and returns a new instance of class nsRegistryNode.  The node      |
01664 | object will hold the curent mEnum value so it can obtain its name from       |
01665 | the registry when asked.                                                     |
01666 ------------------------------------------------------------------------------*/
01667 NS_IMETHODIMP
01668 nsRegSubtreeEnumerator::CurrentItem( nsISupports **result) {
01669     nsresult rv = NS_OK;
01670     // Make sure there is a place to put the result.
01671     if( result ) {
01672         *result = new nsRegistryNode( mReg, mName, (RKEY) mNext );
01673         if( *result ) {
01674             NS_ADDREF(*result);
01675         } else {
01676             rv = NS_ERROR_OUT_OF_MEMORY;
01677         }
01678     } else {
01679         rv = NS_ERROR_NULL_POINTER;
01680     }
01681     return rv;
01682 }
01683 
01684 /*--------------nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8-----------------
01685 | An ugly name for an ugly function.  Hands back a shared pointer to the      |
01686 | name (encoded as UTF-8), and the subkey identifier.                         |
01687 -----------------------------------------------------------------------------*/
01688 NS_IMETHODIMP
01689 nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8(  nsRegistryKey *childKey ,
01690                                                  const char **name )
01691 {
01692   *childKey = mNext;
01693   /* [shared] */
01694   *name = mName;
01695   return NS_OK;
01696 }
01697 
01698 /*---------------------- nsRegSubtreeEnumerator::IsDone ------------------------
01699 | Simply return mDone.                                                         |
01700 ------------------------------------------------------------------------------*/
01701 NS_IMETHODIMP
01702 nsRegSubtreeEnumerator::IsDone() {
01703     nsresult rv = mDone ? NS_OK : NS_ENUMERATOR_FALSE;
01704     return rv;
01705 }
01706 
01707 
01708 /*---------------- nsRegValueEnumerator::nsRegValueEnumerator ------------------
01709 | Delegates everything to the base class constructor.                          |
01710 ------------------------------------------------------------------------------*/
01711 nsRegValueEnumerator::nsRegValueEnumerator( HREG hReg, RKEY rKey )
01712     : nsRegSubtreeEnumerator( hReg, rKey, PR_FALSE ) {
01713     return;
01714 }
01715 
01716 
01717 /*--------------------- nsRegValueEnumerator::CurrentItem ----------------------
01718 | As the nsRegSubtreeEnumerator counterpart, but allocates an object of        |
01719 | class nsRegistryValue.                                                       |
01720 ------------------------------------------------------------------------------*/
01721 NS_IMETHODIMP
01722 nsRegValueEnumerator::CurrentItem( nsISupports **result ) {
01723     nsresult rv = NS_OK;
01724     // Make sure there is a place to put the result.
01725     if( result ) {
01726         *result = new nsRegistryValue( mReg, mKey, mEnum );
01727         if( *result ) {
01728             NS_ADDREF(*result);
01729         } else {
01730             rv = NS_ERROR_OUT_OF_MEMORY;
01731         }
01732     } else {
01733         rv = NS_ERROR_NULL_POINTER;
01734     }
01735     return rv;
01736 }
01737 
01738 /*----------------------- nsRegValueEnumerator::advance ------------------------
01739 | Advance mNext to next subkey using NR_RegEnumEntries.  We set mDone if       |
01740 | there are no more entries.                                                   |
01741 ------------------------------------------------------------------------------*/
01742 NS_IMETHODIMP nsRegValueEnumerator::advance() {
01743     REGERR err = REGERR_OK;
01744     char name[MAXREGNAMELEN];
01745     PRUint32 len = sizeof name;
01746     REGINFO info = { sizeof info, 0, 0 };
01747     PR_Lock(mregLock);
01748     err = NR_RegEnumEntries( mReg, mKey, &mNext, name, len, &info );
01749     // See if we ran off end.
01750     if( err == REGERR_NOMORE ) {
01751         // Remember we've run off end.
01752         mDone = PR_TRUE;
01753     }
01754     PR_Unlock(mregLock);
01755     // Convert result.
01756     nsresult rv = regerr2nsresult( err );
01757     return rv;
01758 }
01759 
01760 
01761 /*---------------------- nsRegistryNode::nsRegistryNode ------------------------
01762 | Store the arguments in the corresponding data members and initialize         |
01763 | the other data members.  We defer the libreg calls till we're asked for      |
01764 | our name.  We use mErr==-1 to indicate we haven't fetched the name yet.      |
01765 ------------------------------------------------------------------------------*/
01766 nsRegistryNode::nsRegistryNode( HREG hReg, char *name, RKEY childKey )
01767     : mReg( hReg ), mChildKey( childKey ) {
01768 
01769     PR_ASSERT(name != nsnull);
01770     strcpy(mName, name);
01771 
01772 #ifdef EXTRA_THREADSAFE
01773     mregLock = PR_NewLock();
01774 #endif
01775     
01776     return;
01777 }
01778 
01779 nsRegistryNode::~nsRegistryNode()
01780 {
01781 #ifdef EXTRA_THREADSAFE
01782     if (mregLock) {
01783         PR_DestroyLock(mregLock);
01784     }
01785 #endif
01786 }
01787 
01788 /*-------------------------- nsRegistryNode::GetName ---------------------------
01789 | If we haven't fetched it yet, get the name of the corresponding subkey now,  |
01790 | using NR_RegEnumSubkeys.                                                     |
01791 ------------------------------------------------------------------------------*/
01792 NS_IMETHODIMP nsRegistryNode::GetName( PRUnichar **result ) {
01793     if (result == nsnull) return NS_ERROR_NULL_POINTER;
01794     // Make sure there is a place to put the result.
01795     *result = nsTextFormatter::smprintf( widestrFormat, mName );
01796     if ( !*result ) return NS_ERROR_OUT_OF_MEMORY;
01797     return NS_OK;
01798 }
01799 
01800 /*-------------------------- nsRegistryNode::GetNameUTF8 -----------------------
01801 | If we haven't fetched it yet, get the name of the corresponding subkey now,  |
01802 | using NR_RegEnumSubkeys.                                                     |
01803 ------------------------------------------------------------------------------*/
01804 NS_IMETHODIMP nsRegistryNode::GetNameUTF8( char **result ) {
01805     if (result == nsnull) return NS_ERROR_NULL_POINTER;
01806     // Make sure there is a place to put the result.
01807     *result = nsCRT::strdup( mName );
01808     if ( !*result ) return NS_ERROR_OUT_OF_MEMORY;
01809     return NS_OK;
01810 }
01811 
01812 /*-------------------------- nsRegistryNode::GetKey ----------------------------
01813 | Get the subkey corresponding to this node                                    |                        
01814 | using NR_RegEnumSubkeys.                                                     |
01815 ------------------------------------------------------------------------------*/
01816 NS_IMETHODIMP nsRegistryNode::GetKey( nsRegistryKey *r_key ) {
01817     nsresult rv = NS_OK;
01818     if (r_key == nsnull) return NS_ERROR_NULL_POINTER;
01819     *r_key = mChildKey;
01820     return rv;
01821 }
01822     
01823 
01824 
01825 /*--------------------- nsRegistryValue::nsRegistryValue -----------------------
01826 | Implemented the same way as the nsRegistryNode ctor.                         |
01827 ------------------------------------------------------------------------------*/
01828 nsRegistryValue::nsRegistryValue( HREG hReg, RKEY key, REGENUM slot )
01829     : mReg( hReg ), mKey( key ), mEnum( slot ), mErr( -1 ) {
01830 #ifdef EXTRA_THREADSAFE
01831     mregLock = PR_NewLock();
01832 #endif
01833     mInfo.size = sizeof(REGINFO);
01834 }
01835 
01836 nsRegistryValue::~nsRegistryValue()
01837 {
01838 #ifdef EXTRA_THREADSAFE
01839     if (mregLock) {
01840         PR_DestroyLock(mregLock);
01841     }
01842 #endif
01843 }
01844 
01845 /*------------------------- nsRegistryValue::GetName ---------------------------
01846 | See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case.         |
01847 ------------------------------------------------------------------------------*/
01848 NS_IMETHODIMP nsRegistryValue::GetName( PRUnichar **result ) {
01849     nsresult rv = NS_OK;
01850     // Make sure we have a place to put the result.
01851     if( result ) {
01852         // Ensure we've got the info we need.
01853         rv = getInfo();            
01854         if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) {
01855             // worked, return actual result.
01856             *result = nsTextFormatter::smprintf( widestrFormat, mName );
01857             if ( *result ) {
01858                 rv = NS_OK;
01859             } else {
01860                 rv = NS_ERROR_OUT_OF_MEMORY;
01861             }
01862         }
01863     } else {
01864         rv = NS_ERROR_NULL_POINTER;
01865     }
01866     return rv;
01867 }
01868 
01869 /*------------------------- nsRegistryValue::GetNameUTF8 -----------------------
01870 | See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case.         |
01871 ------------------------------------------------------------------------------*/
01872 NS_IMETHODIMP nsRegistryValue::GetNameUTF8( char **result ) {
01873     nsresult rv = NS_OK;
01874     // Make sure we have a place to put the result.
01875     if( result ) {
01876         // Ensure we've got the info we need.
01877         rv = getInfo();            
01878         if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) {
01879             // worked, return actual result.
01880             *result = nsCRT::strdup( mName );
01881             if ( *result ) {
01882                 rv = NS_OK;
01883             } else {
01884                 rv = NS_ERROR_OUT_OF_MEMORY;
01885             }
01886         }
01887     } else {
01888         rv = NS_ERROR_NULL_POINTER;
01889     }
01890     return rv;
01891 }
01892 
01893 /*----------------------- nsRegistryValue::GetType ------------------------
01894 | We test if we've got the info already.  If not, we git it by calling         |
01895 | getInfo.  We calculate the result by converting the REGINFO type field to    |
01896 | a nsIRegistry::DataType value (using reginfo2DataType).                      |
01897 ------------------------------------------------------------------------------*/
01898 NS_IMETHODIMP nsRegistryValue::GetType( PRUint32 *result ) {
01899     nsresult rv = NS_OK;
01900     // Make sure we have room for th result.
01901     if( result ) {
01902         // Make sure we've got the info we need.
01903         rv = getInfo();
01904         // Check if it worked.
01905         if( rv == NS_OK ) {
01906             // Convert result from REGINFO to nsIRegistry::ValueInfo.
01907             reginfo2DataType( mInfo, *result );
01908         }
01909     } else {
01910         rv = NS_ERROR_NULL_POINTER;
01911     }
01912     return rv;
01913 }
01914 
01915 /*---------------------- nsRegistryValue::GetLength -----------------------
01916 | We test if we've got the info already.  If not, we git it by calling         |
01917 | getInfo.  We calculate the result by converting the REGINFO type field to    |
01918 | a nsIRegistry::DataType value (using reginfo2Length).                        |
01919 ------------------------------------------------------------------------------*/
01920 NS_IMETHODIMP nsRegistryValue::GetLength( PRUint32 *result ) {
01921     nsresult rv = NS_OK;
01922     // Make sure we have room for th result.
01923     if( result ) {
01924         // Make sure we've got the info we need.
01925         rv = getInfo();
01926         // Check if it worked.
01927         if( rv == NS_OK ) {
01928             // Convert result from REGINFO to length.
01929             reginfo2Length( mInfo, *result );
01930         }
01931     } else {
01932         rv = NS_ERROR_NULL_POINTER;
01933     }
01934     return rv;
01935 }
01936 
01937 /*------------------------- nsRegistryValue::getInfo ---------------------------
01938 | Call NR_RegEnumEntries to set the mInfo/mName data members.                  |
01939 ------------------------------------------------------------------------------*/
01940 nsresult nsRegistryValue::getInfo() {
01941     nsresult rv = NS_OK;
01942     // Test whether we haven't tried to get it yet.
01943     if( mErr == -1 ) {
01944         REGENUM temp = mEnum;
01945         // Get name and info.
01946         PR_Lock(mregLock);
01947         mErr = NR_RegEnumEntries( mReg, mKey, &temp, mName, sizeof mName, &mInfo );
01948         // Convert result.
01949         rv = regerr2nsresult( mErr );            
01950         PR_Unlock(mregLock);
01951     }
01952     return rv;
01953 }
01954 
01955 
01956 nsRegistryFactory::nsRegistryFactory() {
01957 }
01958 
01959 NS_IMPL_ISUPPORTS1(nsRegistryFactory, nsIFactory)
01960 
01961 NS_IMETHODIMP
01962 nsRegistryFactory::CreateInstance(nsISupports *aOuter,
01963                                    const nsIID &aIID,
01964                                    void **aResult) {
01965     nsresult rv = NS_OK;
01966     nsRegistry* newRegistry;
01967 
01968     if(aResult == nsnull) {
01969         return NS_ERROR_NULL_POINTER;
01970     } else {
01971         *aResult = nsnull;
01972     }
01973 
01974     if(0 != aOuter) {
01975         return NS_ERROR_NO_AGGREGATION;
01976     }
01977 
01978     NS_NEWXPCOM(newRegistry, nsRegistry);
01979 
01980     if(newRegistry == nsnull) {
01981         return NS_ERROR_OUT_OF_MEMORY;
01982     }
01983 
01984     NS_ADDREF(newRegistry);
01985     rv = newRegistry->QueryInterface(aIID, aResult);
01986     NS_RELEASE(newRegistry);
01987 
01988     return rv;
01989 }
01990 
01991 nsresult
01992 nsRegistryFactory::LockFactory(PRBool aLock)
01993 {
01994   // Not implemented in simplest case.
01995   return NS_OK;
01996 }
01997 
01998 // This is a temporary hack; needs work to support dynamic binding
01999 // via nsComponentManager and support for multiple factories per DLL.
02000 extern "C" NS_EXPORT nsresult
02001 NS_RegistryGetFactory(nsIFactory** aFactory ) {
02002     nsresult rv = NS_OK;
02003 
02004     if( aFactory == 0 ) {
02005         return NS_ERROR_NULL_POINTER;
02006     } else {
02007         *aFactory = 0;
02008     }
02009 
02010     nsIFactory* inst = new nsRegistryFactory();
02011     if(0 == inst) {
02012         rv = NS_ERROR_OUT_OF_MEMORY;
02013     } else {
02014         NS_ADDREF(inst);
02015         *aFactory = inst;
02016     }
02017 
02018     return rv;
02019 }