1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * John Bandhauer <jband@netscape.com> (original author)
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /* nsIVariant implementation for xpconnect. */
42 :
43 : #include "xpcprivate.h"
44 : #include "XPCWrapper.h"
45 :
46 : #include "jsfriendapi.h"
47 :
48 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
49 :
50 : NS_IMPL_CLASSINFO(XPCVariant, NULL, 0, XPCVARIANT_CID)
51 13896 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant)
52 3431 : NS_INTERFACE_MAP_ENTRY(XPCVariant)
53 3061 : NS_INTERFACE_MAP_ENTRY(nsIVariant)
54 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
55 0 : NS_IMPL_QUERY_CLASSINFO(XPCVariant)
56 0 : NS_INTERFACE_MAP_END
57 0 : NS_IMPL_CI_INTERFACE_GETTER2(XPCVariant, XPCVariant, nsIVariant)
58 :
59 13636 : NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant)
60 13636 : NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant)
61 :
62 6515 : XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal)
63 6515 : : mJSVal(aJSVal), mCCGeneration(0)
64 : {
65 6515 : nsVariant::Initialize(&mData);
66 6515 : if (!JSVAL_IS_PRIMITIVE(mJSVal)) {
67 887 : JSObject *obj = JS_ObjectToInnerObject(ccx, JSVAL_TO_OBJECT(mJSVal));
68 :
69 887 : mJSVal = OBJECT_TO_JSVAL(obj);
70 :
71 : // If the incoming object is an XPCWrappedNative, then it could be a
72 : // double-wrapped object, and we should return the double-wrapped
73 : // object back out to script.
74 :
75 : JSObject* proto;
76 : XPCWrappedNative* wn =
77 : XPCWrappedNative::GetWrappedNativeOfJSObject(ccx,
78 : JSVAL_TO_OBJECT(mJSVal),
79 : nsnull,
80 887 : &proto);
81 887 : mReturnRawObject = !wn && !proto;
82 : } else
83 5628 : mReturnRawObject = false;
84 6515 : }
85 :
86 10389 : XPCTraceableVariant::~XPCTraceableVariant()
87 : {
88 3463 : jsval val = GetJSValPreserveColor();
89 :
90 3463 : NS_ASSERTION(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked");
91 :
92 : // If val is JSVAL_STRING, we don't need to clean anything up; simply
93 : // removing the string from the root set is good.
94 3463 : if (!JSVAL_IS_STRING(val))
95 887 : nsVariant::Cleanup(&mData);
96 :
97 3463 : if (!JSVAL_IS_NULL(val))
98 3463 : RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
99 13852 : }
100 :
101 551 : void XPCTraceableVariant::TraceJS(JSTracer* trc)
102 : {
103 551 : jsval val = GetJSValPreserveColor();
104 :
105 551 : NS_ASSERTION(JSVAL_IS_TRACEABLE(val), "Must be traceable");
106 551 : JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
107 551 : JS_CallTracer(trc, JSVAL_TO_TRACEABLE(val), JSVAL_TRACE_KIND(val));
108 551 : }
109 :
110 : #ifdef DEBUG
111 : // static
112 : void
113 0 : XPCTraceableVariant::PrintTraceName(JSTracer* trc, char *buf, size_t bufsize)
114 : {
115 0 : JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg);
116 0 : }
117 : #endif
118 :
119 2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
120 2 : jsval val = tmp->GetJSValPreserveColor();
121 2 : if (JSVAL_IS_OBJECT(val)) {
122 2 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
123 : cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
124 2 : JSVAL_TO_OBJECT(val));
125 : }
126 :
127 2 : nsVariant::Traverse(tmp->mData, cb);
128 2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
129 :
130 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
131 0 : jsval val = tmp->GetJSValPreserveColor();
132 :
133 : // We're sharing val's buffer, clear the pointer to it so Cleanup() won't
134 : // try to delete it
135 0 : if (JSVAL_IS_STRING(val))
136 0 : tmp->mData.u.wstr.mWStringValue = nsnull;
137 0 : nsVariant::Cleanup(&tmp->mData);
138 :
139 0 : if (JSVAL_IS_TRACEABLE(val)) {
140 0 : XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp);
141 0 : v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
142 : }
143 0 : tmp->mJSVal = JSVAL_NULL;
144 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
145 :
146 : // static
147 6515 : XPCVariant* XPCVariant::newVariant(XPCCallContext& ccx, jsval aJSVal)
148 : {
149 : XPCVariant* variant;
150 :
151 6515 : if (!JSVAL_IS_TRACEABLE(aJSVal))
152 3052 : variant = new XPCVariant(ccx, aJSVal);
153 : else
154 3463 : variant = new XPCTraceableVariant(ccx, aJSVal);
155 :
156 6515 : if (!variant)
157 0 : return nsnull;
158 6515 : NS_ADDREF(variant);
159 :
160 6515 : if (!variant->InitializeData(ccx))
161 0 : NS_RELEASE(variant); // Also sets variant to nsnull.
162 :
163 6515 : return variant;
164 : }
165 :
166 : // Helper class to give us a namespace for the table based code below.
167 : class XPCArrayHomogenizer
168 : {
169 : private:
170 : enum Type
171 : {
172 : tNull = 0 , // null value
173 : tInt , // Integer
174 : tDbl , // Double
175 : tBool , // Boolean
176 : tStr , // String
177 : tID , // ID
178 : tArr , // Array
179 : tISup , // nsISupports (really just a plain JSObject)
180 : tUnk , // Unknown. Used only for initial state.
181 :
182 : tTypeCount , // Just a count for table dimensioning.
183 :
184 : tVar , // nsVariant - last ditch if no other common type found.
185 : tErr // No valid state or type has this value.
186 : };
187 :
188 : // Table has tUnk as a state (column) but not as a type (row).
189 : static const Type StateTable[tTypeCount][tTypeCount-1];
190 :
191 : public:
192 : static JSBool GetTypeForArray(XPCCallContext& ccx, JSObject* array,
193 : uint32_t length,
194 : nsXPTType* resultType, nsID* resultID);
195 : };
196 :
197 :
198 : // Current state is the column down the side.
199 : // Current type is the row along the top.
200 : // New state is in the box at the intersection.
201 :
202 : const XPCArrayHomogenizer::Type
203 : XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = {
204 : /* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */
205 : /* tNull */{tNull,tVar ,tVar ,tVar ,tStr ,tID ,tVar ,tISup },
206 : /* tInt */{tVar ,tInt ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
207 : /* tDbl */{tVar ,tDbl ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
208 : /* tBool */{tVar ,tVar ,tVar ,tBool,tVar ,tVar ,tVar ,tVar },
209 : /* tStr */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar },
210 : /* tID */{tID ,tVar ,tVar ,tVar ,tVar ,tID ,tVar ,tVar },
211 : /* tArr */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr },
212 : /* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup },
213 : /* tUnk */{tNull,tInt ,tDbl ,tBool,tStr ,tID ,tVar ,tISup }};
214 :
215 : // static
216 : JSBool
217 436 : XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array,
218 : uint32_t length,
219 : nsXPTType* resultType, nsID* resultID)
220 : {
221 436 : Type state = tUnk;
222 : Type type;
223 :
224 1930 : for (uint32_t i = 0; i < length; i++) {
225 : jsval val;
226 1505 : if (!JS_GetElement(ccx, array, i, &val))
227 0 : return false;
228 :
229 1505 : if (JSVAL_IS_INT(val))
230 6 : type = tInt;
231 1499 : else if (JSVAL_IS_DOUBLE(val))
232 5 : type = tDbl;
233 1494 : else if (JSVAL_IS_BOOLEAN(val))
234 0 : type = tBool;
235 1494 : else if (JSVAL_IS_VOID(val)) {
236 4 : state = tVar;
237 4 : break;
238 1490 : } else if (JSVAL_IS_NULL(val))
239 2 : type = tNull;
240 1488 : else if (JSVAL_IS_STRING(val))
241 1389 : type = tStr;
242 : else {
243 99 : NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!");
244 99 : JSObject* jsobj = JSVAL_TO_OBJECT(val);
245 99 : if (JS_IsArrayObject(ccx, jsobj))
246 0 : type = tArr;
247 99 : else if (xpc_JSObjectIsID(ccx, jsobj))
248 0 : type = tID;
249 : else
250 99 : type = tISup;
251 : }
252 :
253 1501 : NS_ASSERTION(state != tErr, "bad state table!");
254 1501 : NS_ASSERTION(type != tErr, "bad type!");
255 1501 : NS_ASSERTION(type != tVar, "bad type!");
256 1501 : NS_ASSERTION(type != tUnk, "bad type!");
257 :
258 1501 : state = StateTable[state][type];
259 :
260 1501 : NS_ASSERTION(state != tErr, "bad state table!");
261 1501 : NS_ASSERTION(state != tUnk, "bad state table!");
262 :
263 1501 : if (state == tVar)
264 7 : break;
265 : }
266 :
267 436 : switch (state) {
268 : case tInt :
269 1 : *resultType = nsXPTType((uint8_t)TD_INT32);
270 1 : break;
271 : case tDbl :
272 1 : *resultType = nsXPTType((uint8_t)TD_DOUBLE);
273 1 : break;
274 : case tBool:
275 0 : *resultType = nsXPTType((uint8_t)TD_BOOL);
276 0 : break;
277 : case tStr :
278 404 : *resultType = nsXPTType((uint8_t)TD_PWSTRING);
279 404 : break;
280 : case tID :
281 0 : *resultType = nsXPTType((uint8_t)TD_PNSIID);
282 0 : break;
283 : case tISup:
284 18 : *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
285 18 : *resultID = NS_GET_IID(nsISupports);
286 18 : break;
287 : case tNull:
288 : // FALL THROUGH
289 : case tVar :
290 12 : *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
291 12 : *resultID = NS_GET_IID(nsIVariant);
292 12 : break;
293 : case tArr :
294 : // FALL THROUGH
295 : case tUnk :
296 : // FALL THROUGH
297 : case tErr :
298 : // FALL THROUGH
299 : default:
300 0 : NS_ERROR("bad state");
301 0 : return false;
302 : }
303 436 : return true;
304 : }
305 :
306 6515 : JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
307 : {
308 6515 : JS_CHECK_RECURSION(ccx.GetJSContext(), return false);
309 :
310 6515 : jsval val = GetJSVal();
311 :
312 6515 : if (JSVAL_IS_INT(val))
313 1212 : return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, JSVAL_TO_INT(val)));
314 5303 : if (JSVAL_IS_DOUBLE(val))
315 566 : return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData,
316 : JSVAL_TO_DOUBLE(val)));
317 4737 : if (JSVAL_IS_BOOLEAN(val))
318 388 : return NS_SUCCEEDED(nsVariant::SetFromBool(&mData,
319 : JSVAL_TO_BOOLEAN(val)));
320 4349 : if (JSVAL_IS_VOID(val))
321 50 : return NS_SUCCEEDED(nsVariant::SetToVoid(&mData));
322 4299 : if (JSVAL_IS_NULL(val))
323 836 : return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData));
324 3463 : if (JSVAL_IS_STRING(val)) {
325 : // Make our string immutable. This will also ensure null-termination,
326 : // which nsVariant assumes for its PRUnichar* stuff.
327 2576 : JSString* str = JSVAL_TO_STRING(val);
328 2576 : if (!JS_MakeStringImmutable(ccx, str))
329 0 : return false;
330 :
331 : // Don't use nsVariant::SetFromWStringWithSize, because that will copy
332 : // the data. Just handle this ourselves. Note that it's ok to not
333 : // copy because we added mJSVal as a GC root.
334 2576 : NS_ASSERTION(mData.mType == nsIDataType::VTYPE_EMPTY,
335 : "Why do we already have data?");
336 :
337 : // Despite the fact that the variant holds the length, there are
338 : // implicit assumptions that mWStringValue[mWStringLength] == 0
339 : size_t length;
340 2576 : const jschar *chars = JS_GetStringCharsZAndLength(ccx, str, &length);
341 2576 : if (!chars)
342 0 : return false;
343 :
344 2576 : mData.u.wstr.mWStringValue = const_cast<jschar *>(chars);
345 : // Use C-style cast, because reinterpret cast from size_t to
346 : // PRUint32 is not valid on some platforms.
347 2576 : mData.u.wstr.mWStringLength = (PRUint32)length;
348 2576 : mData.mType = nsIDataType::VTYPE_WSTRING_SIZE_IS;
349 :
350 2576 : return true;
351 : }
352 :
353 : // leaving only JSObject...
354 887 : NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!");
355 :
356 887 : JSObject* jsobj = JSVAL_TO_OBJECT(val);
357 :
358 : // Let's see if it is a xpcJSID.
359 :
360 887 : const nsID* id = xpc_JSObjectToID(ccx, jsobj);
361 887 : if (id)
362 0 : return NS_SUCCEEDED(nsVariant::SetFromID(&mData, *id));
363 :
364 : // Let's see if it is a js array object.
365 :
366 : uint32_t len;
367 :
368 887 : if (JS_IsArrayObject(ccx, jsobj) && JS_GetArrayLength(ccx, jsobj, &len)) {
369 508 : if (!len) {
370 : // Zero length array
371 72 : nsVariant::SetToEmptyArray(&mData);
372 72 : return true;
373 : }
374 :
375 436 : nsXPTType type;
376 : nsID id;
377 :
378 436 : if (!XPCArrayHomogenizer::GetTypeForArray(ccx, jsobj, len, &type, &id))
379 0 : return false;
380 :
381 436 : if (!XPCConvert::JSArray2Native(ccx, &mData.u.array.mArrayValue,
382 436 : val, len, type, &id, nsnull))
383 0 : return false;
384 :
385 436 : mData.mType = nsIDataType::VTYPE_ARRAY;
386 436 : if (type.IsInterfacePointer())
387 30 : mData.u.array.mArrayInterfaceID = id;
388 436 : mData.u.array.mArrayCount = len;
389 436 : mData.u.array.mArrayType = type.TagPart();
390 :
391 436 : return true;
392 : }
393 :
394 : // XXX This could be smarter and pick some more interesting iface.
395 :
396 : nsXPConnect* xpc;
397 758 : nsCOMPtr<nsISupports> wrapper;
398 379 : const nsIID& iid = NS_GET_IID(nsISupports);
399 :
400 : return nsnull != (xpc = nsXPConnect::GetXPConnect()) &&
401 1137 : NS_SUCCEEDED(xpc->WrapJS(ccx, jsobj,
402 : iid, getter_AddRefs(wrapper))) &&
403 1137 : NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
404 : }
405 :
406 : NS_IMETHODIMP
407 1487 : XPCVariant::GetAsJSVal(jsval* result)
408 : {
409 1487 : NS_PRECONDITION(result, "null result arg.");
410 1487 : *result = GetJSVal();
411 1487 : return NS_OK;
412 : }
413 :
414 : // static
415 : JSBool
416 126658 : XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
417 : nsIVariant* variant,
418 : nsresult* pErr, jsval* pJSVal)
419 : {
420 : // Get the type early because we might need to spoof it below.
421 : PRUint16 type;
422 126658 : if (NS_FAILED(variant->GetDataType(&type)))
423 0 : return false;
424 :
425 : jsval realVal;
426 126658 : nsresult rv = variant->GetAsJSVal(&realVal);
427 :
428 128145 : if (NS_SUCCEEDED(rv) &&
429 1487 : (JSVAL_IS_PRIMITIVE(realVal) ||
430 : type == nsIDataType::VTYPE_ARRAY ||
431 : type == nsIDataType::VTYPE_EMPTY_ARRAY ||
432 : type == nsIDataType::VTYPE_ID)) {
433 1117 : JSContext *cx = lccx.GetJSContext();
434 1117 : if (!JS_WrapValue(cx, &realVal))
435 0 : return false;
436 1117 : *pJSVal = realVal;
437 1117 : return true;
438 : }
439 :
440 251082 : nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
441 125541 : if (xpcvariant && xpcvariant->mReturnRawObject) {
442 122 : NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
443 : type == nsIDataType::VTYPE_INTERFACE_IS,
444 : "Weird variant");
445 :
446 122 : JSContext *cx = lccx.GetJSContext();
447 122 : if (!JS_WrapValue(cx, &realVal))
448 0 : return false;
449 122 : *pJSVal = realVal;
450 122 : return true;
451 : }
452 :
453 : // else, it's an object and we really need to double wrap it if we've
454 : // already decided that its 'natural' type is as some sort of interface.
455 :
456 : // We just fall through to the code below and let it do what it does.
457 :
458 : // The nsIVariant is not a XPCVariant (or we act like it isn't).
459 : // So we extract the data and do the Right Thing.
460 :
461 : // We ASSUME that the variant implementation can do these conversions...
462 :
463 125419 : nsXPTCVariant xpctvar;
464 : nsID iid;
465 250838 : nsAutoString astring;
466 250838 : nsCAutoString cString;
467 250838 : nsUTF8String utf8String;
468 : PRUint32 size;
469 125419 : xpctvar.flags = 0;
470 : JSBool success;
471 :
472 125419 : JSContext* cx = lccx.GetJSContext();
473 125419 : NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
474 : "bad scope for new JSObjects");
475 :
476 125419 : switch (type) {
477 : case nsIDataType::VTYPE_INT8:
478 : case nsIDataType::VTYPE_INT16:
479 : case nsIDataType::VTYPE_INT32:
480 : case nsIDataType::VTYPE_INT64:
481 : case nsIDataType::VTYPE_UINT8:
482 : case nsIDataType::VTYPE_UINT16:
483 : case nsIDataType::VTYPE_UINT32:
484 : case nsIDataType::VTYPE_UINT64:
485 : case nsIDataType::VTYPE_FLOAT:
486 : case nsIDataType::VTYPE_DOUBLE:
487 : {
488 : // Easy. Handle inline.
489 47037 : if (NS_FAILED(variant->GetAsDouble(&xpctvar.val.d)))
490 0 : return false;
491 47037 : return JS_NewNumberValue(cx, xpctvar.val.d, pJSVal);
492 : }
493 : case nsIDataType::VTYPE_BOOL:
494 : {
495 : // Easy. Handle inline.
496 44 : if (NS_FAILED(variant->GetAsBool(&xpctvar.val.b)))
497 0 : return false;
498 44 : *pJSVal = BOOLEAN_TO_JSVAL(xpctvar.val.b);
499 44 : return true;
500 : }
501 : case nsIDataType::VTYPE_CHAR:
502 0 : if (NS_FAILED(variant->GetAsChar(&xpctvar.val.c)))
503 0 : return false;
504 0 : xpctvar.type = (uint8_t)TD_CHAR;
505 0 : break;
506 : case nsIDataType::VTYPE_WCHAR:
507 0 : if (NS_FAILED(variant->GetAsWChar(&xpctvar.val.wc)))
508 0 : return false;
509 0 : xpctvar.type = (uint8_t)TD_WCHAR;
510 0 : break;
511 : case nsIDataType::VTYPE_ID:
512 0 : if (NS_FAILED(variant->GetAsID(&iid)))
513 0 : return false;
514 0 : xpctvar.type = (uint8_t)TD_PNSIID;
515 0 : xpctvar.val.p = &iid;
516 0 : break;
517 : case nsIDataType::VTYPE_ASTRING:
518 33406 : if (NS_FAILED(variant->GetAsAString(astring)))
519 0 : return false;
520 33406 : xpctvar.type = (uint8_t)TD_ASTRING;
521 33406 : xpctvar.val.p = &astring;
522 33406 : break;
523 : case nsIDataType::VTYPE_DOMSTRING:
524 0 : if (NS_FAILED(variant->GetAsAString(astring)))
525 0 : return false;
526 0 : xpctvar.type = (uint8_t)TD_DOMSTRING;
527 0 : xpctvar.val.p = &astring;
528 0 : break;
529 : case nsIDataType::VTYPE_CSTRING:
530 135 : if (NS_FAILED(variant->GetAsACString(cString)))
531 0 : return false;
532 135 : xpctvar.type = (uint8_t)TD_CSTRING;
533 135 : xpctvar.val.p = &cString;
534 135 : break;
535 : case nsIDataType::VTYPE_UTF8STRING:
536 244 : if (NS_FAILED(variant->GetAsAUTF8String(utf8String)))
537 0 : return false;
538 244 : xpctvar.type = (uint8_t)TD_UTF8STRING;
539 244 : xpctvar.val.p = &utf8String;
540 244 : break;
541 : case nsIDataType::VTYPE_CHAR_STR:
542 0 : if (NS_FAILED(variant->GetAsString((char**)&xpctvar.val.p)))
543 0 : return false;
544 0 : xpctvar.type = (uint8_t)TD_PSTRING;
545 0 : xpctvar.SetValNeedsCleanup();
546 0 : break;
547 : case nsIDataType::VTYPE_STRING_SIZE_IS:
548 0 : if (NS_FAILED(variant->GetAsStringWithSize(&size,
549 : (char**)&xpctvar.val.p)))
550 0 : return false;
551 0 : xpctvar.type = (uint8_t)TD_PSTRING_SIZE_IS;
552 0 : xpctvar.SetValNeedsCleanup();
553 0 : break;
554 : case nsIDataType::VTYPE_WCHAR_STR:
555 0 : if (NS_FAILED(variant->GetAsWString((PRUnichar**)&xpctvar.val.p)))
556 0 : return false;
557 0 : xpctvar.type = (uint8_t)TD_PWSTRING;
558 0 : xpctvar.SetValNeedsCleanup();
559 0 : break;
560 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
561 0 : if (NS_FAILED(variant->GetAsWStringWithSize(&size,
562 : (PRUnichar**)&xpctvar.val.p)))
563 0 : return false;
564 0 : xpctvar.type = (uint8_t)TD_PWSTRING_SIZE_IS;
565 0 : xpctvar.SetValNeedsCleanup();
566 0 : break;
567 : case nsIDataType::VTYPE_INTERFACE:
568 : case nsIDataType::VTYPE_INTERFACE_IS:
569 : {
570 : nsID* piid;
571 2844 : if (NS_FAILED(variant->GetAsInterface(&piid, &xpctvar.val.p)))
572 0 : return false;
573 :
574 2844 : iid = *piid;
575 2844 : nsMemory::Free((char*)piid);
576 :
577 2844 : xpctvar.type = (uint8_t)TD_INTERFACE_IS_TYPE;
578 2844 : if (xpctvar.val.p)
579 2844 : xpctvar.SetValNeedsCleanup();
580 2844 : break;
581 : }
582 : case nsIDataType::VTYPE_ARRAY:
583 : {
584 : nsDiscriminatedUnion du;
585 1268 : nsVariant::Initialize(&du);
586 : nsresult rv;
587 :
588 : rv = variant->GetAsArray(&du.u.array.mArrayType,
589 : &du.u.array.mArrayInterfaceID,
590 : &du.u.array.mArrayCount,
591 1268 : &du.u.array.mArrayValue);
592 1268 : if (NS_FAILED(rv))
593 0 : return false;
594 :
595 : // must exit via VARIANT_DONE from here on...
596 1268 : du.mType = nsIDataType::VTYPE_ARRAY;
597 1268 : success = false;
598 :
599 1268 : nsXPTType conversionType;
600 1268 : PRUint16 elementType = du.u.array.mArrayType;
601 1268 : const nsID* pid = nsnull;
602 :
603 1268 : switch (elementType) {
604 : case nsIDataType::VTYPE_INT8:
605 : case nsIDataType::VTYPE_INT16:
606 : case nsIDataType::VTYPE_INT32:
607 : case nsIDataType::VTYPE_INT64:
608 : case nsIDataType::VTYPE_UINT8:
609 : case nsIDataType::VTYPE_UINT16:
610 : case nsIDataType::VTYPE_UINT32:
611 : case nsIDataType::VTYPE_UINT64:
612 : case nsIDataType::VTYPE_FLOAT:
613 : case nsIDataType::VTYPE_DOUBLE:
614 : case nsIDataType::VTYPE_BOOL:
615 : case nsIDataType::VTYPE_CHAR:
616 : case nsIDataType::VTYPE_WCHAR:
617 4 : conversionType = nsXPTType((uint8_t)elementType);
618 4 : break;
619 :
620 : case nsIDataType::VTYPE_ID:
621 : case nsIDataType::VTYPE_CHAR_STR:
622 : case nsIDataType::VTYPE_WCHAR_STR:
623 1264 : conversionType = nsXPTType((uint8_t)elementType);
624 1264 : break;
625 :
626 : case nsIDataType::VTYPE_INTERFACE:
627 0 : pid = &NS_GET_IID(nsISupports);
628 0 : conversionType = nsXPTType((uint8_t)elementType);
629 0 : break;
630 :
631 : case nsIDataType::VTYPE_INTERFACE_IS:
632 0 : pid = &du.u.array.mArrayInterfaceID;
633 0 : conversionType = nsXPTType((uint8_t)elementType);
634 0 : break;
635 :
636 : // The rest are illegal.
637 : case nsIDataType::VTYPE_VOID:
638 : case nsIDataType::VTYPE_ASTRING:
639 : case nsIDataType::VTYPE_DOMSTRING:
640 : case nsIDataType::VTYPE_CSTRING:
641 : case nsIDataType::VTYPE_UTF8STRING:
642 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
643 : case nsIDataType::VTYPE_STRING_SIZE_IS:
644 : case nsIDataType::VTYPE_ARRAY:
645 : case nsIDataType::VTYPE_EMPTY_ARRAY:
646 : case nsIDataType::VTYPE_EMPTY:
647 : default:
648 0 : NS_ERROR("bad type in array!");
649 0 : goto VARIANT_DONE;
650 : }
651 :
652 : success =
653 : XPCConvert::NativeArray2JS(lccx, pJSVal,
654 : (const void**)&du.u.array.mArrayValue,
655 : conversionType, pid,
656 1268 : du.u.array.mArrayCount, pErr);
657 :
658 : VARIANT_DONE:
659 1268 : nsVariant::Cleanup(&du);
660 1268 : return success;
661 : }
662 : case nsIDataType::VTYPE_EMPTY_ARRAY:
663 : {
664 7213 : JSObject* array = JS_NewArrayObject(cx, 0, nsnull);
665 7213 : if (!array)
666 0 : return false;
667 7213 : *pJSVal = OBJECT_TO_JSVAL(array);
668 7213 : return true;
669 : }
670 : case nsIDataType::VTYPE_VOID:
671 0 : *pJSVal = JSVAL_VOID;
672 0 : return true;
673 : case nsIDataType::VTYPE_EMPTY:
674 33228 : *pJSVal = JSVAL_NULL;
675 33228 : return true;
676 : default:
677 0 : NS_ERROR("bad type in variant!");
678 0 : return false;
679 : }
680 :
681 : // If we are here then we need to convert the data in the xpctvar.
682 :
683 73258 : if (xpctvar.type.TagPart() == TD_PSTRING_SIZE_IS ||
684 36629 : xpctvar.type.TagPart() == TD_PWSTRING_SIZE_IS) {
685 : success = XPCConvert::NativeStringWithSize2JS(cx, pJSVal,
686 : (const void*)&xpctvar.val,
687 : xpctvar.type,
688 0 : size, pErr);
689 : } else {
690 : success = XPCConvert::NativeData2JS(lccx, pJSVal,
691 : (const void*)&xpctvar.val,
692 : xpctvar.type,
693 36629 : &iid, pErr);
694 : }
695 :
696 : // We may have done something in the above code that requires cleanup.
697 36629 : if (xpctvar.DoesValNeedCleanup()) {
698 2844 : if (type == nsIDataType::VTYPE_INTERFACE ||
699 : type == nsIDataType::VTYPE_INTERFACE_IS)
700 2844 : ((nsISupports*)xpctvar.val.p)->Release();
701 : else
702 0 : nsMemory::Free((char*)xpctvar.val.p);
703 : }
704 :
705 36629 : return success;
706 : }
707 :
708 : /***************************************************************************/
709 : /***************************************************************************/
710 : // XXX These default implementations need to be improved to allow for
711 : // some more interesting conversions.
712 :
713 :
714 : /* readonly attribute PRUint16 dataType; */
715 5903 : NS_IMETHODIMP XPCVariant::GetDataType(PRUint16 *aDataType)
716 : {
717 5903 : *aDataType = mData.mType;
718 5903 : return NS_OK;
719 : }
720 :
721 : /* PRUint8 getAsInt8 (); */
722 0 : NS_IMETHODIMP XPCVariant::GetAsInt8(PRUint8 *_retval)
723 : {
724 0 : return nsVariant::ConvertToInt8(mData, _retval);
725 : }
726 :
727 : /* PRInt16 getAsInt16 (); */
728 0 : NS_IMETHODIMP XPCVariant::GetAsInt16(PRInt16 *_retval)
729 : {
730 0 : return nsVariant::ConvertToInt16(mData, _retval);
731 : }
732 :
733 : /* PRInt32 getAsInt32 (); */
734 850 : NS_IMETHODIMP XPCVariant::GetAsInt32(PRInt32 *_retval)
735 : {
736 850 : return nsVariant::ConvertToInt32(mData, _retval);
737 : }
738 :
739 : /* PRInt64 getAsInt64 (); */
740 0 : NS_IMETHODIMP XPCVariant::GetAsInt64(PRInt64 *_retval)
741 : {
742 0 : return nsVariant::ConvertToInt64(mData, _retval);
743 : }
744 :
745 : /* PRUint8 getAsUint8 (); */
746 0 : NS_IMETHODIMP XPCVariant::GetAsUint8(PRUint8 *_retval)
747 : {
748 0 : return nsVariant::ConvertToUint8(mData, _retval);
749 : }
750 :
751 : /* PRUint16 getAsUint16 (); */
752 0 : NS_IMETHODIMP XPCVariant::GetAsUint16(PRUint16 *_retval)
753 : {
754 0 : return nsVariant::ConvertToUint16(mData, _retval);
755 : }
756 :
757 : /* PRUint32 getAsUint32 (); */
758 0 : NS_IMETHODIMP XPCVariant::GetAsUint32(PRUint32 *_retval)
759 : {
760 0 : return nsVariant::ConvertToUint32(mData, _retval);
761 : }
762 :
763 : /* PRUint64 getAsUint64 (); */
764 0 : NS_IMETHODIMP XPCVariant::GetAsUint64(PRUint64 *_retval)
765 : {
766 0 : return nsVariant::ConvertToUint64(mData, _retval);
767 : }
768 :
769 : /* float getAsFloat (); */
770 0 : NS_IMETHODIMP XPCVariant::GetAsFloat(float *_retval)
771 : {
772 0 : return nsVariant::ConvertToFloat(mData, _retval);
773 : }
774 :
775 : /* double getAsDouble (); */
776 551 : NS_IMETHODIMP XPCVariant::GetAsDouble(double *_retval)
777 : {
778 551 : return nsVariant::ConvertToDouble(mData, _retval);
779 : }
780 :
781 : /* bool getAsBool (); */
782 382 : NS_IMETHODIMP XPCVariant::GetAsBool(bool *_retval)
783 : {
784 382 : return nsVariant::ConvertToBool(mData, _retval);
785 : }
786 :
787 : /* char getAsChar (); */
788 0 : NS_IMETHODIMP XPCVariant::GetAsChar(char *_retval)
789 : {
790 0 : return nsVariant::ConvertToChar(mData, _retval);
791 : }
792 :
793 : /* wchar getAsWChar (); */
794 0 : NS_IMETHODIMP XPCVariant::GetAsWChar(PRUnichar *_retval)
795 : {
796 0 : return nsVariant::ConvertToWChar(mData, _retval);
797 : }
798 :
799 : /* [notxpcom] nsresult getAsID (out nsID retval); */
800 0 : NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID *retval)
801 : {
802 0 : return nsVariant::ConvertToID(mData, retval);
803 : }
804 :
805 : /* AString getAsAString (); */
806 2169 : NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval)
807 : {
808 2169 : return nsVariant::ConvertToAString(mData, _retval);
809 : }
810 :
811 : /* DOMString getAsDOMString (); */
812 0 : NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval)
813 : {
814 : // A DOMString maps to an AString internally, so we can re-use
815 : // ConvertToAString here.
816 0 : return nsVariant::ConvertToAString(mData, _retval);
817 : }
818 :
819 : /* ACString getAsACString (); */
820 0 : NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval)
821 : {
822 0 : return nsVariant::ConvertToACString(mData, _retval);
823 : }
824 :
825 : /* AUTF8String getAsAUTF8String (); */
826 0 : NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval)
827 : {
828 0 : return nsVariant::ConvertToAUTF8String(mData, _retval);
829 : }
830 :
831 : /* string getAsString (); */
832 0 : NS_IMETHODIMP XPCVariant::GetAsString(char **_retval)
833 : {
834 0 : return nsVariant::ConvertToString(mData, _retval);
835 : }
836 :
837 : /* wstring getAsWString (); */
838 0 : NS_IMETHODIMP XPCVariant::GetAsWString(PRUnichar **_retval)
839 : {
840 0 : return nsVariant::ConvertToWString(mData, _retval);
841 : }
842 :
843 : /* nsISupports getAsISupports (); */
844 0 : NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports **_retval)
845 : {
846 0 : return nsVariant::ConvertToISupports(mData, _retval);
847 : }
848 :
849 : /* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */
850 252 : NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID * *iid, void * *iface)
851 : {
852 252 : return nsVariant::ConvertToInterface(mData, iid, iface);
853 : }
854 :
855 :
856 : /* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */
857 189 : NS_IMETHODIMP_(nsresult) XPCVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr)
858 : {
859 189 : return nsVariant::ConvertToArray(mData, type, iid, count, ptr);
860 : }
861 :
862 : /* void getAsStringWithSize (out PRUint32 size, [size_is (size), retval] out string str); */
863 0 : NS_IMETHODIMP XPCVariant::GetAsStringWithSize(PRUint32 *size, char **str)
864 : {
865 0 : return nsVariant::ConvertToStringWithSize(mData, size, str);
866 : }
867 :
868 : /* void getAsWStringWithSize (out PRUint32 size, [size_is (size), retval] out wstring str); */
869 0 : NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str)
870 : {
871 0 : return nsVariant::ConvertToWStringWithSize(mData, size, str);
872 4392 : }
873 :
874 :
|