/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Alec Flett */ #include "nsIComponentManager.h" #include "nsXPIDLString.h" #include "nsTextFormatter.h" #include "nsPrefBranch.h" #include "nsIPrefListener.h" #include "prefapi.h" #include "prefapi_private_data.h" // this needs to be removed! static nsresult _convertRes(int res) //--------------------------------------------------------------------------- { switch (res) { case PREF_OUT_OF_MEMORY: return NS_ERROR_OUT_OF_MEMORY; case PREF_NOT_INITIALIZED: return NS_ERROR_NOT_INITIALIZED; case PREF_TYPE_CHANGE_ERR: case PREF_ERROR: case PREF_BAD_LOCKFILE: case PREF_DEFAULT_VALUE_NOT_INITIALIZED: return NS_ERROR_UNEXPECTED; case PREF_VALUECHANGED: return 1; } NS_ASSERTION((res >= PREF_DEFAULT_VALUE_NOT_INITIALIZED) && (res <= PREF_PROFILE_UPGRADE), "you added a new error code to prefapi.h and didn't update _convertRes"); return NS_OK; } struct EnumerateData { char *parent; PrefEnumerationFunc callback; void *arg; }; // roll this into the base class por favor PR_STATIC_CALLBACK(PRIntn) pref_enumChild(PLHashEntry *he, int i, void *arg) { EnumerateData *d = (EnumerateData *) arg; if (PL_strncmp((char*)he->key, d->parent, PL_strlen(d->parent)) == 0) { (*d->callback)((char*)he->key, d->arg); } return HT_ENUMERATE_NEXT; } nsPrefBranch::nsPrefBranch(const char *aPrefRoot) { mPrefRoot = aPrefRoot; mPrefRootLength = mPrefRoot.Length(); } nsPrefBranch::~nsPrefBranch() { } NS_IMPL_ISUPPORTS1(nsPrefBranch, nsIPrefBranch) nsCString& nsPrefBranch::getPrefRoot() { mPrefRoot.Truncate(mPrefRootLength); return mPrefRoot; } const char * nsPrefBranch::getPrefName(const char *aPrefName) { // for speed, avoid strcpy if we can: if (mPrefRoot.IsEmpty()) return aPrefName; getPrefRoot(); mPrefRoot.Append(aPrefName); return mPrefRoot.GetBuffer(); } nsresult nsPrefBranch::GetRoot(char **aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = getPrefRoot().ToNewCString(); return NS_OK; } NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPref, PRBool *aResult) { return _convertRes(PREF_GetBoolPref(getPrefName(aPref), aResult)); } NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPref, PRInt32 *aResult) { return _convertRes(PREF_GetIntPref(getPrefName(aPref), aResult)); } nsresult nsPrefBranch::GetCharPref(const char *aPref, char **aResult) { return _convertRes(PREF_CopyCharPref(getPrefName(aPref), aResult)); } NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPref, PRBool aValue) { return _convertRes(PREF_SetBoolPref(getPrefName(aPref), aValue)); } NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPref, PRInt32 aValue) { return _convertRes(PREF_SetIntPref(getPrefName(aPref), aValue)); } NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPref, const char* aValue) { return _convertRes(PREF_SetCharPref(getPrefName(aPref), aValue)); } // defaults NS_IMETHODIMP nsPrefBranch::GetDefaultBoolPref(const char *aPref, PRBool *aResult) { return _convertRes(PREF_GetDefaultBoolPref(getPrefName(aPref), aResult)); } NS_IMETHODIMP nsPrefBranch::GetDefaultIntPref(const char *aPref, PRInt32 *aResult) { return _convertRes(PREF_GetDefaultIntPref(getPrefName(aPref), aResult)); } nsresult nsPrefBranch::GetDefaultCharPref(const char *aPref, char **aResult) { return _convertRes(PREF_CopyDefaultCharPref(getPrefName(aPref), aResult)); } NS_IMETHODIMP nsPrefBranch::SetDefaultBoolPref(const char *aPref, PRBool aValue) { return _convertRes(PREF_SetDefaultBoolPref(getPrefName(aPref), aValue)); } NS_IMETHODIMP nsPrefBranch::SetDefaultIntPref(const char *aPref, PRInt32 aValue) { return _convertRes(PREF_SetDefaultIntPref(getPrefName(aPref), aValue)); } NS_IMETHODIMP nsPrefBranch::SetDefaultCharPref(const char *aPref, const char* aValue) { return _convertRes(PREF_SetDefaultCharPref(getPrefName(aPref), aValue)); } NS_IMETHODIMP nsPrefBranch::GetFileSpecPref(const char *pref_name, nsIFileSpec** value) { return getFileSpecPrefInternal(getPrefName(pref_name), value, PR_FALSE); } NS_IMETHODIMP nsPrefBranch::GetDefaultFileSpecPref(const char *pref_name, nsIFileSpec** value) { return getFileSpecPrefInternal(getPrefName(pref_name), value, PR_TRUE); } nsresult nsPrefBranch::getFileSpecPrefInternal(const char *real_pref_name, nsIFileSpec **value, PRBool get_default) { if (!value) return NS_ERROR_NULL_POINTER; nsresult rv = nsComponentManager::CreateInstance( (const char*)NS_FILESPEC_PROGID, (nsISupports*)nsnull, (const nsID&)NS_GET_IID(nsIFileSpec), (void**)value); NS_ASSERTION(NS_SUCCEEDED(rv), "ERROR: Could not make a file spec."); if (!*value) return NS_ERROR_FAILURE; nsXPIDLCString encodedString; PrefResult result; if (get_default) result = PREF_CopyCharPref(real_pref_name, getter_Copies(encodedString)); else result = PREF_CopyDefaultCharPref(real_pref_name, getter_Copies(encodedString)); if (result != PREF_NOERROR) return _convertRes(result); PRBool valid; (*value)->SetPersistentDescriptorString(encodedString); (*value)->IsValid(&valid); if (! valid) /* if the ecodedString wasn't a valid persitent descriptor, it might be a valid native path*/ (*value)->SetNativePath(encodedString); return NS_OK; } NS_IMETHODIMP nsPrefBranch::SetFileSpecPref(const char *pref_name, nsIFileSpec* value) { return setFileSpecPrefInternal(getPrefName(pref_name), value, PR_FALSE); } NS_IMETHODIMP nsPrefBranch::SetDefaultFileSpecPref(const char *pref_name, nsIFileSpec* value) { return setFileSpecPrefInternal(getPrefName(pref_name), value, PR_TRUE); } nsresult nsPrefBranch::setFileSpecPrefInternal(const char *real_pref_name, nsIFileSpec* value, PRBool set_default) { if (!value) return NS_ERROR_NULL_POINTER; nsresult rv = NS_OK; if (!Exists(value)) { // nsPersistentFileDescriptor requires an existing // object. Make it first. COM makes this difficult, of course... nsIFileSpec* tmp = nsnull; rv = nsComponentManager::CreateInstance(NS_FILESPEC_PROGID, nsnull, NS_GET_IID(nsIFileSpec), (void**)&tmp); NS_ASSERTION(NS_SUCCEEDED(rv), "ERROR: Could not make a file spec."); if (!tmp) return NS_ERROR_FAILURE; tmp->FromFileSpec(value); tmp->CreateDir(); NS_RELEASE(tmp); } nsXPIDLCString encodedString; value->GetPersistentDescriptorString(getter_Copies(encodedString)); if (encodedString && *(const char*)encodedString) { if (set_default) rv = PREF_SetDefaultCharPref(real_pref_name, encodedString); else rv = PREF_SetCharPref(real_pref_name, encodedString); } return _convertRes(rv); } // unicode "%s" format string static const PRUnichar unicodeFormatter[] = { (PRUnichar)'%', (PRUnichar)'s', (PRUnichar)0, }; NS_IMETHODIMP nsPrefBranch::GetUnicharPref(const char *pref, PRUnichar ** return_buf) { nsresult rv; // get the UTF8 string for conversion nsXPIDLCString utf8String; rv = GetCharPref(pref, getter_Copies(utf8String)); if (NS_FAILED(rv)) return rv; return convertUTF8ToUnicode(utf8String, return_buf); } nsresult nsPrefBranch::convertUTF8ToUnicode(const char *utf8String, PRUnichar ** aResult) { NS_ENSURE_ARG_POINTER(aResult); // convert to PRUnichar using nsTextFormatter // this is so ugly, it allocates memory at least 4 times :( PRUnichar *unicodeString = nsTextFormatter::smprintf(unicodeFormatter, utf8String); if (!unicodeString) return NS_ERROR_OUT_OF_MEMORY; // use the right allocator *aResult = nsCRT::strdup(unicodeString); nsTextFormatter::smprintf_free(unicodeString); if (!*aResult) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } NS_IMETHODIMP nsPrefBranch::GetDefaultUnicharPref( const char *pref, PRUnichar ** return_buf) { nsresult rv; nsXPIDLCString utf8String; rv = GetDefaultCharPref(pref, getter_Copies(utf8String)); if (NS_FAILED(rv)) return rv; return convertUTF8ToUnicode(utf8String, return_buf); } NS_IMETHODIMP nsPrefBranch::SetUnicharPref(const char *pref, const PRUnichar *value) { nsresult rv; nsAutoString str(value); char *utf8String = str.ToNewUTF8String(); if (!utf8String) return NS_ERROR_OUT_OF_MEMORY; rv = SetCharPref(pref, utf8String); nsCRT::free(utf8String); return rv; } NS_IMETHODIMP nsPrefBranch::SetDefaultUnicharPref(const char *pref, const PRUnichar *value) { nsresult rv; nsAutoString str(value); char *utf8String = str.ToNewUTF8String(); if (!utf8String) return NS_ERROR_OUT_OF_MEMORY; rv = SetDefaultCharPref(pref, utf8String); nsCRT::free(utf8String); return NS_OK; } NS_IMETHODIMP nsPrefBranch::ClearBranch(const char *branchName) { return _convertRes(PREF_DeleteBranch(getPrefName(branchName))); } NS_IMETHODIMP nsPrefBranch::ClearPref(const char *pref_name) { return _convertRes(PREF_ClearUserPref(getPrefName(pref_name))); } NS_IMETHODIMP nsPrefBranch::EnumerateChildren(const char *parent, PrefEnumerationFunc callback, void *arg) { EnumerateData ed; ed.parent = nsCRT::strdup(getPrefName(parent)); ed.callback = callback; ed.arg = arg; PL_HashTableEnumerateEntries(gHashTable, pref_enumChild, &ed); nsCRT::free(ed.parent); return NS_OK; } NS_IMETHODIMP nsPrefBranch::RegisterCallback( const char* domain, PrefChangedFunc callback, void* instance_data ) { PREF_RegisterCallback(getPrefName(domain), callback, instance_data); return NS_OK; } NS_IMETHODIMP nsPrefBranch::UnregisterCallback( const char* domain, PrefChangedFunc callback, void* instance_data ) { return _convertRes(PREF_UnregisterCallback(getPrefName(domain), callback, instance_data)); } NS_IMETHODIMP nsPrefBranch::AddListener(const char* domain, nsIPrefListener *listener) { NS_ASSERTION(0, "nsPrefBranch::AddListener not implemented"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsPrefBranch::RemoveListener(const char* domain, nsIPrefListener *listener) { NS_ASSERTION(0, "nsPrefBranch::RemoveListener not implemented"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *pref, PRInt32 *aResult) { *aResult = PREF_GetPrefType(getPrefName(pref)); return NS_OK; } NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *pref, PRBool *res) { if (res == NULL) return NS_ERROR_INVALID_POINTER; *res = PREF_PrefIsLocked(getPrefName(pref)); return NS_OK; }