LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCConvert.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 398 895 44.5 %
Date: 2017-07-14 16:53:18 Functions: 20 33 60.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Data conversion between native and JavaScript types. */
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/Range.h"
      11             : 
      12             : #include "xpcprivate.h"
      13             : #include "nsIAtom.h"
      14             : #include "nsIScriptError.h"
      15             : #include "nsWrapperCache.h"
      16             : #include "nsJSUtils.h"
      17             : #include "nsQueryObject.h"
      18             : #include "nsScriptError.h"
      19             : #include "WrapperFactory.h"
      20             : 
      21             : #include "nsWrapperCacheInlines.h"
      22             : 
      23             : #include "jsapi.h"
      24             : #include "jsfriendapi.h"
      25             : #include "js/CharacterEncoding.h"
      26             : #include "jsprf.h"
      27             : 
      28             : #include "mozilla/dom/BindingUtils.h"
      29             : #include "mozilla/dom/DOMException.h"
      30             : #include "mozilla/dom/PrimitiveConversions.h"
      31             : #include "mozilla/dom/Promise.h"
      32             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      33             : 
      34             : using namespace xpc;
      35             : using namespace mozilla;
      36             : using namespace mozilla::dom;
      37             : using namespace JS;
      38             : 
      39             : //#define STRICT_CHECK_OF_UNICODE
      40             : #ifdef STRICT_CHECK_OF_UNICODE
      41             : #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80))
      42             : #else // STRICT_CHECK_OF_UNICODE
      43             : #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00))
      44             : #endif // STRICT_CHECK_OF_UNICODE
      45             : 
      46             : #define ILLEGAL_CHAR_RANGE(c) (0!=((c) & 0x80))
      47             : 
      48             : /***********************************************************/
      49             : 
      50             : // static
      51             : bool
      52       11274 : XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info)
      53             : {
      54       11274 :     if (XPT_MD_IS_NOTXPCOM(info.flags) || XPT_MD_IS_HIDDEN(info.flags))
      55         727 :         return false;
      56             : 
      57       30885 :     for (int i = info.num_args-1; i >= 0; i--) {
      58       20340 :         const nsXPTParamInfo& param = info.params[i];
      59       20340 :         const nsXPTType& type = param.GetType();
      60             : 
      61             :         // Reflected methods can't use native types. All native types end up
      62             :         // getting tagged as void*, so this check is easy.
      63       20340 :         if (type.TagPart() == nsXPTType::T_VOID)
      64           2 :             return false;
      65             :     }
      66       10545 :     return true;
      67             : }
      68             : 
      69             : static JSObject*
      70        8009 : UnwrapNativeCPOW(nsISupports* wrapper)
      71             : {
      72       16018 :     nsCOMPtr<nsIXPConnectWrappedJS> underware = do_QueryInterface(wrapper);
      73        8009 :     if (underware) {
      74         119 :         JSObject* mainObj = underware->GetJSObject();
      75         119 :         if (mainObj && mozilla::jsipc::IsWrappedCPOW(mainObj))
      76           0 :             return mainObj;
      77             :     }
      78        8009 :     return nullptr;
      79             : }
      80             : 
      81             : /***************************************************************************/
      82             : 
      83             : // static
      84             : bool
      85        1291 : XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface)
      86             : {
      87        1291 :     const JSClass* jsclass = js::GetObjectJSClass(obj);
      88        1291 :     MOZ_ASSERT(jsclass, "obj has no class");
      89        2582 :     if (jsclass &&
      90        1291 :         (jsclass->flags & JSCLASS_HAS_PRIVATE) &&
      91           0 :         (jsclass->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
      92           0 :         *iface = (nsISupports*) xpc_GetJSPrivate(obj);
      93           0 :         return true;
      94             :     }
      95        1291 :     *iface = UnwrapDOMObjectToISupports(obj);
      96        1291 :     return !!*iface;
      97             : }
      98             : 
      99             : /***************************************************************************/
     100             : 
     101             : // static
     102             : bool
     103       13133 : XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
     104             :                           const nsXPTType& type, const nsID* iid, nsresult* pErr)
     105             : {
     106       13133 :     NS_PRECONDITION(s, "bad param");
     107             : 
     108       26266 :     AutoJSContext cx;
     109       13133 :     if (pErr)
     110        8959 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
     111             : 
     112       13133 :     switch (type.TagPart()) {
     113             :     case nsXPTType::T_I8    :
     114           0 :         d.setInt32(*static_cast<const int8_t*>(s));
     115           0 :         return true;
     116             :     case nsXPTType::T_I16   :
     117           0 :         d.setInt32(*static_cast<const int16_t*>(s));
     118           0 :         return true;
     119             :     case nsXPTType::T_I32   :
     120         339 :         d.setInt32(*static_cast<const int32_t*>(s));
     121         339 :         return true;
     122             :     case nsXPTType::T_I64   :
     123          20 :         d.setNumber(static_cast<double>(*static_cast<const int64_t*>(s)));
     124          20 :         return true;
     125             :     case nsXPTType::T_U8    :
     126        2754 :         d.setInt32(*static_cast<const uint8_t*>(s));
     127        2754 :         return true;
     128             :     case nsXPTType::T_U16   :
     129          11 :         d.setInt32(*static_cast<const uint16_t*>(s));
     130          11 :         return true;
     131             :     case nsXPTType::T_U32   :
     132         153 :         d.setNumber(*static_cast<const uint32_t*>(s));
     133         153 :         return true;
     134             :     case nsXPTType::T_U64   :
     135          23 :         d.setNumber(static_cast<double>(*static_cast<const uint64_t*>(s)));
     136          23 :         return true;
     137             :     case nsXPTType::T_FLOAT :
     138           7 :         d.setNumber(*static_cast<const float*>(s));
     139           7 :         return true;
     140             :     case nsXPTType::T_DOUBLE:
     141          24 :         d.setNumber(*static_cast<const double*>(s));
     142          24 :         return true;
     143             :     case nsXPTType::T_BOOL  :
     144        2597 :         d.setBoolean(*static_cast<const bool*>(s));
     145        2597 :         return true;
     146             :     case nsXPTType::T_CHAR  :
     147             :     {
     148           0 :         char p = *static_cast<const char*>(s);
     149             : 
     150             : #ifdef STRICT_CHECK_OF_UNICODE
     151             :         MOZ_ASSERT(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data");
     152             : #endif // STRICT_CHECK_OF_UNICODE
     153             : 
     154           0 :         JSString* str = JS_NewStringCopyN(cx, &p, 1);
     155           0 :         if (!str)
     156           0 :             return false;
     157             : 
     158           0 :         d.setString(str);
     159           0 :         return true;
     160             :     }
     161             :     case nsXPTType::T_WCHAR :
     162             :     {
     163           0 :         char16_t p = *static_cast<const char16_t*>(s);
     164             : 
     165           0 :         JSString* str = JS_NewUCStringCopyN(cx, &p, 1);
     166           0 :         if (!str)
     167           0 :             return false;
     168             : 
     169           0 :         d.setString(str);
     170           0 :         return true;
     171             :     }
     172             : 
     173             :     case nsXPTType::T_JSVAL :
     174             :     {
     175        1409 :         d.set(*static_cast<const Value*>(s));
     176        1409 :         return JS_WrapValue(cx, d);
     177             :     }
     178             : 
     179             :     case nsXPTType::T_VOID:
     180           0 :         XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
     181           0 :         return false;
     182             : 
     183             :     case nsXPTType::T_IID:
     184             :     {
     185         110 :         nsID* iid2 = *static_cast<nsID* const*>(s);
     186         110 :         if (!iid2) {
     187           0 :             d.setNull();
     188           0 :             return true;
     189             :         }
     190             : 
     191         220 :         RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
     192         110 :         JSObject* obj = xpc_NewIDObject(cx, scope, *iid2);
     193         110 :         if (!obj)
     194           0 :             return false;
     195             : 
     196         110 :         d.setObject(*obj);
     197         110 :         return true;
     198             :     }
     199             : 
     200             :     case nsXPTType::T_ASTRING:
     201             :         // Fall through to T_DOMSTRING case
     202             : 
     203             :     case nsXPTType::T_DOMSTRING:
     204             :     {
     205         256 :         const nsAString* p = *static_cast<const nsAString* const*>(s);
     206         256 :         if (!p || p->IsVoid()) {
     207          19 :             d.setNull();
     208          19 :             return true;
     209             :         }
     210             : 
     211             :         nsStringBuffer* buf;
     212         237 :         if (!XPCStringConvert::ReadableToJSVal(cx, *p, &buf, d))
     213           0 :             return false;
     214         237 :         if (buf)
     215         165 :             buf->AddRef();
     216         237 :         return true;
     217             :     }
     218             : 
     219             :     case nsXPTType::T_CHAR_STR:
     220             :     {
     221        2034 :         const char* p = *static_cast<const char* const*>(s);
     222        2034 :         if (!p) {
     223           3 :             d.setNull();
     224           3 :             return true;
     225             :         }
     226             : 
     227             : #ifdef STRICT_CHECK_OF_UNICODE
     228             :         bool isAscii = true;
     229             :         for (char* t = p; *t && isAscii; t++) {
     230             :           if (ILLEGAL_CHAR_RANGE(*t))
     231             :               isAscii = false;
     232             :         }
     233             :         MOZ_ASSERT(isAscii, "passing non ASCII data");
     234             : #endif // STRICT_CHECK_OF_UNICODE
     235             : 
     236        2031 :         JSString* str = JS_NewStringCopyZ(cx, p);
     237        2031 :         if (!str)
     238           0 :             return false;
     239             : 
     240        2031 :         d.setString(str);
     241        2031 :         return true;
     242             :     }
     243             : 
     244             :     case nsXPTType::T_WCHAR_STR:
     245             :     {
     246         282 :         const char16_t* p = *static_cast<const char16_t* const*>(s);
     247         282 :         if (!p) {
     248          50 :             d.setNull();
     249          50 :             return true;
     250             :         }
     251             : 
     252         232 :         JSString* str = JS_NewUCStringCopyZ(cx, p);
     253         232 :         if (!str)
     254           0 :             return false;
     255             : 
     256         232 :         d.setString(str);
     257         232 :         return true;
     258             :     }
     259             :     case nsXPTType::T_UTF8STRING:
     260             :     {
     261         160 :         const nsACString* utf8String = *static_cast<const nsACString* const*>(s);
     262             : 
     263         160 :         if (!utf8String || utf8String->IsVoid()) {
     264           4 :             d.setNull();
     265           4 :             return true;
     266             :         }
     267             : 
     268         156 :         if (utf8String->IsEmpty()) {
     269           2 :             d.set(JS_GetEmptyStringValue(cx));
     270           2 :             return true;
     271             :         }
     272             : 
     273         154 :         const uint32_t len = CalcUTF8ToUnicodeLength(*utf8String);
     274             :         // The cString is not empty at this point, but the calculated
     275             :         // UTF-16 length is zero, meaning no valid conversion exists.
     276         154 :         if (!len)
     277           0 :             return false;
     278             : 
     279         154 :         const size_t buffer_size = (len + 1) * sizeof(char16_t);
     280             :         char16_t* buffer =
     281         154 :             static_cast<char16_t*>(JS_malloc(cx, buffer_size));
     282         154 :         if (!buffer)
     283           0 :             return false;
     284             : 
     285             :         uint32_t copied;
     286         308 :         if (!UTF8ToUnicodeBuffer(*utf8String, buffer, &copied) ||
     287         154 :             len != copied) {
     288             :             // Copy or conversion during copy failed. Did not copy the
     289             :             // whole string.
     290           0 :             JS_free(cx, buffer);
     291           0 :             return false;
     292             :         }
     293             : 
     294             :         // JS_NewUCString takes ownership on success, i.e. a
     295             :         // successful call will make it the responsiblity of the JS VM
     296             :         // to free the buffer.
     297         154 :         JSString* str = JS_NewUCString(cx, buffer, len);
     298         154 :         if (!str) {
     299           0 :             JS_free(cx, buffer);
     300           0 :             return false;
     301             :         }
     302             : 
     303         154 :         d.setString(str);
     304         154 :         return true;
     305             :     }
     306             :     case nsXPTType::T_CSTRING:
     307             :     {
     308         150 :         const nsACString* cString = *static_cast<const nsACString* const*>(s);
     309             : 
     310         150 :         if (!cString || cString->IsVoid()) {
     311           0 :             d.setNull();
     312           0 :             return true;
     313             :         }
     314             : 
     315             :         // c-strings (binary blobs) are deliberately not converted from
     316             :         // UTF-8 to UTF-16. T_UTF8Sting is for UTF-8 encoded strings
     317             :         // with automatic conversion.
     318         150 :         JSString* str = JS_NewStringCopyN(cx, cString->Data(),
     319         300 :                                           cString->Length());
     320         150 :         if (!str)
     321           0 :             return false;
     322             : 
     323         150 :         d.setString(str);
     324         150 :         return true;
     325             :     }
     326             : 
     327             :     case nsXPTType::T_INTERFACE:
     328             :     case nsXPTType::T_INTERFACE_IS:
     329             :     {
     330        2804 :         nsISupports* iface = *static_cast<nsISupports* const*>(s);
     331        2804 :         if (!iface) {
     332         305 :             d.setNull();
     333         305 :             return true;
     334             :         }
     335             : 
     336        2499 :         if (iid->Equals(NS_GET_IID(nsIVariant))) {
     337          90 :             nsCOMPtr<nsIVariant> variant = do_QueryInterface(iface);
     338          45 :             if (!variant)
     339           0 :                 return false;
     340             : 
     341          45 :             return XPCVariant::VariantDataToJS(variant,
     342          45 :                                                pErr, d);
     343             :         }
     344             : 
     345        4908 :         xpcObjectHelper helper(iface);
     346        2454 :         return NativeInterface2JSObject(d, nullptr, helper, iid, true, pErr);
     347             :     }
     348             : 
     349             :     default:
     350           0 :         NS_ERROR("bad type");
     351           0 :         return false;
     352             :     }
     353             :     return true;
     354             : }
     355             : 
     356             : /***************************************************************************/
     357             : 
     358             : #ifdef DEBUG
     359             : static bool
     360      132286 : CheckChar16InCharRange(char16_t c)
     361             : {
     362      132286 :     if (ILLEGAL_RANGE(c)) {
     363             :         /* U+0080/U+0100 - U+FFFF data lost. */
     364             :         static const size_t MSG_BUF_SIZE = 64;
     365             :         char msg[MSG_BUF_SIZE];
     366           0 :         snprintf(msg, MSG_BUF_SIZE, "char16_t out of char range; high bits of data lost: 0x%x", int(c));
     367           0 :         NS_WARNING(msg);
     368           0 :         return false;
     369             :     }
     370             : 
     371      132286 :     return true;
     372             : }
     373             : 
     374             : template<typename CharT>
     375             : static void
     376        3830 : CheckCharsInCharRange(const CharT* chars, size_t len)
     377             : {
     378      136116 :     for (size_t i = 0; i < len; i++) {
     379      132286 :         if (!CheckChar16InCharRange(chars[i]))
     380           0 :             break;
     381             :     }
     382        3830 : }
     383             : #endif
     384             : 
     385             : template<typename T>
     386        1768 : bool ConvertToPrimitive(JSContext* cx, HandleValue v, T* retval)
     387             : {
     388        1768 :     return ValueToPrimitive<T, eDefault>(cx, v, retval);
     389             : }
     390             : 
     391             : // static
     392             : bool
     393       14879 : XPCConvert::JSData2Native(void* d, HandleValue s,
     394             :                           const nsXPTType& type,
     395             :                           const nsID* iid,
     396             :                           nsresult* pErr)
     397             : {
     398       14879 :     NS_PRECONDITION(d, "bad param");
     399             : 
     400       29757 :     AutoJSContext cx;
     401       14879 :     if (pErr)
     402       14589 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
     403             : 
     404       14879 :     switch (type.TagPart()) {
     405             :     case nsXPTType::T_I8     :
     406           0 :         return ConvertToPrimitive(cx, s, static_cast<int8_t*>(d));
     407             :     case nsXPTType::T_I16    :
     408           6 :         return ConvertToPrimitive(cx, s, static_cast<int16_t*>(d));
     409             :     case nsXPTType::T_I32    :
     410          87 :         return ConvertToPrimitive(cx, s, static_cast<int32_t*>(d));
     411             :     case nsXPTType::T_I64    :
     412           0 :         return ConvertToPrimitive(cx, s, static_cast<int64_t*>(d));
     413             :     case nsXPTType::T_U8     :
     414           0 :         return ConvertToPrimitive(cx, s, static_cast<uint8_t*>(d));
     415             :     case nsXPTType::T_U16    :
     416           6 :         return ConvertToPrimitive(cx, s, static_cast<uint16_t*>(d));
     417             :     case nsXPTType::T_U32    :
     418         117 :         return ConvertToPrimitive(cx, s, static_cast<uint32_t*>(d));
     419             :     case nsXPTType::T_U64    :
     420           0 :         return ConvertToPrimitive(cx, s, static_cast<uint64_t*>(d));
     421             :     case nsXPTType::T_FLOAT  :
     422           4 :         return ConvertToPrimitive(cx, s, static_cast<float*>(d));
     423             :     case nsXPTType::T_DOUBLE :
     424           0 :         return ConvertToPrimitive(cx, s, static_cast<double*>(d));
     425             :     case nsXPTType::T_BOOL   :
     426        1548 :         return ConvertToPrimitive(cx, s, static_cast<bool*>(d));
     427             :     case nsXPTType::T_CHAR   :
     428             :     {
     429           0 :         JSString* str = ToString(cx, s);
     430           0 :         if (!str) {
     431           0 :             return false;
     432             :         }
     433             : 
     434             :         char16_t ch;
     435           0 :         if (JS_GetStringLength(str) == 0) {
     436           0 :             ch = 0;
     437             :         } else {
     438           0 :             if (!JS_GetStringCharAt(cx, str, 0, &ch))
     439           0 :                 return false;
     440             :         }
     441             : #ifdef DEBUG
     442           0 :         CheckChar16InCharRange(ch);
     443             : #endif
     444           0 :         *((char*)d) = char(ch);
     445           0 :         break;
     446             :     }
     447             :     case nsXPTType::T_WCHAR  :
     448             :     {
     449             :         JSString* str;
     450           1 :         if (!(str = ToString(cx, s))) {
     451           0 :             return false;
     452             :         }
     453           1 :         size_t length = JS_GetStringLength(str);
     454           1 :         if (length == 0) {
     455           0 :             *((uint16_t*)d) = 0;
     456           1 :             break;
     457             :         }
     458             : 
     459             :         char16_t ch;
     460           1 :         if (!JS_GetStringCharAt(cx, str, 0, &ch))
     461           0 :             return false;
     462             : 
     463           1 :         *((uint16_t*)d) = uint16_t(ch);
     464           1 :         break;
     465             :     }
     466             :     case nsXPTType::T_JSVAL :
     467        1541 :         *((Value*)d) = s;
     468        1541 :         break;
     469             :     case nsXPTType::T_VOID:
     470           0 :         XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
     471           0 :         NS_ERROR("void* params not supported");
     472           0 :         return false;
     473             :     case nsXPTType::T_IID:
     474             :     {
     475        2399 :         const nsID* pid = nullptr;
     476             : 
     477             :         // There's no good reason to pass a null IID.
     478        2399 :         if (s.isNullOrUndefined()) {
     479           0 :             if (pErr)
     480           0 :                 *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
     481           0 :             return false;
     482             :         }
     483             : 
     484        7197 :         if (!s.isObject() ||
     485        4798 :             (!(pid = xpc_JSObjectToID(cx, &s.toObject()))) ||
     486             :             (!(pid = (const nsID*) nsMemory::Clone(pid, sizeof(nsID))))) {
     487           0 :             return false;
     488             :         }
     489        2399 :         *((const nsID**)d) = pid;
     490        2399 :         return true;
     491             :     }
     492             : 
     493             :     case nsXPTType::T_ASTRING:
     494             :     {
     495         753 :         if (s.isUndefined()) {
     496           0 :             (**((nsAString**)d)).SetIsVoid(true);
     497           0 :             return true;
     498             :         }
     499             :         MOZ_FALLTHROUGH;
     500             :     }
     501             :     case nsXPTType::T_DOMSTRING:
     502             :     {
     503         907 :         if (s.isNull()) {
     504          19 :             (**((nsAString**)d)).SetIsVoid(true);
     505          19 :             return true;
     506             :         }
     507         888 :         size_t length = 0;
     508         888 :         JSString* str = nullptr;
     509         888 :         if (!s.isUndefined()) {
     510         888 :             str = ToString(cx, s);
     511         888 :             if (!str)
     512           0 :                 return false;
     513             : 
     514         888 :             length = JS_GetStringLength(str);
     515         888 :             if (!length) {
     516           3 :                 (**((nsAString**)d)).Truncate();
     517           3 :                 return true;
     518             :             }
     519             :         }
     520             : 
     521         885 :         nsAString* ws = *((nsAString**)d);
     522             : 
     523         885 :         if (!str) {
     524           0 :             ws->AssignLiteral(u"undefined");
     525         885 :         } else if (XPCStringConvert::IsDOMString(str)) {
     526             :             // The characters represent an existing nsStringBuffer that
     527             :             // was shared by XPCStringConvert::ReadableToJSVal.
     528          37 :             const char16_t* chars = JS_GetTwoByteExternalStringChars(str);
     529          37 :             if (chars[length] == '\0') {
     530             :                 // Safe to share the buffer.
     531          37 :                 nsStringBuffer::FromData((void*)chars)->ToString(length, *ws);
     532             :             } else {
     533             :                 // We have to copy to ensure null-termination.
     534           0 :                 ws->Assign(chars, length);
     535             :             }
     536         848 :         } else if (XPCStringConvert::IsLiteral(str)) {
     537             :             // The characters represent a literal char16_t string constant
     538             :             // compiled into libxul, such as the string "undefined" above.
     539           0 :             const char16_t* chars = JS_GetTwoByteExternalStringChars(str);
     540           0 :             ws->AssignLiteral(chars, length);
     541             :         } else {
     542         848 :             if (!AssignJSString(cx, *ws, str))
     543           0 :                 return false;
     544             :         }
     545         885 :         return true;
     546             :     }
     547             : 
     548             :     case nsXPTType::T_CHAR_STR:
     549             :     {
     550        3907 :         if (s.isUndefined() || s.isNull()) {
     551          77 :             *((char**)d) = nullptr;
     552          77 :             return true;
     553             :         }
     554             : 
     555        3830 :         JSString* str = ToString(cx, s);
     556        3830 :         if (!str) {
     557           0 :             return false;
     558             :         }
     559             : #ifdef DEBUG
     560        3830 :         if (JS_StringHasLatin1Chars(str)) {
     561             :             size_t len;
     562        7618 :             AutoCheckCannotGC nogc;
     563        3809 :             const Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &len);
     564        3809 :             if (chars)
     565        3809 :                 CheckCharsInCharRange(chars, len);
     566             :         } else {
     567             :             size_t len;
     568          42 :             AutoCheckCannotGC nogc;
     569          21 :             const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str, &len);
     570          21 :             if (chars)
     571          21 :                 CheckCharsInCharRange(chars, len);
     572             :         }
     573             : #endif // DEBUG
     574        3830 :         size_t length = JS_GetStringEncodingLength(cx, str);
     575        3830 :         if (length == size_t(-1)) {
     576           0 :             return false;
     577             :         }
     578        3830 :         char* buffer = static_cast<char*>(moz_xmalloc(length + 1));
     579        3830 :         if (!buffer) {
     580           0 :             return false;
     581             :         }
     582        3830 :         JS_EncodeStringToBuffer(cx, str, buffer, length);
     583        3830 :         buffer[length] = '\0';
     584        3830 :         *((void**)d) = buffer;
     585        3830 :         return true;
     586             :     }
     587             : 
     588             :     case nsXPTType::T_WCHAR_STR:
     589             :     {
     590             :         JSString* str;
     591             : 
     592          92 :         if (s.isUndefined() || s.isNull()) {
     593          24 :             *((char16_t**)d) = nullptr;
     594          24 :             return true;
     595             :         }
     596             : 
     597          68 :         if (!(str = ToString(cx, s))) {
     598           0 :             return false;
     599             :         }
     600          68 :         int len = JS_GetStringLength(str);
     601          68 :         int byte_len = (len+1)*sizeof(char16_t);
     602          68 :         if (!(*((void**)d) = moz_xmalloc(byte_len))) {
     603             :             // XXX should report error
     604           0 :             return false;
     605             :         }
     606          68 :         mozilla::Range<char16_t> destChars(*((char16_t**)d), len + 1);
     607          68 :         if (!JS_CopyStringChars(cx, destChars, str))
     608           0 :             return false;
     609          68 :         destChars[len] = 0;
     610             : 
     611          68 :         return true;
     612             :     }
     613             : 
     614             :     case nsXPTType::T_UTF8STRING:
     615             :     {
     616        1144 :         if (s.isNull() || s.isUndefined()) {
     617          15 :             nsCString* rs = *((nsCString**)d);
     618          15 :             rs->SetIsVoid(true);
     619          15 :             return true;
     620             :         }
     621             : 
     622             :         // The JS val is neither null nor void...
     623        1129 :         JSString* str = ToString(cx, s);
     624        1129 :         if (!str)
     625           0 :             return false;
     626             : 
     627        1129 :         size_t length = JS_GetStringLength(str);
     628        1129 :         if (!length) {
     629           3 :             nsCString* rs = *((nsCString**)d);
     630           3 :             rs->Truncate();
     631           3 :             return true;
     632             :         }
     633             : 
     634        1126 :         JSFlatString* flat = JS_FlattenString(cx, str);
     635        1126 :         if (!flat)
     636           0 :             return false;
     637             : 
     638        1126 :         size_t utf8Length = JS::GetDeflatedUTF8StringLength(flat);
     639        1126 :         nsACString* rs = *((nsACString**)d);
     640        1126 :         rs->SetLength(utf8Length);
     641             : 
     642        1126 :         JS::DeflateStringToUTF8Buffer(flat, mozilla::RangedPtr<char>(rs->BeginWriting(), utf8Length));
     643             : 
     644        1126 :         return true;
     645             :     }
     646             : 
     647             :     case nsXPTType::T_CSTRING:
     648             :     {
     649          92 :         if (s.isNull() || s.isUndefined()) {
     650           0 :             nsACString* rs = *((nsACString**)d);
     651           0 :             rs->SetIsVoid(true);
     652           0 :             return true;
     653             :         }
     654             : 
     655             :         // The JS val is neither null nor void...
     656          92 :         JSString* str = ToString(cx, s);
     657          92 :         if (!str) {
     658           0 :             return false;
     659             :         }
     660             : 
     661          92 :         size_t length = JS_GetStringEncodingLength(cx, str);
     662          92 :         if (length == size_t(-1)) {
     663           0 :             return false;
     664             :         }
     665             : 
     666          92 :         if (!length) {
     667           2 :             nsCString* rs = *((nsCString**)d);
     668           2 :             rs->Truncate();
     669           2 :             return true;
     670             :         }
     671             : 
     672          90 :         nsACString* rs = *((nsACString**)d);
     673          90 :         rs->SetLength(uint32_t(length));
     674          90 :         if (rs->Length() != uint32_t(length)) {
     675           0 :             return false;
     676             :         }
     677          90 :         JS_EncodeStringToBuffer(cx, str, rs->BeginWriting(), length);
     678             : 
     679          90 :         return true;
     680             :     }
     681             : 
     682             :     case nsXPTType::T_INTERFACE:
     683             :     case nsXPTType::T_INTERFACE_IS:
     684             :     {
     685        3028 :         MOZ_ASSERT(iid,"can't do interface conversions without iid");
     686             : 
     687        3028 :         if (iid->Equals(NS_GET_IID(nsIVariant))) {
     688           6 :             nsCOMPtr<nsIVariant> variant = XPCVariant::newVariant(cx, s);
     689           3 :             if (!variant)
     690           0 :                 return false;
     691             : 
     692           3 :             variant.forget(static_cast<nsISupports**>(d));
     693           3 :             return true;
     694        3025 :         } else if (iid->Equals(NS_GET_IID(nsIAtom)) && s.isString()) {
     695             :             // We're trying to pass a string as an nsIAtom.  Let's atomize!
     696           0 :             JSString* str = s.toString();
     697           0 :             nsAutoJSString autoStr;
     698           0 :             if (!autoStr.init(cx, str)) {
     699           0 :                 if (pErr)
     700           0 :                     *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
     701           0 :                 return false;
     702             :             }
     703           0 :             nsCOMPtr<nsIAtom> atom = NS_Atomize(autoStr);
     704           0 :             atom.forget((nsISupports**)d);
     705           0 :             return true;
     706             :         }
     707             :         //else ...
     708             : 
     709        3025 :         if (s.isNullOrUndefined()) {
     710         143 :             *((nsISupports**)d) = nullptr;
     711         143 :             return true;
     712             :         }
     713             : 
     714             :         // only wrap JSObjects
     715        2882 :         if (!s.isObject()) {
     716           0 :             if (pErr && s.isInt32() && 0 == s.toInt32())
     717           0 :                 *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
     718           0 :             return false;
     719             :         }
     720             : 
     721        5763 :         RootedObject src(cx, &s.toObject());
     722        2882 :         return JSObject2NativeInterface((void**)d, src, iid, nullptr, pErr);
     723             :     }
     724             :     default:
     725           0 :         NS_ERROR("bad type");
     726           0 :         return false;
     727             :     }
     728        1542 :     return true;
     729             : }
     730             : 
     731             : static inline bool
     732         790 : CreateHolderIfNeeded(JSContext* cx, HandleObject obj, MutableHandleValue d,
     733             :                      nsIXPConnectJSObjectHolder** dest)
     734             : {
     735         790 :     if (dest) {
     736           0 :         if (!obj)
     737           0 :             return false;
     738           0 :         RefPtr<XPCJSObjectHolder> objHolder = new XPCJSObjectHolder(cx, obj);
     739           0 :         objHolder.forget(dest);
     740             :     }
     741             : 
     742         790 :     d.setObjectOrNull(obj);
     743             : 
     744         790 :     return true;
     745             : }
     746             : 
     747             : /***************************************************************************/
     748             : // static
     749             : bool
     750        8799 : XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
     751             :                                      nsIXPConnectJSObjectHolder** dest,
     752             :                                      xpcObjectHelper& aHelper,
     753             :                                      const nsID* iid,
     754             :                                      bool allowNativeWrapper,
     755             :                                      nsresult* pErr)
     756             : {
     757        8799 :     if (!iid)
     758         944 :         iid = &NS_GET_IID(nsISupports);
     759             : 
     760        8799 :     d.setNull();
     761        8799 :     if (dest)
     762           2 :         *dest = nullptr;
     763        8799 :     if (!aHelper.Object())
     764           0 :         return true;
     765        8799 :     if (pErr)
     766        8324 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
     767             : 
     768             :     // We used to have code here that unwrapped and simply exposed the
     769             :     // underlying JSObject. That caused anomolies when JSComponents were
     770             :     // accessed from other JS code - they didn't act like other xpconnect
     771             :     // wrapped components. So, instead, we create "double wrapped" objects
     772             :     // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't
     773             :     // optimal -- we could detect this and roll the functionality into a
     774             :     // single wrapper, but the current solution is good enough for now.
     775       17598 :     AutoJSContext cx;
     776        8799 :     XPCWrappedNativeScope* xpcscope = ObjectScope(JS::CurrentGlobalOrNull(cx));
     777        8799 :     if (!xpcscope)
     778           0 :         return false;
     779             : 
     780             :     // First, see if this object supports the wrapper cache.
     781             :     // Note: If |cache->IsDOMBinding()| is true, then it means that the object
     782             :     // implementing it doesn't want a wrapped native as its JS Object, but
     783             :     // instead it provides its own proxy object. In that case, the object
     784             :     // to use is found as cache->GetWrapper(). If that is null, then the
     785             :     // object will create (and fill the cache) from its WrapObject call.
     786        8799 :     nsWrapperCache* cache = aHelper.GetWrapperCache();
     787             : 
     788       17598 :     RootedObject flat(cx, cache ? cache->GetWrapper() : nullptr);
     789        8799 :     if (!flat && cache && cache->IsDOMBinding()) {
     790         468 :         RootedObject global(cx, xpcscope->GetGlobalJSObject());
     791         234 :         js::AssertSameCompartment(cx, global);
     792         234 :         flat = cache->WrapObject(cx, nullptr);
     793         234 :         if (!flat)
     794           0 :             return false;
     795             :     }
     796        8799 :     if (flat) {
     797         790 :         if (allowNativeWrapper && !JS_WrapObject(cx, &flat))
     798           0 :             return false;
     799         790 :         return CreateHolderIfNeeded(cx, flat, d, dest);
     800             :     }
     801             : 
     802        8009 :     if (iid->Equals(NS_GET_IID(nsISupports))) {
     803             :         // Check for a Promise being returned via nsISupports.  In that
     804             :         // situation, we want to dig out its underlying JS object and return
     805             :         // that.
     806        6282 :         RefPtr<Promise> promise = do_QueryObject(aHelper.Object());
     807        3141 :         if (promise) {
     808           0 :             flat = promise->PromiseObj();
     809           0 :             if (!JS_WrapObject(cx, &flat))
     810           0 :                 return false;
     811           0 :             return CreateHolderIfNeeded(cx, flat, d, dest);
     812             :         }
     813             :     }
     814             : 
     815             :     // Don't double wrap CPOWs. This is a temporary measure for compatibility
     816             :     // with objects that don't provide necessary QIs (such as objects under
     817             :     // the new DOM bindings). We expect the other side of the CPOW to have
     818             :     // the appropriate wrappers in place.
     819       16018 :     RootedObject cpow(cx, UnwrapNativeCPOW(aHelper.Object()));
     820        8009 :     if (cpow) {
     821           0 :         if (!JS_WrapObject(cx, &cpow))
     822           0 :             return false;
     823           0 :         d.setObject(*cpow);
     824           0 :         return true;
     825             :     }
     826             : 
     827             :     // Go ahead and create an XPCWrappedNative for this object.
     828             :     RefPtr<XPCNativeInterface> iface =
     829       16018 :         XPCNativeInterface::GetNewOrUsed(iid);
     830        8009 :     if (!iface)
     831           0 :         return false;
     832             : 
     833       16018 :     RefPtr<XPCWrappedNative> wrapper;
     834        8009 :     nsresult rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface,
     835       16018 :                                                  getter_AddRefs(wrapper));
     836        8009 :     if (NS_FAILED(rv) && pErr)
     837           0 :         *pErr = rv;
     838             : 
     839             :     // If creating the wrapped native failed, then return early.
     840        8009 :     if (NS_FAILED(rv) || !wrapper)
     841           0 :         return false;
     842             : 
     843             :     // If we're not creating security wrappers, we can return the
     844             :     // XPCWrappedNative as-is here.
     845        8009 :     flat = wrapper->GetFlatJSObject();
     846        8009 :     if (!allowNativeWrapper) {
     847        3051 :         d.setObjectOrNull(flat);
     848        3051 :         if (dest)
     849           0 :             wrapper.forget(dest);
     850        3051 :         if (pErr)
     851        2772 :             *pErr = NS_OK;
     852        3051 :         return true;
     853             :     }
     854             : 
     855             :     // The call to wrap here handles both cross-compartment and same-compartment
     856             :     // security wrappers.
     857        9916 :     RootedObject original(cx, flat);
     858        4958 :     if (!JS_WrapObject(cx, &flat))
     859           0 :         return false;
     860             : 
     861        4958 :     d.setObjectOrNull(flat);
     862             : 
     863        4958 :     if (dest) {
     864             :         // The wrapper still holds the original flat object.
     865           2 :         if (flat == original) {
     866           2 :             wrapper.forget(dest);
     867             :         } else {
     868           0 :             if (!flat)
     869           0 :                 return false;
     870           0 :             RefPtr<XPCJSObjectHolder> objHolder = new XPCJSObjectHolder(cx, flat);
     871           0 :             objHolder.forget(dest);
     872             :         }
     873             :     }
     874             : 
     875        4958 :     if (pErr)
     876        4842 :         *pErr = NS_OK;
     877             : 
     878        4958 :     return true;
     879             : }
     880             : 
     881             : /***************************************************************************/
     882             : 
     883             : // static
     884             : bool
     885        2949 : XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src,
     886             :                                      const nsID* iid,
     887             :                                      nsISupports* aOuter,
     888             :                                      nsresult* pErr)
     889             : {
     890        2949 :     MOZ_ASSERT(dest, "bad param");
     891        2949 :     MOZ_ASSERT(src, "bad param");
     892        2949 :     MOZ_ASSERT(iid, "bad param");
     893             : 
     894        5897 :     AutoJSContext cx;
     895        5897 :     JSAutoCompartment ac(cx, src);
     896             : 
     897        2949 :     *dest = nullptr;
     898        2949 :      if (pErr)
     899        2789 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
     900             : 
     901             :     nsISupports* iface;
     902             : 
     903        2949 :     if (!aOuter) {
     904             :         // Note that if we have a non-null aOuter then it means that we are
     905             :         // forcing the creation of a wrapper even if the object *is* a
     906             :         // wrappedNative or other wise has 'nsISupportness'.
     907             :         // This allows wrapJSAggregatedToNative to work.
     908             : 
     909             :         // If we're looking at a security wrapper, see now if we're allowed to
     910             :         // pass it to C++. If we are, then fall through to the code below. If
     911             :         // we aren't, throw an exception eagerly.
     912             :         //
     913             :         // NB: It's very important that we _don't_ unwrap in the aOuter case,
     914             :         // because the caller may explicitly want to create the XPCWrappedJS
     915             :         // around a security wrapper. XBL does this with Xrays from the XBL
     916             :         // scope - see nsBindingManager::GetBindingImplementation.
     917             :         //
     918             :         // It's also very important that "inner" be rooted here.
     919             :         RootedObject inner(cx,
     920        5862 :                            js::CheckedUnwrap(src,
     921        7082 :                                              /* stopAtWindowProxy = */ false));
     922        2931 :         if (!inner) {
     923           0 :             if (pErr)
     924           0 :                 *pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     925           0 :             return false;
     926             :         }
     927             : 
     928             :         // Is this really a native xpcom object with a wrapper?
     929        2931 :         XPCWrappedNative* wrappedNative = nullptr;
     930        2931 :         if (IS_WN_REFLECTOR(inner))
     931        1640 :             wrappedNative = XPCWrappedNative::Get(inner);
     932        2931 :         if (wrappedNative) {
     933        1640 :             iface = wrappedNative->GetIdentityObject();
     934        1640 :             return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
     935             :         }
     936             :         // else...
     937             : 
     938             :         // Deal with slim wrappers here.
     939        1291 :         if (GetISupportsFromJSObject(inner ? inner : src, &iface)) {
     940          71 :             if (iface && NS_SUCCEEDED(iface->QueryInterface(*iid, dest))) {
     941          70 :                 return true;
     942             :             }
     943             : 
     944             :             // If that failed, and iid is for mozIDOMWindowProxy, we actually
     945             :             // want the outer!
     946           1 :             if (iid->Equals(NS_GET_IID(mozIDOMWindowProxy))) {
     947           1 :                 if (nsCOMPtr<mozIDOMWindow> inner = do_QueryInterface(iface)) {
     948           1 :                     iface = nsPIDOMWindowInner::From(inner)->GetOuterWindow();
     949           1 :                     return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
     950             :                 }
     951             :             }
     952             : 
     953           0 :             return false;
     954             :         }
     955             : 
     956             :         // Deal with Promises being passed as nsISupports.  In that situation we
     957             :         // want to create a dom::Promise and use that.
     958        1220 :         if (iid->Equals(NS_GET_IID(nsISupports))) {
     959          98 :             RootedObject innerObj(cx, inner);
     960          49 :             if (IsPromiseObject(innerObj)) {
     961           0 :                 nsIGlobalObject* glob = NativeGlobal(innerObj);
     962           0 :                 RefPtr<Promise> p = Promise::CreateFromExisting(glob, innerObj);
     963           0 :                 return p && NS_SUCCEEDED(p->QueryInterface(*iid, dest));
     964             :             }
     965             :         }
     966             :     }
     967             : 
     968        2475 :     RefPtr<nsXPCWrappedJS> wrapper;
     969        1238 :     nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, *iid, getter_AddRefs(wrapper));
     970        1237 :     if (pErr)
     971        1127 :         *pErr = rv;
     972             : 
     973        1237 :     if (NS_FAILED(rv) || !wrapper)
     974           0 :         return false;
     975             : 
     976             :     // If the caller wanted to aggregate this JS object to a native,
     977             :     // attach it to the wrapper. Note that we allow a maximum of one
     978             :     // aggregated native for a given XPCWrappedJS.
     979        1237 :     if (aOuter)
     980          18 :         wrapper->SetAggregatedNativeObject(aOuter);
     981             : 
     982             :     // We need to go through the QueryInterface logic to make this return
     983             :     // the right thing for the various 'special' interfaces; e.g.
     984             :     // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
     985             :     // there is an outer to avoid nasty recursion.
     986        2456 :     rv = aOuter ? wrapper->AggregatedQueryInterface(*iid, dest) :
     987        1219 :         wrapper->QueryInterface(*iid, dest);
     988        1237 :     if (pErr)
     989        1127 :         *pErr = rv;
     990        1237 :     return NS_SUCCEEDED(rv);
     991             : }
     992             : 
     993             : /***************************************************************************/
     994             : /***************************************************************************/
     995             : 
     996             : // static
     997             : nsresult
     998           4 : XPCConvert::ConstructException(nsresult rv, const char* message,
     999             :                                const char* ifaceName, const char* methodName,
    1000             :                                nsISupports* data,
    1001             :                                nsIException** exceptn,
    1002             :                                JSContext* cx,
    1003             :                                Value* jsExceptionPtr)
    1004             : {
    1005           4 :     MOZ_ASSERT(!cx == !jsExceptionPtr, "Expected cx and jsExceptionPtr to cooccur.");
    1006             : 
    1007             :     static const char format[] = "\'%s\' when calling method: [%s::%s]";
    1008           4 :     const char * msg = message;
    1009           8 :     nsXPIDLString xmsg;
    1010           8 :     nsAutoCString sxmsg;
    1011             : 
    1012           8 :     nsCOMPtr<nsIScriptError> errorObject = do_QueryInterface(data);
    1013           4 :     if (errorObject) {
    1014           0 :         if (NS_SUCCEEDED(errorObject->GetMessageMoz(getter_Copies(xmsg)))) {
    1015           0 :             CopyUTF16toUTF8(xmsg, sxmsg);
    1016           0 :             msg = sxmsg.get();
    1017             :         }
    1018             :     }
    1019           4 :     if (!msg)
    1020           0 :         if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &msg) || ! msg)
    1021           0 :             msg = "<error>";
    1022             : 
    1023           8 :     nsCString msgStr(msg);
    1024           4 :     if (ifaceName && methodName)
    1025           4 :         msgStr.AppendPrintf(format, msg, ifaceName, methodName);
    1026             : 
    1027          12 :     RefPtr<Exception> e = new Exception(msgStr, rv, EmptyCString(), nullptr, data);
    1028             : 
    1029           4 :     if (cx && jsExceptionPtr) {
    1030           0 :         e->StowJSVal(*jsExceptionPtr);
    1031             :     }
    1032             : 
    1033           4 :     e.forget(exceptn);
    1034           8 :     return NS_OK;
    1035             : }
    1036             : 
    1037             : /********************************/
    1038             : 
    1039             : class MOZ_STACK_CLASS AutoExceptionRestorer
    1040             : {
    1041             : public:
    1042           0 :     AutoExceptionRestorer(JSContext* cx, const Value& v)
    1043           0 :         : mContext(cx), tvr(cx, v)
    1044             :     {
    1045           0 :         JS_ClearPendingException(mContext);
    1046           0 :     }
    1047             : 
    1048           0 :     ~AutoExceptionRestorer()
    1049           0 :     {
    1050           0 :         JS_SetPendingException(mContext, tvr);
    1051           0 :     }
    1052             : 
    1053             : private:
    1054             :     JSContext * const mContext;
    1055             :     RootedValue tvr;
    1056             : };
    1057             : 
    1058             : static nsresult
    1059           0 : JSErrorToXPCException(const char* toStringResult,
    1060             :                       const char* ifaceName,
    1061             :                       const char* methodName,
    1062             :                       const JSErrorReport* report,
    1063             :                       nsIException** exceptn)
    1064             : {
    1065           0 :     AutoJSContext cx;
    1066           0 :     nsresult rv = NS_ERROR_FAILURE;
    1067           0 :     RefPtr<nsScriptError> data;
    1068           0 :     if (report) {
    1069           0 :         nsAutoString bestMessage;
    1070           0 :         if (report && report->message()) {
    1071           0 :             CopyUTF8toUTF16(report->message().c_str(), bestMessage);
    1072           0 :         } else if (toStringResult) {
    1073           0 :             CopyUTF8toUTF16(toStringResult, bestMessage);
    1074             :         } else {
    1075           0 :             bestMessage.AssignLiteral("JavaScript Error");
    1076             :         }
    1077             : 
    1078           0 :         const char16_t* linebuf = report->linebuf();
    1079             : 
    1080           0 :         data = new nsScriptError();
    1081           0 :         data->InitWithWindowID(
    1082             :             bestMessage,
    1083           0 :             NS_ConvertASCIItoUTF16(report->filename),
    1084           0 :             linebuf ? nsDependentString(linebuf, report->linebufLength()) : EmptyString(),
    1085           0 :             report->lineno,
    1086           0 :             report->tokenOffset(), report->flags,
    1087           0 :             NS_LITERAL_CSTRING("XPConnect JavaScript"),
    1088           0 :             nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
    1089             :     }
    1090             : 
    1091           0 :     if (data) {
    1092           0 :         nsAutoCString formattedMsg;
    1093           0 :         data->ToString(formattedMsg);
    1094             : 
    1095           0 :         rv = XPCConvert::ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS,
    1096             :                                             formattedMsg.get(), ifaceName,
    1097             :                                             methodName,
    1098           0 :                                             static_cast<nsIScriptError*>(data.get()),
    1099           0 :                                             exceptn, nullptr, nullptr);
    1100             :     } else {
    1101             :         rv = XPCConvert::ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR,
    1102             :                                             nullptr, ifaceName, methodName,
    1103           0 :                                             nullptr, exceptn, nullptr, nullptr);
    1104             :     }
    1105           0 :     return rv;
    1106             : }
    1107             : 
    1108             : // static
    1109             : nsresult
    1110           0 : XPCConvert::JSValToXPCException(MutableHandleValue s,
    1111             :                                 const char* ifaceName,
    1112             :                                 const char* methodName,
    1113             :                                 nsIException** exceptn)
    1114             : {
    1115           0 :     AutoJSContext cx;
    1116           0 :     AutoExceptionRestorer aer(cx, s);
    1117             : 
    1118           0 :     if (!s.isPrimitive()) {
    1119             :         // we have a JSObject
    1120           0 :         RootedObject obj(cx, s.toObjectOrNull());
    1121             : 
    1122           0 :         if (!obj) {
    1123           0 :             NS_ERROR("when is an object not an object?");
    1124           0 :             return NS_ERROR_FAILURE;
    1125             :         }
    1126             : 
    1127             :         // is this really a native xpcom object with a wrapper?
    1128           0 :         JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
    1129           0 :         if (!unwrapped)
    1130           0 :             return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
    1131           0 :         if (nsCOMPtr<nsISupports> supports = UnwrapReflectorToISupports(unwrapped)) {
    1132           0 :             nsCOMPtr<nsIException> iface = do_QueryInterface(supports);
    1133           0 :             if (iface) {
    1134             :                 // just pass through the exception (with extra ref and all)
    1135           0 :                 nsCOMPtr<nsIException> temp = iface;
    1136           0 :                 temp.forget(exceptn);
    1137           0 :                 return NS_OK;
    1138             :             } else {
    1139             :                 // it is a wrapped native, but not an exception!
    1140           0 :                 return ConstructException(NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT,
    1141             :                                           nullptr, ifaceName, methodName, supports,
    1142           0 :                                           exceptn, nullptr, nullptr);
    1143             :             }
    1144             :         } else {
    1145             :             // It is a JSObject, but not a wrapped native...
    1146             : 
    1147             :             // If it is an engine Error with an error report then let's
    1148             :             // extract the report and build an xpcexception from that
    1149             :             const JSErrorReport* report;
    1150           0 :             if (nullptr != (report = JS_ErrorFromException(cx, obj))) {
    1151           0 :                 JSAutoByteString toStringResult;
    1152           0 :                 RootedString str(cx, ToString(cx, s));
    1153           0 :                 if (str)
    1154           0 :                     toStringResult.encodeUtf8(cx, str);
    1155           0 :                 return JSErrorToXPCException(toStringResult.ptr(), ifaceName,
    1156           0 :                                              methodName, report, exceptn);
    1157             :             }
    1158             : 
    1159             :             // XXX we should do a check against 'js_ErrorClass' here and
    1160             :             // do the right thing - even though it has no JSErrorReport,
    1161             :             // The fact that it is a JSError exceptions means we can extract
    1162             :             // particular info and our 'result' should reflect that.
    1163             : 
    1164             :             // otherwise we'll just try to convert it to a string
    1165             : 
    1166           0 :             JSString* str = ToString(cx, s);
    1167           0 :             if (!str)
    1168           0 :                 return NS_ERROR_FAILURE;
    1169             : 
    1170           0 :             JSAutoByteString strBytes(cx, str);
    1171           0 :             if (!strBytes)
    1172           0 :                 return NS_ERROR_FAILURE;
    1173             : 
    1174           0 :             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
    1175           0 :                                       strBytes.ptr(), ifaceName, methodName,
    1176           0 :                                       nullptr, exceptn, cx, s.address());
    1177             :         }
    1178             :     }
    1179             : 
    1180           0 :     if (s.isUndefined() || s.isNull()) {
    1181           0 :         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
    1182             :                                   nullptr, ifaceName, methodName, nullptr,
    1183           0 :                                   exceptn, cx, s.address());
    1184             :     }
    1185             : 
    1186           0 :     if (s.isNumber()) {
    1187             :         // lets see if it looks like an nsresult
    1188             :         nsresult rv;
    1189             :         double number;
    1190           0 :         bool isResult = false;
    1191             : 
    1192           0 :         if (s.isInt32()) {
    1193           0 :             rv = (nsresult) s.toInt32();
    1194           0 :             if (NS_FAILED(rv))
    1195           0 :                 isResult = true;
    1196             :             else
    1197           0 :                 number = (double) s.toInt32();
    1198             :         } else {
    1199           0 :             number = s.toDouble();
    1200           0 :             if (number > 0.0 &&
    1201           0 :                 number < (double)0xffffffff &&
    1202           0 :                 0.0 == fmod(number,1)) {
    1203             :                 // Visual Studio 9 doesn't allow casting directly from a
    1204             :                 // double to an enumeration type, contrary to 5.2.9(10) of
    1205             :                 // C++11, so add an intermediate cast.
    1206           0 :                 rv = (nsresult)(uint32_t) number;
    1207           0 :                 if (NS_FAILED(rv))
    1208           0 :                     isResult = true;
    1209             :             }
    1210             :         }
    1211             : 
    1212           0 :         if (isResult)
    1213           0 :             return ConstructException(rv, nullptr, ifaceName, methodName,
    1214           0 :                                       nullptr, exceptn, cx, s.address());
    1215             :         else {
    1216             :             // XXX all this nsISupportsDouble code seems a little redundant
    1217             :             // now that we're storing the Value in the exception...
    1218           0 :             nsCOMPtr<nsISupportsDouble> data;
    1219           0 :             nsCOMPtr<nsIComponentManager> cm;
    1220           0 :             if (NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm))) || !cm ||
    1221           0 :                 NS_FAILED(cm->CreateInstanceByContractID(NS_SUPPORTS_DOUBLE_CONTRACTID,
    1222             :                                                          nullptr,
    1223             :                                                          NS_GET_IID(nsISupportsDouble),
    1224             :                                                          getter_AddRefs(data))))
    1225           0 :                 return NS_ERROR_FAILURE;
    1226           0 :             data->SetData(number);
    1227           0 :             rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nullptr,
    1228           0 :                                     ifaceName, methodName, data, exceptn, cx, s.address());
    1229           0 :             return rv;
    1230             :         }
    1231             :     }
    1232             : 
    1233             :     // otherwise we'll just try to convert it to a string
    1234             :     // Note: e.g., bools get converted to JSStrings by this code.
    1235             : 
    1236           0 :     JSString* str = ToString(cx, s);
    1237           0 :     if (str) {
    1238           0 :         JSAutoByteString strBytes(cx, str);
    1239           0 :         if (!!strBytes) {
    1240           0 :             return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
    1241           0 :                                       strBytes.ptr(), ifaceName, methodName,
    1242           0 :                                       nullptr, exceptn, cx, s.address());
    1243             :         }
    1244             :     }
    1245           0 :     return NS_ERROR_FAILURE;
    1246             : }
    1247             : 
    1248             : /***************************************************************************/
    1249             : 
    1250             : // array fun...
    1251             : 
    1252             : #ifdef POPULATE
    1253             : #undef POPULATE
    1254             : #endif
    1255             : 
    1256             : // static
    1257             : bool
    1258          31 : XPCConvert::NativeArray2JS(MutableHandleValue d, const void** s,
    1259             :                            const nsXPTType& type, const nsID* iid,
    1260             :                            uint32_t count, nsresult* pErr)
    1261             : {
    1262          31 :     NS_PRECONDITION(s, "bad param");
    1263             : 
    1264          62 :     AutoJSContext cx;
    1265             : 
    1266             :     // XXX add support for putting chars in a string rather than an array
    1267             : 
    1268             :     // XXX add support to indicate *which* array element was not convertable
    1269             : 
    1270          62 :     RootedObject array(cx, JS_NewArrayObject(cx, count));
    1271          31 :     if (!array)
    1272           0 :         return false;
    1273             : 
    1274          31 :     if (pErr)
    1275          25 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1276             : 
    1277             :     uint32_t i;
    1278          62 :     RootedValue current(cx, JS::NullValue());
    1279             : 
    1280             : #define POPULATE(_t)                                                                    \
    1281             :     PR_BEGIN_MACRO                                                                      \
    1282             :         for (i = 0; i < count; i++) {                                                   \
    1283             :             if (!NativeData2JS(&current, ((_t*)*s)+i, type, iid, pErr) ||               \
    1284             :                 !JS_DefineElement(cx, array, i, current, JSPROP_ENUMERATE))             \
    1285             :                 return false;                                                           \
    1286             :         }                                                                               \
    1287             :     PR_END_MACRO
    1288             : 
    1289             :     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
    1290             : 
    1291          31 :     switch (type.TagPart()) {
    1292           0 :     case nsXPTType::T_I8            : POPULATE(int8_t);         break;
    1293           0 :     case nsXPTType::T_I16           : POPULATE(int16_t);        break;
    1294           0 :     case nsXPTType::T_I32           : POPULATE(int32_t);        break;
    1295           0 :     case nsXPTType::T_I64           : POPULATE(int64_t);        break;
    1296           1 :     case nsXPTType::T_U8            : POPULATE(uint8_t);        break;
    1297           0 :     case nsXPTType::T_U16           : POPULATE(uint16_t);       break;
    1298           0 :     case nsXPTType::T_U32           : POPULATE(uint32_t);       break;
    1299           0 :     case nsXPTType::T_U64           : POPULATE(uint64_t);       break;
    1300           0 :     case nsXPTType::T_FLOAT         : POPULATE(float);          break;
    1301           0 :     case nsXPTType::T_DOUBLE        : POPULATE(double);         break;
    1302           0 :     case nsXPTType::T_BOOL          : POPULATE(bool);           break;
    1303           0 :     case nsXPTType::T_CHAR          : POPULATE(char);           break;
    1304           0 :     case nsXPTType::T_WCHAR         : POPULATE(char16_t);       break;
    1305           0 :     case nsXPTType::T_VOID          : NS_ERROR("bad type");     return false;
    1306           0 :     case nsXPTType::T_IID           : POPULATE(nsID*);          break;
    1307           0 :     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type");     return false;
    1308          27 :     case nsXPTType::T_CHAR_STR      : POPULATE(char*);          break;
    1309           0 :     case nsXPTType::T_WCHAR_STR     : POPULATE(char16_t*);      break;
    1310           3 :     case nsXPTType::T_INTERFACE     : POPULATE(nsISupports*);   break;
    1311           0 :     case nsXPTType::T_INTERFACE_IS  : POPULATE(nsISupports*);   break;
    1312           0 :     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type");     return false;
    1313           0 :     case nsXPTType::T_CSTRING       : NS_ERROR("bad type");     return false;
    1314           0 :     case nsXPTType::T_ASTRING       : NS_ERROR("bad type");     return false;
    1315           0 :     default                         : NS_ERROR("bad type");     return false;
    1316             :     }
    1317             : 
    1318          31 :     if (pErr)
    1319          25 :         *pErr = NS_OK;
    1320          31 :     d.setObject(*array);
    1321          31 :     return true;
    1322             : 
    1323             : #undef POPULATE
    1324             : }
    1325             : 
    1326             : 
    1327             : 
    1328             : // Check that the tag part of the type matches the type
    1329             : // of the array. If the check succeeds, check that the size
    1330             : // of the output does not exceed UINT32_MAX bytes. Allocate
    1331             : // the memory and copy the elements by memcpy.
    1332             : static void*
    1333           0 : CheckTargetAndPopulate(const nsXPTType& type,
    1334             :                        uint8_t requiredType,
    1335             :                        size_t typeSize,
    1336             :                        uint32_t count,
    1337             :                        JSObject* tArr,
    1338             :                        nsresult* pErr)
    1339             : {
    1340             :     // Check that the element type expected by the interface matches
    1341             :     // the type of the elements in the typed array exactly, including
    1342             :     // signedness.
    1343           0 :     if (type.TagPart() != requiredType) {
    1344           0 :         if (pErr)
    1345           0 :             *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1346             : 
    1347           0 :         return nullptr;
    1348             :     }
    1349             : 
    1350             :     // Calculate the maximum number of elements that can fit in
    1351             :     // UINT32_MAX bytes.
    1352           0 :     size_t max = UINT32_MAX / typeSize;
    1353             : 
    1354             :     // This could overflow on 32-bit systems so check max first.
    1355           0 :     size_t byteSize = count * typeSize;
    1356           0 :     if (count > max) {
    1357           0 :         if (pErr)
    1358           0 :             *pErr = NS_ERROR_OUT_OF_MEMORY;
    1359             : 
    1360           0 :         return nullptr;
    1361             :     }
    1362             : 
    1363           0 :     JS::AutoCheckCannotGC nogc;
    1364             :     bool isShared;
    1365           0 :     void* buf = JS_GetArrayBufferViewData(tArr, &isShared, nogc);
    1366             : 
    1367             :     // Require opting in to shared memory - a future project.
    1368           0 :     if (isShared) {
    1369           0 :         if (pErr)
    1370           0 :             *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1371             : 
    1372           0 :         return nullptr;
    1373             :     }
    1374             : 
    1375           0 :     void* output = moz_xmalloc(byteSize);
    1376             : 
    1377           0 :     memcpy(output, buf, byteSize);
    1378           0 :     return output;
    1379             : }
    1380             : 
    1381             : // Fast conversion of typed arrays to native using memcpy.
    1382             : // No float or double canonicalization is done. Called by
    1383             : // JSarray2Native whenever a TypedArray is met. ArrayBuffers
    1384             : // are not accepted; create a properly typed array view on them
    1385             : // first. The element type of array must match the XPCOM
    1386             : // type in size, type and signedness exactly. As an exception,
    1387             : // Uint8ClampedArray is allowed for arrays of uint8_t. DataViews
    1388             : // are not supported.
    1389             : 
    1390             : // static
    1391             : bool
    1392           0 : XPCConvert::JSTypedArray2Native(void** d,
    1393             :                                 JSObject* jsArray,
    1394             :                                 uint32_t count,
    1395             :                                 const nsXPTType& type,
    1396             :                                 nsresult* pErr)
    1397             : {
    1398           0 :     MOZ_ASSERT(jsArray, "bad param");
    1399           0 :     MOZ_ASSERT(d, "bad param");
    1400           0 :     MOZ_ASSERT(JS_IsTypedArrayObject(jsArray), "not a typed array");
    1401             : 
    1402             :     // Check the actual length of the input array against the
    1403             :     // given size_is.
    1404           0 :     uint32_t len = JS_GetTypedArrayLength(jsArray);
    1405           0 :     if (len < count) {
    1406           0 :         if (pErr)
    1407           0 :             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1408             : 
    1409           0 :         return false;
    1410             :     }
    1411             : 
    1412           0 :     void* output = nullptr;
    1413             : 
    1414           0 :     switch (JS_GetArrayBufferViewType(jsArray)) {
    1415             :     case js::Scalar::Int8:
    1416           0 :         output = CheckTargetAndPopulate(nsXPTType::T_I8, type,
    1417             :                                         sizeof(int8_t), count,
    1418           0 :                                         jsArray, pErr);
    1419           0 :         if (!output) {
    1420           0 :             return false;
    1421             :         }
    1422           0 :         break;
    1423             : 
    1424             :     case js::Scalar::Uint8:
    1425             :     case js::Scalar::Uint8Clamped:
    1426           0 :         output = CheckTargetAndPopulate(nsXPTType::T_U8, type,
    1427             :                                         sizeof(uint8_t), count,
    1428           0 :                                         jsArray, pErr);
    1429           0 :         if (!output) {
    1430           0 :             return false;
    1431             :         }
    1432           0 :         break;
    1433             : 
    1434             :     case js::Scalar::Int16:
    1435           0 :         output = CheckTargetAndPopulate(nsXPTType::T_I16, type,
    1436             :                                         sizeof(int16_t), count,
    1437           0 :                                         jsArray, pErr);
    1438           0 :         if (!output) {
    1439           0 :             return false;
    1440             :         }
    1441           0 :         break;
    1442             : 
    1443             :     case js::Scalar::Uint16:
    1444           0 :         output = CheckTargetAndPopulate(nsXPTType::T_U16, type,
    1445             :                                         sizeof(uint16_t), count,
    1446           0 :                                         jsArray, pErr);
    1447           0 :         if (!output) {
    1448           0 :             return false;
    1449             :         }
    1450           0 :         break;
    1451             : 
    1452             :     case js::Scalar::Int32:
    1453           0 :         output = CheckTargetAndPopulate(nsXPTType::T_I32, type,
    1454             :                                         sizeof(int32_t), count,
    1455           0 :                                         jsArray, pErr);
    1456           0 :         if (!output) {
    1457           0 :             return false;
    1458             :         }
    1459           0 :         break;
    1460             : 
    1461             :     case js::Scalar::Uint32:
    1462           0 :         output = CheckTargetAndPopulate(nsXPTType::T_U32, type,
    1463             :                                         sizeof(uint32_t), count,
    1464           0 :                                         jsArray, pErr);
    1465           0 :         if (!output) {
    1466           0 :             return false;
    1467             :         }
    1468           0 :         break;
    1469             : 
    1470             :     case js::Scalar::Float32:
    1471           0 :         output = CheckTargetAndPopulate(nsXPTType::T_FLOAT, type,
    1472             :                                         sizeof(float), count,
    1473           0 :                                         jsArray, pErr);
    1474           0 :         if (!output) {
    1475           0 :             return false;
    1476             :         }
    1477           0 :         break;
    1478             : 
    1479             :     case js::Scalar::Float64:
    1480           0 :         output = CheckTargetAndPopulate(nsXPTType::T_DOUBLE, type,
    1481             :                                         sizeof(double), count,
    1482           0 :                                         jsArray, pErr);
    1483           0 :         if (!output) {
    1484           0 :             return false;
    1485             :         }
    1486           0 :         break;
    1487             : 
    1488             :     // Yet another array type was defined? It is not supported yet...
    1489             :     default:
    1490           0 :         if (pErr)
    1491           0 :             *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1492             : 
    1493           0 :         return false;
    1494             :     }
    1495             : 
    1496           0 :     *d = output;
    1497           0 :     if (pErr)
    1498           0 :         *pErr = NS_OK;
    1499             : 
    1500           0 :     return true;
    1501             : }
    1502             : 
    1503             : // static
    1504             : bool
    1505           7 : XPCConvert::JSArray2Native(void** d, HandleValue s,
    1506             :                            uint32_t count, const nsXPTType& type,
    1507             :                            const nsID* iid, nsresult* pErr)
    1508             : {
    1509           7 :     MOZ_ASSERT(d, "bad param");
    1510             : 
    1511          14 :     AutoJSContext cx;
    1512             : 
    1513             :     // XXX add support for getting chars from strings
    1514             : 
    1515             :     // XXX add support to indicate *which* array element was not convertable
    1516             : 
    1517           7 :     if (s.isNullOrUndefined()) {
    1518           0 :         if (0 != count) {
    1519           0 :             if (pErr)
    1520           0 :                 *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1521           0 :             return false;
    1522             :         }
    1523             : 
    1524           0 :         *d = nullptr;
    1525           0 :         return true;
    1526             :     }
    1527             : 
    1528           7 :     if (!s.isObject()) {
    1529           0 :         if (pErr)
    1530           0 :             *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
    1531           0 :         return false;
    1532             :     }
    1533             : 
    1534          14 :     RootedObject jsarray(cx, &s.toObject());
    1535             : 
    1536             :     // If this is a typed array, then try a fast conversion with memcpy.
    1537           7 :     if (JS_IsTypedArrayObject(jsarray)) {
    1538           0 :         return JSTypedArray2Native(d, jsarray, count, type, pErr);
    1539             :     }
    1540             : 
    1541             :     bool isArray;
    1542           7 :     if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray) {
    1543           0 :         if (pErr)
    1544           0 :             *pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
    1545           0 :         return false;
    1546             :     }
    1547             : 
    1548             :     uint32_t len;
    1549           7 :     if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
    1550           0 :         if (pErr)
    1551           0 :             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
    1552           0 :         return false;
    1553             :     }
    1554             : 
    1555           7 :     if (pErr)
    1556           7 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
    1557             : 
    1558             : #define POPULATE(_mode, _t)                                                    \
    1559             :     PR_BEGIN_MACRO                                                             \
    1560             :         cleanupMode = _mode;                                                   \
    1561             :         size_t max = UINT32_MAX / sizeof(_t);                                  \
    1562             :         if (count > max ||                                                     \
    1563             :             nullptr == (array = moz_xmalloc(count * sizeof(_t)))) {            \
    1564             :             if (pErr)                                                          \
    1565             :                 *pErr = NS_ERROR_OUT_OF_MEMORY;                                \
    1566             :             goto failure;                                                      \
    1567             :         }                                                                      \
    1568             :         for (initedCount = 0; initedCount < count; initedCount++) {            \
    1569             :             if (!JS_GetElement(cx, jsarray, initedCount, &current) ||          \
    1570             :                 !JSData2Native(((_t*)array)+initedCount, current, type,        \
    1571             :                                iid, pErr))                                     \
    1572             :                 goto failure;                                                  \
    1573             :         }                                                                      \
    1574             :     PR_END_MACRO
    1575             : 
    1576             :     // No Action, FRee memory, RElease object
    1577             :     enum CleanupMode {na, fr, re};
    1578             : 
    1579             :     CleanupMode cleanupMode;
    1580             : 
    1581           7 :     void* array = nullptr;
    1582             :     uint32_t initedCount;
    1583          14 :     RootedValue current(cx);
    1584             : 
    1585             :     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
    1586             :     // XXX make extra space at end of char* and wchar* and null termintate
    1587             : 
    1588           7 :     switch (type.TagPart()) {
    1589           0 :     case nsXPTType::T_I8            : POPULATE(na, int8_t);         break;
    1590           0 :     case nsXPTType::T_I16           : POPULATE(na, int16_t);        break;
    1591           0 :     case nsXPTType::T_I32           : POPULATE(na, int32_t);        break;
    1592           0 :     case nsXPTType::T_I64           : POPULATE(na, int64_t);        break;
    1593           0 :     case nsXPTType::T_U8            : POPULATE(na, uint8_t);        break;
    1594           0 :     case nsXPTType::T_U16           : POPULATE(na, uint16_t);       break;
    1595           0 :     case nsXPTType::T_U32           : POPULATE(na, uint32_t);       break;
    1596           0 :     case nsXPTType::T_U64           : POPULATE(na, uint64_t);       break;
    1597           0 :     case nsXPTType::T_FLOAT         : POPULATE(na, float);          break;
    1598           0 :     case nsXPTType::T_DOUBLE        : POPULATE(na, double);         break;
    1599           0 :     case nsXPTType::T_BOOL          : POPULATE(na, bool);           break;
    1600           0 :     case nsXPTType::T_CHAR          : POPULATE(na, char);           break;
    1601           0 :     case nsXPTType::T_WCHAR         : POPULATE(na, char16_t);       break;
    1602           0 :     case nsXPTType::T_VOID          : NS_ERROR("bad type");         goto failure;
    1603           0 :     case nsXPTType::T_IID           : POPULATE(fr, nsID*);          break;
    1604           0 :     case nsXPTType::T_DOMSTRING     : NS_ERROR("bad type");         goto failure;
    1605           0 :     case nsXPTType::T_CHAR_STR      : POPULATE(fr, char*);          break;
    1606           4 :     case nsXPTType::T_WCHAR_STR     : POPULATE(fr, char16_t*);      break;
    1607           3 :     case nsXPTType::T_INTERFACE     : POPULATE(re, nsISupports*);   break;
    1608           0 :     case nsXPTType::T_INTERFACE_IS  : POPULATE(re, nsISupports*);   break;
    1609           0 :     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type");         goto failure;
    1610           0 :     case nsXPTType::T_CSTRING       : NS_ERROR("bad type");         goto failure;
    1611           0 :     case nsXPTType::T_ASTRING       : NS_ERROR("bad type");         goto failure;
    1612           0 :     default                         : NS_ERROR("bad type");         goto failure;
    1613             :     }
    1614             : 
    1615           7 :     *d = array;
    1616           7 :     if (pErr)
    1617           7 :         *pErr = NS_OK;
    1618           7 :     return true;
    1619             : 
    1620             : failure:
    1621             :     // we may need to cleanup the partially filled array of converted stuff
    1622           0 :     if (array) {
    1623           0 :         if (cleanupMode == re) {
    1624           0 :             nsISupports** a = (nsISupports**) array;
    1625           0 :             for (uint32_t i = 0; i < initedCount; i++) {
    1626           0 :                 nsISupports* p = a[i];
    1627           0 :                 NS_IF_RELEASE(p);
    1628             :             }
    1629           0 :         } else if (cleanupMode == fr) {
    1630           0 :             void** a = (void**) array;
    1631           0 :             for (uint32_t i = 0; i < initedCount; i++) {
    1632           0 :                 void* p = a[i];
    1633           0 :                 if (p) free(p);
    1634             :             }
    1635             :         }
    1636           0 :         free(array);
    1637             :     }
    1638             : 
    1639           0 :     return false;
    1640             : 
    1641             : #undef POPULATE
    1642             : }
    1643             : 
    1644             : // static
    1645             : bool
    1646           0 : XPCConvert::NativeStringWithSize2JS(MutableHandleValue d, const void* s,
    1647             :                                     const nsXPTType& type,
    1648             :                                     uint32_t count,
    1649             :                                     nsresult* pErr)
    1650             : {
    1651           0 :     NS_PRECONDITION(s, "bad param");
    1652             : 
    1653           0 :     AutoJSContext cx;
    1654           0 :     if (pErr)
    1655           0 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1656             : 
    1657           0 :     switch (type.TagPart()) {
    1658             :         case nsXPTType::T_PSTRING_SIZE_IS:
    1659             :         {
    1660           0 :             char* p = *((char**)s);
    1661           0 :             if (!p)
    1662           0 :                 break;
    1663             :             JSString* str;
    1664           0 :             if (!(str = JS_NewStringCopyN(cx, p, count)))
    1665           0 :                 return false;
    1666           0 :             d.setString(str);
    1667           0 :             break;
    1668             :         }
    1669             :         case nsXPTType::T_PWSTRING_SIZE_IS:
    1670             :         {
    1671           0 :             char16_t* p = *((char16_t**)s);
    1672           0 :             if (!p)
    1673           0 :                 break;
    1674             :             JSString* str;
    1675           0 :             if (!(str = JS_NewUCStringCopyN(cx, p, count)))
    1676           0 :                 return false;
    1677           0 :             d.setString(str);
    1678           0 :             break;
    1679             :         }
    1680             :         default:
    1681           0 :             XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
    1682           0 :             return false;
    1683             :     }
    1684           0 :     return true;
    1685             : }
    1686             : 
    1687             : // static
    1688             : bool
    1689           0 : XPCConvert::JSStringWithSize2Native(void* d, HandleValue s,
    1690             :                                     uint32_t count, const nsXPTType& type,
    1691             :                                     nsresult* pErr)
    1692             : {
    1693           0 :     NS_PRECONDITION(!s.isNull(), "bad param");
    1694           0 :     NS_PRECONDITION(d, "bad param");
    1695             : 
    1696           0 :     AutoJSContext cx;
    1697             :     uint32_t len;
    1698             : 
    1699           0 :     if (pErr)
    1700           0 :         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
    1701             : 
    1702           0 :     switch (type.TagPart()) {
    1703             :         case nsXPTType::T_PSTRING_SIZE_IS:
    1704             :         {
    1705           0 :             if (s.isUndefined() || s.isNull()) {
    1706           0 :                 if (0 != count) {
    1707           0 :                     if (pErr)
    1708           0 :                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    1709           0 :                     return false;
    1710             :                 }
    1711           0 :                 if (0 != count) {
    1712           0 :                     len = (count + 1) * sizeof(char);
    1713           0 :                     if (!(*((void**)d) = moz_xmalloc(len)))
    1714           0 :                         return false;
    1715           0 :                     return true;
    1716             :                 }
    1717             :                 // else ...
    1718             : 
    1719           0 :                 *((char**)d) = nullptr;
    1720           0 :                 return true;
    1721             :             }
    1722             : 
    1723           0 :             JSString* str = ToString(cx, s);
    1724           0 :             if (!str) {
    1725           0 :                 return false;
    1726             :             }
    1727             : 
    1728           0 :             size_t length = JS_GetStringEncodingLength(cx, str);
    1729           0 :             if (length == size_t(-1)) {
    1730           0 :                 return false;
    1731             :             }
    1732           0 :             if (length > count) {
    1733           0 :                 if (pErr)
    1734           0 :                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    1735           0 :                 return false;
    1736             :             }
    1737           0 :             len = uint32_t(length);
    1738             : 
    1739           0 :             if (len < count)
    1740           0 :                 len = count;
    1741             : 
    1742           0 :             uint32_t alloc_len = (len + 1) * sizeof(char);
    1743           0 :             char* buffer = static_cast<char*>(moz_xmalloc(alloc_len));
    1744           0 :             if (!buffer) {
    1745           0 :                 return false;
    1746             :             }
    1747           0 :             JS_EncodeStringToBuffer(cx, str, buffer, len);
    1748           0 :             buffer[len] = '\0';
    1749           0 :             *((char**)d) = buffer;
    1750             : 
    1751           0 :             return true;
    1752             :         }
    1753             : 
    1754             :         case nsXPTType::T_PWSTRING_SIZE_IS:
    1755             :         {
    1756             :             JSString* str;
    1757             : 
    1758           0 :             if (s.isUndefined() || s.isNull()) {
    1759           0 :                 if (0 != count) {
    1760           0 :                     if (pErr)
    1761           0 :                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    1762           0 :                     return false;
    1763             :                 }
    1764             : 
    1765           0 :                 if (0 != count) {
    1766           0 :                     len = (count + 1) * sizeof(char16_t);
    1767           0 :                     if (!(*((void**)d) = moz_xmalloc(len)))
    1768           0 :                         return false;
    1769           0 :                     return true;
    1770             :                 }
    1771             : 
    1772             :                 // else ...
    1773           0 :                 *((const char16_t**)d) = nullptr;
    1774           0 :                 return true;
    1775             :             }
    1776             : 
    1777           0 :             if (!(str = ToString(cx, s))) {
    1778           0 :                 return false;
    1779             :             }
    1780             : 
    1781           0 :             len = JS_GetStringLength(str);
    1782           0 :             if (len > count) {
    1783           0 :                 if (pErr)
    1784           0 :                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
    1785           0 :                 return false;
    1786             :             }
    1787             : 
    1788           0 :             len = count;
    1789             : 
    1790           0 :             uint32_t alloc_len = (len + 1) * sizeof(char16_t);
    1791           0 :             if (!(*((void**)d) = moz_xmalloc(alloc_len))) {
    1792             :                 // XXX should report error
    1793           0 :                 return false;
    1794             :             }
    1795           0 :             mozilla::Range<char16_t> destChars(*((char16_t**)d), len + 1);
    1796           0 :             if (!JS_CopyStringChars(cx, destChars, str))
    1797           0 :                 return false;
    1798           0 :             destChars[count] = 0;
    1799             : 
    1800           0 :             return true;
    1801             :         }
    1802             :         default:
    1803           0 :             XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
    1804           0 :             return false;
    1805             :     }
    1806             : }

Generated by: LCOV version 1.13