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 : /* nsIVariant implementation for xpconnect. */
8 :
9 : #include "mozilla/Range.h"
10 :
11 : #include "xpcprivate.h"
12 :
13 : #include "jsfriendapi.h"
14 : #include "jsprf.h"
15 : #include "jswrapper.h"
16 :
17 : using namespace JS;
18 : using namespace mozilla;
19 :
20 3 : NS_IMPL_CLASSINFO(XPCVariant, nullptr, 0, XPCVARIANT_CID)
21 21 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant)
22 6 : NS_INTERFACE_MAP_ENTRY(XPCVariant)
23 6 : NS_INTERFACE_MAP_ENTRY(nsIVariant)
24 3 : NS_INTERFACE_MAP_ENTRY(nsISupports)
25 3 : NS_IMPL_QUERY_CLASSINFO(XPCVariant)
26 3 : NS_INTERFACE_MAP_END
27 0 : NS_IMPL_CI_INTERFACE_GETTER(XPCVariant, XPCVariant, nsIVariant)
28 :
29 6 : NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant)
30 9 : NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant)
31 :
32 3 : XPCVariant::XPCVariant(JSContext* cx, const Value& aJSVal)
33 3 : : mJSVal(aJSVal), mCCGeneration(0)
34 : {
35 3 : if (!mJSVal.isPrimitive()) {
36 : // XXXbholley - The innerization here was from bug 638026. Blake says
37 : // the basic problem was that we were storing the C++ inner but the JS
38 : // outer, which meant that, after navigation, the JS inner could be
39 : // collected, which would cause us to try to recreate the JS inner at
40 : // some later point after teardown, which would crash. This is shouldn't
41 : // be a problem anymore because SetParentToWindow will do the right
42 : // thing, but I'm saving the cleanup here for another day. Blake thinks
43 : // that we should just not store the WN if we're creating a variant for
44 : // an outer window.
45 0 : JSObject* obj = js::ToWindowIfWindowProxy(&mJSVal.toObject());
46 0 : mJSVal = JS::ObjectValue(*obj);
47 :
48 0 : JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
49 0 : mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped));
50 : } else
51 3 : mReturnRawObject = false;
52 3 : }
53 :
54 6 : XPCTraceableVariant::~XPCTraceableVariant()
55 : {
56 2 : Value val = GetJSValPreserveColor();
57 :
58 2 : MOZ_ASSERT(val.isGCThing() || val.isNull(), "Must be traceable or unlinked");
59 :
60 2 : mData.Cleanup();
61 :
62 2 : if (!val.isNull())
63 2 : RemoveFromRootSet();
64 6 : }
65 :
66 2 : void XPCTraceableVariant::TraceJS(JSTracer* trc)
67 : {
68 2 : MOZ_ASSERT(GetJSValPreserveColor().isGCThing());
69 2 : JS::TraceEdge(trc, &mJSVal, "XPCTraceableVariant::mJSVal");
70 2 : }
71 :
72 : NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
73 :
74 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
75 0 : JS::Value val = tmp->GetJSValPreserveColor();
76 0 : if (val.isObject()) {
77 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
78 0 : cb.NoteJSChild(JS::GCCellPtr(val));
79 : }
80 :
81 0 : tmp->mData.Traverse(cb);
82 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
83 :
84 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
85 0 : JS::Value val = tmp->GetJSValPreserveColor();
86 :
87 0 : tmp->mData.Cleanup();
88 :
89 0 : if (val.isGCThing()) {
90 0 : XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(tmp);
91 0 : v->RemoveFromRootSet();
92 : }
93 0 : tmp->mJSVal = JS::NullValue();
94 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
95 :
96 : // static
97 : already_AddRefed<XPCVariant>
98 3 : XPCVariant::newVariant(JSContext* cx, const Value& aJSVal)
99 : {
100 6 : RefPtr<XPCVariant> variant;
101 :
102 3 : if (!aJSVal.isGCThing())
103 1 : variant = new XPCVariant(cx, aJSVal);
104 : else
105 2 : variant = new XPCTraceableVariant(cx, aJSVal);
106 :
107 3 : if (!variant->InitializeData(cx))
108 0 : return nullptr;
109 :
110 3 : return variant.forget();
111 : }
112 :
113 : // Helper class to give us a namespace for the table based code below.
114 : class XPCArrayHomogenizer
115 : {
116 : private:
117 : enum Type
118 : {
119 : tNull = 0 , // null value
120 : tInt , // Integer
121 : tDbl , // Double
122 : tBool , // Boolean
123 : tStr , // String
124 : tID , // ID
125 : tArr , // Array
126 : tISup , // nsISupports (really just a plain JSObject)
127 : tUnk , // Unknown. Used only for initial state.
128 :
129 : tTypeCount , // Just a count for table dimensioning.
130 :
131 : tVar , // nsVariant - last ditch if no other common type found.
132 : tErr // No valid state or type has this value.
133 : };
134 :
135 : // Table has tUnk as a state (column) but not as a type (row).
136 : static const Type StateTable[tTypeCount][tTypeCount-1];
137 :
138 : public:
139 : static bool GetTypeForArray(JSContext* cx, HandleObject array,
140 : uint32_t length,
141 : nsXPTType* resultType, nsID* resultID);
142 : };
143 :
144 :
145 : // Current state is the column down the side.
146 : // Current type is the row along the top.
147 : // New state is in the box at the intersection.
148 :
149 : const XPCArrayHomogenizer::Type
150 : XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = {
151 : /* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */
152 : /* tNull */{tNull,tVar ,tVar ,tVar ,tStr ,tID ,tVar ,tISup },
153 : /* tInt */{tVar ,tInt ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
154 : /* tDbl */{tVar ,tDbl ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
155 : /* tBool */{tVar ,tVar ,tVar ,tBool,tVar ,tVar ,tVar ,tVar },
156 : /* tStr */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar },
157 : /* tID */{tID ,tVar ,tVar ,tVar ,tVar ,tID ,tVar ,tVar },
158 : /* tArr */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr },
159 : /* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup },
160 : /* tUnk */{tNull,tInt ,tDbl ,tBool,tStr ,tID ,tVar ,tISup }};
161 :
162 : // static
163 : bool
164 0 : XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
165 : uint32_t length,
166 : nsXPTType* resultType, nsID* resultID)
167 : {
168 0 : Type state = tUnk;
169 : Type type;
170 :
171 0 : RootedValue val(cx);
172 0 : RootedObject jsobj(cx);
173 0 : for (uint32_t i = 0; i < length; i++) {
174 0 : if (!JS_GetElement(cx, array, i, &val))
175 0 : return false;
176 :
177 0 : if (val.isInt32()) {
178 0 : type = tInt;
179 0 : } else if (val.isDouble()) {
180 0 : type = tDbl;
181 0 : } else if (val.isBoolean()) {
182 0 : type = tBool;
183 0 : } else if (val.isUndefined() || val.isSymbol()) {
184 0 : state = tVar;
185 0 : break;
186 0 : } else if (val.isNull()) {
187 0 : type = tNull;
188 0 : } else if (val.isString()) {
189 0 : type = tStr;
190 : } else {
191 0 : MOZ_ASSERT(val.isObject(), "invalid type of jsval!");
192 0 : jsobj = &val.toObject();
193 :
194 : bool isArray;
195 0 : if (!JS_IsArrayObject(cx, jsobj, &isArray))
196 0 : return false;
197 :
198 0 : if (isArray)
199 0 : type = tArr;
200 0 : else if (xpc_JSObjectIsID(cx, jsobj))
201 0 : type = tID;
202 : else
203 0 : type = tISup;
204 : }
205 :
206 0 : MOZ_ASSERT(state != tErr, "bad state table!");
207 0 : MOZ_ASSERT(type != tErr, "bad type!");
208 0 : MOZ_ASSERT(type != tVar, "bad type!");
209 0 : MOZ_ASSERT(type != tUnk, "bad type!");
210 :
211 0 : state = StateTable[state][type];
212 :
213 0 : MOZ_ASSERT(state != tErr, "bad state table!");
214 0 : MOZ_ASSERT(state != tUnk, "bad state table!");
215 :
216 0 : if (state == tVar)
217 0 : break;
218 : }
219 :
220 0 : switch (state) {
221 : case tInt :
222 0 : *resultType = nsXPTType((uint8_t)TD_INT32);
223 0 : break;
224 : case tDbl :
225 0 : *resultType = nsXPTType((uint8_t)TD_DOUBLE);
226 0 : break;
227 : case tBool:
228 0 : *resultType = nsXPTType((uint8_t)TD_BOOL);
229 0 : break;
230 : case tStr :
231 0 : *resultType = nsXPTType((uint8_t)TD_PWSTRING);
232 0 : break;
233 : case tID :
234 0 : *resultType = nsXPTType((uint8_t)TD_PNSIID);
235 0 : break;
236 : case tISup:
237 0 : *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
238 0 : *resultID = NS_GET_IID(nsISupports);
239 0 : break;
240 : case tNull:
241 : // FALL THROUGH
242 : case tVar :
243 0 : *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
244 0 : *resultID = NS_GET_IID(nsIVariant);
245 0 : break;
246 : case tArr :
247 : // FALL THROUGH
248 : case tUnk :
249 : // FALL THROUGH
250 : case tErr :
251 : // FALL THROUGH
252 : default:
253 0 : NS_ERROR("bad state");
254 0 : return false;
255 : }
256 0 : return true;
257 : }
258 :
259 3 : bool XPCVariant::InitializeData(JSContext* cx)
260 : {
261 3 : if (!js::CheckRecursionLimit(cx))
262 0 : return false;
263 :
264 6 : RootedValue val(cx, GetJSVal());
265 :
266 3 : if (val.isInt32()) {
267 1 : mData.SetFromInt32(val.toInt32());
268 1 : return true;
269 : }
270 2 : if (val.isDouble()) {
271 0 : mData.SetFromDouble(val.toDouble());
272 0 : return true;
273 : }
274 2 : if (val.isBoolean()) {
275 0 : mData.SetFromBool(val.toBoolean());
276 0 : return true;
277 : }
278 : // We can't represent symbol on C++ side, so pretend it is void.
279 2 : if (val.isUndefined() || val.isSymbol()) {
280 0 : mData.SetToVoid();
281 0 : return true;
282 : }
283 2 : if (val.isNull()) {
284 0 : mData.SetToEmpty();
285 0 : return true;
286 : }
287 2 : if (val.isString()) {
288 2 : JSString* str = val.toString();
289 2 : if (!str)
290 0 : return false;
291 :
292 2 : MOZ_ASSERT(mData.GetType() == nsIDataType::VTYPE_EMPTY,
293 : "Why do we already have data?");
294 :
295 2 : size_t length = JS_GetStringLength(str);
296 2 : mData.AllocateWStringWithSize(length);
297 :
298 2 : mozilla::Range<char16_t> destChars(mData.u.wstr.mWStringValue, length);
299 2 : if (!JS_CopyStringChars(cx, destChars, str))
300 0 : return false;
301 :
302 2 : MOZ_ASSERT(mData.u.wstr.mWStringValue[length] == '\0');
303 2 : return true;
304 : }
305 :
306 : // leaving only JSObject...
307 0 : MOZ_ASSERT(val.isObject(), "invalid type of jsval!");
308 :
309 0 : RootedObject jsobj(cx, &val.toObject());
310 :
311 : // Let's see if it is a xpcJSID.
312 :
313 0 : const nsID* id = xpc_JSObjectToID(cx, jsobj);
314 0 : if (id) {
315 0 : mData.SetFromID(*id);
316 0 : return true;
317 : }
318 :
319 : // Let's see if it is a js array object.
320 :
321 : uint32_t len;
322 :
323 : bool isArray;
324 0 : if (!JS_IsArrayObject(cx, jsobj, &isArray) ||
325 0 : (isArray && !JS_GetArrayLength(cx, jsobj, &len)))
326 : {
327 0 : return false;
328 : }
329 :
330 0 : if (isArray) {
331 0 : if (!len) {
332 : // Zero length array
333 0 : mData.SetToEmptyArray();
334 0 : return true;
335 : }
336 :
337 0 : nsXPTType type;
338 : nsID id;
339 :
340 0 : if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id))
341 0 : return false;
342 :
343 0 : if (!XPCConvert::JSArray2Native(&mData.u.array.mArrayValue,
344 : val, len, type, &id, nullptr))
345 0 : return false;
346 :
347 0 : mData.mType = nsIDataType::VTYPE_ARRAY;
348 0 : if (type.IsInterfacePointer())
349 0 : mData.u.array.mArrayInterfaceID = id;
350 0 : mData.u.array.mArrayCount = len;
351 0 : mData.u.array.mArrayType = type.TagPart();
352 :
353 0 : return true;
354 : }
355 :
356 : // XXX This could be smarter and pick some more interesting iface.
357 :
358 0 : nsXPConnect* xpc = nsXPConnect::XPConnect();
359 0 : nsCOMPtr<nsISupports> wrapper;
360 0 : const nsIID& iid = NS_GET_IID(nsISupports);
361 :
362 0 : if (NS_FAILED(xpc->WrapJS(cx, jsobj, iid, getter_AddRefs(wrapper)))) {
363 0 : return false;
364 : }
365 :
366 0 : mData.SetFromInterface(iid, wrapper);
367 0 : return true;
368 : }
369 :
370 : NS_IMETHODIMP
371 0 : XPCVariant::GetAsJSVal(MutableHandleValue result)
372 : {
373 0 : result.set(GetJSVal());
374 0 : return NS_OK;
375 : }
376 :
377 : // static
378 : bool
379 45 : XPCVariant::VariantDataToJS(nsIVariant* variant,
380 : nsresult* pErr, MutableHandleValue pJSVal)
381 : {
382 : // Get the type early because we might need to spoof it below.
383 : uint16_t type;
384 45 : if (NS_FAILED(variant->GetDataType(&type)))
385 0 : return false;
386 :
387 90 : AutoJSContext cx;
388 90 : RootedValue realVal(cx);
389 45 : nsresult rv = variant->GetAsJSVal(&realVal);
390 :
391 45 : if (NS_SUCCEEDED(rv) &&
392 0 : (realVal.isPrimitive() ||
393 0 : type == nsIDataType::VTYPE_ARRAY ||
394 0 : type == nsIDataType::VTYPE_EMPTY_ARRAY ||
395 0 : type == nsIDataType::VTYPE_ID)) {
396 0 : if (!JS_WrapValue(cx, &realVal))
397 0 : return false;
398 0 : pJSVal.set(realVal);
399 0 : return true;
400 : }
401 :
402 90 : nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
403 45 : if (xpcvariant && xpcvariant->mReturnRawObject) {
404 0 : MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE ||
405 : type == nsIDataType::VTYPE_INTERFACE_IS,
406 : "Weird variant");
407 :
408 0 : if (!JS_WrapValue(cx, &realVal))
409 0 : return false;
410 0 : pJSVal.set(realVal);
411 0 : return true;
412 : }
413 :
414 : // else, it's an object and we really need to double wrap it if we've
415 : // already decided that its 'natural' type is as some sort of interface.
416 :
417 : // We just fall through to the code below and let it do what it does.
418 :
419 : // The nsIVariant is not a XPCVariant (or we act like it isn't).
420 : // So we extract the data and do the Right Thing.
421 :
422 : // We ASSUME that the variant implementation can do these conversions...
423 :
424 : nsID iid;
425 :
426 45 : switch (type) {
427 : case nsIDataType::VTYPE_INT8:
428 : case nsIDataType::VTYPE_INT16:
429 : case nsIDataType::VTYPE_INT32:
430 : case nsIDataType::VTYPE_INT64:
431 : case nsIDataType::VTYPE_UINT8:
432 : case nsIDataType::VTYPE_UINT16:
433 : case nsIDataType::VTYPE_UINT32:
434 : case nsIDataType::VTYPE_UINT64:
435 : case nsIDataType::VTYPE_FLOAT:
436 : case nsIDataType::VTYPE_DOUBLE:
437 : {
438 : double d;
439 15 : if (NS_FAILED(variant->GetAsDouble(&d)))
440 0 : return false;
441 15 : pJSVal.setNumber(d);
442 15 : return true;
443 : }
444 : case nsIDataType::VTYPE_BOOL:
445 : {
446 : bool b;
447 15 : if (NS_FAILED(variant->GetAsBool(&b)))
448 0 : return false;
449 15 : pJSVal.setBoolean(b);
450 15 : return true;
451 : }
452 : case nsIDataType::VTYPE_CHAR:
453 : {
454 : char c;
455 0 : if (NS_FAILED(variant->GetAsChar(&c)))
456 0 : return false;
457 0 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, TD_CHAR, &iid, pErr);
458 : }
459 : case nsIDataType::VTYPE_WCHAR:
460 : {
461 : char16_t wc;
462 0 : if (NS_FAILED(variant->GetAsWChar(&wc)))
463 0 : return false;
464 0 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, TD_WCHAR, &iid, pErr);
465 : }
466 : case nsIDataType::VTYPE_ID:
467 : {
468 0 : if (NS_FAILED(variant->GetAsID(&iid)))
469 0 : return false;
470 0 : nsID* v = &iid;
471 0 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_PNSIID, &iid, pErr);
472 : }
473 : case nsIDataType::VTYPE_ASTRING:
474 : {
475 8 : nsAutoString astring;
476 4 : if (NS_FAILED(variant->GetAsAString(astring)))
477 0 : return false;
478 4 : nsAutoString* v = &astring;
479 4 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_ASTRING, &iid, pErr);
480 : }
481 : case nsIDataType::VTYPE_DOMSTRING:
482 : {
483 0 : nsAutoString astring;
484 0 : if (NS_FAILED(variant->GetAsAString(astring)))
485 0 : return false;
486 0 : nsAutoString* v = &astring;
487 0 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
488 0 : TD_DOMSTRING, &iid, pErr);
489 : }
490 : case nsIDataType::VTYPE_CSTRING:
491 : {
492 18 : nsAutoCString cString;
493 9 : if (NS_FAILED(variant->GetAsACString(cString)))
494 0 : return false;
495 9 : nsAutoCString* v = &cString;
496 18 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
497 9 : TD_CSTRING, &iid, pErr);
498 : }
499 : case nsIDataType::VTYPE_UTF8STRING:
500 : {
501 0 : nsUTF8String utf8String;
502 0 : if (NS_FAILED(variant->GetAsAUTF8String(utf8String)))
503 0 : return false;
504 0 : nsUTF8String* v = &utf8String;
505 0 : return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
506 0 : TD_UTF8STRING, &iid, pErr);
507 : }
508 : case nsIDataType::VTYPE_CHAR_STR:
509 : {
510 : char* pc;
511 0 : if (NS_FAILED(variant->GetAsString(&pc)))
512 0 : return false;
513 0 : bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pc,
514 0 : TD_PSTRING, &iid, pErr);
515 0 : free(pc);
516 0 : return success;
517 : }
518 : case nsIDataType::VTYPE_STRING_SIZE_IS:
519 : {
520 : char* pc;
521 : uint32_t size;
522 0 : if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc)))
523 0 : return false;
524 0 : bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pc,
525 0 : TD_PSTRING_SIZE_IS, size, pErr);
526 0 : free(pc);
527 0 : return success;
528 : }
529 : case nsIDataType::VTYPE_WCHAR_STR:
530 : {
531 : char16_t* pwc;
532 0 : if (NS_FAILED(variant->GetAsWString(&pwc)))
533 0 : return false;
534 0 : bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pwc,
535 0 : TD_PSTRING, &iid, pErr);
536 0 : free(pwc);
537 0 : return success;
538 : }
539 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
540 : {
541 : char16_t* pwc;
542 : uint32_t size;
543 0 : if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc)))
544 0 : return false;
545 0 : bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pwc,
546 0 : TD_PWSTRING_SIZE_IS, size, pErr);
547 0 : free(pwc);
548 0 : return success;
549 : }
550 : case nsIDataType::VTYPE_INTERFACE:
551 : case nsIDataType::VTYPE_INTERFACE_IS:
552 : {
553 : nsISupports* pi;
554 : nsID* piid;
555 0 : if (NS_FAILED(variant->GetAsInterface(&piid, (void**)&pi)))
556 0 : return false;
557 :
558 0 : iid = *piid;
559 0 : free((char*)piid);
560 :
561 0 : bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pi,
562 0 : TD_INTERFACE_IS_TYPE, &iid, pErr);
563 0 : if (pi)
564 0 : pi->Release();
565 0 : return success;
566 : }
567 : case nsIDataType::VTYPE_ARRAY:
568 : {
569 0 : nsDiscriminatedUnion du;
570 : nsresult rv;
571 :
572 : rv = variant->GetAsArray(&du.u.array.mArrayType,
573 : &du.u.array.mArrayInterfaceID,
574 : &du.u.array.mArrayCount,
575 0 : &du.u.array.mArrayValue);
576 0 : if (NS_FAILED(rv))
577 0 : return false;
578 :
579 : // must exit via VARIANT_DONE from here on...
580 0 : du.mType = nsIDataType::VTYPE_ARRAY;
581 :
582 0 : nsXPTType conversionType;
583 0 : uint16_t elementType = du.u.array.mArrayType;
584 0 : const nsID* pid = nullptr;
585 :
586 0 : switch (elementType) {
587 : case nsIDataType::VTYPE_INT8:
588 : case nsIDataType::VTYPE_INT16:
589 : case nsIDataType::VTYPE_INT32:
590 : case nsIDataType::VTYPE_INT64:
591 : case nsIDataType::VTYPE_UINT8:
592 : case nsIDataType::VTYPE_UINT16:
593 : case nsIDataType::VTYPE_UINT32:
594 : case nsIDataType::VTYPE_UINT64:
595 : case nsIDataType::VTYPE_FLOAT:
596 : case nsIDataType::VTYPE_DOUBLE:
597 : case nsIDataType::VTYPE_BOOL:
598 : case nsIDataType::VTYPE_CHAR:
599 : case nsIDataType::VTYPE_WCHAR:
600 0 : conversionType = nsXPTType((uint8_t)elementType);
601 0 : break;
602 :
603 : case nsIDataType::VTYPE_ID:
604 : case nsIDataType::VTYPE_CHAR_STR:
605 : case nsIDataType::VTYPE_WCHAR_STR:
606 0 : conversionType = nsXPTType((uint8_t)elementType);
607 0 : break;
608 :
609 : case nsIDataType::VTYPE_INTERFACE:
610 0 : pid = &NS_GET_IID(nsISupports);
611 0 : conversionType = nsXPTType((uint8_t)elementType);
612 0 : break;
613 :
614 : case nsIDataType::VTYPE_INTERFACE_IS:
615 0 : pid = &du.u.array.mArrayInterfaceID;
616 0 : conversionType = nsXPTType((uint8_t)elementType);
617 0 : break;
618 :
619 : // The rest are illegal.
620 : case nsIDataType::VTYPE_VOID:
621 : case nsIDataType::VTYPE_ASTRING:
622 : case nsIDataType::VTYPE_DOMSTRING:
623 : case nsIDataType::VTYPE_CSTRING:
624 : case nsIDataType::VTYPE_UTF8STRING:
625 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
626 : case nsIDataType::VTYPE_STRING_SIZE_IS:
627 : case nsIDataType::VTYPE_ARRAY:
628 : case nsIDataType::VTYPE_EMPTY_ARRAY:
629 : case nsIDataType::VTYPE_EMPTY:
630 : default:
631 0 : NS_ERROR("bad type in array!");
632 0 : return false;
633 : }
634 :
635 : bool success =
636 0 : XPCConvert::NativeArray2JS(pJSVal,
637 : (const void**)&du.u.array.mArrayValue,
638 : conversionType, pid,
639 0 : du.u.array.mArrayCount, pErr);
640 :
641 0 : return success;
642 : }
643 : case nsIDataType::VTYPE_EMPTY_ARRAY:
644 : {
645 0 : JSObject* array = JS_NewArrayObject(cx, 0);
646 0 : if (!array)
647 0 : return false;
648 0 : pJSVal.setObject(*array);
649 0 : return true;
650 : }
651 : case nsIDataType::VTYPE_VOID:
652 0 : pJSVal.setUndefined();
653 0 : return true;
654 : case nsIDataType::VTYPE_EMPTY:
655 2 : pJSVal.setNull();
656 2 : return true;
657 : default:
658 0 : NS_ERROR("bad type in variant!");
659 0 : return false;
660 : }
661 : }
662 :
663 : /***************************************************************************/
664 : /***************************************************************************/
665 : // XXX These default implementations need to be improved to allow for
666 : // some more interesting conversions.
667 :
668 :
669 3 : NS_IMETHODIMP XPCVariant::GetDataType(uint16_t* aDataType)
670 : {
671 3 : *aDataType = mData.GetType();
672 3 : return NS_OK;
673 : }
674 :
675 0 : NS_IMETHODIMP XPCVariant::GetAsInt8(uint8_t* _retval)
676 : {
677 0 : return mData.ConvertToInt8(_retval);
678 : }
679 :
680 0 : NS_IMETHODIMP XPCVariant::GetAsInt16(int16_t* _retval)
681 : {
682 0 : return mData.ConvertToInt16(_retval);
683 : }
684 :
685 0 : NS_IMETHODIMP XPCVariant::GetAsInt32(int32_t* _retval)
686 : {
687 0 : return mData.ConvertToInt32(_retval);
688 : }
689 :
690 1 : NS_IMETHODIMP XPCVariant::GetAsInt64(int64_t* _retval)
691 : {
692 1 : return mData.ConvertToInt64(_retval);
693 : }
694 :
695 0 : NS_IMETHODIMP XPCVariant::GetAsUint8(uint8_t* _retval)
696 : {
697 0 : return mData.ConvertToUint8(_retval);
698 : }
699 :
700 0 : NS_IMETHODIMP XPCVariant::GetAsUint16(uint16_t* _retval)
701 : {
702 0 : return mData.ConvertToUint16(_retval);
703 : }
704 :
705 0 : NS_IMETHODIMP XPCVariant::GetAsUint32(uint32_t* _retval)
706 : {
707 0 : return mData.ConvertToUint32(_retval);
708 : }
709 :
710 0 : NS_IMETHODIMP XPCVariant::GetAsUint64(uint64_t* _retval)
711 : {
712 0 : return mData.ConvertToUint64(_retval);
713 : }
714 :
715 0 : NS_IMETHODIMP XPCVariant::GetAsFloat(float* _retval)
716 : {
717 0 : return mData.ConvertToFloat(_retval);
718 : }
719 :
720 0 : NS_IMETHODIMP XPCVariant::GetAsDouble(double* _retval)
721 : {
722 0 : return mData.ConvertToDouble(_retval);
723 : }
724 :
725 0 : NS_IMETHODIMP XPCVariant::GetAsBool(bool* _retval)
726 : {
727 0 : return mData.ConvertToBool(_retval);
728 : }
729 :
730 0 : NS_IMETHODIMP XPCVariant::GetAsChar(char* _retval)
731 : {
732 0 : return mData.ConvertToChar(_retval);
733 : }
734 :
735 0 : NS_IMETHODIMP XPCVariant::GetAsWChar(char16_t* _retval)
736 : {
737 0 : return mData.ConvertToWChar(_retval);
738 : }
739 :
740 0 : NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID* retval)
741 : {
742 0 : return mData.ConvertToID(retval);
743 : }
744 :
745 2 : NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval)
746 : {
747 2 : return mData.ConvertToAString(_retval);
748 : }
749 :
750 0 : NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval)
751 : {
752 : // A DOMString maps to an AString internally, so we can re-use
753 : // ConvertToAString here.
754 0 : return mData.ConvertToAString(_retval);
755 : }
756 :
757 0 : NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval)
758 : {
759 0 : return mData.ConvertToACString(_retval);
760 : }
761 :
762 0 : NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval)
763 : {
764 0 : return mData.ConvertToAUTF8String(_retval);
765 : }
766 :
767 0 : NS_IMETHODIMP XPCVariant::GetAsString(char** _retval)
768 : {
769 0 : return mData.ConvertToString(_retval);
770 : }
771 :
772 0 : NS_IMETHODIMP XPCVariant::GetAsWString(char16_t** _retval)
773 : {
774 0 : return mData.ConvertToWString(_retval);
775 : }
776 :
777 0 : NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports** _retval)
778 : {
779 0 : return mData.ConvertToISupports(_retval);
780 : }
781 :
782 0 : NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID** iid, void** iface)
783 : {
784 0 : return mData.ConvertToInterface(iid, iface);
785 : }
786 :
787 :
788 0 : NS_IMETHODIMP_(nsresult) XPCVariant::GetAsArray(uint16_t* type, nsIID* iid, uint32_t* count, void * *ptr)
789 : {
790 0 : return mData.ConvertToArray(type, iid, count, ptr);
791 : }
792 :
793 0 : NS_IMETHODIMP XPCVariant::GetAsStringWithSize(uint32_t* size, char** str)
794 : {
795 0 : return mData.ConvertToStringWithSize(size, str);
796 : }
797 :
798 0 : NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(uint32_t* size, char16_t** str)
799 : {
800 0 : return mData.ConvertToWStringWithSize(size, str);
801 : }
|