Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
6 #include "mozilla/ArrayUtils.h"
7 #include "mozilla/FloatingPoint.h"
9 #include "txExpr.h"
10 #include "nsAutoPtr.h"
11 #include "txNodeSet.h"
12 #include "nsGkAtoms.h"
13 #include "txIXPathContext.h"
14 #include "nsWhitespaceTokenizer.h"
15 #include "txXPathTreeWalker.h"
16 #include <math.h>
17 #include "txStringUtils.h"
18 #include "txXMLUtils.h"
20 using namespace mozilla;
22 struct txCoreFunctionDescriptor
23 {
24 int8_t mMinParams;
25 int8_t mMaxParams;
26 Expr::ResultType mReturnType;
27 nsIAtom** mName;
28 };
30 // This must be ordered in the same order as txCoreFunctionCall::eType.
31 // If you change one, change the other.
32 static const txCoreFunctionDescriptor descriptTable[] =
33 {
34 { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::count }, // COUNT
35 { 1, 1, Expr::NODESET_RESULT, &nsGkAtoms::id }, // ID
36 { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::last }, // LAST
37 { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::localName }, // LOCAL_NAME
38 { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::namespaceUri }, // NAMESPACE_URI
39 { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::name }, // NAME
40 { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::position }, // POSITION
42 { 2, -1, Expr::STRING_RESULT, &nsGkAtoms::concat }, // CONCAT
43 { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::contains }, // CONTAINS
44 { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::normalizeSpace }, // NORMALIZE_SPACE
45 { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::startsWith }, // STARTS_WITH
46 { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::string }, // STRING
47 { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::stringLength }, // STRING_LENGTH
48 { 2, 3, Expr::STRING_RESULT, &nsGkAtoms::substring }, // SUBSTRING
49 { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringAfter }, // SUBSTRING_AFTER
50 { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringBefore }, // SUBSTRING_BEFORE
51 { 3, 3, Expr::STRING_RESULT, &nsGkAtoms::translate }, // TRANSLATE
53 { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::number }, // NUMBER
54 { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::round }, // ROUND
55 { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::floor }, // FLOOR
56 { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::ceiling }, // CEILING
57 { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::sum }, // SUM
59 { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::boolean }, // BOOLEAN
60 { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_false }, // _FALSE
61 { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::lang }, // LANG
62 { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::_not }, // _NOT
63 { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_true } // _TRUE
64 };
67 /*
68 * Evaluates this Expr based on the given context node and processor state
69 * @param context the context node for evaluation of this Expr
70 * @param ps the ContextState containing the stack information needed
71 * for evaluation
72 * @return the result of the evaluation
73 */
74 nsresult
75 txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
76 {
77 *aResult = nullptr;
79 if (!requireParams(descriptTable[mType].mMinParams,
80 descriptTable[mType].mMaxParams,
81 aContext)) {
82 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
83 }
85 nsresult rv = NS_OK;
86 switch (mType) {
87 case COUNT:
88 {
89 nsRefPtr<txNodeSet> nodes;
90 rv = evaluateToNodeSet(mParams[0], aContext,
91 getter_AddRefs(nodes));
92 NS_ENSURE_SUCCESS(rv, rv);
94 return aContext->recycler()->getNumberResult(nodes->size(),
95 aResult);
96 }
97 case ID:
98 {
99 nsRefPtr<txAExprResult> exprResult;
100 rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
101 NS_ENSURE_SUCCESS(rv, rv);
103 nsRefPtr<txNodeSet> resultSet;
104 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
105 NS_ENSURE_SUCCESS(rv, rv);
107 txXPathTreeWalker walker(aContext->getContextNode());
109 if (exprResult->getResultType() == txAExprResult::NODESET) {
110 txNodeSet* nodes = static_cast<txNodeSet*>
111 (static_cast<txAExprResult*>
112 (exprResult));
113 int32_t i;
114 for (i = 0; i < nodes->size(); ++i) {
115 nsAutoString idList;
116 txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
117 nsWhitespaceTokenizer tokenizer(idList);
118 while (tokenizer.hasMoreTokens()) {
119 if (walker.moveToElementById(tokenizer.nextToken())) {
120 resultSet->add(walker.getCurrentPosition());
121 }
122 }
123 }
124 }
125 else {
126 nsAutoString idList;
127 exprResult->stringValue(idList);
128 nsWhitespaceTokenizer tokenizer(idList);
129 while (tokenizer.hasMoreTokens()) {
130 if (walker.moveToElementById(tokenizer.nextToken())) {
131 resultSet->add(walker.getCurrentPosition());
132 }
133 }
134 }
136 *aResult = resultSet;
137 NS_ADDREF(*aResult);
139 return NS_OK;
140 }
141 case LAST:
142 {
143 return aContext->recycler()->getNumberResult(aContext->size(),
144 aResult);
145 }
146 case LOCAL_NAME:
147 case NAME:
148 case NAMESPACE_URI:
149 {
150 // Check for optional arg
151 nsRefPtr<txNodeSet> nodes;
152 if (!mParams.IsEmpty()) {
153 rv = evaluateToNodeSet(mParams[0], aContext,
154 getter_AddRefs(nodes));
155 NS_ENSURE_SUCCESS(rv, rv);
157 if (nodes->isEmpty()) {
158 aContext->recycler()->getEmptyStringResult(aResult);
160 return NS_OK;
161 }
162 }
164 const txXPathNode& node = nodes ? nodes->get(0) :
165 aContext->getContextNode();
166 switch (mType) {
167 case LOCAL_NAME:
168 {
169 StringResult* strRes = nullptr;
170 rv = aContext->recycler()->getStringResult(&strRes);
171 NS_ENSURE_SUCCESS(rv, rv);
173 *aResult = strRes;
174 txXPathNodeUtils::getLocalName(node, strRes->mValue);
176 return NS_OK;
177 }
178 case NAMESPACE_URI:
179 {
180 StringResult* strRes = nullptr;
181 rv = aContext->recycler()->getStringResult(&strRes);
182 NS_ENSURE_SUCCESS(rv, rv);
184 *aResult = strRes;
185 txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
187 return NS_OK;
188 }
189 case NAME:
190 {
191 // XXX Namespace: namespaces have a name
192 if (txXPathNodeUtils::isAttribute(node) ||
193 txXPathNodeUtils::isElement(node) ||
194 txXPathNodeUtils::isProcessingInstruction(node)) {
195 StringResult* strRes = nullptr;
196 rv = aContext->recycler()->getStringResult(&strRes);
197 NS_ENSURE_SUCCESS(rv, rv);
199 *aResult = strRes;
200 txXPathNodeUtils::getNodeName(node, strRes->mValue);
201 }
202 else {
203 aContext->recycler()->getEmptyStringResult(aResult);
204 }
206 return NS_OK;
207 }
208 default:
209 {
210 break;
211 }
212 }
213 }
214 case POSITION:
215 {
216 return aContext->recycler()->getNumberResult(aContext->position(),
217 aResult);
218 }
220 // String functions
222 case CONCAT:
223 {
224 nsRefPtr<StringResult> strRes;
225 rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
226 NS_ENSURE_SUCCESS(rv, rv);
228 uint32_t i, len = mParams.Length();
229 for (i = 0; i < len; ++i) {
230 rv = mParams[i]->evaluateToString(aContext, strRes->mValue);
231 NS_ENSURE_SUCCESS(rv, rv);
232 }
234 NS_ADDREF(*aResult = strRes);
236 return NS_OK;
237 }
238 case CONTAINS:
239 {
240 nsAutoString arg2;
241 rv = mParams[1]->evaluateToString(aContext, arg2);
242 NS_ENSURE_SUCCESS(rv, rv);
244 if (arg2.IsEmpty()) {
245 aContext->recycler()->getBoolResult(true, aResult);
246 }
247 else {
248 nsAutoString arg1;
249 rv = mParams[0]->evaluateToString(aContext, arg1);
250 NS_ENSURE_SUCCESS(rv, rv);
252 aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1),
253 aResult);
254 }
256 return NS_OK;
257 }
258 case NORMALIZE_SPACE:
259 {
260 nsAutoString resultStr;
261 if (!mParams.IsEmpty()) {
262 rv = mParams[0]->evaluateToString(aContext, resultStr);
263 NS_ENSURE_SUCCESS(rv, rv);
264 }
265 else {
266 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
267 resultStr);
268 }
270 nsRefPtr<StringResult> strRes;
271 rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
272 NS_ENSURE_SUCCESS(rv, rv);
274 bool addSpace = false;
275 bool first = true;
276 strRes->mValue.SetCapacity(resultStr.Length());
277 char16_t c;
278 uint32_t src;
279 for (src = 0; src < resultStr.Length(); src++) {
280 c = resultStr.CharAt(src);
281 if (XMLUtils::isWhitespace(c)) {
282 addSpace = true;
283 }
284 else {
285 if (addSpace && !first)
286 strRes->mValue.Append(char16_t(' '));
288 strRes->mValue.Append(c);
289 addSpace = false;
290 first = false;
291 }
292 }
293 *aResult = strRes;
294 NS_ADDREF(*aResult);
296 return NS_OK;
297 }
298 case STARTS_WITH:
299 {
300 nsAutoString arg2;
301 rv = mParams[1]->evaluateToString(aContext, arg2);
302 NS_ENSURE_SUCCESS(rv, rv);
304 bool result = false;
305 if (arg2.IsEmpty()) {
306 result = true;
307 }
308 else {
309 nsAutoString arg1;
310 rv = mParams[0]->evaluateToString(aContext, arg1);
311 NS_ENSURE_SUCCESS(rv, rv);
313 result = StringBeginsWith(arg1, arg2);
314 }
316 aContext->recycler()->getBoolResult(result, aResult);
318 return NS_OK;
319 }
320 case STRING:
321 {
322 nsRefPtr<StringResult> strRes;
323 rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
324 NS_ENSURE_SUCCESS(rv, rv);
326 if (!mParams.IsEmpty()) {
327 rv = mParams[0]->evaluateToString(aContext, strRes->mValue);
328 NS_ENSURE_SUCCESS(rv, rv);
329 }
330 else {
331 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
332 strRes->mValue);
333 }
335 NS_ADDREF(*aResult = strRes);
337 return NS_OK;
338 }
339 case STRING_LENGTH:
340 {
341 nsAutoString resultStr;
342 if (!mParams.IsEmpty()) {
343 rv = mParams[0]->evaluateToString(aContext, resultStr);
344 NS_ENSURE_SUCCESS(rv, rv);
345 }
346 else {
347 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
348 resultStr);
349 }
350 rv = aContext->recycler()->getNumberResult(resultStr.Length(),
351 aResult);
352 NS_ENSURE_SUCCESS(rv, rv);
354 return NS_OK;
355 }
356 case SUBSTRING:
357 {
358 nsAutoString src;
359 rv = mParams[0]->evaluateToString(aContext, src);
360 NS_ENSURE_SUCCESS(rv, rv);
362 double start;
363 rv = evaluateToNumber(mParams[1], aContext, &start);
364 NS_ENSURE_SUCCESS(rv, rv);
366 // check for NaN or +/-Inf
367 if (mozilla::IsNaN(start) ||
368 mozilla::IsInfinite(start) ||
369 start >= src.Length() + 0.5) {
370 aContext->recycler()->getEmptyStringResult(aResult);
372 return NS_OK;
373 }
375 start = floor(start + 0.5) - 1;
377 double end;
378 if (mParams.Length() == 3) {
379 rv = evaluateToNumber(mParams[2], aContext, &end);
380 NS_ENSURE_SUCCESS(rv, rv);
382 end += start;
383 if (mozilla::IsNaN(end) || end < 0) {
384 aContext->recycler()->getEmptyStringResult(aResult);
386 return NS_OK;
387 }
389 if (end > src.Length())
390 end = src.Length();
391 else
392 end = floor(end + 0.5);
393 }
394 else {
395 end = src.Length();
396 }
398 if (start < 0)
399 start = 0;
401 if (start > end) {
402 aContext->recycler()->getEmptyStringResult(aResult);
404 return NS_OK;
405 }
407 return aContext->recycler()->getStringResult(
408 Substring(src, (uint32_t)start, (uint32_t)(end - start)),
409 aResult);
410 }
411 case SUBSTRING_AFTER:
412 {
413 nsAutoString arg1;
414 rv = mParams[0]->evaluateToString(aContext, arg1);
415 NS_ENSURE_SUCCESS(rv, rv);
417 nsAutoString arg2;
418 rv = mParams[1]->evaluateToString(aContext, arg2);
419 NS_ENSURE_SUCCESS(rv, rv);
421 if (arg2.IsEmpty()) {
422 return aContext->recycler()->getStringResult(arg1, aResult);
423 }
425 int32_t idx = arg1.Find(arg2);
426 if (idx == kNotFound) {
427 aContext->recycler()->getEmptyStringResult(aResult);
429 return NS_OK;
430 }
432 const nsSubstring& result = Substring(arg1, idx + arg2.Length());
433 return aContext->recycler()->getStringResult(result, aResult);
434 }
435 case SUBSTRING_BEFORE:
436 {
437 nsAutoString arg2;
438 rv = mParams[1]->evaluateToString(aContext, arg2);
439 NS_ENSURE_SUCCESS(rv, rv);
441 if (arg2.IsEmpty()) {
442 aContext->recycler()->getEmptyStringResult(aResult);
444 return NS_OK;
445 }
447 nsAutoString arg1;
448 rv = mParams[0]->evaluateToString(aContext, arg1);
449 NS_ENSURE_SUCCESS(rv, rv);
451 int32_t idx = arg1.Find(arg2);
452 if (idx == kNotFound) {
453 aContext->recycler()->getEmptyStringResult(aResult);
455 return NS_OK;
456 }
458 return aContext->recycler()->getStringResult(StringHead(arg1, idx),
459 aResult);
460 }
461 case TRANSLATE:
462 {
463 nsAutoString src;
464 rv = mParams[0]->evaluateToString(aContext, src);
465 NS_ENSURE_SUCCESS(rv, rv);
467 if (src.IsEmpty()) {
468 aContext->recycler()->getEmptyStringResult(aResult);
470 return NS_OK;
471 }
473 nsRefPtr<StringResult> strRes;
474 rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
475 NS_ENSURE_SUCCESS(rv, rv);
477 strRes->mValue.SetCapacity(src.Length());
479 nsAutoString oldChars, newChars;
480 rv = mParams[1]->evaluateToString(aContext, oldChars);
481 NS_ENSURE_SUCCESS(rv, rv);
483 rv = mParams[2]->evaluateToString(aContext, newChars);
484 NS_ENSURE_SUCCESS(rv, rv);
486 uint32_t i;
487 int32_t newCharsLength = (int32_t)newChars.Length();
488 for (i = 0; i < src.Length(); i++) {
489 int32_t idx = oldChars.FindChar(src.CharAt(i));
490 if (idx != kNotFound) {
491 if (idx < newCharsLength)
492 strRes->mValue.Append(newChars.CharAt((uint32_t)idx));
493 }
494 else {
495 strRes->mValue.Append(src.CharAt(i));
496 }
497 }
499 NS_ADDREF(*aResult = strRes);
501 return NS_OK;
502 }
504 // Number functions
506 case NUMBER:
507 {
508 double res;
509 if (!mParams.IsEmpty()) {
510 rv = evaluateToNumber(mParams[0], aContext, &res);
511 NS_ENSURE_SUCCESS(rv, rv);
512 }
513 else {
514 nsAutoString resultStr;
515 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
516 resultStr);
517 res = txDouble::toDouble(resultStr);
518 }
519 return aContext->recycler()->getNumberResult(res, aResult);
520 }
521 case ROUND:
522 {
523 double dbl;
524 rv = evaluateToNumber(mParams[0], aContext, &dbl);
525 NS_ENSURE_SUCCESS(rv, rv);
527 if (mozilla::IsFinite(dbl)) {
528 if (mozilla::IsNegative(dbl) && dbl >= -0.5) {
529 dbl *= 0;
530 }
531 else {
532 dbl = floor(dbl + 0.5);
533 }
534 }
536 return aContext->recycler()->getNumberResult(dbl, aResult);
537 }
538 case FLOOR:
539 {
540 double dbl;
541 rv = evaluateToNumber(mParams[0], aContext, &dbl);
542 NS_ENSURE_SUCCESS(rv, rv);
544 if (mozilla::IsFinite(dbl) && !mozilla::IsNegativeZero(dbl))
545 dbl = floor(dbl);
547 return aContext->recycler()->getNumberResult(dbl, aResult);
548 }
549 case CEILING:
550 {
551 double dbl;
552 rv = evaluateToNumber(mParams[0], aContext, &dbl);
553 NS_ENSURE_SUCCESS(rv, rv);
555 if (mozilla::IsFinite(dbl)) {
556 if (mozilla::IsNegative(dbl) && dbl > -1)
557 dbl *= 0;
558 else
559 dbl = ceil(dbl);
560 }
562 return aContext->recycler()->getNumberResult(dbl, aResult);
563 }
564 case SUM:
565 {
566 nsRefPtr<txNodeSet> nodes;
567 nsresult rv = evaluateToNodeSet(mParams[0], aContext,
568 getter_AddRefs(nodes));
569 NS_ENSURE_SUCCESS(rv, rv);
571 double res = 0;
572 int32_t i;
573 for (i = 0; i < nodes->size(); ++i) {
574 nsAutoString resultStr;
575 txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
576 res += txDouble::toDouble(resultStr);
577 }
578 return aContext->recycler()->getNumberResult(res, aResult);
579 }
581 // Boolean functions
583 case BOOLEAN:
584 {
585 bool result;
586 nsresult rv = mParams[0]->evaluateToBool(aContext, result);
587 NS_ENSURE_SUCCESS(rv, rv);
589 aContext->recycler()->getBoolResult(result, aResult);
591 return NS_OK;
592 }
593 case _FALSE:
594 {
595 aContext->recycler()->getBoolResult(false, aResult);
597 return NS_OK;
598 }
599 case LANG:
600 {
601 txXPathTreeWalker walker(aContext->getContextNode());
603 nsAutoString lang;
604 bool found;
605 do {
606 found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML,
607 lang);
608 } while (!found && walker.moveToParent());
610 if (!found) {
611 aContext->recycler()->getBoolResult(false, aResult);
613 return NS_OK;
614 }
616 nsAutoString arg;
617 rv = mParams[0]->evaluateToString(aContext, arg);
618 NS_ENSURE_SUCCESS(rv, rv);
620 bool result =
621 StringBeginsWith(lang, arg,
622 txCaseInsensitiveStringComparator()) &&
623 (lang.Length() == arg.Length() ||
624 lang.CharAt(arg.Length()) == '-');
626 aContext->recycler()->getBoolResult(result, aResult);
628 return NS_OK;
629 }
630 case _NOT:
631 {
632 bool result;
633 rv = mParams[0]->evaluateToBool(aContext, result);
634 NS_ENSURE_SUCCESS(rv, rv);
636 aContext->recycler()->getBoolResult(!result, aResult);
638 return NS_OK;
639 }
640 case _TRUE:
641 {
642 aContext->recycler()->getBoolResult(true, aResult);
644 return NS_OK;
645 }
646 }
648 aContext->receiveError(NS_LITERAL_STRING("Internal error"),
649 NS_ERROR_UNEXPECTED);
650 return NS_ERROR_UNEXPECTED;
651 }
653 Expr::ResultType
654 txCoreFunctionCall::getReturnType()
655 {
656 return descriptTable[mType].mReturnType;
657 }
659 bool
660 txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext)
661 {
662 switch (mType) {
663 case COUNT:
664 case CONCAT:
665 case CONTAINS:
666 case STARTS_WITH:
667 case SUBSTRING:
668 case SUBSTRING_AFTER:
669 case SUBSTRING_BEFORE:
670 case TRANSLATE:
671 case ROUND:
672 case FLOOR:
673 case CEILING:
674 case SUM:
675 case BOOLEAN:
676 case _NOT:
677 case _FALSE:
678 case _TRUE:
679 {
680 return argsSensitiveTo(aContext);
681 }
682 case ID:
683 {
684 return (aContext & NODE_CONTEXT) ||
685 argsSensitiveTo(aContext);
686 }
687 case LAST:
688 {
689 return !!(aContext & SIZE_CONTEXT);
690 }
691 case LOCAL_NAME:
692 case NAME:
693 case NAMESPACE_URI:
694 case NORMALIZE_SPACE:
695 case STRING:
696 case STRING_LENGTH:
697 case NUMBER:
698 {
699 if (mParams.IsEmpty()) {
700 return !!(aContext & NODE_CONTEXT);
701 }
702 return argsSensitiveTo(aContext);
703 }
704 case POSITION:
705 {
706 return !!(aContext & POSITION_CONTEXT);
707 }
708 case LANG:
709 {
710 return (aContext & NODE_CONTEXT) ||
711 argsSensitiveTo(aContext);
712 }
713 }
715 NS_NOTREACHED("how'd we get here?");
716 return true;
717 }
719 // static
720 bool
721 txCoreFunctionCall::getTypeFromAtom(nsIAtom* aName, eType& aType)
722 {
723 uint32_t i;
724 for (i = 0; i < ArrayLength(descriptTable); ++i) {
725 if (aName == *descriptTable[i].mName) {
726 aType = static_cast<eType>(i);
728 return true;
729 }
730 }
732 return false;
733 }
735 #ifdef TX_TO_STRING
736 nsresult
737 txCoreFunctionCall::getNameAtom(nsIAtom** aAtom)
738 {
739 NS_ADDREF(*aAtom = *descriptTable[mType].mName);
740 return NS_OK;
741 }
742 #endif