|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "mozilla/dom/DOMException.h" |
|
7 |
|
8 #include "jsprf.h" |
|
9 #include "js/OldDebugAPI.h" |
|
10 #include "mozilla/ArrayUtils.h" |
|
11 #include "mozilla/HoldDropJSObjects.h" |
|
12 #include "mozilla/dom/Exceptions.h" |
|
13 #include "nsContentUtils.h" |
|
14 #include "nsCOMPtr.h" |
|
15 #include "nsIClassInfoImpl.h" |
|
16 #include "nsIDocument.h" |
|
17 #include "nsIDOMDOMException.h" |
|
18 #include "nsIException.h" |
|
19 #include "nsIProgrammingLanguage.h" |
|
20 #include "nsMemory.h" |
|
21 #include "prprf.h" |
|
22 #include "xpcprivate.h" |
|
23 |
|
24 #include "mozilla/dom/DOMExceptionBinding.h" |
|
25 |
|
26 using namespace mozilla; |
|
27 |
|
28 enum DOM4ErrorTypeCodeMap { |
|
29 /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */ |
|
30 IndexSizeError = nsIDOMDOMException::INDEX_SIZE_ERR, |
|
31 HierarchyRequestError = nsIDOMDOMException::HIERARCHY_REQUEST_ERR, |
|
32 WrongDocumentError = nsIDOMDOMException::WRONG_DOCUMENT_ERR, |
|
33 InvalidCharacterError = nsIDOMDOMException::INVALID_CHARACTER_ERR, |
|
34 NoModificationAllowedError = nsIDOMDOMException::NO_MODIFICATION_ALLOWED_ERR, |
|
35 NotFoundError = nsIDOMDOMException::NOT_FOUND_ERR, |
|
36 NotSupportedError = nsIDOMDOMException::NOT_SUPPORTED_ERR, |
|
37 // Can't remove until setNamedItem is removed |
|
38 InUseAttributeError = nsIDOMDOMException::INUSE_ATTRIBUTE_ERR, |
|
39 InvalidStateError = nsIDOMDOMException::INVALID_STATE_ERR, |
|
40 SyntaxError = nsIDOMDOMException::SYNTAX_ERR, |
|
41 InvalidModificationError = nsIDOMDOMException::INVALID_MODIFICATION_ERR, |
|
42 NamespaceError = nsIDOMDOMException::NAMESPACE_ERR, |
|
43 InvalidAccessError = nsIDOMDOMException::INVALID_ACCESS_ERR, |
|
44 TypeMismatchError = nsIDOMDOMException::TYPE_MISMATCH_ERR, |
|
45 SecurityError = nsIDOMDOMException::SECURITY_ERR, |
|
46 NetworkError = nsIDOMDOMException::NETWORK_ERR, |
|
47 AbortError = nsIDOMDOMException::ABORT_ERR, |
|
48 URLMismatchError = nsIDOMDOMException::URL_MISMATCH_ERR, |
|
49 QuotaExceededError = nsIDOMDOMException::QUOTA_EXCEEDED_ERR, |
|
50 TimeoutError = nsIDOMDOMException::TIMEOUT_ERR, |
|
51 InvalidNodeTypeError = nsIDOMDOMException::INVALID_NODE_TYPE_ERR, |
|
52 DataCloneError = nsIDOMDOMException::DATA_CLONE_ERR, |
|
53 InvalidPointerId = nsIDOMDOMException::INVALID_POINTER_ERR, |
|
54 EncodingError = 0, |
|
55 |
|
56 /* XXX Should be JavaScript native errors */ |
|
57 TypeError = 0, |
|
58 RangeError = 0, |
|
59 |
|
60 /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */ |
|
61 UnknownError = 0, |
|
62 ConstraintError = 0, |
|
63 DataError = 0, |
|
64 TransactionInactiveError = 0, |
|
65 ReadOnlyError = 0, |
|
66 VersionError = 0, |
|
67 |
|
68 /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */ |
|
69 NotReadableError = 0, |
|
70 |
|
71 /* FileHandle API errors */ |
|
72 LockedFileInactiveError = 0, |
|
73 }; |
|
74 |
|
75 #define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message}, |
|
76 #define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message}, |
|
77 |
|
78 static const struct ResultStruct |
|
79 { |
|
80 nsresult mNSResult; |
|
81 uint16_t mCode; |
|
82 const char* mName; |
|
83 const char* mMessage; |
|
84 } sDOMErrorMsgMap[] = { |
|
85 #include "domerr.msg" |
|
86 }; |
|
87 |
|
88 #undef DOM4_MSG_DEF |
|
89 #undef DOM_MSG_DEF |
|
90 |
|
91 static void |
|
92 NSResultToNameAndMessage(nsresult aNSResult, |
|
93 nsCString& aName, |
|
94 nsCString& aMessage, |
|
95 uint16_t* aCode) |
|
96 { |
|
97 aName.Truncate(); |
|
98 aMessage.Truncate(); |
|
99 *aCode = 0; |
|
100 for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) { |
|
101 if (aNSResult == sDOMErrorMsgMap[idx].mNSResult) { |
|
102 aName.Rebind(sDOMErrorMsgMap[idx].mName, |
|
103 strlen(sDOMErrorMsgMap[idx].mName)); |
|
104 aMessage.Rebind(sDOMErrorMsgMap[idx].mMessage, |
|
105 strlen(sDOMErrorMsgMap[idx].mMessage)); |
|
106 *aCode = sDOMErrorMsgMap[idx].mCode; |
|
107 return; |
|
108 } |
|
109 } |
|
110 |
|
111 NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!"); |
|
112 |
|
113 return; |
|
114 } |
|
115 |
|
116 nsresult |
|
117 NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName, |
|
118 nsACString& aMessage, uint16_t* aCode) |
|
119 { |
|
120 nsCString name; |
|
121 nsCString message; |
|
122 uint16_t code = 0; |
|
123 NSResultToNameAndMessage(aNSResult, name, message, &code); |
|
124 |
|
125 if (!name.IsEmpty() && !message.IsEmpty()) { |
|
126 aName = name; |
|
127 aMessage = message; |
|
128 if (aCode) { |
|
129 *aCode = code; |
|
130 } |
|
131 return NS_OK; |
|
132 } |
|
133 |
|
134 return NS_ERROR_NOT_AVAILABLE; |
|
135 } |
|
136 |
|
137 namespace mozilla { |
|
138 namespace dom { |
|
139 |
|
140 bool Exception::sEverMadeOneFromFactory = false; |
|
141 |
|
142 NS_IMPL_CLASSINFO(Exception, nullptr, nsIClassInfo::DOM_OBJECT, |
|
143 NS_XPCEXCEPTION_CID) |
|
144 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception) |
|
145 NS_INTERFACE_MAP_ENTRY(nsIException) |
|
146 NS_INTERFACE_MAP_ENTRY(nsIXPCException) |
|
147 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException) |
|
148 NS_IMPL_QUERY_CLASSINFO(Exception) |
|
149 NS_INTERFACE_MAP_END |
|
150 |
|
151 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception) |
|
152 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception) |
|
153 |
|
154 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception) |
|
155 |
|
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception) |
|
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) |
|
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner) |
|
159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS |
|
160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
|
161 |
|
162 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception) |
|
163 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
|
164 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal); |
|
165 NS_IMPL_CYCLE_COLLECTION_TRACE_END |
|
166 |
|
167 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception) |
|
168 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) |
|
169 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner) |
|
170 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
|
171 tmp->mThrownJSVal.setNull(); |
|
172 NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
|
173 |
|
174 NS_IMPL_CI_INTERFACE_GETTER(Exception, nsIXPCException) |
|
175 |
|
176 Exception::Exception(const nsACString& aMessage, |
|
177 nsresult aResult, |
|
178 const nsACString& aName, |
|
179 nsIStackFrame *aLocation, |
|
180 nsISupports *aData) |
|
181 : mResult(NS_OK), |
|
182 mLineNumber(0), |
|
183 mInitialized(false), |
|
184 mHoldingJSVal(false) |
|
185 { |
|
186 SetIsDOMBinding(); |
|
187 |
|
188 // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there |
|
189 // having been at least one instance made via the factory. Otherwise, the |
|
190 // shared factory/classinsance object never gets created and our QI getter |
|
191 // for our instance's pointer to our nsIClassInfo will always return null. |
|
192 // This is bad because it means that wrapped exceptions will never have a |
|
193 // shared prototype. So... We force one to be created via the factory |
|
194 // *once* and then go about our business. |
|
195 if (!sEverMadeOneFromFactory) { |
|
196 nsCOMPtr<nsIXPCException> e = |
|
197 do_CreateInstance(XPC_EXCEPTION_CONTRACTID); |
|
198 sEverMadeOneFromFactory = true; |
|
199 } |
|
200 |
|
201 nsCOMPtr<nsIStackFrame> location; |
|
202 if (aLocation) { |
|
203 location = aLocation; |
|
204 } else { |
|
205 location = GetCurrentJSStack(); |
|
206 // it is legal for there to be no active JS stack, if C++ code |
|
207 // is operating on a JS-implemented interface pointer without |
|
208 // having been called in turn by JS. This happens in the JS |
|
209 // component loader, and will become more common as additional |
|
210 // components are implemented in JS. |
|
211 } |
|
212 // We want to trim off any leading native 'dataless' frames |
|
213 if (location) { |
|
214 while (1) { |
|
215 uint32_t language; |
|
216 int32_t lineNumber; |
|
217 if (NS_FAILED(location->GetLanguage(&language)) || |
|
218 language == nsIProgrammingLanguage::JAVASCRIPT || |
|
219 NS_FAILED(location->GetLineNumber(&lineNumber)) || |
|
220 lineNumber) { |
|
221 break; |
|
222 } |
|
223 nsCOMPtr<nsIStackFrame> caller; |
|
224 if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) { |
|
225 break; |
|
226 } |
|
227 location = caller; |
|
228 } |
|
229 } |
|
230 |
|
231 Initialize(aMessage, aResult, aName, location, aData, nullptr); |
|
232 } |
|
233 |
|
234 Exception::Exception() |
|
235 : mResult(NS_OK), |
|
236 mLineNumber(-1), |
|
237 mInitialized(false), |
|
238 mHoldingJSVal(false) |
|
239 { |
|
240 } |
|
241 |
|
242 Exception::~Exception() |
|
243 { |
|
244 if (mHoldingJSVal) { |
|
245 MOZ_ASSERT(NS_IsMainThread()); |
|
246 |
|
247 mozilla::DropJSObjects(this); |
|
248 } |
|
249 } |
|
250 |
|
251 bool |
|
252 Exception::StealJSVal(JS::Value* aVp) |
|
253 { |
|
254 MOZ_ASSERT(NS_IsMainThread()); |
|
255 |
|
256 if (mHoldingJSVal) { |
|
257 *aVp = mThrownJSVal; |
|
258 mThrownJSVal.setNull(); |
|
259 |
|
260 mozilla::DropJSObjects(this); |
|
261 mHoldingJSVal = false; |
|
262 return true; |
|
263 } |
|
264 |
|
265 return false; |
|
266 } |
|
267 |
|
268 void |
|
269 Exception::StowJSVal(JS::Value& aVp) |
|
270 { |
|
271 MOZ_ASSERT(NS_IsMainThread()); |
|
272 |
|
273 mThrownJSVal = aVp; |
|
274 if (!mHoldingJSVal) { |
|
275 mozilla::HoldJSObjects(this); |
|
276 mHoldingJSVal = true; |
|
277 } |
|
278 } |
|
279 |
|
280 /* readonly attribute AUTF8String message; */ |
|
281 NS_IMETHODIMP |
|
282 Exception::GetMessageMoz(nsACString& aMessage) |
|
283 { |
|
284 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
285 |
|
286 aMessage.Assign(mMessage); |
|
287 return NS_OK; |
|
288 } |
|
289 |
|
290 /* readonly attribute nsresult result; */ |
|
291 NS_IMETHODIMP |
|
292 Exception::GetResult(nsresult* aResult) |
|
293 { |
|
294 NS_ENSURE_ARG_POINTER(aResult); |
|
295 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
296 |
|
297 *aResult = mResult; |
|
298 return NS_OK; |
|
299 } |
|
300 |
|
301 /* readonly attribute AUTF8String name; */ |
|
302 NS_IMETHODIMP |
|
303 Exception::GetName(nsACString& aName) |
|
304 { |
|
305 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
306 |
|
307 if (!mName.IsEmpty()) { |
|
308 aName.Assign(mName); |
|
309 } else { |
|
310 aName.Truncate(); |
|
311 |
|
312 const char* name = nullptr; |
|
313 nsXPCException::NameAndFormatForNSResult(mResult, &name, nullptr); |
|
314 |
|
315 if (name) { |
|
316 aName.Assign(name); |
|
317 } |
|
318 } |
|
319 |
|
320 return NS_OK; |
|
321 } |
|
322 |
|
323 /* readonly attribute AString filename; */ |
|
324 NS_IMETHODIMP |
|
325 Exception::GetFilename(nsAString& aFilename) |
|
326 { |
|
327 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
328 |
|
329 if (mLocation) { |
|
330 return mLocation->GetFilename(aFilename); |
|
331 } |
|
332 |
|
333 aFilename.Assign(mFilename); |
|
334 return NS_OK; |
|
335 } |
|
336 |
|
337 /* readonly attribute uint32_t lineNumber; */ |
|
338 NS_IMETHODIMP |
|
339 Exception::GetLineNumber(uint32_t *aLineNumber) |
|
340 { |
|
341 NS_ENSURE_ARG_POINTER(aLineNumber); |
|
342 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
343 |
|
344 if (mLocation) { |
|
345 int32_t lineno; |
|
346 nsresult rv = mLocation->GetLineNumber(&lineno); |
|
347 *aLineNumber = lineno; |
|
348 return rv; |
|
349 } |
|
350 |
|
351 *aLineNumber = mLineNumber; |
|
352 return NS_OK; |
|
353 } |
|
354 |
|
355 /* readonly attribute uint32_t columnNumber; */ |
|
356 NS_IMETHODIMP |
|
357 Exception::GetColumnNumber(uint32_t* aColumnNumber) |
|
358 { |
|
359 NS_ENSURE_ARG_POINTER(aColumnNumber); |
|
360 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
361 |
|
362 *aColumnNumber = 0; |
|
363 return NS_OK; |
|
364 } |
|
365 |
|
366 /* readonly attribute nsIStackFrame location; */ |
|
367 NS_IMETHODIMP |
|
368 Exception::GetLocation(nsIStackFrame** aLocation) |
|
369 { |
|
370 NS_ENSURE_ARG_POINTER(aLocation); |
|
371 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
372 |
|
373 nsCOMPtr<nsIStackFrame> location = mLocation; |
|
374 location.forget(aLocation); |
|
375 return NS_OK; |
|
376 } |
|
377 |
|
378 /* readonly attribute nsISupports data; */ |
|
379 NS_IMETHODIMP |
|
380 Exception::GetData(nsISupports** aData) |
|
381 { |
|
382 NS_ENSURE_ARG_POINTER(aData); |
|
383 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
384 |
|
385 nsCOMPtr<nsISupports> data = mData; |
|
386 data.forget(aData); |
|
387 return NS_OK; |
|
388 } |
|
389 |
|
390 /* readonly attribute nsIException inner; */ |
|
391 NS_IMETHODIMP |
|
392 Exception::GetInner(nsIException** aException) |
|
393 { |
|
394 NS_ENSURE_ARG_POINTER(aException); |
|
395 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
396 |
|
397 nsCOMPtr<nsIException> inner = mInner; |
|
398 inner.forget(aException); |
|
399 return NS_OK; |
|
400 } |
|
401 |
|
402 /* AUTF8String toString (); */ |
|
403 NS_IMETHODIMP |
|
404 Exception::ToString(nsACString& _retval) |
|
405 { |
|
406 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); |
|
407 |
|
408 static const char defaultMsg[] = "<no message>"; |
|
409 static const char defaultLocation[] = "<unknown>"; |
|
410 static const char format[] = |
|
411 "[Exception... \"%s\" nsresult: \"0x%x (%s)\" location: \"%s\" data: %s]"; |
|
412 |
|
413 nsCString location; |
|
414 |
|
415 if (mLocation) { |
|
416 // we need to free this if it does not fail |
|
417 nsresult rv = mLocation->ToString(location); |
|
418 NS_ENSURE_SUCCESS(rv, rv); |
|
419 } |
|
420 |
|
421 if (location.IsEmpty()) { |
|
422 location.Assign(defaultLocation); |
|
423 } |
|
424 |
|
425 const char* msg = mMessage.IsEmpty() ? nullptr : mMessage.get(); |
|
426 |
|
427 const char* resultName = mName.IsEmpty() ? nullptr: mName.get(); |
|
428 if (!resultName && |
|
429 !nsXPCException::NameAndFormatForNSResult(mResult, &resultName, |
|
430 (!msg) ? &msg : nullptr)) { |
|
431 if (!msg) { |
|
432 msg = defaultMsg; |
|
433 } |
|
434 resultName = "<unknown>"; |
|
435 } |
|
436 const char* data = mData ? "yes" : "no"; |
|
437 |
|
438 _retval.Truncate(); |
|
439 _retval.AppendPrintf(format, msg, mResult, resultName, |
|
440 location.get(), data); |
|
441 return NS_OK; |
|
442 } |
|
443 |
|
444 /* void initialize (in AUTF8String aMessage, in nsresult aResult, |
|
445 * in AUTF8String aName, in nsIStackFrame aLocation, |
|
446 * in nsISupports aData, in nsIException aInner); */ |
|
447 NS_IMETHODIMP |
|
448 Exception::Initialize(const nsACString& aMessage, nsresult aResult, |
|
449 const nsACString& aName, nsIStackFrame *aLocation, |
|
450 nsISupports *aData, nsIException *aInner) |
|
451 { |
|
452 NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED); |
|
453 |
|
454 mMessage = aMessage; |
|
455 mName = aName; |
|
456 mResult = aResult; |
|
457 |
|
458 if (aLocation) { |
|
459 mLocation = aLocation; |
|
460 } else { |
|
461 nsresult rv; |
|
462 nsXPConnect* xpc = nsXPConnect::XPConnect(); |
|
463 rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation)); |
|
464 if (NS_FAILED(rv)) { |
|
465 return rv; |
|
466 } |
|
467 } |
|
468 |
|
469 mData = aData; |
|
470 mInner = aInner; |
|
471 |
|
472 mInitialized = true; |
|
473 return NS_OK; |
|
474 } |
|
475 |
|
476 JSObject* |
|
477 Exception::WrapObject(JSContext* cx) |
|
478 { |
|
479 return ExceptionBinding::Wrap(cx, this); |
|
480 } |
|
481 |
|
482 void |
|
483 Exception::GetMessageMoz(nsString& retval) |
|
484 { |
|
485 nsCString str; |
|
486 #ifdef DEBUG |
|
487 DebugOnly<nsresult> rv = |
|
488 #endif |
|
489 GetMessageMoz(str); |
|
490 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
491 CopyUTF8toUTF16(str, retval); |
|
492 } |
|
493 |
|
494 uint32_t |
|
495 Exception::Result() const |
|
496 { |
|
497 return (uint32_t)mResult; |
|
498 } |
|
499 |
|
500 void |
|
501 Exception::GetName(nsString& retval) |
|
502 { |
|
503 nsCString str; |
|
504 #ifdef DEBUG |
|
505 DebugOnly<nsresult> rv = |
|
506 #endif |
|
507 GetName(str); |
|
508 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
509 CopyUTF8toUTF16(str, retval); |
|
510 } |
|
511 |
|
512 uint32_t |
|
513 Exception::LineNumber() const |
|
514 { |
|
515 if (mLocation) { |
|
516 int32_t lineno; |
|
517 if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) { |
|
518 return lineno; |
|
519 } |
|
520 return 0; |
|
521 } |
|
522 |
|
523 return mLineNumber; |
|
524 } |
|
525 |
|
526 uint32_t |
|
527 Exception::ColumnNumber() const |
|
528 { |
|
529 return 0; |
|
530 } |
|
531 |
|
532 already_AddRefed<nsIStackFrame> |
|
533 Exception::GetLocation() const |
|
534 { |
|
535 nsCOMPtr<nsIStackFrame> location = mLocation; |
|
536 return location.forget(); |
|
537 } |
|
538 |
|
539 already_AddRefed<nsISupports> |
|
540 Exception::GetInner() const |
|
541 { |
|
542 nsCOMPtr<nsIException> inner = mInner; |
|
543 return inner.forget(); |
|
544 } |
|
545 |
|
546 already_AddRefed<nsISupports> |
|
547 Exception::GetData() const |
|
548 { |
|
549 nsCOMPtr<nsISupports> data = mData; |
|
550 return data.forget(); |
|
551 } |
|
552 |
|
553 void |
|
554 Exception::Stringify(nsString& retval) |
|
555 { |
|
556 nsCString str; |
|
557 #ifdef DEBUG |
|
558 DebugOnly<nsresult> rv = |
|
559 #endif |
|
560 ToString(str); |
|
561 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
562 CopyUTF8toUTF16(str, retval); |
|
563 } |
|
564 |
|
565 NS_IMPL_ADDREF_INHERITED(DOMException, Exception) |
|
566 NS_IMPL_RELEASE_INHERITED(DOMException, Exception) |
|
567 NS_INTERFACE_MAP_BEGIN(DOMException) |
|
568 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException) |
|
569 NS_INTERFACE_MAP_END_INHERITING(Exception) |
|
570 |
|
571 DOMException::DOMException(nsresult aRv, const nsACString& aMessage, |
|
572 const nsACString& aName, uint16_t aCode) |
|
573 : Exception(EmptyCString(), aRv, EmptyCString(), nullptr, nullptr), |
|
574 mName(aName), |
|
575 mMessage(aMessage), |
|
576 mCode(aCode) |
|
577 { |
|
578 SetIsDOMBinding(); |
|
579 } |
|
580 |
|
581 NS_IMETHODIMP |
|
582 DOMException::GetCode(uint16_t* aCode) |
|
583 { |
|
584 NS_ENSURE_ARG_POINTER(aCode); |
|
585 *aCode = mCode; |
|
586 |
|
587 // Warn only when the code was changed (other than DOM Core) |
|
588 // or the code is useless (zero) |
|
589 if (NS_ERROR_GET_MODULE(mResult) != NS_ERROR_MODULE_DOM || !mCode) { |
|
590 nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller(); |
|
591 if (doc) { |
|
592 doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode); |
|
593 } |
|
594 } |
|
595 |
|
596 return NS_OK; |
|
597 } |
|
598 |
|
599 NS_IMETHODIMP |
|
600 DOMException::ToString(nsACString& aReturn) |
|
601 { |
|
602 aReturn.Truncate(); |
|
603 |
|
604 static const char defaultMsg[] = "<no message>"; |
|
605 static const char defaultLocation[] = "<unknown>"; |
|
606 static const char defaultName[] = "<unknown>"; |
|
607 static const char format[] = |
|
608 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%x (%s)\" location: \"%s\"]"; |
|
609 |
|
610 nsAutoCString location; |
|
611 |
|
612 if (mInner) { |
|
613 nsString filename; |
|
614 mInner->GetFilename(filename); |
|
615 |
|
616 if (!filename.IsEmpty()) { |
|
617 uint32_t line_nr = 0; |
|
618 |
|
619 mInner->GetLineNumber(&line_nr); |
|
620 |
|
621 char *temp = PR_smprintf("%s Line: %d", |
|
622 NS_ConvertUTF16toUTF8(filename).get(), |
|
623 line_nr); |
|
624 if (temp) { |
|
625 location.Assign(temp); |
|
626 PR_smprintf_free(temp); |
|
627 } |
|
628 } |
|
629 } |
|
630 |
|
631 if (location.IsEmpty()) { |
|
632 location = defaultLocation; |
|
633 } |
|
634 |
|
635 const char* msg = !mMessage.IsEmpty() ? mMessage.get() : defaultMsg; |
|
636 const char* resultName = !mName.IsEmpty() ? mName.get() : defaultName; |
|
637 |
|
638 aReturn.AppendPrintf(format, msg, mCode, mResult, resultName, |
|
639 location.get()); |
|
640 |
|
641 return NS_OK; |
|
642 } |
|
643 |
|
644 void |
|
645 DOMException::GetName(nsString& retval) |
|
646 { |
|
647 CopyUTF8toUTF16(mName, retval); |
|
648 } |
|
649 |
|
650 void |
|
651 DOMException::GetMessageMoz(nsString& retval) |
|
652 { |
|
653 CopyUTF8toUTF16(mMessage, retval); |
|
654 } |
|
655 |
|
656 JSObject* |
|
657 DOMException::WrapObject(JSContext* aCx) |
|
658 { |
|
659 return DOMExceptionBinding::Wrap(aCx, this); |
|
660 } |
|
661 |
|
662 /* static */already_AddRefed<DOMException> |
|
663 DOMException::Create(nsresult aRv) |
|
664 { |
|
665 nsCString name; |
|
666 nsCString message; |
|
667 uint16_t code; |
|
668 NSResultToNameAndMessage(aRv, name, message, &code); |
|
669 nsRefPtr<DOMException> inst = |
|
670 new DOMException(aRv, message, name, code); |
|
671 return inst.forget(); |
|
672 } |
|
673 |
|
674 } // namespace dom |
|
675 } // namespace mozilla |