LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCConvert.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 998 687 68.8 %
Date: 2012-06-02 Functions: 20 20 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=78:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *   John Bandhauer <jband@netscape.com> (original author)
      27                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      28                 :  *   Mike Shaver <shaver@mozilla.org>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      32                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK ***** */
      43                 : 
      44                 : /* Data conversion between native and JavaScript types. */
      45                 : 
      46                 : #include "mozilla/Util.h"
      47                 : 
      48                 : #include "xpcprivate.h"
      49                 : #include "nsString.h"
      50                 : #include "nsIAtom.h"
      51                 : #include "XPCWrapper.h"
      52                 : #include "nsJSPrincipals.h"
      53                 : #include "nsWrapperCache.h"
      54                 : #include "WrapperFactory.h"
      55                 : #include "AccessCheck.h"
      56                 : #include "nsJSUtils.h"
      57                 : 
      58                 : #include "dombindings.h"
      59                 : #include "nsWrapperCacheInlines.h"
      60                 : 
      61                 : #include "jsapi.h"
      62                 : #include "jsfriendapi.h"
      63                 : #include "jstypedarray.h"
      64                 : 
      65                 : using namespace mozilla;
      66                 : 
      67                 : //#define STRICT_CHECK_OF_UNICODE
      68                 : #ifdef STRICT_CHECK_OF_UNICODE
      69                 : #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80))
      70                 : #else // STRICT_CHECK_OF_UNICODE
      71                 : #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00))
      72                 : #endif // STRICT_CHECK_OF_UNICODE
      73                 : 
      74                 : #define ILLEGAL_CHAR_RANGE(c) (0!=((c) & 0x80))
      75                 : 
      76                 : /***********************************************************/
      77                 : 
      78                 : // static
      79                 : JSBool
      80         1780915 : XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info)
      81                 : {
      82         1780915 :     if (XPT_MD_IS_NOTXPCOM(info.flags) || XPT_MD_IS_HIDDEN(info.flags))
      83          177185 :         return false;
      84                 : 
      85         3981905 :     for (int i = info.num_args-1; i >= 0; i--) {
      86         2378267 :         const nsXPTParamInfo& param = info.params[i];
      87         2378267 :         const nsXPTType& type = param.GetType();
      88                 : 
      89                 :         // Reflected methods can't use native types. All native types end up
      90                 :         // getting tagged as void*, so this check is easy.
      91         2378267 :         if (type.TagPart() == nsXPTType::T_VOID)
      92              92 :             return false;
      93                 :     }
      94         1603638 :     return true;
      95                 : }
      96                 : 
      97                 : /***************************************************************************/
      98                 : 
      99                 : // static
     100                 : JSBool
     101          147308 : XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface)
     102                 : {
     103          147308 :     JSClass* jsclass = js::GetObjectJSClass(obj);
     104          147308 :     NS_ASSERTION(jsclass, "obj has no class");
     105          147308 :     if (jsclass &&
     106                 :         (jsclass->flags & JSCLASS_HAS_PRIVATE) &&
     107                 :         (jsclass->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
     108             415 :         *iface = (nsISupports*) xpc_GetJSPrivate(obj);
     109             415 :         return true;
     110                 :     }
     111          146893 :     return false;
     112                 : }
     113                 : 
     114                 : /***************************************************************************/
     115                 : 
     116                 : static void
     117          871361 : FinalizeXPCOMUCString(const JSStringFinalizer *fin, jschar *chars)
     118                 : {
     119          871361 :     nsMemory::Free(chars);
     120          871361 : }
     121                 : 
     122                 : static const JSStringFinalizer sXPCOMUCStringFinalizer = { FinalizeXPCOMUCString };
     123                 : 
     124                 : // static
     125                 : JSBool
     126        20388463 : XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s,
     127                 :                           const nsXPTType& type, const nsID* iid, nsresult* pErr)
     128                 : {
     129        20388463 :     NS_PRECONDITION(s, "bad param");
     130        20388463 :     NS_PRECONDITION(d, "bad param");
     131                 : 
     132        20388463 :    JSContext* cx = lccx.GetJSContext();
     133                 : 
     134                 :     // Allow wrong compartment or unset ScopeForNewObject when the caller knows
     135                 :     // the value is primitive (viz., XPCNativeMember::GetConstantValue).
     136        20388463 :     NS_ABORT_IF_FALSE(type.IsArithmetic() ||
     137                 :                       js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
     138                 :                       "bad scope for new JSObjects");
     139                 : 
     140        20388463 :     if (pErr)
     141        19663070 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
     142                 : 
     143        20388463 :     switch (type.TagPart()) {
     144               0 :     case nsXPTType::T_I8    : *d = INT_TO_JSVAL(int32_t(*((int8_t*)s)));             break;
     145            3553 :     case nsXPTType::T_I16   : *d = INT_TO_JSVAL(int32_t(*((int16_t*)s)));            break;
     146          244194 :     case nsXPTType::T_I32   : *d = INT_TO_JSVAL(*((int32_t*)s));                     break;
     147          125097 :     case nsXPTType::T_I64   : *d = DOUBLE_TO_JSVAL(double(*((int64_t*)s)));          break;
     148        13479284 :     case nsXPTType::T_U8    : *d = INT_TO_JSVAL(int32_t(*((uint8_t*)s)));            break;
     149           56934 :     case nsXPTType::T_U16   : *d = INT_TO_JSVAL(int32_t(*((uint16_t*)s)));           break;
     150          569778 :     case nsXPTType::T_U32   : *d = UINT_TO_JSVAL(*((uint32_t*)s));                   break;
     151           21946 :     case nsXPTType::T_U64   : *d = DOUBLE_TO_JSVAL(double(*((uint64_t*)s)));         break;
     152              25 :     case nsXPTType::T_FLOAT : *d = DOUBLE_TO_JSVAL(*((float*)s));                    break;
     153              52 :     case nsXPTType::T_DOUBLE: *d = DOUBLE_TO_JSVAL(*((double*)s));                   break;
     154                 :     case nsXPTType::T_BOOL  :
     155                 :         {
     156         1310981 :             bool b = *((bool*)s);
     157                 : 
     158                 :             NS_WARN_IF_FALSE(b == 1 || b == 0,
     159                 :                              "Passing a malformed bool through XPConnect");
     160         1310981 :             *d = BOOLEAN_TO_JSVAL(!!b);
     161         1310981 :             break;
     162                 :         }
     163                 :     case nsXPTType::T_CHAR  :
     164                 :         {
     165              13 :             char* p = (char*)s;
     166              13 :             if (!p)
     167               0 :                 return false;
     168                 : 
     169                 : #ifdef STRICT_CHECK_OF_UNICODE
     170                 :             NS_ASSERTION(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data");
     171                 : #endif // STRICT_CHECK_OF_UNICODE
     172                 : 
     173                 :             JSString* str;
     174              13 :             if (!(str = JS_NewStringCopyN(cx, p, 1)))
     175               0 :                 return false;
     176              13 :             *d = STRING_TO_JSVAL(str);
     177              13 :             break;
     178                 :         }
     179                 :     case nsXPTType::T_WCHAR :
     180                 :         {
     181               6 :             jschar* p = (jschar*)s;
     182               6 :             if (!p)
     183               0 :                 return false;
     184                 :             JSString* str;
     185               6 :             if (!(str = JS_NewUCStringCopyN(cx, p, 1)))
     186               0 :                 return false;
     187               6 :             *d = STRING_TO_JSVAL(str);
     188               6 :             break;
     189                 :         }
     190                 : 
     191                 :     case nsXPTType::T_JSVAL :
     192                 :         {
     193          218919 :             *d = *((jsval*)s);
     194          218919 :             if (!JS_WrapValue(cx, d))
     195               0 :                 return false;
     196          218919 :             break;
     197                 :         }
     198                 : 
     199                 :     default:
     200                 : 
     201                 :         // set the default result
     202         4357681 :         *d = JSVAL_NULL;
     203                 : 
     204         4357681 :         switch (type.TagPart()) {
     205                 :         case nsXPTType::T_VOID:
     206               0 :             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
     207               0 :             return false;
     208                 : 
     209                 :         case nsXPTType::T_IID:
     210                 :             {
     211           23528 :                 nsID* iid2 = *((nsID**)s);
     212           23528 :                 if (!iid2)
     213               0 :                     break;
     214                 :                 JSObject* obj;
     215           23528 :                 if (!(obj = xpc_NewIDObject(cx, lccx.GetScopeForNewJSObjects(), *iid2)))
     216               0 :                     return false;
     217           23528 :                 *d = OBJECT_TO_JSVAL(obj);
     218           23528 :                 break;
     219                 :             }
     220                 : 
     221                 :         case nsXPTType::T_ASTRING:
     222                 :             // Fall through to T_DOMSTRING case
     223                 : 
     224                 :         case nsXPTType::T_DOMSTRING:
     225                 :             {
     226         1451653 :                 const nsAString* p = *((const nsAString**)s);
     227         1451653 :                 if (!p)
     228               0 :                     break;
     229                 : 
     230         1451653 :                 if (!p->IsVoid()) {
     231                 :                     nsStringBuffer* buf;
     232         1357529 :                     jsval str = XPCStringConvert::ReadableToJSVal(cx, *p, &buf);
     233         1357529 :                     if (JSVAL_IS_NULL(str))
     234               0 :                         return false;
     235         1357529 :                     if (buf)
     236           89071 :                         buf->AddRef();
     237                 : 
     238         1357529 :                     *d = str;
     239                 :                 }
     240                 : 
     241                 :                 // *d is defaulted to JSVAL_NULL so no need to set it
     242                 :                 // again if p is a "void" string
     243                 : 
     244         1451653 :                 break;
     245                 :             }
     246                 : 
     247                 :         case nsXPTType::T_CHAR_STR:
     248                 :             {
     249          429574 :                 char* p = *((char**)s);
     250          429574 :                 if (!p)
     251           29961 :                     break;
     252                 : 
     253                 : #ifdef STRICT_CHECK_OF_UNICODE
     254                 :                 bool isAscii = true;
     255                 :                 char* t;
     256                 :                 for (t=p; *t && isAscii ; t++) {
     257                 :                   if (ILLEGAL_CHAR_RANGE(*t))
     258                 :                       isAscii = false;
     259                 :                 }
     260                 :                 NS_ASSERTION(isAscii, "passing non ASCII data");
     261                 : #endif // STRICT_CHECK_OF_UNICODE
     262                 :                 JSString* str;
     263          399613 :                 if (!(str = JS_NewStringCopyZ(cx, p)))
     264               0 :                     return false;
     265          399613 :                 *d = STRING_TO_JSVAL(str);
     266          399613 :                 break;
     267                 :             }
     268                 : 
     269                 :         case nsXPTType::T_WCHAR_STR:
     270                 :             {
     271           41599 :                 jschar* p = *((jschar**)s);
     272           41599 :                 if (!p)
     273           10436 :                     break;
     274                 :                 JSString* str;
     275           31163 :                 if (!(str = JS_NewUCStringCopyZ(cx, p)))
     276               0 :                     return false;
     277           31163 :                 *d = STRING_TO_JSVAL(str);
     278           31163 :                 break;
     279                 :             }
     280                 :         case nsXPTType::T_UTF8STRING:
     281                 :             {
     282          103997 :                 const nsACString* cString = *((const nsACString**)s);
     283                 : 
     284          103997 :                 if (!cString)
     285               0 :                     break;
     286                 : 
     287          103997 :                 if (!cString->IsVoid()) {
     288                 :                     PRUint32 len;
     289          102675 :                     jschar *p = (jschar *)UTF8ToNewUnicode(*cString, &len);
     290                 : 
     291          102675 :                     if (!p)
     292               0 :                         return false;
     293                 : 
     294                 :                     JSString* jsString =
     295                 :                         JS_NewExternalString(cx, p, len,
     296          102675 :                                              &sXPCOMUCStringFinalizer);
     297                 : 
     298          102675 :                     if (!jsString) {
     299               0 :                         nsMemory::Free(p);
     300               0 :                         return false;
     301                 :                     }
     302                 : 
     303          102675 :                     *d = STRING_TO_JSVAL(jsString);
     304                 :                 }
     305                 : 
     306          103997 :                 break;
     307                 : 
     308                 :             }
     309                 :         case nsXPTType::T_CSTRING:
     310                 :             {
     311          768687 :                 const nsACString* cString = *((const nsACString**)s);
     312                 : 
     313          768687 :                 if (!cString)
     314               0 :                     break;
     315                 : 
     316          768687 :                 if (!cString->IsVoid()) {
     317          768686 :                     PRUnichar* unicodeString = ToNewUnicode(*cString);
     318          768686 :                     if (!unicodeString)
     319               0 :                         return false;
     320                 : 
     321                 :                     JSString* jsString = JS_NewExternalString(cx,
     322                 :                                                               (jschar*)unicodeString,
     323                 :                                                               cString->Length(),
     324          768686 :                                                               &sXPCOMUCStringFinalizer);
     325                 : 
     326          768686 :                     if (!jsString) {
     327               0 :                         nsMemory::Free(unicodeString);
     328               0 :                         return false;
     329                 :                     }
     330                 : 
     331          768686 :                     *d = STRING_TO_JSVAL(jsString);
     332                 :                 }
     333                 : 
     334          768687 :                 break;
     335                 :             }
     336                 : 
     337                 :         case nsXPTType::T_INTERFACE:
     338                 :         case nsXPTType::T_INTERFACE_IS:
     339                 :             {
     340         1538643 :                 nsISupports* iface = *((nsISupports**)s);
     341         1538643 :                 if (iface) {
     342         1466255 :                     if (iid->Equals(NS_GET_IID(nsIVariant))) {
     343          253316 :                         nsCOMPtr<nsIVariant> variant = do_QueryInterface(iface);
     344          126658 :                         if (!variant)
     345               0 :                             return false;
     346                 : 
     347                 :                         return XPCVariant::VariantDataToJS(lccx, variant,
     348          126658 :                                                            pErr, d);
     349                 :                     }
     350                 :                     // else...
     351         2679194 :                     xpcObjectHelper helper(iface);
     352         1339597 :                     if (!NativeInterface2JSObject(lccx, d, nsnull, helper, iid,
     353         1339597 :                                                   nsnull, true, pErr))
     354               0 :                         return false;
     355                 : 
     356                 : #ifdef DEBUG
     357         1339597 :                     JSObject* jsobj = JSVAL_TO_OBJECT(*d);
     358         1339597 :                     if (jsobj && !js::GetObjectParent(jsobj))
     359              30 :                         NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
     360                 :                                      "Why did we recreate this wrapper?");
     361                 : #endif
     362                 :                 }
     363         1411985 :                 break;
     364                 :             }
     365                 : 
     366                 :         default:
     367               0 :             NS_ERROR("bad type");
     368               0 :             return false;
     369                 :         }
     370                 :     }
     371        20261805 :     return true;
     372                 : }
     373                 : 
     374                 : /***************************************************************************/
     375                 : 
     376                 : #ifdef DEBUG
     377                 : static bool
     378       220630210 : CheckJSCharInCharRange(jschar c)
     379                 : {
     380       220630210 :     if (ILLEGAL_RANGE(c)) {
     381                 :         /* U+0080/U+0100 - U+FFFF data lost. */
     382                 :         static const size_t MSG_BUF_SIZE = 64;
     383                 :         char msg[MSG_BUF_SIZE];
     384               0 :         JS_snprintf(msg, MSG_BUF_SIZE, "jschar out of char range; high bits of data lost: 0x%x", c);
     385               0 :         NS_WARNING(msg);
     386               0 :         return false;
     387                 :     }
     388                 : 
     389       220630210 :     return true;
     390                 : }
     391                 : #endif
     392                 : 
     393                 : // static
     394                 : JSBool
     395        10136273 : XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
     396                 :                           const nsXPTType& type,
     397                 :                           JSBool useAllocator, const nsID* iid,
     398                 :                           nsresult* pErr)
     399                 : {
     400        10136273 :     NS_PRECONDITION(d, "bad param");
     401                 : 
     402        10136273 :     JSContext* cx = ccx.GetJSContext();
     403                 : 
     404                 :     int32_t  ti;
     405                 :     uint32_t tu;
     406                 :     double td;
     407                 :     JSBool   tb;
     408        10136273 :     JSBool isDOMString = true;
     409                 : 
     410        10136273 :     if (pErr)
     411         9083927 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
     412                 : 
     413        10136273 :     switch (type.TagPart()) {
     414                 :     case nsXPTType::T_I8     :
     415               0 :         if (!JS_ValueToECMAInt32(cx, s, &ti))
     416               0 :             return false;
     417               0 :         *((int8_t*)d)  = int8_t(ti);
     418               0 :         break;
     419                 :     case nsXPTType::T_I16    :
     420            2534 :         if (!JS_ValueToECMAInt32(cx, s, &ti))
     421               0 :             return false;
     422            2534 :         *((int16_t*)d)  = int16_t(ti);
     423            2534 :         break;
     424                 :     case nsXPTType::T_I32    :
     425           44828 :         if (!JS_ValueToECMAInt32(cx, s, (int32_t*)d))
     426               0 :             return false;
     427           44828 :         break;
     428                 :     case nsXPTType::T_I64    :
     429           13866 :         if (JSVAL_IS_INT(s)) {
     430            4278 :             if (!JS_ValueToECMAInt32(cx, s, &ti))
     431               0 :                 return false;
     432            4278 :            *((int64_t*)d) = ti;
     433                 : 
     434                 :         } else {
     435            9588 :             if (!JS_ValueToNumber(cx, s, &td))
     436               0 :                 return false;
     437            9588 :             *((int64_t*)d) = int64_t(td);
     438                 :         }
     439           13866 :         break;
     440                 :     case nsXPTType::T_U8     :
     441         4439971 :         if (!JS_ValueToECMAUint32(cx, s, &tu))
     442               0 :             return false;
     443         4439971 :         *((uint8_t*)d)  = uint8_t(tu);
     444         4439971 :         break;
     445                 :     case nsXPTType::T_U16    :
     446            3544 :         if (!JS_ValueToECMAUint32(cx, s, &tu))
     447               0 :             return false;
     448            3544 :         *((uint16_t*)d)  = uint16_t(tu);
     449            3544 :         break;
     450                 :     case nsXPTType::T_U32    :
     451          695156 :         if (!JS_ValueToECMAUint32(cx, s, (uint32_t*)d))
     452               0 :             return false;
     453          695156 :         break;
     454                 :     case nsXPTType::T_U64    :
     455           13468 :         if (JSVAL_IS_INT(s)) {
     456             554 :             if (!JS_ValueToECMAUint32(cx, s, &tu))
     457               0 :                 return false;
     458             554 :             *((uint64_t*)d) = tu;
     459                 :         } else {
     460           12914 :             if (!JS_ValueToNumber(cx, s, &td))
     461               0 :                 return false;
     462           12914 :             *((uint64_t*)d) = uint64_t(td);
     463                 :         }
     464           13468 :         break;
     465                 :     case nsXPTType::T_FLOAT  :
     466              20 :         if (!JS_ValueToNumber(cx, s, &td))
     467               0 :             return false;
     468              20 :         *((float*)d) = (float) td;
     469              20 :         break;
     470                 :     case nsXPTType::T_DOUBLE :
     471              29 :         if (!JS_ValueToNumber(cx, s, (double*)d))
     472               0 :             return false;
     473              29 :         break;
     474                 :     case nsXPTType::T_BOOL   :
     475          570536 :         JS_ValueToBoolean(cx, s, &tb);
     476          570536 :         *((bool*)d) = tb;
     477          570536 :         break;
     478                 :     case nsXPTType::T_CHAR   :
     479                 :         {
     480              11 :             JSString* str = JS_ValueToString(cx, s);
     481              11 :             if (!str) {
     482               0 :                 return false;
     483                 :             }
     484                 :             size_t length;
     485              11 :             const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
     486              11 :             if (!chars) {
     487               0 :                 return false;
     488                 :             }
     489              11 :             jschar ch = length ? chars[0] : 0;
     490                 : #ifdef DEBUG
     491              11 :             CheckJSCharInCharRange(ch);
     492                 : #endif
     493              11 :             *((char*)d) = char(ch);
     494              11 :             break;
     495                 :         }
     496                 :     case nsXPTType::T_WCHAR  :
     497                 :         {
     498                 :             JSString* str;
     499             106 :             if (!(str = JS_ValueToString(cx, s))) {
     500               0 :                 return false;
     501                 :             }
     502                 :             size_t length;
     503             106 :             const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
     504             106 :             if (!chars) {
     505               0 :                 return false;
     506                 :             }
     507             106 :             if (length == 0) {
     508               0 :                 *((uint16_t*)d) = 0;
     509               0 :                 break;
     510                 :             }
     511             106 :             *((uint16_t*)d) = uint16_t(chars[0]);
     512             106 :             break;
     513                 :         }
     514                 :     case nsXPTType::T_JSVAL :
     515          222255 :         *((jsval*)d) = s;
     516          222255 :         break;
     517                 :     default:
     518                 : 
     519         4129949 :         switch (type.TagPart()) {
     520                 :         case nsXPTType::T_VOID:
     521               0 :             XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
     522               0 :             NS_ERROR("void* params not supported");
     523               0 :             return false;
     524                 :         case nsXPTType::T_IID:
     525                 :         {
     526                 :             JSObject* obj;
     527           40733 :             const nsID* pid=nsnull;
     528                 : 
     529                 :             // There's no good reason to pass a null IID.
     530           40733 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
     531               0 :                 if (pErr)
     532               0 :                   *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
     533               0 :                 return false;
     534                 :             }
     535                 : 
     536           81466 :             if (!JSVAL_IS_OBJECT(s) ||
     537                 :                 (!(obj = JSVAL_TO_OBJECT(s))) ||
     538                 :                 (!(pid = xpc_JSObjectToID(cx, obj))) ||
     539           40733 :                 (!(pid = (const nsID*) nsMemory::Clone(pid, sizeof(nsID))))) {
     540               0 :                 return false;
     541                 :             }
     542           40733 :             *((const nsID**)d) = pid;
     543           40733 :             return true;
     544                 :         }
     545                 : 
     546                 :         case nsXPTType::T_ASTRING:
     547                 :         {
     548          911812 :             isDOMString = false;
     549                 :             // Fall through to T_DOMSTRING case.
     550                 :         }
     551                 :         case nsXPTType::T_DOMSTRING:
     552                 :         {
     553                 :             static const PRUnichar EMPTY_STRING[] = { '\0' };
     554                 :             static const PRUnichar VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
     555                 : 
     556          911971 :             const PRUnichar* chars = nsnull;
     557          911971 :             JSString* str = nsnull;
     558          911971 :             JSBool isNewString = false;
     559          911971 :             PRUint32 length = 0;
     560                 : 
     561          911971 :             if (JSVAL_IS_VOID(s)) {
     562             582 :                 if (isDOMString) {
     563               0 :                     chars  = VOID_STRING;
     564               0 :                     length = ArrayLength(VOID_STRING) - 1;
     565                 :                 } else {
     566             582 :                     chars = EMPTY_STRING;
     567             582 :                     length = 0;
     568                 :                 }
     569          911389 :             } else if (!JSVAL_IS_NULL(s)) {
     570          818189 :                 str = JS_ValueToString(cx, s);
     571          818189 :                 if (!str)
     572               0 :                     return false;
     573                 : 
     574          818189 :                 length = (PRUint32) JS_GetStringLength(str);
     575          818189 :                 if (length) {
     576          812614 :                     chars = JS_GetStringCharsZ(cx, str);
     577          812614 :                     if (!chars)
     578               0 :                         return false;
     579          812614 :                     if (STRING_TO_JSVAL(str) != s)
     580              17 :                         isNewString = true;
     581                 :                 } else {
     582            5575 :                     str = nsnull;
     583            5575 :                     chars = EMPTY_STRING;
     584                 :                 }
     585                 :             }
     586                 : 
     587          911971 :             if (useAllocator) {
     588                 :                 // XXX extra string copy when isNewString
     589          284915 :                 if (str && !isNewString) {
     590                 :                     size_t strLength;
     591          258385 :                     const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
     592          258385 :                     if (!strChars)
     593               0 :                         return false;
     594                 : 
     595                 :                     XPCReadableJSStringWrapper *wrapper =
     596          258385 :                         ccx.NewStringWrapper(strChars, strLength);
     597          258385 :                     if (!wrapper)
     598               0 :                         return false;
     599                 : 
     600          258385 :                     *((const nsAString**)d) = wrapper;
     601           26530 :                 } else if (JSVAL_IS_NULL(s)) {
     602                 :                     XPCReadableJSStringWrapper *wrapper =
     603           22486 :                         new XPCReadableJSStringWrapper();
     604           22486 :                     if (!wrapper)
     605               0 :                         return false;
     606                 : 
     607           22486 :                     *((const nsAString**)d) = wrapper;
     608                 :                 } else {
     609                 :                     // use nsString to encourage sharing
     610            4044 :                     const nsAString *rs = new nsString(chars, length);
     611            4044 :                     if (!rs)
     612               0 :                         return false;
     613            4044 :                     *((const nsAString**)d) = rs;
     614                 :                 }
     615                 :             } else {
     616          627056 :                 nsAString* ws = *((nsAString**)d);
     617                 : 
     618          627056 :                 if (JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s))) {
     619           70733 :                     ws->Truncate();
     620           70733 :                     ws->SetIsVoid(true);
     621                 :                 } else
     622          556323 :                     ws->Assign(chars, length);
     623                 :             }
     624          911971 :             return true;
     625                 :         }
     626                 : 
     627                 :         case nsXPTType::T_CHAR_STR:
     628                 :         {
     629          766890 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
     630           35429 :                 *((char**)d) = nsnull;
     631           35429 :                 return true;
     632                 :             }
     633                 : 
     634          731461 :             JSString* str = JS_ValueToString(cx, s);
     635          731461 :             if (!str) {
     636               0 :                 return false;
     637                 :             }
     638                 : #ifdef DEBUG
     639          731461 :             const jschar* chars=nsnull;
     640          731461 :             if (nsnull != (chars = JS_GetStringCharsZ(cx, str))) {
     641          731461 :                 bool legalRange = true;
     642          731461 :                 int len = JS_GetStringLength(str);
     643                 :                 const jschar* t;
     644          731461 :                 PRInt32 i=0;
     645       221361660 :                 for (t=chars; (i< len) && legalRange ; i++,t++) {
     646       220630199 :                     if (!CheckJSCharInCharRange(*t))
     647               0 :                         break;
     648                 :                 }
     649                 :             }
     650                 : #endif // DEBUG
     651          731461 :             size_t length = JS_GetStringEncodingLength(cx, str);
     652          731461 :             if (length == size_t(-1)) {
     653               0 :                 return false;
     654                 :             }
     655          731461 :             char *buffer = static_cast<char *>(nsMemory::Alloc(length + 1));
     656          731461 :             if (!buffer) {
     657               0 :                 return false;
     658                 :             }
     659          731461 :             JS_EncodeStringToBuffer(str, buffer, length);
     660          731461 :             buffer[length] = '\0';
     661          731461 :             *((void**)d) = buffer;
     662          731461 :             return true;
     663                 :         }
     664                 : 
     665                 :         case nsXPTType::T_WCHAR_STR:
     666                 :         {
     667           45441 :             const jschar* chars=nsnull;
     668                 :             JSString* str;
     669                 : 
     670           45441 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
     671           13942 :                 *((jschar**)d) = nsnull;
     672           13942 :                 return true;
     673                 :             }
     674                 : 
     675           31499 :             if (!(str = JS_ValueToString(cx, s))) {
     676               0 :                 return false;
     677                 :             }
     678           31499 :             if (!(chars = JS_GetStringCharsZ(cx, str))) {
     679               0 :                 return false;
     680                 :             }
     681           31499 :             int len = JS_GetStringLength(str);
     682           31499 :             int byte_len = (len+1)*sizeof(jschar);
     683           31499 :             if (!(*((void**)d) = nsMemory::Alloc(byte_len))) {
     684                 :                 // XXX should report error
     685               0 :                 return false;
     686                 :             }
     687           31499 :             jschar* destchars = *((jschar**)d);
     688           31499 :             memcpy(destchars, chars, byte_len);
     689           31499 :             destchars[len] = 0;
     690                 : 
     691           31499 :             return true;
     692                 :         }
     693                 : 
     694                 :         case nsXPTType::T_UTF8STRING:
     695                 :         {
     696                 :             const jschar* chars;
     697                 :             PRUint32 length;
     698                 :             JSString* str;
     699                 : 
     700          347770 :             if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
     701            2778 :                 if (useAllocator) {
     702            2458 :                     nsACString *rs = new nsCString();
     703            2458 :                     if (!rs)
     704               0 :                         return false;
     705                 : 
     706            2458 :                     rs->SetIsVoid(true);
     707            2458 :                     *((nsACString**)d) = rs;
     708                 :                 } else {
     709             320 :                     nsCString* rs = *((nsCString**)d);
     710             320 :                     rs->Truncate();
     711             320 :                     rs->SetIsVoid(true);
     712                 :                 }
     713            2778 :                 return true;
     714                 :             }
     715                 : 
     716                 :             // The JS val is neither null nor void...
     717                 : 
     718          344992 :             if (!(str = JS_ValueToString(cx, s))||
     719                 :                 !(chars = JS_GetStringCharsZ(cx, str))) {
     720               0 :                 return false;
     721                 :             }
     722                 : 
     723          344992 :             length = JS_GetStringLength(str);
     724                 : 
     725                 :             nsCString *rs;
     726          344992 :             if (useAllocator) {
     727                 :                 // Use nsCString to enable sharing
     728          313434 :                 rs = new nsCString();
     729          313434 :                 if (!rs)
     730               0 :                     return false;
     731                 : 
     732          313434 :                 *((const nsCString**)d) = rs;
     733                 :             } else {
     734           31558 :                 rs = *((nsCString**)d);
     735                 :             }
     736          344992 :             const PRUnichar* start = (const PRUnichar*)chars;
     737          344992 :             const PRUnichar* end = start + length;
     738          344992 :             CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
     739          344992 :             return true;
     740                 :         }
     741                 : 
     742                 :         case nsXPTType::T_CSTRING:
     743                 :         {
     744          758192 :             if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
     745              86 :                 if (useAllocator) {
     746              86 :                     nsACString *rs = new nsCString();
     747              86 :                     if (!rs)
     748               0 :                         return false;
     749                 : 
     750              86 :                     rs->SetIsVoid(true);
     751              86 :                     *((nsACString**)d) = rs;
     752                 :                 } else {
     753               0 :                     nsACString* rs = *((nsACString**)d);
     754               0 :                     rs->Truncate();
     755               0 :                     rs->SetIsVoid(true);
     756                 :                 }
     757              86 :                 return true;
     758                 :             }
     759                 : 
     760                 :             // The JS val is neither null nor void...
     761          758106 :             JSString* str = JS_ValueToString(cx, s);
     762          758106 :             if (!str) {
     763               0 :                 return false;
     764                 :             }
     765                 : 
     766          758106 :             size_t length = JS_GetStringEncodingLength(cx, str);
     767          758106 :             if (length == size_t(-1)) {
     768               0 :                 return false;
     769                 :             }
     770                 : 
     771                 :             nsACString *rs;
     772          758106 :             if (useAllocator) {
     773          675871 :                 rs = new nsCString();
     774          675871 :                 if (!rs)
     775               0 :                     return false;
     776          675871 :                 *((const nsACString**)d) = rs;
     777                 :             } else {
     778           82235 :                 rs = *((nsACString**)d);
     779                 :             }
     780                 : 
     781          758106 :             rs->SetLength(PRUint32(length));
     782          758106 :             if (rs->Length() != PRUint32(length)) {
     783               0 :                 return false;
     784                 :             }
     785          758106 :             JS_EncodeStringToBuffer(str, rs->BeginWriting(), length);
     786                 : 
     787          758106 :             return true;
     788                 :         }
     789                 : 
     790                 :         case nsXPTType::T_INTERFACE:
     791                 :         case nsXPTType::T_INTERFACE_IS:
     792                 :         {
     793                 :             JSObject* obj;
     794         1258952 :             NS_ASSERTION(iid,"can't do interface conversions without iid");
     795                 : 
     796         1258952 :             if (iid->Equals(NS_GET_IID(nsIVariant))) {
     797            5919 :                 XPCVariant* variant = XPCVariant::newVariant(ccx, s);
     798            5919 :                 if (!variant)
     799               0 :                     return false;
     800            5919 :                 *((nsISupports**)d) = static_cast<nsIVariant*>(variant);
     801            5919 :                 return true;
     802         1253033 :             } else if (iid->Equals(NS_GET_IID(nsIAtom)) &&
     803               0 :                        JSVAL_IS_STRING(s)) {
     804                 :                 // We're trying to pass a string as an nsIAtom.  Let's atomize!
     805               0 :                 JSString* str = JSVAL_TO_STRING(s);
     806               0 :                 const PRUnichar* chars = JS_GetStringCharsZ(cx, str);
     807               0 :                 if (!chars) {
     808               0 :                     if (pErr)
     809               0 :                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
     810               0 :                     return false;
     811                 :                 }
     812               0 :                 PRUint32 length = JS_GetStringLength(str);
     813                 :                 nsIAtom* atom = NS_NewAtom(nsDependentSubstring(chars,
     814               0 :                                                                 chars + length));
     815               0 :                 if (!atom && pErr)
     816               0 :                     *pErr = NS_ERROR_OUT_OF_MEMORY;
     817               0 :                 *((nsISupports**)d) = atom;
     818               0 :                 return atom != nsnull;
     819                 :             }
     820                 :             //else ...
     821                 : 
     822         1253033 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
     823          104904 :                 *((nsISupports**)d) = nsnull;
     824          104904 :                 return true;
     825                 :             }
     826                 : 
     827                 :             // only wrap JSObjects
     828         1148129 :             if (!JSVAL_IS_OBJECT(s) || !(obj = JSVAL_TO_OBJECT(s))) {
     829               1 :                 if (pErr && JSVAL_IS_INT(s) && 0 == JSVAL_TO_INT(s))
     830               0 :                     *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
     831               1 :                 return false;
     832                 :             }
     833                 : 
     834                 :             return JSObject2NativeInterface(ccx, (void**)d, obj, iid,
     835         1148128 :                                             nsnull, pErr);
     836                 :         }
     837                 :         default:
     838               0 :             NS_ERROR("bad type");
     839               0 :             return false;
     840                 :         }
     841                 :     }
     842         6006324 :     return true;
     843                 : }
     844                 : 
     845                 : inline JSBool
     846            4416 : CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
     847                 :                      nsIXPConnectJSObjectHolder** dest)
     848                 : {
     849            4416 :     if (dest) {
     850               0 :         XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj);
     851               0 :         if (!objHolder)
     852               0 :             return false;
     853                 : 
     854               0 :         NS_ADDREF(*dest = objHolder);
     855                 :     }
     856                 : 
     857            4416 :     *d = OBJECT_TO_JSVAL(obj);
     858                 : 
     859            4416 :     return true;
     860                 : }
     861                 : 
     862                 : /***************************************************************************/
     863                 : // static
     864                 : JSBool
     865         2027154 : XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
     866                 :                                      jsval* d,
     867                 :                                      nsIXPConnectJSObjectHolder** dest,
     868                 :                                      xpcObjectHelper& aHelper,
     869                 :                                      const nsID* iid,
     870                 :                                      XPCNativeInterface** Interface,
     871                 :                                      bool allowNativeWrapper,
     872                 :                                      nsresult* pErr)
     873                 : {
     874         2027154 :     NS_ASSERTION(!Interface || iid,
     875                 :                  "Need the iid if you pass in an XPCNativeInterface cache.");
     876                 : 
     877         2027154 :     *d = JSVAL_NULL;
     878         2027154 :     if (dest)
     879          545917 :         *dest = nsnull;
     880         2027154 :     nsISupports *src = aHelper.Object();
     881         2027154 :     if (!src)
     882               0 :         return true;
     883         2027154 :     if (pErr)
     884         1689764 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
     885                 : 
     886                 :     // We used to have code here that unwrapped and simply exposed the
     887                 :     // underlying JSObject. That caused anomolies when JSComponents were
     888                 :     // accessed from other JS code - they didn't act like other xpconnect
     889                 :     // wrapped components. So, instead, we create "double wrapped" objects
     890                 :     // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't
     891                 :     // optimal -- we could detect this and roll the functionality into a
     892                 :     // single wrapper, but the current solution is good enough for now.
     893         2027154 :     JSContext* cx = lccx.GetJSContext();
     894         2027154 :     NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
     895                 :                       "bad scope for new JSObjects");
     896                 : 
     897         2027154 :     JSObject *jsscope = lccx.GetScopeForNewJSObjects();
     898                 :     XPCWrappedNativeScope* xpcscope =
     899         2027154 :         XPCWrappedNativeScope::FindInJSObjectScope(cx, jsscope);
     900         2027154 :     if (!xpcscope)
     901               0 :         return false;
     902                 : 
     903                 :     // First, see if this object supports the wrapper cache.
     904                 :     // Note: If |cache->IsProxy()| is true, then it means that the object
     905                 :     // implementing it doesn't want a wrapped native as its JS Object, but
     906                 :     // instead it provides its own proxy object. In that case, the object
     907                 :     // to use is found as cache->GetWrapper(). If that is null, then the
     908                 :     // object will create (and fill the cache) from its WrapObject call.
     909         2027154 :     nsWrapperCache *cache = aHelper.GetWrapperCache();
     910                 : 
     911         2027154 :     bool tryConstructSlimWrapper = false;
     912                 :     JSObject *flat;
     913         2027154 :     if (cache) {
     914           40218 :         flat = cache->GetWrapper();
     915           40218 :         if (cache->IsProxy()) {
     916            4416 :             XPCCallContext &ccx = lccx.GetXPCCallContext();
     917            4416 :             if (!ccx.IsValid())
     918               0 :                 return false;
     919                 : 
     920            4416 :             if (!flat) {
     921                 :                 bool triedToWrap;
     922                 :                 flat = cache->WrapObject(lccx.GetJSContext(), xpcscope,
     923            4321 :                                          &triedToWrap);
     924            4321 :                 if (!flat && triedToWrap)
     925               0 :                     return false;
     926                 :             }
     927                 : 
     928            4416 :             if (flat) {
     929            4416 :                 if (!JS_WrapObject(ccx, &flat))
     930               0 :                     return false;
     931                 : 
     932            4416 :                 return CreateHolderIfNeeded(ccx, flat, d, dest);
     933                 :             }
     934                 :         }
     935                 : 
     936           35802 :         if (!dest) {
     937           35802 :             if (!flat) {
     938           19761 :                 tryConstructSlimWrapper = true;
     939           16041 :             } else if (IS_SLIM_WRAPPER_OBJECT(flat)) {
     940            6401 :                 if (js::IsObjectInContextCompartment(flat, cx)) {
     941            6401 :                     *d = OBJECT_TO_JSVAL(flat);
     942            6401 :                     return true;
     943                 :                 }
     944                 :             }
     945                 :         }
     946                 :     } else {
     947         1986936 :         flat = nsnull;
     948                 :     }
     949                 : 
     950                 :     // If we're not handing this wrapper to an nsIXPConnectJSObjectHolder, and
     951                 :     // the object supports slim wrappers, try to create one here.
     952         2016337 :     if (tryConstructSlimWrapper) {
     953           19761 :         XPCCallContext &ccx = lccx.GetXPCCallContext();
     954           19761 :         if (!ccx.IsValid())
     955               0 :             return false;
     956                 : 
     957                 :         jsval slim;
     958           19761 :         if (ConstructSlimWrapper(ccx, aHelper, xpcscope, &slim)) {
     959           15155 :             *d = slim;
     960           15155 :             return true;
     961                 :         }
     962                 : 
     963            4606 :         if (JS_IsExceptionPending(cx))
     964               0 :             return false;
     965                 : 
     966                 :         // Even if ConstructSlimWrapper returns false it might have created a
     967                 :         // wrapper (while calling the PreCreate hook). In that case we need to
     968                 :         // fall through because we either have a slim wrapper that needs to be
     969                 :         // morphed or an XPCWrappedNative.
     970            4606 :         flat = cache->GetWrapper();
     971                 :     }
     972                 : 
     973                 :     // We can't simply construct a slim wrapper. Go ahead and create an
     974                 :     // XPCWrappedNative for this object. At this point, |flat| could be
     975                 :     // non-null, meaning that either we already have a wrapped native from
     976                 :     // the cache (which might need to be QI'd to the new interface) or that
     977                 :     // we found a slim wrapper that we'll have to morph.
     978         4002364 :     AutoMarkingNativeInterfacePtr iface;
     979         2001182 :     if (iid) {
     980         1995117 :         XPCCallContext &ccx = lccx.GetXPCCallContext();
     981         1995117 :         if (!ccx.IsValid())
     982               0 :             return false;
     983                 : 
     984         1995117 :         iface.Init(ccx);
     985                 : 
     986         1995117 :         if (Interface)
     987           10939 :             iface = *Interface;
     988                 : 
     989         1995117 :         if (!iface) {
     990         1984593 :             iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
     991         1984593 :             if (!iface)
     992               0 :                 return false;
     993                 : 
     994         1984593 :             if (Interface)
     995             415 :                 *Interface = iface;
     996                 :         }
     997                 :     }
     998                 : 
     999         2001182 :     NS_ASSERTION(!flat || IS_WRAPPER_CLASS(js::GetObjectClass(flat)),
    1000                 :                  "What kind of wrapper is this?");
    1001                 : 
    1002                 :     nsresult rv;
    1003                 :     XPCWrappedNative* wrapper;
    1004         4002364 :     nsRefPtr<XPCWrappedNative> strongWrapper;
    1005         2001182 :     if (!flat) {
    1006         1991542 :         XPCCallContext &ccx = lccx.GetXPCCallContext();
    1007         1991542 :         if (!ccx.IsValid())
    1008               0 :             return false;
    1009                 : 
    1010                 :         rv = XPCWrappedNative::GetNewOrUsed(ccx, aHelper, xpcscope, iface,
    1011         1991542 :                                             getter_AddRefs(strongWrapper));
    1012                 : 
    1013         1991542 :         wrapper = strongWrapper;
    1014            9640 :     } else if (IS_WN_WRAPPER_OBJECT(flat)) {
    1015            9640 :         wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(flat));
    1016                 : 
    1017                 :         // If asked to return the wrapper we'll return a strong reference,
    1018                 :         // otherwise we'll just return its JSObject in d (which should be
    1019                 :         // rooted in that case).
    1020            9640 :         if (dest)
    1021               0 :             strongWrapper = wrapper;
    1022                 :         // If iface is not null we know lccx.GetXPCCallContext() returns
    1023                 :         // a valid XPCCallContext because we checked when calling Init on
    1024                 :         // iface.
    1025            9640 :         if (iface)
    1026            5530 :             wrapper->FindTearOff(lccx.GetXPCCallContext(), iface, false,
    1027           11060 :                                  &rv);
    1028                 :         else
    1029            4110 :             rv = NS_OK;
    1030                 :     } else {
    1031               0 :         NS_ASSERTION(IS_SLIM_WRAPPER(flat),
    1032                 :                      "What kind of wrapper is this?");
    1033                 : 
    1034               0 :         XPCCallContext &ccx = lccx.GetXPCCallContext();
    1035               0 :         if (!ccx.IsValid())
    1036               0 :             return false;
    1037                 : 
    1038                 :         SLIM_LOG(("***** morphing from XPCConvert::NativeInterface2JSObject"
    1039                 :                   "(%p)\n",
    1040                 :                   static_cast<nsISupports*>(xpc_GetJSPrivate(flat))));
    1041                 : 
    1042                 :         rv = XPCWrappedNative::Morph(ccx, flat, iface, cache,
    1043               0 :                                      getter_AddRefs(strongWrapper));
    1044               0 :         wrapper = strongWrapper;
    1045                 :     }
    1046                 : 
    1047         2001182 :     if (NS_FAILED(rv) && pErr)
    1048               0 :         *pErr = rv;
    1049                 : 
    1050                 :     // If creating the wrapped native failed, then return early.
    1051         2001182 :     if (NS_FAILED(rv) || !wrapper)
    1052               0 :         return false;
    1053                 : 
    1054                 :     // If we're not creating security wrappers, we can return the
    1055                 :     // XPCWrappedNative as-is here.
    1056         2001182 :     flat = wrapper->GetFlatJSObject();
    1057         2001182 :     jsval v = OBJECT_TO_JSVAL(flat);
    1058         4002364 :     if (!XPCPerThreadData::IsMainThread(lccx.GetJSContext()) ||
    1059         2001182 :         !allowNativeWrapper) {
    1060          551982 :         *d = v;
    1061          551982 :         if (dest)
    1062          545917 :             *dest = strongWrapper.forget().get();
    1063          551982 :         if (pErr)
    1064          548017 :             *pErr = NS_OK;
    1065          551982 :         return true;
    1066                 :     }
    1067                 : 
    1068         1449200 :     XPCCallContext &ccx = lccx.GetXPCCallContext();
    1069         1449200 :     if (!ccx.IsValid())
    1070               0 :         return false;
    1071                 : 
    1072         1449200 :     JSObject *original = flat;
    1073         1449200 :     if (!JS_WrapObject(ccx, &flat))
    1074               0 :         return false;
    1075                 : 
    1076                 :     // If the object was not wrapped, we are same compartment and don't need
    1077                 :     // to enforce any cross origin policies, except in case of the location
    1078                 :     // object, which always needs a wrapper in between.
    1079         1449200 :     if (original == flat) {
    1080         1449200 :         if (xpc::WrapperFactory::IsLocationObject(flat)) {
    1081               0 :             JSObject *locationWrapper = wrapper->GetWrapper();
    1082               0 :             if (!locationWrapper) {
    1083               0 :                 locationWrapper = xpc::WrapperFactory::WrapLocationObject(cx, flat);
    1084               0 :                 if (!locationWrapper)
    1085               0 :                     return false;
    1086                 : 
    1087                 :                 // Cache the location wrapper to ensure that we maintain
    1088                 :                 // the identity of window/document.location.
    1089               0 :                 wrapper->SetWrapper(locationWrapper);
    1090                 :             }
    1091                 : 
    1092               0 :             flat = locationWrapper;
    1093         1449200 :         } else if (wrapper->NeedsSOW() &&
    1094               0 :                    !xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
    1095               0 :             JSObject *sowWrapper = wrapper->GetWrapper();
    1096               0 :             if (!sowWrapper) {
    1097               0 :                 sowWrapper = xpc::WrapperFactory::WrapSOWObject(cx, flat);
    1098               0 :                 if (!sowWrapper)
    1099               0 :                     return false;
    1100                 : 
    1101                 :                 // Cache the sow wrapper to ensure that we maintain
    1102                 :                 // the identity of this node.
    1103               0 :                 wrapper->SetWrapper(sowWrapper);
    1104                 :             }
    1105                 : 
    1106               0 :             flat = sowWrapper;
    1107                 :         } else {
    1108         1449200 :             flat = JS_ObjectToOuterObject(cx, flat);
    1109         1449200 :             NS_ASSERTION(flat, "bad outer object hook!");
    1110         1449200 :             NS_ASSERTION(js::IsObjectInContextCompartment(flat, cx),
    1111                 :                          "bad compartment");
    1112                 :         }
    1113                 :     }
    1114                 : 
    1115         1449200 :     *d = OBJECT_TO_JSVAL(flat);
    1116                 : 
    1117         1449200 :     if (dest) {
    1118                 :         // The strongWrapper still holds the original flat object.
    1119               0 :         if (flat == original) {
    1120               0 :             *dest = strongWrapper.forget().get();
    1121                 :         } else {
    1122                 :             nsRefPtr<XPCJSObjectHolder> objHolder =
    1123               0 :                 XPCJSObjectHolder::newHolder(ccx, flat);
    1124               0 :             if (!objHolder)
    1125               0 :                 return false;
    1126                 : 
    1127               0 :             *dest = objHolder.forget().get();
    1128                 :         }
    1129                 :     }
    1130                 : 
    1131         1449200 :     if (pErr)
    1132         1116576 :         *pErr = NS_OK;
    1133                 : 
    1134         1449200 :     return true;
    1135                 : }
    1136                 : 
    1137                 : /***************************************************************************/
    1138                 : 
    1139                 : // static
    1140                 : JSBool
    1141         1150580 : XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
    1142                 :                                      void** dest, JSObject* src,
    1143                 :                                      const nsID* iid,
    1144                 :                                      nsISupports* aOuter,
    1145                 :                                      nsresult* pErr)
    1146                 : {
    1147         1150580 :     NS_ASSERTION(dest, "bad param");
    1148         1150580 :     NS_ASSERTION(src, "bad param");
    1149         1150580 :     NS_ASSERTION(iid, "bad param");
    1150                 : 
    1151         1150580 :     JSContext* cx = ccx.GetJSContext();
    1152                 : 
    1153         2301160 :     JSAutoEnterCompartment ac;
    1154                 : 
    1155         1150580 :     if (!ac.enter(cx, src)) {
    1156               0 :        if (pErr)
    1157               0 :            *pErr = NS_ERROR_UNEXPECTED;
    1158               0 :        return false;
    1159                 :     }
    1160                 : 
    1161         1150580 :     *dest = nsnull;
    1162         1150580 :      if (pErr)
    1163         1130101 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1164                 : 
    1165                 :     nsISupports* iface;
    1166                 : 
    1167         1150580 :     if (!aOuter) {
    1168                 :         // Note that if we have a non-null aOuter then it means that we are
    1169                 :         // forcing the creation of a wrapper even if the object *is* a
    1170                 :         // wrappedNative or other wise has 'nsISupportness'.
    1171                 :         // This allows wrapJSAggregatedToNative to work.
    1172                 : 
    1173                 :         // If we're looking at a security wrapper, see now if we're allowed to
    1174                 :         // pass it to C++. If we are, then fall through to the code below. If
    1175                 :         // we aren't, throw an exception eagerly.
    1176         1150580 :         JSObject* inner = nsnull;
    1177         1150580 :         if (XPCWrapper::IsSecurityWrapper(src)) {
    1178              46 :             inner = XPCWrapper::Unwrap(cx, src, false);
    1179              46 :             if (!inner) {
    1180               0 :                 if (pErr)
    1181               0 :                     *pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;
    1182               0 :                 return false;
    1183                 :             }
    1184                 :         }
    1185                 : 
    1186                 :         // Is this really a native xpcom object with a wrapper?
    1187                 :         XPCWrappedNative* wrappedNative =
    1188                 :                     XPCWrappedNative::GetWrappedNativeOfJSObject(cx,
    1189                 :                                                                  inner
    1190                 :                                                                  ? inner
    1191         1150580 :                                                                  : src);
    1192         1150580 :         if (wrappedNative) {
    1193         1007859 :             iface = wrappedNative->GetIdentityObject();
    1194         1007859 :             return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
    1195                 :         }
    1196                 :         // else...
    1197                 : 
    1198                 :         // XXX E4X breaks the world. Don't try wrapping E4X objects!
    1199                 :         // This hack can be removed (or changed accordingly) when the
    1200                 :         // DOM <-> E4X bindings are complete, see bug 270553
    1201          142721 :         if (JS_TypeOfValue(cx, OBJECT_TO_JSVAL(src)) == JSTYPE_XML)
    1202               0 :             return false;
    1203                 : 
    1204                 :         // Deal with slim wrappers here.
    1205          142721 :         if (GetISupportsFromJSObject(src, &iface)) {
    1206             415 :             if (iface)
    1207             415 :                 return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
    1208                 : 
    1209               0 :             return false;
    1210                 :         }
    1211                 :     }
    1212                 : 
    1213                 :     // else...
    1214                 : 
    1215                 :     nsXPCWrappedJS* wrapper;
    1216          142306 :     nsresult rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, *iid, aOuter, &wrapper);
    1217          142306 :     if (pErr)
    1218          128819 :         *pErr = rv;
    1219          142306 :     if (NS_SUCCEEDED(rv) && wrapper) {
    1220                 :         // We need to go through the QueryInterface logic to make this return
    1221                 :         // the right thing for the various 'special' interfaces; e.g.
    1222                 :         // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
    1223                 :         // there is an outer to avoid nasty recursion.
    1224               0 :         rv = aOuter ? wrapper->AggregatedQueryInterface(*iid, dest) :
    1225          142306 :                       wrapper->QueryInterface(*iid, dest);
    1226          142306 :         if (pErr)
    1227          128819 :             *pErr = rv;
    1228          142306 :         NS_RELEASE(wrapper);
    1229          142306 :         return NS_SUCCEEDED(rv);
    1230                 :     }
    1231                 : 
    1232                 :     // else...
    1233               0 :     return false;
    1234                 : }
    1235                 : 
    1236                 : /***************************************************************************/
    1237                 : /***************************************************************************/
    1238                 : 
    1239                 : // static
    1240                 : nsresult
    1241            6716 : XPCConvert::ConstructException(nsresult rv, const char* message,
    1242                 :                                const char* ifaceName, const char* methodName,
    1243                 :                                nsISupports* data,
    1244                 :                                nsIException** exceptn,
    1245                 :                                JSContext* cx,
    1246                 :                                jsval* jsExceptionPtr)
    1247                 : {
    1248            6716 :     NS_ASSERTION(!cx == !jsExceptionPtr, "Expected cx and jsExceptionPtr to cooccur.");
    1249                 : 
    1250                 :     static const char format[] = "\'%s\' when calling method: [%s::%s]";
    1251            6716 :     const char * msg = message;
    1252            6716 :     char* sz = nsnull;
    1253           13432 :     nsXPIDLString xmsg;
    1254           13432 :     nsCAutoString sxmsg;
    1255                 : 
    1256           13432 :     nsCOMPtr<nsIScriptError> errorObject = do_QueryInterface(data);
    1257            6716 :     if (errorObject) {
    1258             256 :         if (NS_SUCCEEDED(errorObject->GetMessageMoz(getter_Copies(xmsg)))) {
    1259             256 :             CopyUTF16toUTF8(xmsg, sxmsg);
    1260             256 :             msg = sxmsg.get();
    1261                 :         }
    1262                 :     }
    1263            6716 :     if (!msg)
    1264            6292 :         if (!nsXPCException::NameAndFormatForNSResult(rv, nsnull, &msg) || ! msg)
    1265               0 :             msg = "<error>";
    1266            6716 :     if (ifaceName && methodName)
    1267            6716 :         msg = sz = JS_smprintf(format, msg, ifaceName, methodName);
    1268                 : 
    1269            6716 :     nsresult res = nsXPCException::NewException(msg, rv, nsnull, data, exceptn);
    1270                 : 
    1271            6716 :     if (NS_SUCCEEDED(res) && cx && jsExceptionPtr && *exceptn) {
    1272           12742 :         nsCOMPtr<nsIXPCException> xpcEx = do_QueryInterface(*exceptn);
    1273            6371 :         if (xpcEx)
    1274            6371 :             xpcEx->StowJSVal(cx, *jsExceptionPtr);
    1275                 :     }
    1276                 : 
    1277            6716 :     if (sz)
    1278            6716 :         JS_smprintf_free(sz);
    1279            6716 :     return res;
    1280                 : }
    1281                 : 
    1282                 : /********************************/
    1283                 : 
    1284                 : class AutoExceptionRestorer
    1285                 : {
    1286                 : public:
    1287            6801 :     AutoExceptionRestorer(JSContext *cx, jsval v)
    1288            6801 :         : mContext(cx), tvr(cx, v)
    1289                 :     {
    1290            6801 :         JS_ClearPendingException(mContext);
    1291            6801 :     }
    1292                 : 
    1293            6801 :     ~AutoExceptionRestorer()
    1294            6801 :     {
    1295            6801 :         JS_SetPendingException(mContext, tvr.jsval_value());
    1296            6801 :     }
    1297                 : 
    1298                 : private:
    1299                 :     JSContext * const mContext;
    1300                 :     JS::AutoValueRooter tvr;
    1301                 : };
    1302                 : 
    1303                 : // static
    1304                 : nsresult
    1305            6801 : XPCConvert::JSValToXPCException(XPCCallContext& ccx,
    1306                 :                                 jsval s,
    1307                 :                                 const char* ifaceName,
    1308                 :                                 const char* methodName,
    1309                 :                                 nsIException** exceptn)
    1310                 : {
    1311            6801 :     JSContext* cx = ccx.GetJSContext();
    1312           13602 :     AutoExceptionRestorer aer(cx, s);
    1313                 : 
    1314            6801 :     if (!JSVAL_IS_PRIMITIVE(s)) {
    1315                 :         // we have a JSObject
    1316             433 :         JSObject* obj = JSVAL_TO_OBJECT(s);
    1317                 : 
    1318             433 :         if (!obj) {
    1319               0 :             NS_ERROR("when is an object not an object?");
    1320               0 :             return NS_ERROR_FAILURE;
    1321                 :         }
    1322                 : 
    1323                 :         // is this really a native xpcom object with a wrapper?
    1324                 :         XPCWrappedNative* wrapper;
    1325             433 :         if (nsnull != (wrapper =
    1326                 :                        XPCWrappedNative::GetWrappedNativeOfJSObject(cx,obj))) {
    1327             173 :             nsISupports* supports = wrapper->GetIdentityObject();
    1328             346 :             nsCOMPtr<nsIException> iface = do_QueryInterface(supports);
    1329             173 :             if (iface) {
    1330                 :                 // just pass through the exception (with extra ref and all)
    1331             172 :                 nsIException* temp = iface;
    1332             172 :                 NS_ADDREF(temp);
    1333             172 :                 *exceptn = temp;
    1334             172 :                 return NS_OK;
    1335                 :             } else {
    1336                 :                 // it is a wrapped native, but not an exception!
    1337                 :                 return ConstructException(NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT,
    1338                 :                                           nsnull, ifaceName, methodName, supports,
    1339               1 :                                           exceptn, nsnull, nsnull);
    1340                 :             }
    1341                 :         } else {
    1342                 :             // It is a JSObject, but not a wrapped native...
    1343                 : 
    1344                 :             // If it is an engine Error with an error report then let's
    1345                 :             // extract the report and build an xpcexception from that
    1346                 :             const JSErrorReport* report;
    1347             260 :             if (nsnull != (report = JS_ErrorFromException(cx, s))) {
    1348             512 :                 JSAutoByteString message;
    1349                 :                 JSString* str;
    1350             256 :                 if (nsnull != (str = JS_ValueToString(cx, s)))
    1351             256 :                     message.encode(cx, str);
    1352             256 :                 return JSErrorToXPCException(ccx, message.ptr(), ifaceName,
    1353             256 :                                              methodName, report, exceptn);
    1354                 :             }
    1355                 : 
    1356                 : 
    1357                 :             unsigned ignored;
    1358                 :             JSBool found;
    1359                 : 
    1360                 :             // heuristic to see if it might be usable as an xpcexception
    1361               4 :             if (!JS_GetPropertyAttributes(cx, obj, "message", &ignored, &found))
    1362               0 :                return NS_ERROR_FAILURE;
    1363                 : 
    1364               4 :             if (found && !JS_GetPropertyAttributes(cx, obj, "result", &ignored, &found))
    1365               0 :                 return NS_ERROR_FAILURE;
    1366                 : 
    1367               4 :             if (found) {
    1368                 :                 // lets try to build a wrapper around the JSObject
    1369                 :                 nsXPCWrappedJS* jswrapper;
    1370                 :                 nsresult rv =
    1371                 :                     nsXPCWrappedJS::GetNewOrUsed(ccx, obj,
    1372                 :                                                  NS_GET_IID(nsIException),
    1373               1 :                                                  nsnull, &jswrapper);
    1374               1 :                 if (NS_FAILED(rv))
    1375               0 :                     return rv;
    1376                 : 
    1377               1 :                 *exceptn = static_cast<nsIException *>(jswrapper->GetXPTCStub());
    1378               1 :                 return NS_OK;
    1379                 :             }
    1380                 : 
    1381                 : 
    1382                 :             // XXX we should do a check against 'js_ErrorClass' here and
    1383                 :             // do the right thing - even though it has no JSErrorReport,
    1384                 :             // The fact that it is a JSError exceptions means we can extract
    1385                 :             // particular info and our 'result' should reflect that.
    1386                 : 
    1387                 :             // otherwise we'll just try to convert it to a string
    1388                 : 
    1389               3 :             JSString* str = JS_ValueToString(cx, s);
    1390               3 :             if (!str)
    1391               0 :                 return NS_ERROR_FAILURE;
    1392                 : 
    1393               6 :             JSAutoByteString strBytes(cx, str);
    1394               3 :             if (!strBytes)
    1395               0 :                 return NS_ERROR_FAILURE;
    1396                 : 
    1397                 :             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
    1398               3 :                                       strBytes.ptr(), ifaceName, methodName,
    1399               3 :                                       nsnull, exceptn, cx, &s);
    1400                 :         }
    1401                 :     }
    1402                 : 
    1403            6368 :     if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
    1404                 :         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
    1405                 :                                   nsnull, ifaceName, methodName, nsnull,
    1406               0 :                                   exceptn, cx, &s);
    1407                 :     }
    1408                 : 
    1409            6368 :     if (JSVAL_IS_NUMBER(s)) {
    1410                 :         // lets see if it looks like an nsresult
    1411                 :         nsresult rv;
    1412                 :         double number;
    1413            6291 :         JSBool isResult = false;
    1414                 : 
    1415            6291 :         if (JSVAL_IS_INT(s)) {
    1416               0 :             rv = (nsresult) JSVAL_TO_INT(s);
    1417               0 :             if (NS_FAILED(rv))
    1418               0 :                 isResult = true;
    1419                 :             else
    1420               0 :                 number = (double) JSVAL_TO_INT(s);
    1421                 :         } else {
    1422            6291 :             number = JSVAL_TO_DOUBLE(s);
    1423           12582 :             if (number > 0.0 &&
    1424                 :                 number < (double)0xffffffff &&
    1425            6291 :                 0.0 == fmod(number,1)) {
    1426            6291 :                 rv = (nsresult) number;
    1427            6291 :                 if (NS_FAILED(rv))
    1428            6291 :                     isResult = true;
    1429                 :             }
    1430                 :         }
    1431                 : 
    1432            6291 :         if (isResult)
    1433                 :             return ConstructException(rv, nsnull, ifaceName, methodName,
    1434            6291 :                                       nsnull, exceptn, cx, &s);
    1435                 :         else {
    1436                 :             // XXX all this nsISupportsDouble code seems a little redundant
    1437                 :             // now that we're storing the jsval in the exception...
    1438                 :             nsISupportsDouble* data;
    1439               0 :             nsCOMPtr<nsIComponentManager> cm;
    1440               0 :             if (NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm))) || !cm ||
    1441               0 :                 NS_FAILED(cm->CreateInstanceByContractID(NS_SUPPORTS_DOUBLE_CONTRACTID,
    1442                 :                                                          nsnull,
    1443                 :                                                          NS_GET_IID(nsISupportsDouble),
    1444                 :                                                          (void**)&data)))
    1445               0 :                 return NS_ERROR_FAILURE;
    1446               0 :             data->SetData(number);
    1447                 :             rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nsnull,
    1448               0 :                                     ifaceName, methodName, data, exceptn, cx, &s);
    1449               0 :             NS_RELEASE(data);
    1450               0 :             return rv;
    1451                 :         }
    1452                 :     }
    1453                 : 
    1454                 :     // otherwise we'll just try to convert it to a string
    1455                 :     // Note: e.g., JSBools get converted to JSStrings by this code.
    1456                 : 
    1457              77 :     JSString* str = JS_ValueToString(cx, s);
    1458              77 :     if (str) {
    1459             154 :         JSAutoByteString strBytes(cx, str);
    1460              77 :         if (!!strBytes) {
    1461                 :             return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
    1462              77 :                                       strBytes.ptr(), ifaceName, methodName,
    1463              77 :                                       nsnull, exceptn, cx, &s);
    1464                 :         }
    1465                 :     }
    1466               0 :     return NS_ERROR_FAILURE;
    1467                 : }
    1468                 : 
    1469                 : /********************************/
    1470                 : 
    1471                 : // static
    1472                 : nsresult
    1473             256 : XPCConvert::JSErrorToXPCException(XPCCallContext& ccx,
    1474                 :                                   const char* message,
    1475                 :                                   const char* ifaceName,
    1476                 :                                   const char* methodName,
    1477                 :                                   const JSErrorReport* report,
    1478                 :                                   nsIException** exceptn)
    1479                 : {
    1480             256 :     nsresult rv = NS_ERROR_FAILURE;
    1481             512 :     nsRefPtr<nsScriptError> data;
    1482             256 :     if (report) {
    1483             512 :         nsAutoString bestMessage;
    1484             256 :         if (report && report->ucmessage) {
    1485             256 :             bestMessage = (const PRUnichar *)report->ucmessage;
    1486               0 :         } else if (message) {
    1487               0 :             bestMessage.AssignWithConversion(message);
    1488                 :         } else {
    1489               0 :             bestMessage.AssignLiteral("JavaScript Error");
    1490                 :         }
    1491                 : 
    1492             256 :         data = new nsScriptError();
    1493             256 :         if (!data)
    1494               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1495                 : 
    1496                 : 
    1497             256 :         data->InitWithWindowID(bestMessage.get(),
    1498             512 :                                NS_ConvertASCIItoUTF16(report->filename).get(),
    1499                 :                                (const PRUnichar *)report->uclinebuf, report->lineno,
    1500                 :                                report->uctokenptr - report->uclinebuf, report->flags,
    1501                 :                                "XPConnect JavaScript",
    1502             256 :                                nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(ccx.GetJSContext()));
    1503                 :     }
    1504                 : 
    1505             256 :     if (data) {
    1506             512 :         nsCAutoString formattedMsg;
    1507             256 :         data->ToString(formattedMsg);
    1508                 : 
    1509                 :         rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS,
    1510                 :                                 formattedMsg.get(), ifaceName, methodName,
    1511             256 :                                 static_cast<nsIScriptError*>(data.get()),
    1512             256 :                                 exceptn, nsnull, nsnull);
    1513                 :     } else {
    1514                 :         rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR,
    1515                 :                                 nsnull, ifaceName, methodName, nsnull,
    1516               0 :                                 exceptn, nsnull, nsnull);
    1517                 :     }
    1518             256 :     return rv;
    1519                 : }
    1520                 : 
    1521                 : /***************************************************************************/
    1522                 : 
    1523                 : // array fun...
    1524                 : 
    1525                 : #ifdef POPULATE
    1526                 : #undef POPULATE
    1527                 : #endif
    1528                 : 
    1529                 : // static
    1530                 : JSBool
    1531           40181 : XPCConvert::NativeArray2JS(XPCLazyCallContext& lccx,
    1532                 :                            jsval* d, const void** s,
    1533                 :                            const nsXPTType& type, const nsID* iid,
    1534                 :                            uint32_t count, nsresult* pErr)
    1535                 : {
    1536           40181 :     NS_PRECONDITION(s, "bad param");
    1537           40181 :     NS_PRECONDITION(d, "bad param");
    1538                 : 
    1539           40181 :     XPCCallContext& ccx = lccx.GetXPCCallContext();
    1540           40181 :     if (!ccx.IsValid())
    1541               0 :         return false;
    1542                 : 
    1543           40181 :     JSContext* cx = ccx.GetJSContext();
    1544           40181 :     NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
    1545                 :                       "bad scope for new JSObjects");
    1546                 : 
    1547                 :     // XXX add support for putting chars in a string rather than an array
    1548                 : 
    1549                 :     // XXX add support to indicate *which* array element was not convertable
    1550                 : 
    1551           40181 :     JSObject *array = JS_NewArrayObject(cx, count, nsnull);
    1552                 : 
    1553           40181 :     if (!array)
    1554               0 :         return false;
    1555                 : 
    1556                 :     // root this early
    1557           40181 :     *d = OBJECT_TO_JSVAL(array);
    1558           80362 :     AUTO_MARK_JSVAL(ccx, d);
    1559                 : 
    1560           40181 :     if (pErr)
    1561           40087 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1562                 : 
    1563                 :     uint32_t i;
    1564           40181 :     jsval current = JSVAL_NULL;
    1565           80362 :     AUTO_MARK_JSVAL(ccx, &current);
    1566                 : 
    1567                 : #define POPULATE(_t)                                                          \
    1568                 :     PR_BEGIN_MACRO                                                            \
    1569                 :         for (i = 0; i < count; i++) {                                         \
    1570                 :             if (!NativeData2JS(ccx, &current, ((_t*)*s)+i, type, iid, pErr) ||\
    1571                 :                 !JS_SetElement(cx, array, i, &current))                       \
    1572                 :                 goto failure;                                                 \
    1573                 :         }                                                                     \
    1574                 :     PR_END_MACRO
    1575                 : 
    1576                 :     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
    1577                 : 
    1578           40181 :     switch (type.TagPart()) {
    1579               0 :     case nsXPTType::T_I8            : POPULATE(int8_t);         break;
    1580              12 :     case nsXPTType::T_I16           : POPULATE(int16_t);        break;
    1581               0 :     case nsXPTType::T_I32           : POPULATE(int32_t);        break;
    1582            8867 :     case nsXPTType::T_I64           : POPULATE(int64_t);        break;
    1583           14828 :     case nsXPTType::T_U8            : POPULATE(uint8_t);        break;
    1584               0 :     case nsXPTType::T_U16           : POPULATE(uint16_t);       break;
    1585            8342 :     case nsXPTType::T_U32           : POPULATE(uint32_t);       break;
    1586               0 :     case nsXPTType::T_U64           : POPULATE(uint64_t);       break;
    1587               0 :     case nsXPTType::T_FLOAT         : POPULATE(float);          break;
    1588              12 :     case nsXPTType::T_DOUBLE        : POPULATE(double);         break;
    1589               0 :     case nsXPTType::T_BOOL          : POPULATE(bool);           break;
    1590               0 :     case nsXPTType::T_CHAR          : POPULATE(char);           break;
    1591               0 :     case nsXPTType::T_WCHAR         : POPULATE(jschar);         break;
    1592               0 :     case nsXPTType::T_VOID          : NS_ERROR("bad type"); goto failure;
    1593               1 :     case nsXPTType::T_IID           : POPULATE(nsID*);          break;
    1594               0 :     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type"); goto failure;
    1595            1152 :     case nsXPTType::T_CHAR_STR      : POPULATE(char*);          break;
    1596            1737 :     case nsXPTType::T_WCHAR_STR     : POPULATE(jschar*);        break;
    1597            5224 :     case nsXPTType::T_INTERFACE     : POPULATE(nsISupports*);   break;
    1598               6 :     case nsXPTType::T_INTERFACE_IS  : POPULATE(nsISupports*);   break;
    1599               0 :     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type"); goto failure;
    1600               0 :     case nsXPTType::T_CSTRING       : NS_ERROR("bad type"); goto failure;
    1601               0 :     case nsXPTType::T_ASTRING       : NS_ERROR("bad type"); goto failure;
    1602               0 :     default                         : NS_ERROR("bad type"); goto failure;
    1603                 :     }
    1604                 : 
    1605           40181 :     if (pErr)
    1606           40087 :         *pErr = NS_OK;
    1607           40181 :     return true;
    1608                 : 
    1609                 : failure:
    1610               0 :     return false;
    1611                 : 
    1612                 : #undef POPULATE
    1613                 : }
    1614                 : 
    1615                 : 
    1616                 : 
    1617                 : // Check that the tag part of the type matches the type
    1618                 : // of the array. If the check succeeds, check that the size
    1619                 : // of the output does not exceed PR_UINT32_MAX bytes. Allocate
    1620                 : // the memory and copy the elements by memcpy.
    1621                 : static JSBool
    1622              11 : CheckTargetAndPopulate(const nsXPTType& type,
    1623                 :                        PRUint8 requiredType,
    1624                 :                        size_t typeSize,
    1625                 :                        uint32_t count,
    1626                 :                        JSObject* tArr,
    1627                 :                        void** output,
    1628                 :                        nsresult* pErr)
    1629                 : {
    1630                 :     // Check that the element type expected by the interface matches
    1631                 :     // the type of the elements in the typed array exactly, including
    1632                 :     // signedness.
    1633              11 :     if (type.TagPart() != requiredType) {
    1634               2 :         if (pErr)
    1635               2 :             *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1636                 : 
    1637               2 :         return false;
    1638                 :     }
    1639                 : 
    1640                 :     // Calulate the maximum number of elements that can fit in
    1641                 :     // PR_UINT32_MAX bytes.
    1642               9 :     size_t max = PR_UINT32_MAX / typeSize;
    1643                 : 
    1644                 :     // This could overflow on 32-bit systems so check max first.
    1645               9 :     size_t byteSize = count * typeSize;
    1646               9 :     if (count > max || !(*output = nsMemory::Alloc(byteSize))) {
    1647               0 :         if (pErr)
    1648               0 :             *pErr = NS_ERROR_OUT_OF_MEMORY;
    1649                 : 
    1650               0 :         return false;
    1651                 :     }
    1652                 : 
    1653               9 :     memcpy(*output, JS_GetTypedArrayData(tArr), byteSize);
    1654               9 :     return true;
    1655                 : }
    1656                 : 
    1657                 : // Fast conversion of typed arrays to native using memcpy.
    1658                 : // No float or double canonicalization is done. Called by
    1659                 : // JSarray2Native whenever a TypedArray is met. ArrayBuffers
    1660                 : // are not accepted; create a properly typed array view on them
    1661                 : // first. The element type of array must match the XPCOM
    1662                 : // type in size, type and signedness exactly. As an exception,
    1663                 : // Uint8ClampedArray is allowed for arrays of uint8_t.
    1664                 : 
    1665                 : // static
    1666                 : JSBool
    1667              13 : XPCConvert::JSTypedArray2Native(XPCCallContext& ccx,
    1668                 :                                 void** d,
    1669                 :                                 JSObject* jsArray,
    1670                 :                                 uint32_t count,
    1671                 :                                 const nsXPTType& type,
    1672                 :                                 nsresult* pErr)
    1673                 : {
    1674              13 :     NS_ABORT_IF_FALSE(jsArray, "bad param");
    1675              13 :     NS_ABORT_IF_FALSE(d, "bad param");
    1676              13 :     NS_ABORT_IF_FALSE(js_IsTypedArray(jsArray), "not a typed array");
    1677                 : 
    1678                 :     // Check the actual length of the input array against the
    1679                 :     // given size_is.
    1680              13 :     uint32_t len = JS_GetTypedArrayLength(jsArray);
    1681              13 :     if (len < count) {
    1682               2 :         if (pErr)
    1683               2 :             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1684                 : 
    1685               2 :         return false;
    1686                 :     }
    1687                 : 
    1688              11 :     void* output = nsnull;
    1689                 : 
    1690              11 :     switch (JS_GetTypedArrayType(jsArray)) {
    1691                 :     case js::TypedArray::TYPE_INT8:
    1692               0 :         if (!CheckTargetAndPopulate(nsXPTType::T_I8, type,
    1693                 :                                     sizeof(int8_t), count,
    1694               0 :                                     jsArray, &output, pErr)) {
    1695               0 :             return false;
    1696                 :         }
    1697               0 :         break;
    1698                 : 
    1699                 :     case js::TypedArray::TYPE_UINT8:
    1700                 :     case js::TypedArray::TYPE_UINT8_CLAMPED:
    1701               1 :         if (!CheckTargetAndPopulate(nsXPTType::T_U8, type,
    1702                 :                                     sizeof(uint8_t), count,
    1703               1 :                                     jsArray, &output, pErr)) {
    1704               0 :             return false;
    1705                 :         }
    1706               1 :         break;
    1707                 : 
    1708                 :     case js::TypedArray::TYPE_INT16:
    1709               4 :         if (!CheckTargetAndPopulate(nsXPTType::T_I16, type,
    1710                 :                                     sizeof(int16_t), count,
    1711               4 :                                     jsArray, &output, pErr)) {
    1712               0 :             return false;
    1713                 :         }
    1714               4 :         break;
    1715                 : 
    1716                 :     case js::TypedArray::TYPE_UINT16:
    1717               2 :         if (!CheckTargetAndPopulate(nsXPTType::T_U16, type,
    1718                 :                                     sizeof(uint16_t), count,
    1719               2 :                                     jsArray, &output, pErr)) {
    1720               2 :             return false;
    1721                 :         }
    1722               0 :         break;
    1723                 : 
    1724                 :     case js::TypedArray::TYPE_INT32:
    1725               0 :         if (!CheckTargetAndPopulate(nsXPTType::T_I32, type,
    1726                 :                                     sizeof(int32_t), count,
    1727               0 :                                     jsArray, &output, pErr)) {
    1728               0 :             return false;
    1729                 :         }
    1730               0 :         break;
    1731                 : 
    1732                 :     case js::TypedArray::TYPE_UINT32:
    1733               0 :         if (!CheckTargetAndPopulate(nsXPTType::T_U32, type,
    1734                 :                                     sizeof(uint32_t), count,
    1735               0 :                                     jsArray, &output, pErr)) {
    1736               0 :             return false;
    1737                 :         }
    1738               0 :         break;
    1739                 : 
    1740                 :     case js::TypedArray::TYPE_FLOAT32:
    1741               0 :         if (!CheckTargetAndPopulate(nsXPTType::T_FLOAT, type,
    1742                 :                                     sizeof(float), count,
    1743               0 :                                     jsArray, &output, pErr)) {
    1744               0 :             return false;
    1745                 :         }
    1746               0 :         break;
    1747                 : 
    1748                 :     case js::TypedArray::TYPE_FLOAT64:
    1749               4 :         if (!CheckTargetAndPopulate(nsXPTType::T_DOUBLE, type,
    1750                 :                                     sizeof(double), count,
    1751               4 :                                     jsArray, &output, pErr)) {
    1752               0 :             return false;
    1753                 :         }
    1754               4 :         break;
    1755                 : 
    1756                 :     // Yet another array type was defined? It is not supported yet...
    1757                 :     default:
    1758               0 :         if (pErr)
    1759               0 :             *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1760                 : 
    1761               0 :         return false;
    1762                 :     }
    1763                 : 
    1764               9 :     *d = output;
    1765               9 :     if (pErr)
    1766               9 :         *pErr = NS_OK;
    1767                 : 
    1768               9 :     return true;
    1769                 : }
    1770                 : 
    1771                 : // static
    1772                 : JSBool
    1773           28525 : XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
    1774                 :                            uint32_t count, const nsXPTType& type,
    1775                 :                            const nsID* iid, nsresult* pErr)
    1776                 : {
    1777           28525 :     NS_ABORT_IF_FALSE(d, "bad param");
    1778                 : 
    1779           28525 :     JSContext* cx = ccx.GetJSContext();
    1780                 : 
    1781                 :     // No Action, FRee memory, RElease object
    1782                 :     enum CleanupMode {na, fr, re};
    1783                 : 
    1784                 :     CleanupMode cleanupMode;
    1785                 : 
    1786           28525 :     JSObject* jsarray = nsnull;
    1787           28525 :     void* array = nsnull;
    1788                 :     uint32_t initedCount;
    1789                 :     jsval current;
    1790                 : 
    1791                 :     // XXX add support for getting chars from strings
    1792                 : 
    1793                 :     // XXX add support to indicate *which* array element was not convertable
    1794                 : 
    1795           28525 :     if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
    1796               0 :         if (0 != count) {
    1797               0 :             if (pErr)
    1798               0 :                 *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1799               0 :             return false;
    1800                 :         }
    1801                 : 
    1802               0 :         *d = nsnull;
    1803               0 :         return true;
    1804                 :     }
    1805                 : 
    1806           28525 :     if (!JSVAL_IS_OBJECT(s)) {
    1807               0 :         if (pErr)
    1808               0 :             *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
    1809               0 :         return false;
    1810                 :     }
    1811                 : 
    1812           28525 :     jsarray = JSVAL_TO_OBJECT(s);
    1813                 : 
    1814                 :     // If this is a typed array, then do a fast conversion with memcpy.
    1815           28525 :     if (js_IsTypedArray(jsarray)) {
    1816              13 :         return JSTypedArray2Native(ccx, d, jsarray, count, type, pErr);
    1817                 :     }
    1818                 : 
    1819           28512 :     if (!JS_IsArrayObject(cx, jsarray)) {
    1820               0 :         if (pErr)
    1821               0 :             *pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
    1822               0 :         return false;
    1823                 :     }
    1824                 : 
    1825                 :     uint32_t len;
    1826           28512 :     if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
    1827               0 :         if (pErr)
    1828               0 :             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1829               0 :         return false;
    1830                 :     }
    1831                 : 
    1832           28512 :     if (pErr)
    1833           27613 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1834                 : 
    1835                 : #define POPULATE(_mode, _t)                                                   \
    1836                 :     PR_BEGIN_MACRO                                                            \
    1837                 :         cleanupMode = _mode;                                                  \
    1838                 :         size_t max = PR_UINT32_MAX / sizeof(_t);                              \
    1839                 :         if (count > max ||                                                    \
    1840                 :             nsnull == (array = nsMemory::Alloc(count * sizeof(_t)))) {        \
    1841                 :             if (pErr)                                                         \
    1842                 :                 *pErr = NS_ERROR_OUT_OF_MEMORY;                               \
    1843                 :             goto failure;                                                     \
    1844                 :         }                                                                     \
    1845                 :         for (initedCount = 0; initedCount < count; initedCount++) {           \
    1846                 :             if (!JS_GetElement(cx, jsarray, initedCount, &current) ||         \
    1847                 :                 !JSData2Native(ccx, ((_t*)array)+initedCount, current, type,  \
    1848                 :                                true, iid, pErr))                              \
    1849                 :                 goto failure;                                                 \
    1850                 :         }                                                                     \
    1851                 :     PR_END_MACRO
    1852                 : 
    1853                 : 
    1854                 :     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
    1855                 : 
    1856                 :     // XXX make extra space at end of char* and wchar* and null termintate
    1857                 : 
    1858           28512 :     switch (type.TagPart()) {
    1859               0 :     case nsXPTType::T_I8            : POPULATE(na, int8_t);         break;
    1860               8 :     case nsXPTType::T_I16           : POPULATE(na, int16_t);        break;
    1861               1 :     case nsXPTType::T_I32           : POPULATE(na, int32_t);        break;
    1862             571 :     case nsXPTType::T_I64           : POPULATE(na, int64_t);        break;
    1863           23256 :     case nsXPTType::T_U8            : POPULATE(na, uint8_t);        break;
    1864               0 :     case nsXPTType::T_U16           : POPULATE(na, uint16_t);       break;
    1865              85 :     case nsXPTType::T_U32           : POPULATE(na, uint32_t);       break;
    1866               0 :     case nsXPTType::T_U64           : POPULATE(na, uint64_t);       break;
    1867               0 :     case nsXPTType::T_FLOAT         : POPULATE(na, float);          break;
    1868               9 :     case nsXPTType::T_DOUBLE        : POPULATE(na, double);         break;
    1869               0 :     case nsXPTType::T_BOOL          : POPULATE(na, bool);           break;
    1870               0 :     case nsXPTType::T_CHAR          : POPULATE(na, char);           break;
    1871               0 :     case nsXPTType::T_WCHAR         : POPULATE(na, jschar);         break;
    1872               0 :     case nsXPTType::T_VOID          : NS_ERROR("bad type"); goto failure;
    1873              37 :     case nsXPTType::T_IID           : POPULATE(fr, nsID*);          break;
    1874               0 :     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type"); goto failure;
    1875              29 :     case nsXPTType::T_CHAR_STR      : POPULATE(fr, char*);          break;
    1876             779 :     case nsXPTType::T_WCHAR_STR     : POPULATE(fr, jschar*);        break;
    1877            3701 :     case nsXPTType::T_INTERFACE     : POPULATE(re, nsISupports*);   break;
    1878              36 :     case nsXPTType::T_INTERFACE_IS  : POPULATE(re, nsISupports*);   break;
    1879               0 :     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type"); goto failure;
    1880               0 :     case nsXPTType::T_CSTRING       : NS_ERROR("bad type"); goto failure;
    1881               0 :     case nsXPTType::T_ASTRING       : NS_ERROR("bad type"); goto failure;
    1882               0 :     default                         : NS_ERROR("bad type"); goto failure;
    1883                 :     }
    1884                 : 
    1885           28512 :     *d = array;
    1886           28512 :     if (pErr)
    1887           27613 :         *pErr = NS_OK;
    1888           28512 :     return true;
    1889                 : 
    1890                 : failure:
    1891                 :     // we may need to cleanup the partially filled array of converted stuff
    1892               0 :     if (array) {
    1893               0 :         if (cleanupMode == re) {
    1894               0 :             nsISupports** a = (nsISupports**) array;
    1895               0 :             for (PRUint32 i = 0; i < initedCount; i++) {
    1896               0 :                 nsISupports* p = a[i];
    1897               0 :                 NS_IF_RELEASE(p);
    1898                 :             }
    1899               0 :         } else if (cleanupMode == fr) {
    1900               0 :             void** a = (void**) array;
    1901               0 :             for (PRUint32 i = 0; i < initedCount; i++) {
    1902               0 :                 void* p = a[i];
    1903               0 :                 if (p) nsMemory::Free(p);
    1904                 :             }
    1905                 :         }
    1906               0 :         nsMemory::Free(array);
    1907                 :     }
    1908                 : 
    1909               0 :     return false;
    1910                 : 
    1911                 : #undef POPULATE
    1912                 : }
    1913                 : 
    1914                 : // static
    1915                 : JSBool
    1916             656 : XPCConvert::NativeStringWithSize2JS(JSContext* cx,
    1917                 :                                     jsval* d, const void* s,
    1918                 :                                     const nsXPTType& type,
    1919                 :                                     uint32_t count,
    1920                 :                                     nsresult* pErr)
    1921                 : {
    1922             656 :     NS_PRECONDITION(s, "bad param");
    1923             656 :     NS_PRECONDITION(d, "bad param");
    1924                 : 
    1925             656 :     if (pErr)
    1926             652 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1927                 : 
    1928             656 :     switch (type.TagPart()) {
    1929                 :         case nsXPTType::T_PSTRING_SIZE_IS:
    1930                 :         {
    1931             650 :             char* p = *((char**)s);
    1932             650 :             if (!p)
    1933               0 :                 break;
    1934                 :             JSString* str;
    1935             650 :             if (!(str = JS_NewStringCopyN(cx, p, count)))
    1936               0 :                 return false;
    1937             650 :             *d = STRING_TO_JSVAL(str);
    1938             650 :             break;
    1939                 :         }
    1940                 :         case nsXPTType::T_PWSTRING_SIZE_IS:
    1941                 :         {
    1942               6 :             jschar* p = *((jschar**)s);
    1943               6 :             if (!p)
    1944               0 :                 break;
    1945                 :             JSString* str;
    1946               6 :             if (!(str = JS_NewUCStringCopyN(cx, p, count)))
    1947               0 :                 return false;
    1948               6 :             *d = STRING_TO_JSVAL(str);
    1949               6 :             break;
    1950                 :         }
    1951                 :         default:
    1952               0 :             XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
    1953               0 :             return false;
    1954                 :     }
    1955             656 :     return true;
    1956                 : }
    1957                 : 
    1958                 : // static
    1959                 : JSBool
    1960              14 : XPCConvert::JSStringWithSize2Native(XPCCallContext& ccx, void* d, jsval s,
    1961                 :                                     uint32_t count, const nsXPTType& type,
    1962                 :                                     nsresult* pErr)
    1963                 : {
    1964              14 :     NS_PRECONDITION(!JSVAL_IS_NULL(s), "bad param");
    1965              14 :     NS_PRECONDITION(d, "bad param");
    1966                 : 
    1967              14 :     JSContext* cx = ccx.GetJSContext();
    1968                 : 
    1969                 :     uint32_t len;
    1970                 : 
    1971              14 :     if (pErr)
    1972              10 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1973                 : 
    1974              14 :     switch (type.TagPart()) {
    1975                 :         case nsXPTType::T_PSTRING_SIZE_IS:
    1976                 :         {
    1977               8 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
    1978               0 :                 if (0 != count) {
    1979               0 :                     if (pErr)
    1980               0 :                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    1981               0 :                     return false;
    1982                 :                 }
    1983               0 :                 if (0 != count) {
    1984               0 :                     len = (count + 1) * sizeof(char);
    1985               0 :                     if (!(*((void**)d) = nsMemory::Alloc(len)))
    1986               0 :                         return false;
    1987               0 :                     return true;
    1988                 :                 }
    1989                 :                 // else ...
    1990                 : 
    1991               0 :                 *((char**)d) = nsnull;
    1992               0 :                 return true;
    1993                 :             }
    1994                 : 
    1995               8 :             JSString* str = JS_ValueToString(cx, s);
    1996               8 :             if (!str) {
    1997               0 :                 return false;
    1998                 :             }
    1999                 : 
    2000               8 :             size_t length = JS_GetStringEncodingLength(cx, str);
    2001               8 :             if (length == size_t(-1)) {
    2002               0 :                 return false;
    2003                 :             }
    2004               8 :             if (length > count) {
    2005               0 :                 if (pErr)
    2006               0 :                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    2007               0 :                 return false;
    2008                 :             }
    2009               8 :             len = PRUint32(length);
    2010                 : 
    2011               8 :             if (len < count)
    2012               0 :                 len = count;
    2013                 : 
    2014               8 :             uint32_t alloc_len = (len + 1) * sizeof(char);
    2015               8 :             char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
    2016               8 :             if (!buffer) {
    2017               0 :                 return false;
    2018                 :             }
    2019               8 :             JS_EncodeStringToBuffer(str, buffer, len);
    2020               8 :             buffer[len] = '\0';
    2021               8 :             *((char**)d) = buffer;
    2022                 : 
    2023               8 :             return true;
    2024                 :         }
    2025                 : 
    2026                 :         case nsXPTType::T_PWSTRING_SIZE_IS:
    2027                 :         {
    2028               6 :             const jschar* chars=nsnull;
    2029                 :             JSString* str;
    2030                 : 
    2031               6 :             if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
    2032               0 :                 if (0 != count) {
    2033               0 :                     if (pErr)
    2034               0 :                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    2035               0 :                     return false;
    2036                 :                 }
    2037                 : 
    2038               0 :                 if (0 != count) {
    2039               0 :                     len = (count + 1) * sizeof(jschar);
    2040               0 :                     if (!(*((void**)d) = nsMemory::Alloc(len)))
    2041               0 :                         return false;
    2042               0 :                     return true;
    2043                 :                 }
    2044                 : 
    2045                 :                 // else ...
    2046               0 :                 *((const jschar**)d) = nsnull;
    2047               0 :                 return true;
    2048                 :             }
    2049                 : 
    2050               6 :             if (!(str = JS_ValueToString(cx, s))) {
    2051               0 :                 return false;
    2052                 :             }
    2053                 : 
    2054               6 :             len = JS_GetStringLength(str);
    2055               6 :             if (len > count) {
    2056               0 :                 if (pErr)
    2057               0 :                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    2058               0 :                 return false;
    2059                 :             }
    2060               6 :             if (len < count)
    2061               0 :                 len = count;
    2062                 : 
    2063               6 :             if (!(chars = JS_GetStringCharsZ(cx, str))) {
    2064               0 :                 return false;
    2065                 :             }
    2066               6 :             uint32_t alloc_len = (len + 1) * sizeof(jschar);
    2067               6 :             if (!(*((void**)d) = nsMemory::Alloc(alloc_len))) {
    2068                 :                 // XXX should report error
    2069               0 :                 return false;
    2070                 :             }
    2071               6 :             memcpy(*((jschar**)d), chars, alloc_len);
    2072               6 :             (*((jschar**)d))[count] = 0;
    2073                 : 
    2074               6 :             return true;
    2075                 :         }
    2076                 :         default:
    2077               0 :             XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
    2078               0 :             return false;
    2079                 :     }
    2080                 : }
    2081                 : 

Generated by: LCOV version 1.7