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/. */
7 /* Data conversion between native and JavaScript types. */
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/Range.h"
12 #include "xpcprivate.h"
14 #include "nsWrapperCache.h"
15 #include "nsJSUtils.h"
16 #include "WrapperFactory.h"
18 #include "nsWrapperCacheInlines.h"
21 #include "jsfriendapi.h"
22 #include "js/CharacterEncoding.h"
24 #include "JavaScriptParent.h"
26 #include "mozilla/dom/BindingUtils.h"
27 #include "mozilla/dom/DOMException.h"
28 #include "mozilla/dom/PrimitiveConversions.h"
31 using namespace mozilla
;
32 using namespace mozilla::dom
;
35 //#define STRICT_CHECK_OF_UNICODE
36 #ifdef STRICT_CHECK_OF_UNICODE
37 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80))
38 #else // STRICT_CHECK_OF_UNICODE
39 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00))
40 #endif // STRICT_CHECK_OF_UNICODE
42 #define ILLEGAL_CHAR_RANGE(c) (0!=((c) & 0x80))
44 /***********************************************************/
48 XPCConvert::IsMethodReflectable(const XPTMethodDescriptor
& info
)
50 if (XPT_MD_IS_NOTXPCOM(info
.flags
) || XPT_MD_IS_HIDDEN(info
.flags
))
53 for (int i
= info
.num_args
-1; i
>= 0; i
--) {
54 const nsXPTParamInfo
& param
= info
.params
[i
];
55 const nsXPTType
& type
= param
.GetType();
57 // Reflected methods can't use native types. All native types end up
58 // getting tagged as void*, so this check is easy.
59 if (type
.TagPart() == nsXPTType::T_VOID
)
66 UnwrapNativeCPOW(nsISupports
* wrapper
)
68 nsCOMPtr
<nsIXPConnectWrappedJS
> underware
= do_QueryInterface(wrapper
);
70 JSObject
* mainObj
= underware
->GetJSObject();
71 if (mainObj
&& mozilla::jsipc::IsWrappedCPOW(mainObj
))
77 /***************************************************************************/
81 XPCConvert::GetISupportsFromJSObject(JSObject
* obj
, nsISupports
** iface
)
83 const JSClass
* jsclass
= js::GetObjectJSClass(obj
);
84 MOZ_ASSERT(jsclass
, "obj has no class");
86 (jsclass
->flags
& JSCLASS_HAS_PRIVATE
) &&
87 (jsclass
->flags
& JSCLASS_PRIVATE_IS_NSISUPPORTS
)) {
88 *iface
= (nsISupports
*) xpc_GetJSPrivate(obj
);
91 *iface
= UnwrapDOMObjectToISupports(obj
);
95 /***************************************************************************/
99 XPCConvert::NativeData2JS(MutableHandleValue d
, const void* s
,
100 const nsXPTType
& type
, const nsID
* iid
, nsresult
* pErr
)
102 NS_PRECONDITION(s
, "bad param");
106 *pErr
= NS_ERROR_XPC_BAD_CONVERT_NATIVE
;
108 switch (type
.TagPart()) {
109 case nsXPTType::T_I8
:
110 d
.setInt32(*static_cast<const int8_t*>(s
));
112 case nsXPTType::T_I16
:
113 d
.setInt32(*static_cast<const int16_t*>(s
));
115 case nsXPTType::T_I32
:
116 d
.setInt32(*static_cast<const int32_t*>(s
));
118 case nsXPTType::T_I64
:
119 d
.setNumber(static_cast<double>(*static_cast<const int64_t*>(s
)));
121 case nsXPTType::T_U8
:
122 d
.setInt32(*static_cast<const uint8_t*>(s
));
124 case nsXPTType::T_U16
:
125 d
.setInt32(*static_cast<const uint16_t*>(s
));
127 case nsXPTType::T_U32
:
128 d
.setNumber(*static_cast<const uint32_t*>(s
));
130 case nsXPTType::T_U64
:
131 d
.setNumber(static_cast<double>(*static_cast<const uint64_t*>(s
)));
133 case nsXPTType::T_FLOAT
:
134 d
.setNumber(*static_cast<const float*>(s
));
136 case nsXPTType::T_DOUBLE
:
137 d
.setNumber(*static_cast<const double*>(s
));
139 case nsXPTType::T_BOOL
:
140 d
.setBoolean(*static_cast<const bool*>(s
));
142 case nsXPTType::T_CHAR
:
144 char p
= *static_cast<const char*>(s
);
146 #ifdef STRICT_CHECK_OF_UNICODE
147 MOZ_ASSERT(! ILLEGAL_CHAR_RANGE(p
) , "passing non ASCII data");
148 #endif // STRICT_CHECK_OF_UNICODE
150 JSString
* str
= JS_NewStringCopyN(cx
, &p
, 1);
157 case nsXPTType::T_WCHAR
:
159 jschar p
= *static_cast<const jschar
*>(s
);
161 JSString
* str
= JS_NewUCStringCopyN(cx
, &p
, 1);
169 case nsXPTType::T_JSVAL
:
171 d
.set(*static_cast<const Value
*>(s
));
172 return JS_WrapValue(cx
, d
);
175 case nsXPTType::T_VOID
:
176 XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
179 case nsXPTType::T_IID
:
181 nsID
* iid2
= *static_cast<nsID
* const*>(s
);
187 RootedObject
scope(cx
, JS::CurrentGlobalOrNull(cx
));
188 JSObject
* obj
= xpc_NewIDObject(cx
, scope
, *iid2
);
196 case nsXPTType::T_ASTRING
:
197 // Fall through to T_DOMSTRING case
199 case nsXPTType::T_DOMSTRING
:
201 const nsAString
* p
= *static_cast<const nsAString
* const*>(s
);
202 if (!p
|| p
->IsVoid()) {
208 if (!XPCStringConvert::ReadableToJSVal(cx
, *p
, &buf
, d
))
215 case nsXPTType::T_CHAR_STR
:
217 const char* p
= *static_cast<const char* const*>(s
);
223 #ifdef STRICT_CHECK_OF_UNICODE
225 for (char* t
= p
; *t
&& isAscii
; t
++) {
226 if (ILLEGAL_CHAR_RANGE(*t
))
229 MOZ_ASSERT(isAscii
, "passing non ASCII data");
230 #endif // STRICT_CHECK_OF_UNICODE
232 JSString
* str
= JS_NewStringCopyZ(cx
, p
);
240 case nsXPTType::T_WCHAR_STR
:
242 const jschar
* p
= *static_cast<const jschar
* const*>(s
);
248 JSString
* str
= JS_NewUCStringCopyZ(cx
, p
);
255 case nsXPTType::T_UTF8STRING
:
257 const nsACString
* utf8String
= *static_cast<const nsACString
* const*>(s
);
259 if (!utf8String
|| utf8String
->IsVoid()) {
264 if (utf8String
->IsEmpty()) {
265 d
.set(JS_GetEmptyStringValue(cx
));
269 const uint32_t len
= CalcUTF8ToUnicodeLength(*utf8String
);
270 // The cString is not empty at this point, but the calculated
271 // UTF-16 length is zero, meaning no valid conversion exists.
275 const size_t buffer_size
= (len
+ 1) * sizeof(char16_t
);
277 static_cast<char16_t
*>(JS_malloc(cx
, buffer_size
));
282 if (!UTF8ToUnicodeBuffer(*utf8String
, buffer
, &copied
) ||
284 // Copy or conversion during copy failed. Did not copy the
290 // JS_NewUCString takes ownership on success, i.e. a
291 // successful call will make it the responsiblity of the JS VM
292 // to free the buffer.
293 JSString
* str
= JS_NewUCString(cx
, buffer
, len
);
302 case nsXPTType::T_CSTRING
:
304 const nsACString
* cString
= *static_cast<const nsACString
* const*>(s
);
306 if (!cString
|| cString
->IsVoid()) {
311 // c-strings (binary blobs) are deliberately not converted from
312 // UTF-8 to UTF-16. T_UTF8Sting is for UTF-8 encoded strings
313 // with automatic conversion.
314 JSString
* str
= JS_NewStringCopyN(cx
, cString
->Data(),
323 case nsXPTType::T_INTERFACE
:
324 case nsXPTType::T_INTERFACE_IS
:
326 nsISupports
* iface
= *static_cast<nsISupports
* const*>(s
);
332 if (iid
->Equals(NS_GET_IID(nsIVariant
))) {
333 nsCOMPtr
<nsIVariant
> variant
= do_QueryInterface(iface
);
337 return XPCVariant::VariantDataToJS(variant
,
341 xpcObjectHelper
helper(iface
);
342 return NativeInterface2JSObject(d
, nullptr, helper
, iid
, nullptr, true, pErr
);
346 NS_ERROR("bad type");
352 /***************************************************************************/
356 CheckJSCharInCharRange(jschar c
)
358 if (ILLEGAL_RANGE(c
)) {
359 /* U+0080/U+0100 - U+FFFF data lost. */
360 static const size_t MSG_BUF_SIZE
= 64;
361 char msg
[MSG_BUF_SIZE
];
362 JS_snprintf(msg
, MSG_BUF_SIZE
, "jschar out of char range; high bits of data lost: 0x%x", c
);
370 template<typename CharT
>
372 CheckCharsInCharRange(const CharT
* chars
, size_t len
)
374 for (size_t i
= 0; i
< len
; i
++) {
375 if (!CheckJSCharInCharRange(chars
[i
]))
382 bool ConvertToPrimitive(JSContext
* cx
, HandleValue v
, T
* retval
)
384 return ValueToPrimitive
<T
, eDefault
>(cx
, v
, retval
);
389 XPCConvert::JSData2Native(void* d
, HandleValue s
,
390 const nsXPTType
& type
,
394 NS_PRECONDITION(d
, "bad param");
398 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
400 switch (type
.TagPart()) {
401 case nsXPTType::T_I8
:
402 return ConvertToPrimitive(cx
, s
, static_cast<int8_t*>(d
));
403 case nsXPTType::T_I16
:
404 return ConvertToPrimitive(cx
, s
, static_cast<int16_t*>(d
));
405 case nsXPTType::T_I32
:
406 return ConvertToPrimitive(cx
, s
, static_cast<int32_t*>(d
));
407 case nsXPTType::T_I64
:
408 return ConvertToPrimitive(cx
, s
, static_cast<int64_t*>(d
));
409 case nsXPTType::T_U8
:
410 return ConvertToPrimitive(cx
, s
, static_cast<uint8_t*>(d
));
411 case nsXPTType::T_U16
:
412 return ConvertToPrimitive(cx
, s
, static_cast<uint16_t*>(d
));
413 case nsXPTType::T_U32
:
414 return ConvertToPrimitive(cx
, s
, static_cast<uint32_t*>(d
));
415 case nsXPTType::T_U64
:
416 return ConvertToPrimitive(cx
, s
, static_cast<uint64_t*>(d
));
417 case nsXPTType::T_FLOAT
:
418 return ConvertToPrimitive(cx
, s
, static_cast<float*>(d
));
419 case nsXPTType::T_DOUBLE
:
420 return ConvertToPrimitive(cx
, s
, static_cast<double*>(d
));
421 case nsXPTType::T_BOOL
:
422 return ConvertToPrimitive(cx
, s
, static_cast<bool*>(d
));
423 case nsXPTType::T_CHAR
:
425 JSString
* str
= ToString(cx
, s
);
431 if (JS_GetStringLength(str
) == 0) {
434 if (!JS_GetStringCharAt(cx
, str
, 0, &ch
))
438 CheckJSCharInCharRange(ch
);
440 *((char*)d
) = char(ch
);
443 case nsXPTType::T_WCHAR
:
446 if (!(str
= ToString(cx
, s
))) {
449 size_t length
= JS_GetStringLength(str
);
456 if (!JS_GetStringCharAt(cx
, str
, 0, &ch
))
459 *((uint16_t*)d
) = uint16_t(ch
);
462 case nsXPTType::T_JSVAL
:
465 case nsXPTType::T_VOID
:
466 XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
467 NS_ERROR("void* params not supported");
469 case nsXPTType::T_IID
:
471 const nsID
* pid
= nullptr;
473 // There's no good reason to pass a null IID.
474 if (s
.isNullOrUndefined()) {
476 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
481 (!(pid
= xpc_JSObjectToID(cx
, &s
.toObject()))) ||
482 (!(pid
= (const nsID
*) nsMemory::Clone(pid
, sizeof(nsID
))))) {
485 *((const nsID
**)d
) = pid
;
489 case nsXPTType::T_ASTRING
:
491 if (s
.isUndefined()) {
492 (**((nsAString
**)d
)).SetIsVoid(true);
495 // Fall through to T_DOMSTRING case.
497 case nsXPTType::T_DOMSTRING
:
500 (**((nsAString
**)d
)).SetIsVoid(true);
504 JSString
* str
= nullptr;
505 if (!s
.isUndefined()) {
506 str
= ToString(cx
, s
);
510 length
= JS_GetStringLength(str
);
512 (**((nsAString
**)d
)).Truncate();
517 nsAString
* ws
= *((nsAString
**)d
);
520 ws
->AssignLiteral(MOZ_UTF16("undefined"));
521 } else if (XPCStringConvert::IsDOMString(str
)) {
522 // The characters represent an existing nsStringBuffer that
523 // was shared by XPCStringConvert::ReadableToJSVal.
524 const jschar
* chars
= JS_GetTwoByteExternalStringChars(str
);
525 nsStringBuffer::FromData((void*)chars
)->ToString(length
, *ws
);
526 } else if (XPCStringConvert::IsLiteral(str
)) {
527 // The characters represent a literal char16_t string constant
528 // compiled into libxul, such as the string "undefined" above.
529 const jschar
* chars
= JS_GetTwoByteExternalStringChars(str
);
530 ws
->AssignLiteral(chars
, length
);
532 if (!AssignJSString(cx
, *ws
, str
))
538 case nsXPTType::T_CHAR_STR
:
540 if (s
.isUndefined() || s
.isNull()) {
541 *((char**)d
) = nullptr;
545 JSString
* str
= ToString(cx
, s
);
550 if (JS_StringHasLatin1Chars(str
)) {
552 AutoCheckCannotGC nogc
;
553 const Latin1Char
* chars
= JS_GetLatin1StringCharsAndLength(cx
, nogc
, str
, &len
);
555 CheckCharsInCharRange(chars
, len
);
558 AutoCheckCannotGC nogc
;
559 const jschar
* chars
= JS_GetTwoByteStringCharsAndLength(cx
, nogc
, str
, &len
);
561 CheckCharsInCharRange(chars
, len
);
564 size_t length
= JS_GetStringEncodingLength(cx
, str
);
565 if (length
== size_t(-1)) {
568 char* buffer
= static_cast<char*>(nsMemory::Alloc(length
+ 1));
572 JS_EncodeStringToBuffer(cx
, str
, buffer
, length
);
573 buffer
[length
] = '\0';
574 *((void**)d
) = buffer
;
578 case nsXPTType::T_WCHAR_STR
:
582 if (s
.isUndefined() || s
.isNull()) {
583 *((jschar
**)d
) = nullptr;
587 if (!(str
= ToString(cx
, s
))) {
590 int len
= JS_GetStringLength(str
);
591 int byte_len
= (len
+1)*sizeof(jschar
);
592 if (!(*((void**)d
) = nsMemory::Alloc(byte_len
))) {
593 // XXX should report error
596 mozilla::Range
<jschar
> destChars(*((jschar
**)d
), len
+ 1);
597 if (!JS_CopyStringChars(cx
, destChars
, str
))
604 case nsXPTType::T_UTF8STRING
:
606 if (s
.isNull() || s
.isUndefined()) {
607 nsCString
* rs
= *((nsCString
**)d
);
612 // The JS val is neither null nor void...
613 JSString
* str
= ToString(cx
, s
);
617 size_t length
= JS_GetStringLength(str
);
619 nsCString
* rs
= *((nsCString
**)d
);
624 JSFlatString
* flat
= JS_FlattenString(cx
, str
);
628 size_t utf8Length
= JS::GetDeflatedUTF8StringLength(flat
);
629 nsACString
* rs
= *((nsACString
**)d
);
630 rs
->SetLength(utf8Length
);
632 JS::DeflateStringToUTF8Buffer(flat
, mozilla::RangedPtr
<char>(rs
->BeginWriting(), utf8Length
));
637 case nsXPTType::T_CSTRING
:
639 if (s
.isNull() || s
.isUndefined()) {
640 nsACString
* rs
= *((nsACString
**)d
);
646 // The JS val is neither null nor void...
647 JSString
* str
= ToString(cx
, s
);
652 size_t length
= JS_GetStringEncodingLength(cx
, str
);
653 if (length
== size_t(-1)) {
658 nsCString
* rs
= *((nsCString
**)d
);
663 nsACString
* rs
= *((nsACString
**)d
);
664 rs
->SetLength(uint32_t(length
));
665 if (rs
->Length() != uint32_t(length
)) {
668 JS_EncodeStringToBuffer(cx
, str
, rs
->BeginWriting(), length
);
673 case nsXPTType::T_INTERFACE
:
674 case nsXPTType::T_INTERFACE_IS
:
676 MOZ_ASSERT(iid
,"can't do interface conversions without iid");
678 if (iid
->Equals(NS_GET_IID(nsIVariant
))) {
679 nsCOMPtr
<nsIVariant
> variant
= XPCVariant::newVariant(cx
, s
);
683 variant
.forget(static_cast<nsISupports
**>(d
));
685 } else if (iid
->Equals(NS_GET_IID(nsIAtom
)) && s
.isString()) {
686 // We're trying to pass a string as an nsIAtom. Let's atomize!
687 JSString
* str
= s
.toString();
688 nsAutoJSString autoStr
;
689 if (!autoStr
.init(cx
, str
)) {
691 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF
;
694 nsCOMPtr
<nsIAtom
> atom
= NS_NewAtom(autoStr
);
695 atom
.forget((nsISupports
**)d
);
700 if (s
.isNullOrUndefined()) {
701 *((nsISupports
**)d
) = nullptr;
705 // only wrap JSObjects
707 if (pErr
&& s
.isInt32() && 0 == s
.toInt32())
708 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL
;
712 RootedObject
src(cx
, &s
.toObject());
713 return JSObject2NativeInterface((void**)d
, src
, iid
, nullptr, pErr
);
716 NS_ERROR("bad type");
723 CreateHolderIfNeeded(HandleObject obj
, MutableHandleValue d
,
724 nsIXPConnectJSObjectHolder
** dest
)
727 nsRefPtr
<XPCJSObjectHolder
> objHolder
= XPCJSObjectHolder::newHolder(obj
);
731 objHolder
.forget(dest
);
734 d
.setObjectOrNull(obj
);
739 /***************************************************************************/
742 XPCConvert::NativeInterface2JSObject(MutableHandleValue d
,
743 nsIXPConnectJSObjectHolder
** dest
,
744 xpcObjectHelper
& aHelper
,
746 XPCNativeInterface
** Interface
,
747 bool allowNativeWrapper
,
750 MOZ_ASSERT_IF(Interface
, iid
);
752 iid
= &NS_GET_IID(nsISupports
);
757 if (!aHelper
.Object())
760 *pErr
= NS_ERROR_XPC_BAD_CONVERT_NATIVE
;
762 // We used to have code here that unwrapped and simply exposed the
763 // underlying JSObject. That caused anomolies when JSComponents were
764 // accessed from other JS code - they didn't act like other xpconnect
765 // wrapped components. So, instead, we create "double wrapped" objects
766 // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't
767 // optimal -- we could detect this and roll the functionality into a
768 // single wrapper, but the current solution is good enough for now.
770 XPCWrappedNativeScope
* xpcscope
= ObjectScope(JS::CurrentGlobalOrNull(cx
));
774 // First, see if this object supports the wrapper cache.
775 // Note: If |cache->IsDOMBinding()| is true, then it means that the object
776 // implementing it doesn't want a wrapped native as its JS Object, but
777 // instead it provides its own proxy object. In that case, the object
778 // to use is found as cache->GetWrapper(). If that is null, then the
779 // object will create (and fill the cache) from its WrapObject call.
780 nsWrapperCache
* cache
= aHelper
.GetWrapperCache();
782 RootedObject
flat(cx
, cache
? cache
->GetWrapper() : nullptr);
783 if (!flat
&& cache
&& cache
->IsDOMBinding()) {
784 RootedObject
global(cx
, xpcscope
->GetGlobalJSObject());
785 js::AssertSameCompartment(cx
, global
);
786 flat
= cache
->WrapObject(cx
);
791 if (allowNativeWrapper
&& !JS_WrapObject(cx
, &flat
))
793 return CreateHolderIfNeeded(flat
, d
, dest
);
796 // Don't double wrap CPOWs. This is a temporary measure for compatibility
797 // with objects that don't provide necessary QIs (such as objects under
798 // the new DOM bindings). We expect the other side of the CPOW to have
799 // the appropriate wrappers in place.
800 RootedObject
cpow(cx
, UnwrapNativeCPOW(aHelper
.Object()));
802 if (!JS_WrapObject(cx
, &cpow
))
808 // Go ahead and create an XPCWrappedNative for this object.
809 AutoMarkingNativeInterfacePtr
iface(cx
);
815 iface
= XPCNativeInterface::GetNewOrUsed(iid
);
824 nsRefPtr
<XPCWrappedNative
> wrapper
;
825 nsresult rv
= XPCWrappedNative::GetNewOrUsed(aHelper
, xpcscope
, iface
,
826 getter_AddRefs(wrapper
));
827 if (NS_FAILED(rv
) && pErr
)
830 // If creating the wrapped native failed, then return early.
831 if (NS_FAILED(rv
) || !wrapper
)
834 // If we're not creating security wrappers, we can return the
835 // XPCWrappedNative as-is here.
836 flat
= wrapper
->GetFlatJSObject();
837 if (!allowNativeWrapper
) {
838 d
.setObjectOrNull(flat
);
840 wrapper
.forget(dest
);
846 // The call to wrap here handles both cross-compartment and same-compartment
847 // security wrappers.
848 RootedObject
original(cx
, flat
);
849 if (!JS_WrapObject(cx
, &flat
))
852 d
.setObjectOrNull(flat
);
855 // The wrapper still holds the original flat object.
856 if (flat
== original
) {
857 wrapper
.forget(dest
);
859 nsRefPtr
<XPCJSObjectHolder
> objHolder
=
860 XPCJSObjectHolder::newHolder(flat
);
864 objHolder
.forget(dest
);
874 /***************************************************************************/
878 XPCConvert::JSObject2NativeInterface(void** dest
, HandleObject src
,
883 MOZ_ASSERT(dest
, "bad param");
884 MOZ_ASSERT(src
, "bad param");
885 MOZ_ASSERT(iid
, "bad param");
888 JSAutoCompartment
ac(cx
, src
);
892 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
897 // Note that if we have a non-null aOuter then it means that we are
898 // forcing the creation of a wrapper even if the object *is* a
899 // wrappedNative or other wise has 'nsISupportness'.
900 // This allows wrapJSAggregatedToNative to work.
902 // If we're looking at a security wrapper, see now if we're allowed to
903 // pass it to C++. If we are, then fall through to the code below. If
904 // we aren't, throw an exception eagerly.
906 // NB: It's very important that we _don't_ unwrap in the aOuter case,
907 // because the caller may explicitly want to create the XPCWrappedJS
908 // around a security wrapper. XBL does this with Xrays from the XBL
909 // scope - see nsBindingManager::GetBindingImplementation.
910 JSObject
* inner
= js::CheckedUnwrap(src
, /* stopAtOuter = */ false);
913 *pErr
= NS_ERROR_XPC_SECURITY_MANAGER_VETO
;
917 // Is this really a native xpcom object with a wrapper?
918 XPCWrappedNative
* wrappedNative
= nullptr;
919 if (IS_WN_REFLECTOR(inner
))
920 wrappedNative
= XPCWrappedNative::Get(inner
);
922 iface
= wrappedNative
->GetIdentityObject();
923 return NS_SUCCEEDED(iface
->QueryInterface(*iid
, dest
));
927 // Deal with slim wrappers here.
928 if (GetISupportsFromJSObject(inner
? inner
: src
, &iface
)) {
930 return NS_SUCCEEDED(iface
->QueryInterface(*iid
, dest
));
938 nsXPCWrappedJS
* wrapper
;
939 nsresult rv
= nsXPCWrappedJS::GetNewOrUsed(src
, *iid
, &wrapper
);
942 if (NS_SUCCEEDED(rv
) && wrapper
) {
943 // If the caller wanted to aggregate this JS object to a native,
944 // attach it to the wrapper. Note that we allow a maximum of one
945 // aggregated native for a given XPCWrappedJS.
947 wrapper
->SetAggregatedNativeObject(aOuter
);
949 // We need to go through the QueryInterface logic to make this return
950 // the right thing for the various 'special' interfaces; e.g.
951 // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
952 // there is an outer to avoid nasty recursion.
953 rv
= aOuter
? wrapper
->AggregatedQueryInterface(*iid
, dest
) :
954 wrapper
->QueryInterface(*iid
, dest
);
958 return NS_SUCCEEDED(rv
);
965 /***************************************************************************/
966 /***************************************************************************/
970 XPCConvert::ConstructException(nsresult rv
, const char* message
,
971 const char* ifaceName
, const char* methodName
,
973 nsIException
** exceptn
,
975 jsval
* jsExceptionPtr
)
977 MOZ_ASSERT(!cx
== !jsExceptionPtr
, "Expected cx and jsExceptionPtr to cooccur.");
979 static const char format
[] = "\'%s\' when calling method: [%s::%s]";
980 const char * msg
= message
;
984 nsCOMPtr
<nsIScriptError
> errorObject
= do_QueryInterface(data
);
986 if (NS_SUCCEEDED(errorObject
->GetMessageMoz(getter_Copies(xmsg
)))) {
987 CopyUTF16toUTF8(xmsg
, sxmsg
);
992 if (!nsXPCException::NameAndFormatForNSResult(rv
, nullptr, &msg
) || ! msg
)
995 nsCString
msgStr(msg
);
996 if (ifaceName
&& methodName
)
997 msgStr
.AppendPrintf(format
, msg
, ifaceName
, methodName
);
999 nsRefPtr
<Exception
> e
= new Exception(msgStr
, rv
, EmptyCString(), nullptr, data
);
1001 if (cx
&& jsExceptionPtr
) {
1002 e
->StowJSVal(*jsExceptionPtr
);
1009 /********************************/
1011 class MOZ_STACK_CLASS AutoExceptionRestorer
1014 AutoExceptionRestorer(JSContext
* cx
, Value v
)
1015 : mContext(cx
), tvr(cx
, v
)
1017 JS_ClearPendingException(mContext
);
1020 ~AutoExceptionRestorer()
1022 JS_SetPendingException(mContext
, tvr
);
1026 JSContext
* const mContext
;
1032 XPCConvert::JSValToXPCException(MutableHandleValue s
,
1033 const char* ifaceName
,
1034 const char* methodName
,
1035 nsIException
** exceptn
)
1038 AutoExceptionRestorer
aer(cx
, s
);
1040 if (!s
.isPrimitive()) {
1041 // we have a JSObject
1042 RootedObject
obj(cx
, s
.toObjectOrNull());
1045 NS_ERROR("when is an object not an object?");
1046 return NS_ERROR_FAILURE
;
1049 // is this really a native xpcom object with a wrapper?
1050 JSObject
* unwrapped
= js::CheckedUnwrap(obj
, /* stopAtOuter = */ false);
1052 return NS_ERROR_XPC_SECURITY_MANAGER_VETO
;
1053 XPCWrappedNative
* wrapper
= IS_WN_REFLECTOR(unwrapped
) ? XPCWrappedNative::Get(unwrapped
)
1056 nsISupports
* supports
= wrapper
->GetIdentityObject();
1057 nsCOMPtr
<nsIException
> iface
= do_QueryInterface(supports
);
1059 // just pass through the exception (with extra ref and all)
1060 nsCOMPtr
<nsIException
> temp
= iface
;
1061 temp
.forget(exceptn
);
1064 // it is a wrapped native, but not an exception!
1065 return ConstructException(NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT
,
1066 nullptr, ifaceName
, methodName
, supports
,
1067 exceptn
, nullptr, nullptr);
1070 // It is a JSObject, but not a wrapped native...
1072 // If it is an engine Error with an error report then let's
1073 // extract the report and build an xpcexception from that
1074 const JSErrorReport
* report
;
1075 if (nullptr != (report
= JS_ErrorFromException(cx
, obj
))) {
1076 JSAutoByteString message
;
1078 if (nullptr != (str
= ToString(cx
, s
)))
1079 message
.encodeLatin1(cx
, str
);
1080 return JSErrorToXPCException(message
.ptr(), ifaceName
,
1081 methodName
, report
, exceptn
);
1087 // heuristic to see if it might be usable as an xpcexception
1088 if (!JS_HasProperty(cx
, obj
, "message", &found
))
1089 return NS_ERROR_FAILURE
;
1091 if (found
&& !JS_HasProperty(cx
, obj
, "result", &found
))
1092 return NS_ERROR_FAILURE
;
1095 // lets try to build a wrapper around the JSObject
1096 nsXPCWrappedJS
* jswrapper
;
1098 nsXPCWrappedJS::GetNewOrUsed(obj
, NS_GET_IID(nsIException
), &jswrapper
);
1102 *exceptn
= static_cast<nsIException
*>(jswrapper
->GetXPTCStub());
1107 // XXX we should do a check against 'js_ErrorClass' here and
1108 // do the right thing - even though it has no JSErrorReport,
1109 // The fact that it is a JSError exceptions means we can extract
1110 // particular info and our 'result' should reflect that.
1112 // otherwise we'll just try to convert it to a string
1114 JSString
* str
= ToString(cx
, s
);
1116 return NS_ERROR_FAILURE
;
1118 JSAutoByteString
strBytes(cx
, str
);
1120 return NS_ERROR_FAILURE
;
1122 return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT
,
1123 strBytes
.ptr(), ifaceName
, methodName
,
1124 nullptr, exceptn
, cx
, s
.address());
1128 if (s
.isUndefined() || s
.isNull()) {
1129 return ConstructException(NS_ERROR_XPC_JS_THREW_NULL
,
1130 nullptr, ifaceName
, methodName
, nullptr,
1131 exceptn
, cx
, s
.address());
1135 // lets see if it looks like an nsresult
1138 bool isResult
= false;
1141 rv
= (nsresult
) s
.toInt32();
1145 number
= (double) s
.toInt32();
1147 number
= s
.toDouble();
1149 number
< (double)0xffffffff &&
1150 0.0 == fmod(number
,1)) {
1151 // Visual Studio 9 doesn't allow casting directly from a
1152 // double to an enumeration type, contrary to 5.2.9(10) of
1153 // C++11, so add an intermediate cast.
1154 rv
= (nsresult
)(uint32_t) number
;
1161 return ConstructException(rv
, nullptr, ifaceName
, methodName
,
1162 nullptr, exceptn
, cx
, s
.address());
1164 // XXX all this nsISupportsDouble code seems a little redundant
1165 // now that we're storing the jsval in the exception...
1166 nsISupportsDouble
* data
;
1167 nsCOMPtr
<nsIComponentManager
> cm
;
1168 if (NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm
))) || !cm
||
1169 NS_FAILED(cm
->CreateInstanceByContractID(NS_SUPPORTS_DOUBLE_CONTRACTID
,
1171 NS_GET_IID(nsISupportsDouble
),
1173 return NS_ERROR_FAILURE
;
1174 data
->SetData(number
);
1175 rv
= ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER
, nullptr,
1176 ifaceName
, methodName
, data
, exceptn
, cx
, s
.address());
1182 // otherwise we'll just try to convert it to a string
1183 // Note: e.g., bools get converted to JSStrings by this code.
1185 JSString
* str
= ToString(cx
, s
);
1187 JSAutoByteString
strBytes(cx
, str
);
1189 return ConstructException(NS_ERROR_XPC_JS_THREW_STRING
,
1190 strBytes
.ptr(), ifaceName
, methodName
,
1191 nullptr, exceptn
, cx
, s
.address());
1194 return NS_ERROR_FAILURE
;
1197 /********************************/
1201 XPCConvert::JSErrorToXPCException(const char* message
,
1202 const char* ifaceName
,
1203 const char* methodName
,
1204 const JSErrorReport
* report
,
1205 nsIException
** exceptn
)
1208 nsresult rv
= NS_ERROR_FAILURE
;
1209 nsRefPtr
<nsScriptError
> data
;
1211 nsAutoString bestMessage
;
1212 if (report
&& report
->ucmessage
) {
1213 bestMessage
= static_cast<const char16_t
*>(report
->ucmessage
);
1214 } else if (message
) {
1215 CopyASCIItoUTF16(message
, bestMessage
);
1217 bestMessage
.AssignLiteral("JavaScript Error");
1220 const char16_t
* uclinebuf
=
1221 static_cast<const char16_t
*>(report
->uclinebuf
);
1223 data
= new nsScriptError();
1224 data
->InitWithWindowID(
1226 NS_ConvertASCIItoUTF16(report
->filename
),
1227 uclinebuf
? nsDependentString(uclinebuf
) : EmptyString(),
1229 report
->uctokenptr
- report
->uclinebuf
, report
->flags
,
1230 NS_LITERAL_CSTRING("XPConnect JavaScript"),
1231 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx
));
1235 nsAutoCString formattedMsg
;
1236 data
->ToString(formattedMsg
);
1238 rv
= ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS
,
1239 formattedMsg
.get(), ifaceName
, methodName
,
1240 static_cast<nsIScriptError
*>(data
.get()),
1241 exceptn
, nullptr, nullptr);
1243 rv
= ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR
,
1244 nullptr, ifaceName
, methodName
, nullptr,
1245 exceptn
, nullptr, nullptr);
1250 /***************************************************************************/
1260 XPCConvert::NativeArray2JS(MutableHandleValue d
, const void** s
,
1261 const nsXPTType
& type
, const nsID
* iid
,
1262 uint32_t count
, nsresult
* pErr
)
1264 NS_PRECONDITION(s
, "bad param");
1268 // XXX add support for putting chars in a string rather than an array
1270 // XXX add support to indicate *which* array element was not convertable
1272 RootedObject
array(cx
, JS_NewArrayObject(cx
, count
));
1277 *pErr
= NS_ERROR_XPC_BAD_CONVERT_NATIVE
;
1280 RootedValue
current(cx
, JSVAL_NULL
);
1282 #define POPULATE(_t) \
1284 for (i = 0; i < count; i++) { \
1285 if (!NativeData2JS(¤t, ((_t*)*s)+i, type, iid, pErr) || \
1286 !JS_SetElement(cx, array, i, current)) \
1291 // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
1293 switch (type
.TagPart()) {
1294 case nsXPTType::T_I8
: POPULATE(int8_t); break;
1295 case nsXPTType::T_I16
: POPULATE(int16_t); break;
1296 case nsXPTType::T_I32
: POPULATE(int32_t); break;
1297 case nsXPTType::T_I64
: POPULATE(int64_t); break;
1298 case nsXPTType::T_U8
: POPULATE(uint8_t); break;
1299 case nsXPTType::T_U16
: POPULATE(uint16_t); break;
1300 case nsXPTType::T_U32
: POPULATE(uint32_t); break;
1301 case nsXPTType::T_U64
: POPULATE(uint64_t); break;
1302 case nsXPTType::T_FLOAT
: POPULATE(float); break;
1303 case nsXPTType::T_DOUBLE
: POPULATE(double); break;
1304 case nsXPTType::T_BOOL
: POPULATE(bool); break;
1305 case nsXPTType::T_CHAR
: POPULATE(char); break;
1306 case nsXPTType::T_WCHAR
: POPULATE(jschar
); break;
1307 case nsXPTType::T_VOID
: NS_ERROR("bad type"); goto failure
;
1308 case nsXPTType::T_IID
: POPULATE(nsID
*); break;
1309 case nsXPTType::T_DOMSTRING
: NS_ERROR("bad type"); goto failure
;
1310 case nsXPTType::T_CHAR_STR
: POPULATE(char*); break;
1311 case nsXPTType::T_WCHAR_STR
: POPULATE(jschar
*); break;
1312 case nsXPTType::T_INTERFACE
: POPULATE(nsISupports
*); break;
1313 case nsXPTType::T_INTERFACE_IS
: POPULATE(nsISupports
*); break;
1314 case nsXPTType::T_UTF8STRING
: NS_ERROR("bad type"); goto failure
;
1315 case nsXPTType::T_CSTRING
: NS_ERROR("bad type"); goto failure
;
1316 case nsXPTType::T_ASTRING
: NS_ERROR("bad type"); goto failure
;
1317 default : NS_ERROR("bad type"); goto failure
;
1322 d
.setObject(*array
);
1333 // Check that the tag part of the type matches the type
1334 // of the array. If the check succeeds, check that the size
1335 // of the output does not exceed UINT32_MAX bytes. Allocate
1336 // the memory and copy the elements by memcpy.
1338 CheckTargetAndPopulate(const nsXPTType
& type
,
1339 uint8_t requiredType
,
1346 // Check that the element type expected by the interface matches
1347 // the type of the elements in the typed array exactly, including
1349 if (type
.TagPart() != requiredType
) {
1351 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
1356 // Calulate the maximum number of elements that can fit in
1357 // UINT32_MAX bytes.
1358 size_t max
= UINT32_MAX
/ typeSize
;
1360 // This could overflow on 32-bit systems so check max first.
1361 size_t byteSize
= count
* typeSize
;
1362 if (count
> max
|| !(*output
= nsMemory::Alloc(byteSize
))) {
1364 *pErr
= NS_ERROR_OUT_OF_MEMORY
;
1369 memcpy(*output
, JS_GetArrayBufferViewData(tArr
), byteSize
);
1373 // Fast conversion of typed arrays to native using memcpy.
1374 // No float or double canonicalization is done. Called by
1375 // JSarray2Native whenever a TypedArray is met. ArrayBuffers
1376 // are not accepted; create a properly typed array view on them
1377 // first. The element type of array must match the XPCOM
1378 // type in size, type and signedness exactly. As an exception,
1379 // Uint8ClampedArray is allowed for arrays of uint8_t. DataViews
1380 // are not supported.
1384 XPCConvert::JSTypedArray2Native(void** d
,
1387 const nsXPTType
& type
,
1390 MOZ_ASSERT(jsArray
, "bad param");
1391 MOZ_ASSERT(d
, "bad param");
1392 MOZ_ASSERT(JS_IsTypedArrayObject(jsArray
), "not a typed array");
1394 // Check the actual length of the input array against the
1396 uint32_t len
= JS_GetTypedArrayLength(jsArray
);
1399 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY
;
1404 void* output
= nullptr;
1406 switch (JS_GetArrayBufferViewType(jsArray
)) {
1407 case js::Scalar::Int8
:
1408 if (!CheckTargetAndPopulate(nsXPTType::T_I8
, type
,
1409 sizeof(int8_t), count
,
1410 jsArray
, &output
, pErr
)) {
1415 case js::Scalar::Uint8
:
1416 case js::Scalar::Uint8Clamped
:
1417 if (!CheckTargetAndPopulate(nsXPTType::T_U8
, type
,
1418 sizeof(uint8_t), count
,
1419 jsArray
, &output
, pErr
)) {
1424 case js::Scalar::Int16
:
1425 if (!CheckTargetAndPopulate(nsXPTType::T_I16
, type
,
1426 sizeof(int16_t), count
,
1427 jsArray
, &output
, pErr
)) {
1432 case js::Scalar::Uint16
:
1433 if (!CheckTargetAndPopulate(nsXPTType::T_U16
, type
,
1434 sizeof(uint16_t), count
,
1435 jsArray
, &output
, pErr
)) {
1440 case js::Scalar::Int32
:
1441 if (!CheckTargetAndPopulate(nsXPTType::T_I32
, type
,
1442 sizeof(int32_t), count
,
1443 jsArray
, &output
, pErr
)) {
1448 case js::Scalar::Uint32
:
1449 if (!CheckTargetAndPopulate(nsXPTType::T_U32
, type
,
1450 sizeof(uint32_t), count
,
1451 jsArray
, &output
, pErr
)) {
1456 case js::Scalar::Float32
:
1457 if (!CheckTargetAndPopulate(nsXPTType::T_FLOAT
, type
,
1458 sizeof(float), count
,
1459 jsArray
, &output
, pErr
)) {
1464 case js::Scalar::Float64
:
1465 if (!CheckTargetAndPopulate(nsXPTType::T_DOUBLE
, type
,
1466 sizeof(double), count
,
1467 jsArray
, &output
, pErr
)) {
1472 // Yet another array type was defined? It is not supported yet...
1475 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
1489 XPCConvert::JSArray2Native(void** d
, HandleValue s
,
1490 uint32_t count
, const nsXPTType
& type
,
1491 const nsID
* iid
, nsresult
* pErr
)
1493 MOZ_ASSERT(d
, "bad param");
1497 // XXX add support for getting chars from strings
1499 // XXX add support to indicate *which* array element was not convertable
1501 if (s
.isNullOrUndefined()) {
1504 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY
;
1512 if (!s
.isObject()) {
1514 *pErr
= NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY
;
1518 RootedObject
jsarray(cx
, &s
.toObject());
1520 // If this is a typed array, then try a fast conversion with memcpy.
1521 if (JS_IsTypedArrayObject(jsarray
)) {
1522 return JSTypedArray2Native(d
, jsarray
, count
, type
, pErr
);
1525 if (!JS_IsArrayObject(cx
, jsarray
)) {
1527 *pErr
= NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY
;
1532 if (!JS_GetArrayLength(cx
, jsarray
, &len
) || len
< count
) {
1534 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY
;
1539 *pErr
= NS_ERROR_XPC_BAD_CONVERT_JS
;
1541 #define POPULATE(_mode, _t) \
1543 cleanupMode = _mode; \
1544 size_t max = UINT32_MAX / sizeof(_t); \
1545 if (count > max || \
1546 nullptr == (array = nsMemory::Alloc(count * sizeof(_t)))) { \
1548 *pErr = NS_ERROR_OUT_OF_MEMORY; \
1551 for (initedCount = 0; initedCount < count; initedCount++) { \
1552 if (!JS_GetElement(cx, jsarray, initedCount, ¤t) || \
1553 !JSData2Native(((_t*)array)+initedCount, current, type, \
1559 // No Action, FRee memory, RElease object
1560 enum CleanupMode
{na
, fr
, re
};
1562 CleanupMode cleanupMode
;
1564 void* array
= nullptr;
1565 uint32_t initedCount
;
1566 RootedValue
current(cx
);
1568 // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
1569 // XXX make extra space at end of char* and wchar* and null termintate
1571 switch (type
.TagPart()) {
1572 case nsXPTType::T_I8
: POPULATE(na
, int8_t); break;
1573 case nsXPTType::T_I16
: POPULATE(na
, int16_t); break;
1574 case nsXPTType::T_I32
: POPULATE(na
, int32_t); break;
1575 case nsXPTType::T_I64
: POPULATE(na
, int64_t); break;
1576 case nsXPTType::T_U8
: POPULATE(na
, uint8_t); break;
1577 case nsXPTType::T_U16
: POPULATE(na
, uint16_t); break;
1578 case nsXPTType::T_U32
: POPULATE(na
, uint32_t); break;
1579 case nsXPTType::T_U64
: POPULATE(na
, uint64_t); break;
1580 case nsXPTType::T_FLOAT
: POPULATE(na
, float); break;
1581 case nsXPTType::T_DOUBLE
: POPULATE(na
, double); break;
1582 case nsXPTType::T_BOOL
: POPULATE(na
, bool); break;
1583 case nsXPTType::T_CHAR
: POPULATE(na
, char); break;
1584 case nsXPTType::T_WCHAR
: POPULATE(na
, jschar
); break;
1585 case nsXPTType::T_VOID
: NS_ERROR("bad type"); goto failure
;
1586 case nsXPTType::T_IID
: POPULATE(fr
, nsID
*); break;
1587 case nsXPTType::T_DOMSTRING
: NS_ERROR("bad type"); goto failure
;
1588 case nsXPTType::T_CHAR_STR
: POPULATE(fr
, char*); break;
1589 case nsXPTType::T_WCHAR_STR
: POPULATE(fr
, jschar
*); break;
1590 case nsXPTType::T_INTERFACE
: POPULATE(re
, nsISupports
*); break;
1591 case nsXPTType::T_INTERFACE_IS
: POPULATE(re
, nsISupports
*); break;
1592 case nsXPTType::T_UTF8STRING
: NS_ERROR("bad type"); goto failure
;
1593 case nsXPTType::T_CSTRING
: NS_ERROR("bad type"); goto failure
;
1594 case nsXPTType::T_ASTRING
: NS_ERROR("bad type"); goto failure
;
1595 default : NS_ERROR("bad type"); goto failure
;
1604 // we may need to cleanup the partially filled array of converted stuff
1606 if (cleanupMode
== re
) {
1607 nsISupports
** a
= (nsISupports
**) array
;
1608 for (uint32_t i
= 0; i
< initedCount
; i
++) {
1609 nsISupports
* p
= a
[i
];
1612 } else if (cleanupMode
== fr
) {
1613 void** a
= (void**) array
;
1614 for (uint32_t i
= 0; i
< initedCount
; i
++) {
1616 if (p
) nsMemory::Free(p
);
1619 nsMemory::Free(array
);
1629 XPCConvert::NativeStringWithSize2JS(MutableHandleValue d
, const void* s
,
1630 const nsXPTType
& type
,
1634 NS_PRECONDITION(s
, "bad param");
1638 *pErr
= NS_ERROR_XPC_BAD_CONVERT_NATIVE
;
1640 switch (type
.TagPart()) {
1641 case nsXPTType::T_PSTRING_SIZE_IS
:
1643 char* p
= *((char**)s
);
1647 if (!(str
= JS_NewStringCopyN(cx
, p
, count
)))
1652 case nsXPTType::T_PWSTRING_SIZE_IS
:
1654 jschar
* p
= *((jschar
**)s
);
1658 if (!(str
= JS_NewUCStringCopyN(cx
, p
, count
)))
1664 XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
1672 XPCConvert::JSStringWithSize2Native(void* d
, HandleValue s
,
1673 uint32_t count
, const nsXPTType
& type
,
1676 NS_PRECONDITION(!s
.isNull(), "bad param");
1677 NS_PRECONDITION(d
, "bad param");
1683 *pErr
= NS_ERROR_XPC_BAD_CONVERT_NATIVE
;
1685 switch (type
.TagPart()) {
1686 case nsXPTType::T_PSTRING_SIZE_IS
:
1688 if (s
.isUndefined() || s
.isNull()) {
1691 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING
;
1695 len
= (count
+ 1) * sizeof(char);
1696 if (!(*((void**)d
) = nsMemory::Alloc(len
)))
1702 *((char**)d
) = nullptr;
1706 JSString
* str
= ToString(cx
, s
);
1711 size_t length
= JS_GetStringEncodingLength(cx
, str
);
1712 if (length
== size_t(-1)) {
1715 if (length
> count
) {
1717 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING
;
1720 len
= uint32_t(length
);
1725 uint32_t alloc_len
= (len
+ 1) * sizeof(char);
1726 char* buffer
= static_cast<char*>(nsMemory::Alloc(alloc_len
));
1730 JS_EncodeStringToBuffer(cx
, str
, buffer
, len
);
1732 *((char**)d
) = buffer
;
1737 case nsXPTType::T_PWSTRING_SIZE_IS
:
1741 if (s
.isUndefined() || s
.isNull()) {
1744 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING
;
1749 len
= (count
+ 1) * sizeof(jschar
);
1750 if (!(*((void**)d
) = nsMemory::Alloc(len
)))
1756 *((const jschar
**)d
) = nullptr;
1760 if (!(str
= ToString(cx
, s
))) {
1764 len
= JS_GetStringLength(str
);
1767 *pErr
= NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING
;
1773 uint32_t alloc_len
= (len
+ 1) * sizeof(jschar
);
1774 if (!(*((void**)d
) = nsMemory::Alloc(alloc_len
))) {
1775 // XXX should report error
1778 mozilla::Range
<jschar
> destChars(*((jschar
**)d
), len
+ 1);
1779 if (!JS_CopyStringChars(cx
, destChars
, str
))
1781 destChars
[count
] = 0;
1786 XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));