Back to index

lightning-sunbird  0.9+nobinonly
xpcexception.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1999
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   John Bandhauer <jband@netscape.com> (original author)
00026  *   Mark Hammond <MarkH@ActiveState.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 /* An implementaion of nsIException. */
00043 
00044 #include "xpcprivate.h"
00045 
00046 /***************************************************************************/
00047 /* Quick and dirty mapping of well known result codes to strings. We only
00048 *  call this when building an exception object, so iterating the short array
00049 *  is not too bad.
00050 *
00051 *  It sure would be nice to have exceptions declared in idl and available
00052 *  in some more global way at runtime.
00053 */
00054 
00055 static struct ResultMap
00056 {nsresult rv; const char* name; const char* format;} map[] = {
00057 #define XPC_MSG_DEF(val, format) \
00058     {(val), #val, format},
00059 #include "xpc.msg"
00060 #undef XPC_MSG_DEF
00061     {0,0,0}   // sentinel to mark end of array
00062 };
00063 
00064 #define RESULT_COUNT ((sizeof(map) / sizeof(map[0]))-1)
00065 
00066 // static
00067 JSBool
00068 nsXPCException::NameAndFormatForNSResult(nsresult rv,
00069                                          const char** name,
00070                                          const char** format)
00071 {
00072 
00073     for(ResultMap* p = map; p->name; p++)
00074     {
00075         if(rv == p->rv)
00076         {
00077             if(name) *name = p->name;
00078             if(format) *format = p->format;
00079             return JS_TRUE;
00080         }
00081     }
00082     return JS_FALSE;
00083 }
00084 
00085 // static
00086 void*
00087 nsXPCException::IterateNSResults(nsresult* rv,
00088                                  const char** name,
00089                                  const char** format,
00090                                  void** iterp)
00091 {
00092     ResultMap* p = (ResultMap*) *iterp;
00093     if(!p)
00094         p = map;
00095     else
00096         p++;
00097     if(!p->name)
00098         p = nsnull;
00099     else
00100     {
00101         if(rv)
00102             *rv = p->rv;
00103         if(name)
00104             *name = p->name;
00105         if(format)
00106             *format = p->format;
00107     }
00108     *iterp = p;
00109     return p;
00110 }
00111 
00112 // static
00113 PRUint32
00114 nsXPCException::GetNSResultCount()
00115 {
00116     return RESULT_COUNT;
00117 }
00118 
00119 /***************************************************************************/
00120 
00121 NS_INTERFACE_MAP_BEGIN(nsXPCException)
00122   NS_INTERFACE_MAP_ENTRY(nsIException)
00123   NS_INTERFACE_MAP_ENTRY(nsIXPCException)
00124 #ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
00125   NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
00126 #endif
00127   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException)
00128   NS_IMPL_QUERY_CLASSINFO(nsXPCException)
00129 NS_INTERFACE_MAP_END_THREADSAFE
00130 
00131 NS_IMPL_THREADSAFE_ADDREF(nsXPCException)
00132 NS_IMPL_THREADSAFE_RELEASE(nsXPCException)
00133 
00134 NS_IMPL_CI_INTERFACE_GETTER1(nsXPCException, nsIXPCException)
00135 
00136 nsXPCException::nsXPCException()
00137     : mMessage(nsnull),
00138       mResult(0),
00139       mName(nsnull),
00140       mLocation(nsnull),
00141       mData(nsnull),
00142       mFilename(nsnull),
00143       mLineNumber(0),
00144       mInner(nsnull),
00145       mInitialized(PR_FALSE)
00146 {
00147     MOZ_COUNT_CTOR(nsXPCException);
00148 }
00149 
00150 nsXPCException::~nsXPCException()
00151 {
00152     MOZ_COUNT_DTOR(nsXPCException);
00153     Reset();
00154 }
00155 
00156 void
00157 nsXPCException::Reset()
00158 {
00159     if(mMessage)
00160     {
00161         nsMemory::Free(mMessage);
00162         mMessage = nsnull;
00163     }
00164     if(mName)
00165     {
00166         nsMemory::Free(mName);
00167         mName = nsnull;
00168     }
00169     if(mFilename)
00170     {
00171         nsMemory::Free(mFilename);
00172         mFilename = nsnull;
00173     }
00174     mLineNumber = (PRUint32)-1;
00175     NS_IF_RELEASE(mLocation);
00176     NS_IF_RELEASE(mData);
00177     NS_IF_RELEASE(mInner);
00178 }
00179 
00180 /* readonly attribute string message; */
00181 NS_IMETHODIMP
00182 nsXPCException::GetMessage(char * *aMessage)
00183 {
00184     if(!mInitialized)
00185         return NS_ERROR_NOT_INITIALIZED;
00186     XPC_STRING_GETTER_BODY(aMessage, mMessage);
00187 }
00188 
00189 /* readonly attribute nsresult result; */
00190 NS_IMETHODIMP
00191 nsXPCException::GetResult(nsresult *aResult)
00192 {
00193     if(!aResult)
00194         return NS_ERROR_NULL_POINTER;
00195     if(!mInitialized)
00196         return NS_ERROR_NOT_INITIALIZED;
00197     *aResult = mResult;
00198     return NS_OK;
00199 }
00200 
00201 /* readonly attribute string name; */
00202 NS_IMETHODIMP
00203 nsXPCException::GetName(char * *aName)
00204 {
00205     if(!mInitialized)
00206         return NS_ERROR_NOT_INITIALIZED;
00207 
00208     const char* name = mName;
00209     if(!name)
00210         NameAndFormatForNSResult(mResult, &name, nsnull);
00211 
00212     XPC_STRING_GETTER_BODY(aName, name);
00213 }
00214 
00215 /* readonly attribute string filename; */
00216 NS_IMETHODIMP nsXPCException::GetFilename(char * *aFilename)
00217 {
00218     if(!mInitialized)
00219         return NS_ERROR_NOT_INITIALIZED;
00220     XPC_STRING_GETTER_BODY(aFilename, mFilename);
00221 }
00222 
00223 /* readonly attribute PRUint32 lineNumber; */
00224 NS_IMETHODIMP nsXPCException::GetLineNumber(PRUint32 *aLineNumber)
00225 {
00226     if(!aLineNumber)
00227         return NS_ERROR_NULL_POINTER;
00228     if(!mInitialized)
00229         return NS_ERROR_NOT_INITIALIZED;
00230     *aLineNumber = mLineNumber;
00231     return NS_OK;
00232 }
00233 
00234 /* readonly attribute PRUint32 columnNumber; */
00235 NS_IMETHODIMP nsXPCException::GetColumnNumber(PRUint32 *aColumnNumber)
00236 {
00237     NS_ENSURE_ARG_POINTER(aColumnNumber);
00238     if(!mInitialized)
00239         return NS_ERROR_NOT_INITIALIZED;
00240     *aColumnNumber = 0;
00241     return NS_OK;
00242 }
00243 
00244 /* readonly attribute nsIStackFrame location; */
00245 NS_IMETHODIMP
00246 nsXPCException::GetLocation(nsIStackFrame * *aLocation)
00247 {
00248     if(!aLocation)
00249         return NS_ERROR_NULL_POINTER;
00250     if(!mInitialized)
00251         return NS_ERROR_NOT_INITIALIZED;
00252     *aLocation = mLocation;
00253     NS_IF_ADDREF(mLocation);
00254     return NS_OK;
00255 }
00256 
00257 /* readonly attribute nsISupports data; */
00258 NS_IMETHODIMP
00259 nsXPCException::GetData(nsISupports * *aData)
00260 {
00261     if(!aData)
00262         return NS_ERROR_NULL_POINTER;
00263     if(!mInitialized)
00264         return NS_ERROR_NOT_INITIALIZED;
00265     *aData = mData;
00266     NS_IF_ADDREF(mData);
00267     return NS_OK;
00268 }
00269 
00270 /* readonly attribute nsIException inner; */
00271 NS_IMETHODIMP
00272 nsXPCException::GetInner(nsIException* *aException)
00273 {
00274     if(!aException)
00275         return NS_ERROR_NULL_POINTER;
00276     if(!mInitialized)
00277         return NS_ERROR_NOT_INITIALIZED;
00278     *aException = mInner;
00279     NS_IF_ADDREF(mInner);
00280     return NS_OK;
00281 }
00282 
00283 /* void initialize (in string aMessage, in nsresult aResult, in string aName, in nsIStackFrame aLocation, in nsISupports aData, in nsIException aInner); */
00284 NS_IMETHODIMP
00285 nsXPCException::Initialize(const char *aMessage, nsresult aResult, const char *aName, nsIStackFrame *aLocation, nsISupports *aData, nsIException *aInner)
00286 {
00287     if(mInitialized)
00288         return NS_ERROR_ALREADY_INITIALIZED;
00289 
00290     Reset();
00291 
00292     if(aMessage)
00293     {
00294         if(!(mMessage = (char*) nsMemory::Clone(aMessage,
00295                                            sizeof(char)*(strlen(aMessage)+1))))
00296             return NS_ERROR_OUT_OF_MEMORY;
00297     }
00298 
00299     if(aName)
00300     {
00301         if(!(mName = (char*) nsMemory::Clone(aName,
00302                                            sizeof(char)*(strlen(aName)+1))))
00303             return NS_ERROR_OUT_OF_MEMORY;
00304     }
00305 
00306     mResult = aResult;
00307 
00308     if(aLocation)
00309     {
00310         mLocation = aLocation;
00311         NS_ADDREF(mLocation);
00312         // For now, fill in our location details from our stack frame.
00313         // Later we may allow other locations?
00314         nsresult rc;
00315         if(NS_FAILED(rc = aLocation->GetFilename(&mFilename)))
00316             return rc;
00317         if(NS_FAILED(rc = aLocation->GetLineNumber(&mLineNumber)))
00318             return rc;
00319     }
00320     else
00321     {
00322         nsresult rv;
00323         nsXPConnect* xpc = nsXPConnect::GetXPConnect();
00324         if(!xpc)
00325             return NS_ERROR_FAILURE;
00326         rv = xpc->GetCurrentJSStack(&mLocation);
00327         if(NS_FAILED(rv))
00328             return rv;
00329     }
00330 
00331     if(aData)
00332     {
00333         mData = aData;
00334         NS_ADDREF(mData);
00335     }
00336     if(aInner)
00337     {
00338         mInner = aInner;
00339         NS_ADDREF(mInner);
00340     }
00341 
00342     mInitialized = PR_TRUE;
00343     return NS_OK;
00344 }
00345 
00346 /* string toString (); */
00347 NS_IMETHODIMP
00348 nsXPCException::ToString(char **_retval)
00349 {
00350     if(!_retval)
00351         return NS_ERROR_NULL_POINTER;
00352     if(!mInitialized)
00353         return NS_ERROR_NOT_INITIALIZED;
00354 
00355     static const char defaultMsg[] = "<no message>";
00356     static const char defaultLocation[] = "<unknown>";
00357     static const char format[] =
00358  "[Exception... \"%s\"  nsresult: \"0x%x (%s)\"  location: \"%s\"  data: %s]";
00359 
00360     char* indicatedLocation = nsnull;
00361 
00362     if(mLocation)
00363     {
00364         // we need to free this if it does not fail
00365         nsresult rv = mLocation->ToString(&indicatedLocation);
00366         if(NS_FAILED(rv))
00367             return rv;
00368     }
00369 
00370     const char* msg = mMessage ? mMessage : nsnull;
00371     const char* location = indicatedLocation ?
00372                                 indicatedLocation : defaultLocation;
00373     const char* resultName = mName;
00374     if(!resultName && !NameAndFormatForNSResult(mResult, &resultName,
00375                                                 (!msg) ? &msg : nsnull))
00376     {
00377         if(!msg)
00378             msg = defaultMsg;
00379         resultName = "<unknown>";
00380     }
00381     const char* data = mData ? "yes" : "no";
00382 
00383     char* temp = JS_smprintf(format, msg, mResult, resultName, location, data);
00384     if(indicatedLocation)
00385         nsMemory::Free(indicatedLocation);
00386 
00387     char* final = nsnull;
00388     if(temp)
00389     {
00390         final = (char*) nsMemory::Clone(temp, sizeof(char)*(strlen(temp)+1));
00391         JS_smprintf_free(temp);
00392     }
00393 
00394     *_retval = final;
00395     return final ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00396 }
00397 
00398 JSBool nsXPCException::sEverMadeOneFromFactory = JS_FALSE;
00399 
00400 // static
00401 nsresult
00402 nsXPCException::NewException(const char *aMessage,
00403                              nsresult aResult,
00404                              nsIStackFrame *aLocation,
00405                              nsISupports *aData,
00406                              nsIException** exceptn)
00407 {
00408     // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there
00409     // having been at least one instance made via the factory. Otherwise, the
00410     // shared factory/classinsance object never gets created and our QI getter
00411     // for our instance's pointer to our nsIClassInfo will always return null.
00412     // This is bad because it means that wrapped exceptions will never have a
00413     // shared prototype. So... We force one to be created via the factory
00414     // *once* and then go about our business.
00415     if(!sEverMadeOneFromFactory)
00416     {
00417         nsCOMPtr<nsIXPCException> e =
00418             do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
00419         sEverMadeOneFromFactory = JS_TRUE;
00420     }
00421 
00422     nsresult rv;
00423     nsXPCException* e = new nsXPCException();
00424     if(e)
00425     {
00426         NS_ADDREF(e);
00427 
00428         nsIStackFrame* location;
00429         if(aLocation)
00430         {
00431             location = aLocation;
00432             NS_ADDREF(location);
00433         }
00434         else
00435         {
00436             nsXPConnect* xpc = nsXPConnect::GetXPConnect();
00437             if(!xpc)
00438             {
00439                 NS_RELEASE(e);
00440                 return NS_ERROR_FAILURE;
00441             }
00442             rv = xpc->GetCurrentJSStack(&location);
00443             if(NS_FAILED(rv))
00444             {
00445                 NS_RELEASE(e);
00446                 return NS_ERROR_FAILURE;
00447             }
00448             // it is legal for there to be no active JS stack, if C++ code
00449             // is operating on a JS-implemented interface pointer without
00450             // having been called in turn by JS.  This happens in the JS
00451             // component loader, and will become more common as additional
00452             // components are implemented in JS.
00453         }
00454         // We want to trim off any leading native 'dataless' frames
00455         if(location)
00456             while(1)
00457             {
00458                 PRUint32 language;
00459                 PRInt32 lineNumber;
00460                 if(NS_FAILED(location->GetLanguage(&language)) ||
00461                    language == nsIProgrammingLanguage::JAVASCRIPT ||
00462                    NS_FAILED(location->GetLineNumber(&lineNumber)) ||
00463                    lineNumber)
00464                 {
00465                     break;
00466                 }
00467                 nsCOMPtr<nsIStackFrame> caller;
00468                 if(NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller)
00469                     break;
00470                 NS_RELEASE(location);
00471                 caller->QueryInterface(NS_GET_IID(nsIStackFrame), (void **)&location);
00472             }
00473         // at this point we have non-null location with one extra addref,
00474         // or no location at all
00475         rv = e->Initialize(aMessage, aResult, nsnull, location, aData, nsnull);
00476         NS_IF_RELEASE(location);
00477         if(NS_FAILED(rv))
00478             NS_RELEASE(e);
00479     }
00480 
00481     if(!e)
00482         return NS_ERROR_FAILURE;
00483 
00484     *exceptn = NS_STATIC_CAST(nsIXPCException*, e);
00485     return NS_OK;
00486 }
00487 
00488 #ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
00489 
00490 /* string canCreateWrapper (in nsIIDPtr iid); */
00491 NS_IMETHODIMP
00492 nsXPCException::CanCreateWrapper(const nsIID * iid, char **_retval)
00493 {
00494     *_retval = xpc_CloneAllAccess();
00495     return NS_OK;
00496 }
00497 
00498 /* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
00499 NS_IMETHODIMP
00500 nsXPCException::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
00501 {
00502     static const char* allowed[] = { "toString", nsnull};
00503 
00504     *_retval = xpc_CheckAccessList(methodName, allowed);
00505     return NS_OK;
00506 }
00507 
00508 /* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
00509 NS_IMETHODIMP
00510 nsXPCException::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
00511 {
00512     static const char* allowed[] = { "message", "result", "name", nsnull};
00513 
00514     *_retval = xpc_CheckAccessList(propertyName, allowed);
00515     return NS_OK;
00516 }
00517 
00518 /* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
00519 NS_IMETHODIMP
00520 nsXPCException::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
00521 {
00522     // If you have to ask, then the answer is NO
00523     *_retval = nsnull;
00524     return NS_OK;
00525 }
00526 #endif