1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
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.
39 * ***** END LICENSE BLOCK ***** */
42 * JS string type implementation.
44 * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
45 * native methods store strings (possibly newborn) converted from their 'this'
46 * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
47 * conversions at their index (argv[0], argv[1]). This is a legitimate method
48 * of rooting things that might lose their newborn root due to subsequent GC
49 * allocations in the same native method.
62 #include "jsbuiltins.h"
64 #include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */
73 #include "jsstaticcheck.h"
77 #include "jsversion.h"
79 #include "jscntxtinlines.h"
80 #include "jsinterpinlines.h"
81 #include "jsobjinlines.h"
82 #include "jsregexpinlines.h"
83 #include "jsstrinlines.h"
84 #include "jsautooplen.h" // generated headers last
87 using namespace js::gc
;
89 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH
) <= size_t(JSVAL_INT_MAX
));
90 JS_STATIC_ASSERT(JSString::MAX_LENGTH
<= JSVAL_INT_MAX
);
93 js_GetStringChars(JSContext
*cx
, JSString
*str
)
95 if (!js_MakeStringImmutable(cx
, str
))
97 return str
->flatChars();
106 * This can be called from any string in the rope, so first traverse to the
109 JSString
*topNode
= this;
110 while (topNode
->isInteriorNode())
111 topNode
= topNode
->interiorNodeParent();
113 const size_t length
= topNode
->length();
114 const size_t capacity
= topNode
->topNodeCapacity();
115 jschar
*const chars
= (jschar
*) topNode
->topNodeBuffer();
118 * To allow a homogeneous tree traversal, transform the top node into an
119 * internal node with null parent (which will be the stop condition).
121 topNode
->e
.mParent
= NULL
;
123 topNode
->mLengthAndFlags
= JSString::INTERIOR_NODE
;
127 * Perform a depth-first tree traversal, splatting each node's characters
128 * into a contiguous buffer. Visit each node three times:
129 * - the first time, record the position in the linear buffer, and recurse
130 * into the left child.
131 * - the second time, recurse into the right child.
132 * - the third time, transform the node into a dependent string.
133 * To avoid maintaining a stack, tree nodes are mutated to indicate how
134 * many times they have been visited.
136 JSString
*str
= topNode
;
139 /* Visiting the node for the first time. */
140 JS_ASSERT(str
->isInteriorNode());
142 JSString
*next
= str
->mLeft
;
143 str
->mChars
= pos
; /* N.B. aliases mLeft */
144 if (next
->isInteriorNode()) {
145 str
->mLengthAndFlags
= 0x200; /* N.B. flags invalidated */
147 continue; /* Visit node for the first time. */
149 size_t len
= next
->length();
150 PodCopy(pos
, next
->mChars
, len
);
152 goto visit_right_child
;
157 if (str
->mLengthAndFlags
== 0x200) {
159 JSString
*next
= str
->e
.mRight
;
160 if (next
->isInteriorNode()) {
161 str
->mLengthAndFlags
= 0x300;
163 continue; /* Visit 'str' for the first time. */
165 size_t len
= next
->length();
166 PodCopy(pos
, next
->mChars
, len
);
171 JS_ASSERT(str
->mLengthAndFlags
== 0x300);
173 JSString
*next
= str
->e
.mParent
;
174 str
->finishTraversalConversion(topNode
, pos
);
176 JS_ASSERT(pos
== chars
+ length
);
178 topNode
->initFlatExtensible(chars
, length
, capacity
);
182 goto revisit_parent
; /* Visit 'str' for the second or third time */
187 JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT
== 8);
188 JSStringFinalizeOp
JSExternalString::str_finalizers
[JSExternalString::TYPE_LIMIT
] = {
189 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
195 js_Flatten(JSString
* str
)
200 JS_DEFINE_CALLINFO_1(extern, INT32
, js_Flatten
, STRING
, 0, nanojit::ACCSET_STORE_ANY
)
202 #endif /* !JS_TRACER */
204 static JS_ALWAYS_INLINE
size_t
205 RopeAllocSize(const size_t length
, size_t *capacity
)
207 static const size_t ROPE_DOUBLING_MAX
= 1024 * 1024;
210 size_t minCap
= (length
+ 1) * sizeof(jschar
);
213 * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
214 * next power of 2. This is similar to what we do with arrays; see
215 * JSObject::ensureDenseArrayElements.
217 if (length
> ROPE_DOUBLING_MAX
)
218 size
= minCap
+ (minCap
/ 8);
220 size
= RoundUpPow2(minCap
);
221 *capacity
= (size
/ sizeof(jschar
)) - 1;
222 JS_ASSERT(size
>= sizeof(JSRopeBufferInfo
));
226 static JS_ALWAYS_INLINE JSRopeBufferInfo
*
227 ObtainRopeBuffer(JSContext
*cx
, bool usingLeft
, bool usingRight
,
228 JSRopeBufferInfo
*sourceBuffer
, size_t length
,
229 JSString
*left
, JSString
*right
)
231 JSRopeBufferInfo
*buf
;
235 * We need to survive a GC upon failure and in case creating a new
236 * string header triggers a GC, but we've broken the invariant that
237 * rope top nodes always point to freeable JSRopeBufferInfo
238 * objects, so make them point to NULL.
241 left
->nullifyTopNodeBuffer();
243 right
->nullifyTopNodeBuffer();
246 * Try to reuse sourceBuffer. If it's not suitable, free it and create a
249 if (length
<= sourceBuffer
->capacity
) {
252 size_t allocSize
= RopeAllocSize(length
, &capacity
);
253 cx
->free(sourceBuffer
);
254 buf
= (JSRopeBufferInfo
*) cx
->malloc(allocSize
);
257 buf
->capacity
= capacity
;
262 static JS_ALWAYS_INLINE JSString
*
263 FinishConcat(JSContext
*cx
, bool usingLeft
, bool usingRight
,
264 JSString
*left
, JSString
*right
, size_t length
,
265 JSRopeBufferInfo
*buf
)
267 JSString
*res
= js_NewGCString(cx
);
272 res
->initTopNode(left
, right
, length
, buf
);
274 left
->convertToInteriorNode(res
);
276 right
->convertToInteriorNode(res
);
280 JSString
* JS_FASTCALL
281 js_ConcatStrings(JSContext
*cx
, JSString
*left
, JSString
*right
)
283 size_t length
, leftLen
, rightLen
;
284 bool leftRopeTop
, rightRopeTop
;
286 leftLen
= left
->length();
289 rightLen
= right
->length();
293 length
= leftLen
+ rightLen
;
295 if (JSShortString::fitsIntoShortString(length
)) {
296 JSShortString
*shortStr
= js_NewGCShortString(cx
);
300 jschar
*buf
= shortStr
->init(length
);
301 js_short_strncpy(buf
, left
->chars(), leftLen
);
302 js_short_strncpy(buf
+ leftLen
, right
->chars(), rightLen
);
304 return shortStr
->header();
308 * We need to enforce a tree structure in ropes: every node needs to have a
309 * unique parent. So, we can't have the left or right child be in the middle
310 * of a rope tree. One potential solution is to traverse the subtree for the
311 * argument string and create a new flat string, but that would add
312 * complexity and is a rare case, so we simply flatten the entire rope that
313 * contains it. The case where left and right are part of the same rope is
314 * handled implicitly.
316 if (left
->isInteriorNode())
318 if (right
->isInteriorNode())
321 if (left
->isExtensible() && !right
->isRope() &&
322 left
->flatCapacity() >= length
) {
323 JS_ASSERT(left
->isFlat());
326 * If left has enough unused space at the end of its buffer that we can
327 * fit the entire new string there, just write there.
329 jschar
*chars
= left
->chars();
330 js_strncpy(chars
+ leftLen
, right
->chars(), rightLen
);
332 JSString
*res
= js_NewString(cx
, chars
, length
);
335 res
->initFlatExtensible(chars
, length
, left
->flatCapacity());
336 left
->initDependent(res
, res
->flatChars(), leftLen
);
340 if (length
> JSString::MAX_LENGTH
) {
341 if (JS_ON_TRACE(cx
)) {
342 if (!CanLeaveTrace(cx
))
346 js_ReportAllocationOverflow(cx
);
350 leftRopeTop
= left
->isTopNode();
351 rightRopeTop
= right
->isTopNode();
354 * To make traversal more manageable, we enforce that, unless the children
355 * are leaves, the two children of a rope node must be distinct.
357 if (left
== right
&& leftRopeTop
) {
360 rightRopeTop
= false;
361 JS_ASSERT(leftLen
== left
->length());
362 JS_ASSERT(rightLen
== right
->length());
363 JS_ASSERT(!left
->isTopNode());
364 JS_ASSERT(!right
->isTopNode());
368 * There are 4 cases, based on whether on whether the left or right is a
369 * rope or non-rope string.
371 JSRopeBufferInfo
*buf
= NULL
;
374 /* Left child is a rope. */
375 JSRopeBufferInfo
*leftBuf
= left
->topNodeBuffer();
377 /* If both children are ropes, steal the larger buffer. */
378 if (JS_UNLIKELY(rightRopeTop
)) {
379 JSRopeBufferInfo
*rightBuf
= right
->topNodeBuffer();
381 /* Put the larger buffer into 'leftBuf'. */
382 if (leftBuf
->capacity
>= rightBuf
->capacity
) {
390 buf
= ObtainRopeBuffer(cx
, true, rightRopeTop
, leftBuf
, length
, left
, right
);
393 } else if (JS_UNLIKELY(rightRopeTop
)) {
394 /* Right child is a rope: steal its buffer if big enough. */
395 JSRopeBufferInfo
*rightBuf
= right
->topNodeBuffer();
397 buf
= ObtainRopeBuffer(cx
, false, true, rightBuf
, length
, left
, right
);
401 /* Neither child is a rope: need to make a new buffer. */
403 size_t allocSize
= RopeAllocSize(length
, &capacity
);
404 buf
= (JSRopeBufferInfo
*) cx
->malloc(allocSize
);
407 buf
->capacity
= capacity
;
410 return FinishConcat(cx
, leftRopeTop
, rightRopeTop
, left
, right
, length
, buf
);
414 JSString::undepend(JSContext
*cx
)
422 n
= dependentLength();
423 size
= (n
+ 1) * sizeof(jschar
);
424 s
= (jschar
*) cx
->malloc(size
);
428 js_strncpy(s
, dependentChars(), n
);
434 JSRuntime
*rt
= cx
->runtime
;
435 JS_RUNTIME_UNMETER(rt
, liveDependentStrings
);
436 JS_RUNTIME_UNMETER(rt
, totalDependentStrings
);
437 JS_LOCK_RUNTIME_VOID(rt
,
438 (rt
->strdepLengthSum
-= (double)n
,
439 rt
->strdepLengthSquaredSum
-= (double)n
* (double)n
));
448 js_MakeStringImmutable(JSContext
*cx
, JSString
*str
)
451 * Flattening a rope may result in a dependent string, so we need to flatten
452 * before undepending the string.
454 str
->ensureNotRope();
455 if (!str
->ensureNotDependent(cx
)) {
456 JS_RUNTIME_METER(cx
->runtime
, badUndependStrings
);
459 str
->flatClearExtensible();
464 ArgToRootedString(JSContext
*cx
, uintN argc
, Value
*vp
, uintN arg
)
467 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
470 if (vp
->isObject() && !DefaultValue(cx
, &vp
->toObject(), JSTYPE_STRING
, vp
))
474 if (vp
->isString()) {
475 str
= vp
->toString();
476 } else if (vp
->isBoolean()) {
477 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.booleanAtoms
[
478 (int)vp
->toBoolean()]);
479 } else if (vp
->isNull()) {
480 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
481 } else if (vp
->isUndefined()) {
482 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
485 str
= js_NumberToString(cx
, vp
->toNumber());
493 * Forward declarations for URI encode/decode and helper routines
496 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
499 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
502 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
505 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
507 static const uint32 OVERLONG_UTF8
= UINT32_MAX
;
510 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
);
513 * Contributions from the String class to the set of methods defined for the
514 * global object. escape and unescape used to be defined in the Mocha library,
515 * but as ECMA decided to spec them, they've been moved to the core engine
516 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
517 * characters by unescape.)
521 * Stuff to emulate the old libmocha escape, which took a second argument
522 * giving the type of escape to perform. Retained for compatibility, and
523 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
526 #define URL_XALPHAS ((uint8) 1)
527 #define URL_XPALPHAS ((uint8) 2)
528 #define URL_PATH ((uint8) 4)
530 static const uint8 urlCharType
[256] =
531 /* Bit 0 xalpha -- the alphas
532 * Bit 1 xpalpha -- as xalpha but
533 * converts spaces to plus and plus to %20
534 * Bit 2 ... path -- as xalphas but doesn't escape '/'
536 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
537 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
538 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
539 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
540 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
541 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
542 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
543 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
544 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
547 /* This matches the ECMA escape set when mask is 7 (default.) */
549 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
551 /* See ECMA-262 Edition 3 B.2.1 */
553 js_str_escape(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
, Value
*rval
)
556 size_t i
, ni
, length
, newlength
;
562 const char digits
[] = {'0', '1', '2', '3', '4', '5', '6', '7',
563 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
565 mask
= URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
;
567 if (!ValueToNumber(cx
, argv
[1], &d
))
569 if (!JSDOUBLE_IS_FINITE(d
) ||
570 (mask
= (jsint
)d
) != d
||
571 mask
& ~(URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
))
574 JS_snprintf(numBuf
, sizeof numBuf
, "%lx", (unsigned long) mask
);
575 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
576 JSMSG_BAD_STRING_MASK
, numBuf
);
581 str
= ArgToRootedString(cx
, argc
, argv
- 2, 0);
585 str
->getCharsAndLength(chars
, length
);
588 /* Take a first pass and see how big the result string will need to be. */
589 for (i
= 0; i
< length
; i
++) {
590 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
))
593 if (mask
== URL_XPALPHAS
&& ch
== ' ')
594 continue; /* The character will be encoded as '+' */
595 newlength
+= 2; /* The character will be encoded as %XX */
597 newlength
+= 5; /* The character will be encoded as %uXXXX */
601 * This overflow test works because newlength is incremented by at
602 * most 5 on each iteration.
604 if (newlength
< length
) {
605 js_ReportAllocationOverflow(cx
);
610 if (newlength
>= ~(size_t)0 / sizeof(jschar
)) {
611 js_ReportAllocationOverflow(cx
);
615 newchars
= (jschar
*) cx
->malloc((newlength
+ 1) * sizeof(jschar
));
618 for (i
= 0, ni
= 0; i
< length
; i
++) {
619 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
)) {
621 } else if (ch
< 256) {
622 if (mask
== URL_XPALPHAS
&& ch
== ' ') {
623 newchars
[ni
++] = '+'; /* convert spaces to pluses */
625 newchars
[ni
++] = '%';
626 newchars
[ni
++] = digits
[ch
>> 4];
627 newchars
[ni
++] = digits
[ch
& 0xF];
630 newchars
[ni
++] = '%';
631 newchars
[ni
++] = 'u';
632 newchars
[ni
++] = digits
[ch
>> 12];
633 newchars
[ni
++] = digits
[(ch
& 0xF00) >> 8];
634 newchars
[ni
++] = digits
[(ch
& 0xF0) >> 4];
635 newchars
[ni
++] = digits
[ch
& 0xF];
638 JS_ASSERT(ni
== newlength
);
639 newchars
[newlength
] = 0;
641 str
= js_NewString(cx
, newchars
, newlength
);
646 rval
->setString(str
);
652 str_escape(JSContext
*cx
, uintN argc
, Value
*vp
)
654 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
655 return obj
&& js_str_escape(cx
, obj
, argc
, vp
+ 2, vp
);
658 /* See ECMA-262 Edition 3 B.2.2 */
660 str_unescape(JSContext
*cx
, uintN argc
, Value
*vp
)
663 size_t i
, ni
, length
;
668 str
= ArgToRootedString(cx
, argc
, vp
, 0);
672 str
->getCharsAndLength(chars
, length
);
674 /* Don't bother allocating less space for the new string. */
675 newchars
= (jschar
*) cx
->malloc((length
+ 1) * sizeof(jschar
));
682 if (i
+ 1 < length
&&
683 JS7_ISHEX(chars
[i
]) && JS7_ISHEX(chars
[i
+ 1]))
685 ch
= JS7_UNHEX(chars
[i
]) * 16 + JS7_UNHEX(chars
[i
+ 1]);
687 } else if (i
+ 4 < length
&& chars
[i
] == 'u' &&
688 JS7_ISHEX(chars
[i
+ 1]) && JS7_ISHEX(chars
[i
+ 2]) &&
689 JS7_ISHEX(chars
[i
+ 3]) && JS7_ISHEX(chars
[i
+ 4]))
691 ch
= (((((JS7_UNHEX(chars
[i
+ 1]) << 4)
692 + JS7_UNHEX(chars
[i
+ 2])) << 4)
693 + JS7_UNHEX(chars
[i
+ 3])) << 4)
694 + JS7_UNHEX(chars
[i
+ 4]);
702 str
= js_NewString(cx
, newchars
, ni
);
713 str_uneval(JSContext
*cx
, uintN argc
, Value
*vp
)
717 str
= js_ValueToSource(cx
, argc
!= 0 ? vp
[2] : UndefinedValue());
725 const char js_escape_str
[] = "escape";
726 const char js_unescape_str
[] = "unescape";
728 const char js_uneval_str
[] = "uneval";
730 const char js_decodeURI_str
[] = "decodeURI";
731 const char js_encodeURI_str
[] = "encodeURI";
732 const char js_decodeURIComponent_str
[] = "decodeURIComponent";
733 const char js_encodeURIComponent_str
[] = "encodeURIComponent";
735 static JSFunctionSpec string_functions
[] = {
736 JS_FN(js_escape_str
, str_escape
, 1,0),
737 JS_FN(js_unescape_str
, str_unescape
, 1,0),
739 JS_FN(js_uneval_str
, str_uneval
, 1,0),
741 JS_FN(js_decodeURI_str
, str_decodeURI
, 1,0),
742 JS_FN(js_encodeURI_str
, str_encodeURI
, 1,0),
743 JS_FN(js_decodeURIComponent_str
, str_decodeURI_Component
, 1,0),
744 JS_FN(js_encodeURIComponent_str
, str_encodeURI_Component
, 1,0),
749 jschar js_empty_ucstr
[] = {0};
750 JSSubString js_EmptySubString
= {0, js_empty_ucstr
};
753 str_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
757 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
758 if (obj
->getClass() == &js_StringClass
) {
759 /* Follow ECMA-262 by fetching intrinsic length of our string. */
760 str
= obj
->getPrimitiveThis().toString();
762 /* Preserve compatibility: convert obj to a string primitive. */
763 str
= js_ValueToString(cx
, ObjectValue(*obj
));
768 vp
->setInt32(str
->length());
774 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
777 str_enumerate(JSContext
*cx
, JSObject
*obj
)
779 JSString
*str
, *str1
;
782 str
= obj
->getPrimitiveThis().toString();
784 length
= str
->length();
785 for (i
= 0; i
< length
; i
++) {
786 str1
= js_NewDependentString(cx
, str
, i
, 1);
789 if (!obj
->defineProperty(cx
, INT_TO_JSID(i
), StringValue(str1
),
790 PropertyStub
, PropertyStub
,
791 STRING_ELEMENT_ATTRS
)) {
796 return obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
797 UndefinedValue(), NULL
, NULL
,
798 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_SHARED
);
802 str_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
805 if (!JSID_IS_INT(id
))
808 JSString
*str
= obj
->getPrimitiveThis().toString();
810 jsint slot
= JSID_TO_INT(id
);
811 if ((size_t)slot
< str
->length()) {
812 JSString
*str1
= JSString::getUnitString(cx
, str
, size_t(slot
));
815 if (!obj
->defineProperty(cx
, id
, StringValue(str1
), NULL
, NULL
,
816 STRING_ELEMENT_ATTRS
)) {
824 Class js_StringClass
= {
826 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE
|
827 JSCLASS_HAS_CACHED_PROTO(JSProto_String
),
828 PropertyStub
, /* addProperty */
829 PropertyStub
, /* delProperty */
831 PropertyStub
, /* setProperty */
833 (JSResolveOp
)str_resolve
,
837 #define NORMALIZE_THIS(cx,vp,str) \
839 if (vp[1].isString()) { \
840 str = vp[1].toString(); \
842 str = NormalizeThis(cx, vp); \
849 NormalizeThis(JSContext
*cx
, Value
*vp
)
851 if (vp
[1].isNullOrUndefined() && !ComputeThisFromVp(cx
, vp
))
855 * String.prototype.{toString,toSource,valueOf} throw a TypeError if the
856 * this-argument is not a string or a String object. So those methods use
857 * js::GetPrimitiveThis which provides that behavior.
859 * By standard, the rest of the String methods must ToString the
860 * this-argument rather than throw a TypeError. So those methods use
861 * NORMALIZE_THIS (and thus NormalizeThis) instead.
863 if (vp
[1].isObject()) {
864 JSObject
*obj
= &vp
[1].toObject();
865 if (obj
->getClass() == &js_StringClass
) {
866 vp
[1] = obj
->getPrimitiveThis();
867 return vp
[1].toString();
871 JSString
*str
= js_ValueToString(cx
, vp
[1]);
874 vp
[1].setString(str
);
881 * String.prototype.quote is generic (as are most string methods), unlike
882 * toSource, toString, and valueOf.
885 str_quote(JSContext
*cx
, uintN argc
, Value
*vp
)
889 NORMALIZE_THIS(cx
, vp
, str
);
890 str
= js_QuoteString(cx
, str
, '"');
898 str_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
901 if (!GetPrimitiveThis(cx
, vp
, &str
))
904 str
= js_QuoteString(cx
, str
, '"');
909 size_t j
= JS_snprintf(buf
, sizeof buf
, "(new String(");
913 str
->getCharsAndLength(s
, k
);
915 size_t n
= j
+ k
+ 2;
916 jschar
*t
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
921 for (i
= 0; i
< j
; i
++)
923 for (j
= 0; j
< k
; i
++, j
++)
929 str
= js_NewString(cx
, t
, n
);
938 #endif /* JS_HAS_TOSOURCE */
941 js_str_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
944 if (!GetPrimitiveThis(cx
, vp
, &str
))
951 * Java-like string native methods.
955 SubstringTail(JSContext
*cx
, JSString
*str
, jsdouble length
, jsdouble begin
, jsdouble end
)
959 else if (begin
> length
)
964 else if (end
> length
)
967 /* ECMA emulates old JDK1.0 java.lang.String.substring. */
968 jsdouble tmp
= begin
;
973 return js_NewDependentString(cx
, str
, (size_t)begin
, (size_t)(end
- begin
));
977 str_substring(JSContext
*cx
, uintN argc
, Value
*vp
)
981 jsdouble length
, begin
, end
;
983 NORMALIZE_THIS(cx
, vp
, str
);
985 if (!ValueToNumber(cx
, vp
[2], &d
))
987 length
= str
->length();
988 begin
= js_DoubleToInteger(d
);
989 if (argc
== 1 || vp
[3].isUndefined()) {
992 if (!ValueToNumber(cx
, vp
[3], &d
))
994 end
= js_DoubleToInteger(d
);
997 str
= SubstringTail(cx
, str
, length
, begin
, end
);
1005 JSString
* JS_FASTCALL
1006 js_toLowerCase(JSContext
*cx
, JSString
*str
)
1012 str
->getCharsAndLength(s
, n
);
1013 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
1016 for (i
= 0; i
< n
; i
++)
1017 news
[i
] = JS_TOLOWER(s
[i
]);
1019 str
= js_NewString(cx
, news
, n
);
1028 str_toLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1032 NORMALIZE_THIS(cx
, vp
, str
);
1033 str
= js_toLowerCase(cx
, str
);
1041 str_toLocaleLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1046 * Forcefully ignore the first (or any) argument and return toLowerCase(),
1047 * ECMA has reserved that argument, presumably for defining the locale.
1049 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToLowerCase
) {
1050 NORMALIZE_THIS(cx
, vp
, str
);
1051 return cx
->localeCallbacks
->localeToLowerCase(cx
, str
, Jsvalify(vp
));
1053 return str_toLowerCase(cx
, 0, vp
);
1056 JSString
* JS_FASTCALL
1057 js_toUpperCase(JSContext
*cx
, JSString
*str
)
1063 str
->getCharsAndLength(s
, n
);
1064 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
1067 for (i
= 0; i
< n
; i
++)
1068 news
[i
] = JS_TOUPPER(s
[i
]);
1070 str
= js_NewString(cx
, news
, n
);
1079 str_toUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1083 NORMALIZE_THIS(cx
, vp
, str
);
1084 str
= js_toUpperCase(cx
, str
);
1092 str_toLocaleUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1097 * Forcefully ignore the first (or any) argument and return toUpperCase(),
1098 * ECMA has reserved that argument, presumably for defining the locale.
1100 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUpperCase
) {
1101 NORMALIZE_THIS(cx
, vp
, str
);
1102 return cx
->localeCallbacks
->localeToUpperCase(cx
, str
, Jsvalify(vp
));
1104 return str_toUpperCase(cx
, 0, vp
);
1108 str_localeCompare(JSContext
*cx
, uintN argc
, Value
*vp
)
1110 JSString
*str
, *thatStr
;
1112 NORMALIZE_THIS(cx
, vp
, str
);
1116 thatStr
= js_ValueToString(cx
, vp
[2]);
1119 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeCompare
) {
1120 vp
[2].setString(thatStr
);
1121 return cx
->localeCallbacks
->localeCompare(cx
, str
, thatStr
, Jsvalify(vp
));
1123 vp
->setInt32(js_CompareStrings(str
, thatStr
));
1129 js_str_charAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1135 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1136 str
= vp
[1].toString();
1137 i
= vp
[2].toInt32();
1138 if ((size_t)i
>= str
->length())
1141 NORMALIZE_THIS(cx
, vp
, str
);
1146 if (!ValueToNumber(cx
, vp
[2], &d
))
1148 d
= js_DoubleToInteger(d
);
1151 if (d
< 0 || str
->length() <= d
)
1156 str
= JSString::getUnitString(cx
, str
, size_t(i
));
1163 vp
->setString(cx
->runtime
->emptyString
);
1168 js_str_charCodeAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1174 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1175 str
= vp
[1].toString();
1176 i
= vp
[2].toInt32();
1177 if ((size_t)i
>= str
->length())
1180 NORMALIZE_THIS(cx
, vp
, str
);
1185 if (!ValueToNumber(cx
, vp
[2], &d
))
1187 d
= js_DoubleToInteger(d
);
1190 if (d
< 0 || str
->length() <= d
)
1195 vp
->setInt32(str
->chars()[i
]);
1199 vp
->setDouble(js_NaN
);
1204 js_BoyerMooreHorspool(const jschar
*text
, jsuint textlen
,
1205 const jschar
*pat
, jsuint patlen
)
1207 uint8 skip
[sBMHCharSetSize
];
1209 JS_ASSERT(0 < patlen
&& patlen
<= sBMHPatLenMax
);
1210 for (jsuint i
= 0; i
< sBMHCharSetSize
; i
++)
1211 skip
[i
] = (uint8
)patlen
;
1212 jsuint m
= patlen
- 1;
1213 for (jsuint i
= 0; i
< m
; i
++) {
1215 if (c
>= sBMHCharSetSize
)
1216 return sBMHBadPattern
;
1217 skip
[c
] = (uint8
)(m
- i
);
1222 k
+= ((c
= text
[k
]) >= sBMHCharSetSize
) ? patlen
: skip
[c
]) {
1223 for (jsuint i
= k
, j
= m
; ; i
--, j
--) {
1224 if (text
[i
] != pat
[j
])
1227 return static_cast<jsint
>(i
); /* safe: max string size */
1234 typedef jsuint Extent
;
1235 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*, jsuint patlen
) {
1236 return (patlen
- 1) * sizeof(jschar
);
1238 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1239 return memcmp(p
, t
, extent
) == 0;
1244 typedef const jschar
*Extent
;
1245 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*pat
, jsuint patlen
) {
1246 return pat
+ patlen
;
1248 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1249 for (; p
!= extent
; ++p
, ++t
) {
1257 template <class InnerMatch
>
1259 UnrolledMatch(const jschar
*text
, jsuint textlen
, const jschar
*pat
, jsuint patlen
)
1261 JS_ASSERT(patlen
> 0 && textlen
> 0);
1262 const jschar
*textend
= text
+ textlen
- (patlen
- 1);
1263 const jschar p0
= *pat
;
1264 const jschar
*const patNext
= pat
+ 1;
1265 const typename
InnerMatch::Extent extent
= InnerMatch::computeExtent(pat
, patlen
);
1268 const jschar
*t
= text
;
1269 switch ((textend
- t
) & 7) {
1270 case 0: if (*t
++ == p0
) { fixup
= 8; goto match
; }
1271 case 7: if (*t
++ == p0
) { fixup
= 7; goto match
; }
1272 case 6: if (*t
++ == p0
) { fixup
= 6; goto match
; }
1273 case 5: if (*t
++ == p0
) { fixup
= 5; goto match
; }
1274 case 4: if (*t
++ == p0
) { fixup
= 4; goto match
; }
1275 case 3: if (*t
++ == p0
) { fixup
= 3; goto match
; }
1276 case 2: if (*t
++ == p0
) { fixup
= 2; goto match
; }
1277 case 1: if (*t
++ == p0
) { fixup
= 1; goto match
; }
1279 while (t
!= textend
) {
1280 if (t
[0] == p0
) { t
+= 1; fixup
= 8; goto match
; }
1281 if (t
[1] == p0
) { t
+= 2; fixup
= 7; goto match
; }
1282 if (t
[2] == p0
) { t
+= 3; fixup
= 6; goto match
; }
1283 if (t
[3] == p0
) { t
+= 4; fixup
= 5; goto match
; }
1284 if (t
[4] == p0
) { t
+= 5; fixup
= 4; goto match
; }
1285 if (t
[5] == p0
) { t
+= 6; fixup
= 3; goto match
; }
1286 if (t
[6] == p0
) { t
+= 7; fixup
= 2; goto match
; }
1287 if (t
[7] == p0
) { t
+= 8; fixup
= 1; goto match
; }
1293 if (!InnerMatch::match(patNext
, t
, extent
))
1295 return t
- text
- 1;
1298 } while (--fixup
> 0);
1303 static JS_ALWAYS_INLINE jsint
1304 StringMatch(const jschar
*text
, jsuint textlen
,
1305 const jschar
*pat
, jsuint patlen
)
1309 if (textlen
< patlen
)
1312 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1314 * Given enough registers, the unrolled loop below is faster than the
1315 * following loop. 32-bit x86 does not have enough registers.
1318 const jschar p0
= *pat
;
1319 for (const jschar
*c
= text
, *end
= text
+ textlen
; c
!= end
; ++c
) {
1328 * If the text or pattern string is short, BMH will be more expensive than
1329 * the basic linear scan due to initialization cost and a more complex loop
1330 * body. While the correct threshold is input-dependent, we can make a few
1331 * conservative observations:
1332 * - When |textlen| is "big enough", the initialization time will be
1333 * proportionally small, so the worst-case slowdown is minimized.
1334 * - When |patlen| is "too small", even the best case for BMH will be
1335 * slower than a simple scan for large |textlen| due to the more complex
1337 * From this, the values for "big enough" and "too small" are determined
1338 * empirically. See bug 526348.
1340 if (textlen
>= 512 && patlen
>= 11 && patlen
<= sBMHPatLenMax
) {
1341 jsint index
= js_BoyerMooreHorspool(text
, textlen
, pat
, patlen
);
1342 if (index
!= sBMHBadPattern
)
1347 * For big patterns with large potential overlap we want the SIMD-optimized
1348 * speed of memcmp. For small patterns, a simple loop is faster.
1350 * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1353 #if !defined(__linux__)
1354 patlen
> 128 ? UnrolledMatch
<MemCmp
>(text
, textlen
, pat
, patlen
)
1357 UnrolledMatch
<ManualCmp
>(text
, textlen
, pat
, patlen
);
1360 static const size_t sRopeMatchThresholdRatioLog2
= 5;
1363 RopeMatch(JSString
*textstr
, const jschar
*pat
, jsuint patlen
)
1365 JS_ASSERT(textstr
->isTopNode());
1369 if (textstr
->length() < patlen
)
1373 * List of leaf nodes in the rope. If we run out of memory when trying to
1374 * append to this list, we can still fall back to StringMatch, so use the
1375 * system allocator so we don't report OOM in that case.
1377 Vector
<JSString
*, 16, SystemAllocPolicy
> strs
;
1380 * We don't want to do rope matching if there is a poor node-to-char ratio,
1381 * since this means spending a lot of time in the match loop below. We also
1382 * need to build the list of leaf nodes. Do both here: iterate over the
1383 * nodes so long as there are not too many.
1385 size_t textstrlen
= textstr
->length();
1386 size_t threshold
= textstrlen
>> sRopeMatchThresholdRatioLog2
;
1387 JSRopeLeafIterator
iter(textstr
);
1388 for (JSString
*str
= iter
.init(); str
; str
= iter
.next()) {
1389 if (threshold
-- == 0 || !strs
.append(str
))
1390 return StringMatch(textstr
->chars(), textstrlen
, pat
, patlen
);
1393 /* Absolute offset from the beginning of the logical string textstr. */
1396 // TODO: consider branching to a simple loop if patlen == 1
1398 for (JSString
**outerp
= strs
.begin(); outerp
!= strs
.end(); ++outerp
) {
1399 /* First try to match without spanning two nodes. */
1400 const jschar
*chars
;
1402 (*outerp
)->getCharsAndLength(chars
, len
);
1403 jsint matchResult
= StringMatch(chars
, len
, pat
, patlen
);
1404 if (matchResult
!= -1)
1405 return pos
+ matchResult
;
1407 /* Test the overlap. */
1408 JSString
**innerp
= outerp
;
1411 * Start searching at the first place where StringMatch wouldn't have
1414 const jschar
*const text
= chars
+ (patlen
> len
? 0 : len
- patlen
+ 1);
1415 const jschar
*const textend
= chars
+ len
;
1416 const jschar p0
= *pat
;
1417 const jschar
*const p1
= pat
+ 1;
1418 const jschar
*const patend
= pat
+ patlen
;
1419 for (const jschar
*t
= text
; t
!= textend
; ) {
1422 const jschar
*ttend
= textend
;
1423 for (const jschar
*pp
= p1
, *tt
= t
; pp
!= patend
; ++pp
, ++tt
) {
1424 while (tt
== ttend
) {
1425 if (++innerp
== strs
.end())
1427 (*innerp
)->getCharsAndEnd(tt
, ttend
);
1430 goto break_continue
;
1434 return pos
+ (t
- chars
) - 1; /* -1 because of *t++ above */
1446 str_indexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1450 NORMALIZE_THIS(cx
, vp
, str
);
1452 JSString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1456 const jschar
*text
= str
->chars();
1457 jsuint textlen
= str
->length();
1458 const jschar
*pat
= patstr
->chars();
1459 jsuint patlen
= patstr
->length();
1463 if (vp
[3].isInt32()) {
1464 jsint i
= vp
[3].toInt32();
1467 } else if (jsuint(i
) > textlen
) {
1477 if (!ValueToNumber(cx
, vp
[3], &d
))
1479 d
= js_DoubleToInteger(d
);
1482 } else if (d
> textlen
) {
1495 jsint match
= StringMatch(text
, textlen
, pat
, patlen
);
1496 vp
->setInt32((match
== -1) ? -1 : start
+ match
);
1501 str_lastIndexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1503 JSString
*str
, *str2
;
1504 const jschar
*text
, *pat
;
1505 jsint i
, j
, textlen
, patlen
;
1508 NORMALIZE_THIS(cx
, vp
, str
);
1509 text
= str
->chars();
1510 textlen
= (jsint
) str
->length();
1512 if (argc
!= 0 && vp
[2].isString()) {
1513 str2
= vp
[2].toString();
1515 str2
= ArgToRootedString(cx
, argc
, vp
, 0);
1519 pat
= str2
->chars();
1520 patlen
= (jsint
) str2
->length();
1522 i
= textlen
- patlen
; // Start searching here
1529 if (vp
[3].isInt32()) {
1530 j
= vp
[3].toInt32();
1536 if (!ValueToNumber(cx
, vp
[3], &d
))
1538 if (!JSDOUBLE_IS_NaN(d
)) {
1539 d
= js_DoubleToInteger(d
);
1553 const jschar
*t
= text
+ i
;
1554 const jschar
*textend
= text
- 1;
1555 const jschar p0
= *pat
;
1556 const jschar
*patNext
= pat
+ 1;
1557 const jschar
*patEnd
= pat
+ patlen
;
1559 for (; t
!= textend
; --t
) {
1561 const jschar
*t1
= t
+ 1;
1562 for (const jschar
*p1
= patNext
; p1
!= patEnd
; ++p1
, ++t1
) {
1564 goto break_continue
;
1566 vp
->setInt32(t
- text
);
1577 js_TrimString(JSContext
*cx
, Value
*vp
, JSBool trimLeft
, JSBool trimRight
)
1580 const jschar
*chars
;
1581 size_t length
, begin
, end
;
1583 NORMALIZE_THIS(cx
, vp
, str
);
1584 str
->getCharsAndLength(chars
, length
);
1589 while (begin
< length
&& JS_ISSPACE(chars
[begin
]))
1594 while (end
> begin
&& JS_ISSPACE(chars
[end
-1]))
1598 str
= js_NewDependentString(cx
, str
, begin
, end
- begin
);
1607 str_trim(JSContext
*cx
, uintN argc
, Value
*vp
)
1609 return js_TrimString(cx
, vp
, JS_TRUE
, JS_TRUE
);
1613 str_trimLeft(JSContext
*cx
, uintN argc
, Value
*vp
)
1615 return js_TrimString(cx
, vp
, JS_TRUE
, JS_FALSE
);
1619 str_trimRight(JSContext
*cx
, uintN argc
, Value
*vp
)
1621 return js_TrimString(cx
, vp
, JS_FALSE
, JS_TRUE
);
1625 * Perl-inspired string functions.
1628 /* Result of a successfully performed flat match. */
1636 friend class RegExpGuard
;
1639 FlatMatch() : patstr(NULL
) {} /* Old GCC wants this initialization. */
1640 JSString
*pattern() const { return patstr
; }
1641 size_t patternLength() const { return patlen
; }
1644 * @note The match is -1 when the match is performed successfully,
1645 * but no match is found.
1647 int32
match() const { return match_
; }
1650 /* A regexp and optional associated object. */
1656 explicit RegExpPair(RegExp
*re
): re_(re
) {}
1657 friend class RegExpGuard
;
1660 /* @note May be null. */
1661 JSObject
*reobj() const { return reobj_
; }
1662 RegExp
&re() const { JS_ASSERT(re_
); return *re_
; }
1666 * RegExpGuard factors logic out of String regexp operations.
1668 * @param optarg Indicates in which argument position RegExp
1669 * flags will be found, if present. This is a Mozilla
1670 * extension and not part of any ECMA spec.
1674 RegExpGuard(const RegExpGuard
&);
1675 void operator=(const RegExpGuard
&);
1682 * Upper bound on the number of characters we are willing to potentially
1683 * waste on searching for RegExp meta-characters.
1685 static const size_t MAX_FLAT_PAT_LEN
= 256;
1687 static JSString
*flattenPattern(JSContext
*cx
, JSString
*patstr
) {
1688 JSCharBuffer
cb(cx
);
1689 if (!cb
.reserve(patstr
->length()))
1692 static const jschar ESCAPE_CHAR
= '\\';
1693 const jschar
*chars
= patstr
->chars();
1694 size_t len
= patstr
->length();
1695 for (const jschar
*it
= chars
; it
!= chars
+ len
; ++it
) {
1696 if (RegExp::isMetaChar(*it
)) {
1697 if (!cb
.append(ESCAPE_CHAR
) || !cb
.append(*it
))
1700 if (!cb
.append(*it
))
1704 return js_NewStringFromCharBuffer(cx
, cb
);
1708 explicit RegExpGuard(JSContext
*cx
) : cx(cx
), rep(NULL
) {}
1712 rep
.re_
->decref(cx
);
1715 /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1717 init(uintN argc
, Value
*vp
)
1719 if (argc
!= 0 && VALUE_IS_REGEXP(cx
, vp
[2])) {
1720 rep
.reobj_
= &vp
[2].toObject();
1721 rep
.re_
= RegExp::extractFrom(rep
.reobj_
);
1722 rep
.re_
->incref(cx
);
1724 fm
.patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1732 * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1733 * pattern string, or a lengthy pattern string can thwart this process.
1735 * @param checkMetaChars Look for regexp metachars in the pattern string.
1736 * @return Whether flat matching could be used.
1739 tryFlatMatch(JSString
*textstr
, uintN optarg
, uintN argc
, bool checkMetaChars
= true)
1744 fm
.patstr
->getCharsAndLength(fm
.pat
, fm
.patlen
);
1749 if (checkMetaChars
&&
1750 (fm
.patlen
> MAX_FLAT_PAT_LEN
|| RegExp::hasMetaChars(fm
.pat
, fm
.patlen
))) {
1755 * textstr could be a rope, so we want to avoid flattening it for as
1758 if (textstr
->isTopNode()) {
1759 fm
.match_
= RopeMatch(textstr
, fm
.pat
, fm
.patlen
);
1763 textstr
->getCharsAndLength(text
, textlen
);
1764 fm
.match_
= StringMatch(text
, textlen
, fm
.pat
, fm
.patlen
);
1769 /* If the pattern is not already a regular expression, make it so. */
1771 normalizeRegExp(bool flat
, uintN optarg
, uintN argc
, Value
*vp
)
1773 /* If we don't have a RegExp, build RegExp from pattern string. */
1778 if (optarg
< argc
) {
1779 opt
= js_ValueToString(cx
, vp
[2 + optarg
]);
1788 patstr
= flattenPattern(cx
, fm
.patstr
);
1796 rep
.re_
= RegExp::createFlagged(cx
, patstr
, opt
);
1804 bool hasRegExpPair() const { return rep
.re_
; }
1808 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1809 static JS_ALWAYS_INLINE
bool
1810 Matched(bool test
, const Value
&v
)
1812 return test
? v
.isTrue() : !v
.isNull();
1815 typedef bool (*DoMatchCallback
)(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *data
);
1818 * BitOR-ing these flags allows the DoMatch caller to control when how the
1819 * RegExp engine is called and when callbacks are fired.
1821 enum MatchControlFlags
{
1822 TEST_GLOBAL_BIT
= 0x1, /* use RegExp.test for global regexps */
1823 TEST_SINGLE_BIT
= 0x2, /* use RegExp.test for non-global regexps */
1824 CALLBACK_ON_SINGLE_BIT
= 0x4, /* fire callback on non-global match */
1826 MATCH_ARGS
= TEST_GLOBAL_BIT
,
1827 MATCHALL_ARGS
= CALLBACK_ON_SINGLE_BIT
,
1828 REPLACE_ARGS
= TEST_GLOBAL_BIT
| TEST_SINGLE_BIT
| CALLBACK_ON_SINGLE_BIT
1831 /* Factor out looping and matching logic. */
1833 DoMatch(JSContext
*cx
, RegExpStatics
*res
, Value
*vp
, JSString
*str
, const RegExpPair
&rep
,
1834 DoMatchCallback callback
, void *data
, MatchControlFlags flags
)
1836 RegExp
&re
= rep
.re();
1838 /* global matching ('g') */
1839 bool testGlobal
= flags
& TEST_GLOBAL_BIT
;
1841 rep
.reobj()->zeroRegExpLastIndex();
1842 for (size_t count
= 0, i
= 0, length
= str
->length(); i
<= length
; ++count
) {
1843 if (!re
.execute(cx
, res
, str
, &i
, testGlobal
, vp
))
1845 if (!Matched(testGlobal
, *vp
))
1847 if (!callback(cx
, res
, count
, data
))
1849 if (!res
->matched())
1854 bool testSingle
= !!(flags
& TEST_SINGLE_BIT
),
1855 callbackOnSingle
= !!(flags
& CALLBACK_ON_SINGLE_BIT
);
1857 if (!re
.execute(cx
, res
, str
, &i
, testSingle
, vp
))
1859 if (callbackOnSingle
&& Matched(testSingle
, *vp
) && !callback(cx
, res
, 0, data
))
1866 BuildFlatMatchArray(JSContext
*cx
, JSString
*textstr
, const FlatMatch
&fm
, Value
*vp
)
1868 if (fm
.match() < 0) {
1873 /* For this non-global match, produce a RegExp.exec-style array. */
1874 JSObject
*obj
= js_NewSlowArrayObject(cx
);
1877 vp
->setObject(*obj
);
1879 return obj
->defineProperty(cx
, INT_TO_JSID(0), StringValue(fm
.pattern())) &&
1880 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.indexAtom
),
1881 Int32Value(fm
.match())) &&
1882 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.inputAtom
),
1883 StringValue(textstr
));
1886 typedef JSObject
**MatchArgType
;
1889 * DoMatch will only callback on global matches, hence this function builds
1890 * only the "array of matches" returned by match on global regexps.
1893 MatchCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
1895 JS_ASSERT(count
<= JSID_INT_MAX
); /* by max string length */
1897 JSObject
*&arrayobj
= *static_cast<MatchArgType
>(p
);
1899 arrayobj
= js_NewArrayObject(cx
, 0, NULL
);
1905 if (!res
->createLastMatch(cx
, &v
))
1908 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
1909 return !!arrayobj
->setProperty(cx
, INT_TO_JSID(count
), &v
, false);
1913 str_match(JSContext
*cx
, uintN argc
, Value
*vp
)
1916 NORMALIZE_THIS(cx
, vp
, str
);
1919 if (!g
.init(argc
, vp
))
1921 if (const FlatMatch
*fm
= g
.tryFlatMatch(str
, 1, argc
))
1922 return BuildFlatMatchArray(cx
, str
, *fm
, vp
);
1924 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1928 AutoObjectRooter
array(cx
);
1929 MatchArgType arg
= array
.addr();
1930 RegExpStatics
*res
= cx
->regExpStatics();
1931 if (!DoMatch(cx
, res
, vp
, str
, *rep
, MatchCallback
, arg
, MATCH_ARGS
))
1934 /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1935 if (rep
->re().global())
1936 vp
->setObjectOrNull(array
.object());
1941 str_search(JSContext
*cx
, uintN argc
, Value
*vp
)
1944 NORMALIZE_THIS(cx
, vp
, str
);
1947 if (!g
.init(argc
, vp
))
1949 if (const FlatMatch
*fm
= g
.tryFlatMatch(str
, 1, argc
)) {
1950 vp
->setInt32(fm
->match());
1953 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1957 RegExpStatics
*res
= cx
->regExpStatics();
1959 if (!rep
->re().execute(cx
, res
, str
, &i
, true, vp
))
1963 vp
->setInt32(res
->matchStart());
1971 ReplaceData(JSContext
*cx
)
1975 JSString
*str
; /* 'this' parameter object as a string */
1976 RegExpGuard g
; /* regexp parameter object and private data */
1977 JSObject
*lambda
; /* replacement function object or null */
1978 JSObject
*elembase
; /* object for function(a){return b[a]} replace */
1979 JSString
*repstr
; /* replacement string */
1980 jschar
*dollar
; /* null or pointer to first $ in repstr */
1981 jschar
*dollarEnd
; /* limit pointer for js_strchr_limit */
1982 jsint index
; /* index in result of next replacement */
1983 jsint leftIndex
; /* left context index in str->chars */
1984 JSSubString dollarStr
; /* for "$$" InterpretDollar result */
1985 bool calledBack
; /* record whether callback has been called */
1986 InvokeSessionGuard session
; /* arguments for repeated lambda Invoke call */
1987 InvokeArgsGuard singleShot
; /* arguments for single lambda Invoke call */
1988 JSCharBuffer cb
; /* buffer built during DoMatch */
1992 InterpretDollar(JSContext
*cx
, RegExpStatics
*res
, jschar
*dp
, jschar
*ep
, ReplaceData
&rdata
,
1993 JSSubString
*out
, size_t *skip
, volatile JSContext::DollarPath
*path
)
1995 JS_ASSERT(*dp
== '$');
1997 /* If there is only a dollar, bail now */
2001 /* Interpret all Perl match-induced dollar variables. */
2003 if (JS7_ISDEC(dc
)) {
2004 /* ECMA-262 Edition 3: 1-9 or 01-99 */
2005 uintN num
= JS7_UNDEC(dc
);
2006 if (num
> res
->parenCount())
2009 jschar
*cp
= dp
+ 2;
2010 if (cp
< ep
&& (dc
= *cp
, JS7_ISDEC(dc
))) {
2011 uintN tmp
= 10 * num
+ JS7_UNDEC(dc
);
2012 if (tmp
<= res
->parenCount()) {
2022 JS_CRASH_UNLESS(num
<= res
->parenCount());
2024 * Note: we index to get the paren with the (1-indexed) pair
2025 * number, as opposed to a (0-indexed) paren number.
2027 res
->getParen(num
, out
);
2034 rdata
.dollarStr
.chars
= dp
;
2035 rdata
.dollarStr
.length
= 1;
2036 *out
= rdata
.dollarStr
;
2037 *path
= JSContext::DOLLAR_LITERAL
;
2040 res
->getLastMatch(out
);
2041 *path
= JSContext::DOLLAR_AMP
;
2044 res
->getLastParen(out
);
2045 *path
= JSContext::DOLLAR_PLUS
;
2048 res
->getLeftContext(out
);
2049 *path
= JSContext::DOLLAR_TICK
;
2052 res
->getRightContext(out
);
2053 *path
= JSContext::DOLLAR_QUOT
;
2060 FindReplaceLength(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, size_t *sizep
)
2062 JSObject
*base
= rdata
.elembase
;
2065 * The base object is used when replace was passed a lambda which looks like
2066 * 'function(a) { return b[a]; }' for the base object b. b will not change
2067 * in the course of the replace unless we end up making a scripted call due
2068 * to accessing a scripted getter or a value with a scripted toString.
2070 JS_ASSERT(rdata
.lambda
);
2071 JS_ASSERT(!base
->getOps()->lookupProperty
);
2072 JS_ASSERT(!base
->getOps()->getProperty
);
2075 if (!res
->createLastMatch(cx
, &match
))
2077 JSString
*str
= match
.toString();
2080 if (str
->isAtomized()) {
2081 atom
= STRING_TO_ATOM(str
);
2083 atom
= js_AtomizeString(cx
, str
, 0);
2087 jsid id
= ATOM_TO_JSID(atom
);
2090 JSProperty
*prop
= NULL
;
2091 if (js_LookupPropertyWithFlags(cx
, base
, id
, JSRESOLVE_QUALIFIED
, &holder
, &prop
) < 0)
2094 /* Only handle the case where the property exists and is on this object. */
2095 if (prop
&& holder
== base
) {
2096 Shape
*shape
= (Shape
*) prop
;
2097 if (shape
->slot
!= SHAPE_INVALID_SLOT
&& shape
->hasDefaultGetter()) {
2098 Value value
= base
->getSlot(shape
->slot
);
2099 if (value
.isString()) {
2100 rdata
.repstr
= value
.toString();
2101 *sizep
= rdata
.repstr
->length();
2108 * Couldn't handle this property, fall through and despecialize to the
2109 * general lambda case.
2111 rdata
.elembase
= NULL
;
2114 JSObject
*lambda
= rdata
.lambda
;
2117 * In the lambda case, not only do we find the replacement string's
2118 * length, we compute repstr and return it via rdata for use within
2119 * DoReplace. The lambda is called with arguments ($&, $1, $2, ...,
2120 * index, input), i.e., all the properties of a regexp match array.
2121 * For $&, etc., we must create string jsvals from cx->regExpStatics.
2122 * We grab up stack space to keep the newborn strings GC-rooted.
2124 uintN p
= res
->parenCount();
2125 uintN argc
= 1 + p
+ 2;
2127 InvokeSessionGuard
&session
= rdata
.session
;
2128 if (!session
.started()) {
2129 Value lambdav
= ObjectValue(*lambda
);
2130 if (!session
.start(cx
, lambdav
, UndefinedValue(), argc
))
2134 PreserveRegExpStatics
staticsGuard(res
);
2135 if (!staticsGuard
.init(cx
))
2138 /* Push $&, $1, $2, ... */
2140 if (!res
->createLastMatch(cx
, &session
[argi
++]))
2143 for (size_t i
= 0; i
< res
->parenCount(); ++i
) {
2144 if (!res
->createParen(cx
, i
+ 1, &session
[argi
++]))
2148 /* Push match index and input string. */
2149 session
[argi
++].setInt32(res
->matchStart());
2150 session
[argi
].setString(rdata
.str
);
2152 if (!session
.invoke(cx
))
2155 /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2156 rdata
.repstr
= ValueToString_TestForStringInline(cx
, session
.rval());
2160 *sizep
= rdata
.repstr
->length();
2164 JSString
*repstr
= rdata
.repstr
;
2165 size_t replen
= repstr
->length();
2166 JSContext::DollarPath path
;
2167 for (jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2170 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
, &path
)) {
2171 replen
+= sub
.length
- skip
;
2182 DoReplace(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, jschar
*chars
)
2184 JSString
*repstr
= rdata
.repstr
;
2186 jschar
*bp
= cp
= repstr
->chars();
2187 volatile JSContext::DollarPath path
;
2188 cx
->dollarPath
= &path
;
2189 jschar sourceBuf
[128];
2190 cx
->blackBox
= sourceBuf
;
2192 for (jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2193 size_t len
= dp
- cp
;
2194 js_strncpy(chars
, cp
, len
);
2200 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
, &path
)) {
2201 if (((size_t(sub
.chars
) & 0xfffffU
) + sub
.length
) > 0x100000U
) {
2202 /* Going to cross a 0xffffe address, so take a gander at the replace value. */
2203 size_t peekLen
= JS_MIN(rdata
.dollarEnd
- rdata
.dollar
, 128);
2204 js_strncpy(sourceBuf
, rdata
.dollar
, peekLen
);
2208 js_strncpy(chars
, sub
.chars
, len
);
2216 js_strncpy(chars
, cp
, repstr
->length() - (cp
- bp
));
2220 ReplaceCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
2222 ReplaceData
&rdata
= *static_cast<ReplaceData
*>(p
);
2224 rdata
.calledBack
= true;
2225 JSString
*str
= rdata
.str
;
2226 size_t leftoff
= rdata
.leftIndex
;
2227 const jschar
*left
= str
->chars() + leftoff
;
2228 size_t leftlen
= res
->matchStart() - leftoff
;
2229 rdata
.leftIndex
= res
->matchLimit();
2231 size_t replen
= 0; /* silence 'unused' warning */
2232 if (!FindReplaceLength(cx
, res
, rdata
, &replen
))
2235 size_t growth
= leftlen
+ replen
;
2236 if (!rdata
.cb
.growByUninitialized(growth
))
2239 jschar
*chars
= rdata
.cb
.begin() + rdata
.index
;
2240 rdata
.index
+= growth
;
2241 js_strncpy(chars
, left
, leftlen
);
2243 DoReplace(cx
, res
, rdata
, chars
);
2248 BuildFlatReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2249 const FlatMatch
&fm
, Value
*vp
)
2251 JSRopeBuilder
builder(cx
);
2252 size_t match
= fm
.match(); /* Avoid signed/unsigned warnings. */
2253 size_t matchEnd
= match
+ fm
.patternLength();
2255 if (textstr
->isTopNode()) {
2257 * If we are replacing over a rope, avoid flattening it by iterating
2258 * through it, building a new rope.
2260 JSRopeLeafIterator
iter(textstr
);
2262 for (JSString
*str
= iter
.init(); str
; str
= iter
.next()) {
2263 size_t len
= str
->length();
2264 size_t strEnd
= pos
+ len
;
2265 if (pos
< matchEnd
&& strEnd
> match
) {
2267 * We need to special-case any part of the rope that overlaps
2268 * with the replacement string.
2272 * If this part of the rope overlaps with the left side of
2273 * the pattern, then it must be the only one to overlap with
2274 * the first character in the pattern, so we include the
2275 * replacement string here.
2277 JSString
*leftSide
= js_NewDependentString(cx
, str
, 0, match
- pos
);
2279 !builder
.append(leftSide
) ||
2280 !builder
.append(repstr
)) {
2286 * If str runs off the end of the matched string, append the
2289 if (strEnd
> matchEnd
) {
2290 JSString
*rightSide
= js_NewDependentString(cx
, str
, matchEnd
- pos
,
2292 if (!rightSide
|| !builder
.append(rightSide
))
2296 if (!builder
.append(str
))
2299 pos
+= str
->length();
2302 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, match
);
2305 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, match
+ fm
.patternLength(),
2306 textstr
->length() - match
- fm
.patternLength());
2308 !builder
.append(leftSide
) ||
2309 !builder
.append(repstr
) ||
2310 !builder
.append(rightSide
)) {
2315 vp
->setString(builder
.getStr());
2320 * Perform a linear-scan dollar substitution on the replacement text,
2321 * constructing a result string that looks like:
2323 * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2326 BuildDollarReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2327 const jschar
*firstDollar
, const FlatMatch
&fm
, Value
*vp
)
2329 JS_ASSERT(repstr
->chars() <= firstDollar
&& firstDollar
< repstr
->chars() + repstr
->length());
2330 size_t matchStart
= fm
.match();
2331 size_t matchLimit
= matchStart
+ fm
.patternLength();
2332 JSCharBuffer
newReplaceChars(cx
);
2337 * len(newstr) >= len(orig) - len(match) + len(replacement)
2339 * Note that dollar vars _could_ make the resulting text smaller than this.
2341 if (!newReplaceChars
.reserve(textstr
->length() - fm
.patternLength() + repstr
->length()))
2344 /* Move the pre-dollar chunk in bulk. */
2345 JS_ALWAYS_TRUE(newReplaceChars
.append(repstr
->chars(), firstDollar
));
2347 /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2348 #define ENSURE(__cond) if (!(__cond)) return false;
2349 const jschar
*repstrLimit
= repstr
->chars() + repstr
->length();
2350 for (const jschar
*it
= firstDollar
; it
< repstrLimit
; ++it
) {
2351 if (*it
!= '$' || it
== repstrLimit
- 1) {
2352 ENSURE(newReplaceChars
.append(*it
));
2356 switch (*(it
+ 1)) {
2357 case '$': /* Eat one of the dollars. */
2358 ENSURE(newReplaceChars
.append(*it
));
2361 ENSURE(newReplaceChars
.append(textstr
->chars() + matchStart
,
2362 textstr
->chars() + matchLimit
));
2365 ENSURE(newReplaceChars
.append(textstr
->chars(), textstr
->chars() + matchStart
));
2368 ENSURE(newReplaceChars
.append(textstr
->chars() + matchLimit
,
2369 textstr
->chars() + textstr
->length()));
2371 default: /* The dollar we saw was not special (no matter what its mother told it). */
2372 ENSURE(newReplaceChars
.append(*it
));
2375 ++it
; /* We always eat an extra char in the above switch. */
2378 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, matchStart
);
2381 JSString
*newReplace
= js_NewStringFromCharBuffer(cx
, newReplaceChars
);
2384 JS_ASSERT(textstr
->length() >= matchLimit
);
2385 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, matchLimit
,
2386 textstr
->length() - matchLimit
);
2389 JSRopeBuilder
builder(cx
);
2390 ENSURE(builder
.append(leftSide
) &&
2391 builder
.append(newReplace
) &&
2392 builder
.append(rightSide
));
2395 vp
->setString(builder
.getStr());
2400 str_replace_regexp(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
)
2402 const RegExpPair
*rep
= rdata
.g
.normalizeRegExp(true, 2, argc
, vp
);
2407 rdata
.leftIndex
= 0;
2408 rdata
.calledBack
= false;
2410 RegExpStatics
*res
= cx
->regExpStatics();
2411 if (!DoMatch(cx
, res
, vp
, rdata
.str
, *rep
, ReplaceCallback
, &rdata
, REPLACE_ARGS
))
2414 if (!rdata
.calledBack
) {
2415 /* Didn't match, so the string is unmodified. */
2416 vp
->setString(rdata
.str
);
2421 res
->getRightContext(&sub
);
2422 if (!rdata
.cb
.append(sub
.chars
, sub
.length
))
2425 JSString
*retstr
= js_NewStringFromCharBuffer(cx
, rdata
.cb
);
2429 vp
->setString(retstr
);
2434 str_replace_flat_lambda(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
,
2435 const FlatMatch
&fm
)
2437 JS_ASSERT(fm
.match() >= 0);
2440 JSString
*matchStr
= js_NewDependentString(cx
, rdata
.str
, fm
.match(), fm
.patternLength());
2444 /* lambda(matchStr, matchStart, textstr) */
2445 static const uint32 lambdaArgc
= 3;
2446 if (!cx
->stack().pushInvokeArgs(cx
, lambdaArgc
, &rdata
.singleShot
))
2449 CallArgs
&args
= rdata
.singleShot
;
2450 args
.callee().setObject(*rdata
.lambda
);
2451 args
.thisv().setUndefined();
2453 Value
*sp
= args
.argv();
2454 sp
[0].setString(matchStr
);
2455 sp
[1].setInt32(fm
.match());
2456 sp
[2].setString(rdata
.str
);
2458 if (!Invoke(cx
, rdata
.singleShot
, 0))
2461 JSString
*repstr
= js_ValueToString(cx
, args
.rval());
2465 JSString
*leftSide
= js_NewDependentString(cx
, rdata
.str
, 0, fm
.match());
2469 size_t matchLimit
= fm
.match() + fm
.patternLength();
2470 JSString
*rightSide
= js_NewDependentString(cx
, rdata
.str
, matchLimit
,
2471 rdata
.str
->length() - matchLimit
);
2475 JSRopeBuilder
builder(cx
);
2476 if (!(builder
.append(leftSide
) &&
2477 builder
.append(repstr
) &&
2478 builder
.append(rightSide
))) {
2482 vp
->setString(builder
.getStr());
2487 js::str_replace(JSContext
*cx
, uintN argc
, Value
*vp
)
2489 ReplaceData
rdata(cx
);
2490 NORMALIZE_THIS(cx
, vp
, rdata
.str
);
2491 static const uint32 optarg
= 2;
2493 /* Extract replacement string/function. */
2494 if (argc
>= optarg
&& js_IsCallable(vp
[3])) {
2495 rdata
.lambda
= &vp
[3].toObject();
2496 rdata
.elembase
= NULL
;
2497 rdata
.repstr
= NULL
;
2498 rdata
.dollar
= rdata
.dollarEnd
= NULL
;
2500 if (rdata
.lambda
->isFunction()) {
2501 JSFunction
*fun
= rdata
.lambda
->getFunctionPrivate();
2502 if (fun
->isInterpreted()) {
2504 * Pattern match the script to check if it is is indexing into a
2505 * particular object, e.g. 'function(a) { return b[a]; }'. Avoid
2506 * calling the script in such cases, which are used by javascript
2507 * packers (particularly the popular Dean Edwards packer) to efficiently
2508 * encode large scripts. We only handle the code patterns generated
2509 * by such packers here.
2511 JSScript
*script
= fun
->u
.i
.script
;
2512 jsbytecode
*pc
= script
->code
;
2514 Value table
= UndefinedValue();
2515 if (JSOp(*pc
) == JSOP_GETFCSLOT
) {
2516 table
= rdata
.lambda
->getFlatClosureUpvar(GET_UINT16(pc
));
2517 pc
+= JSOP_GETFCSLOT_LENGTH
;
2520 if (table
.isObject() &&
2521 JSOp(*pc
) == JSOP_GETARG
&& GET_SLOTNO(pc
) == 0 &&
2522 JSOp(*(pc
+ JSOP_GETARG_LENGTH
)) == JSOP_GETELEM
&&
2523 JSOp(*(pc
+ JSOP_GETARG_LENGTH
+ JSOP_GETELEM_LENGTH
)) == JSOP_RETURN
) {
2524 Class
*clasp
= table
.toObject().getClass();
2525 if (clasp
->isNative() &&
2526 !clasp
->ops
.lookupProperty
&&
2527 !clasp
->ops
.getProperty
) {
2528 rdata
.elembase
= &table
.toObject();
2534 rdata
.lambda
= NULL
;
2535 rdata
.elembase
= NULL
;
2536 rdata
.repstr
= ArgToRootedString(cx
, argc
, vp
, 1);
2540 /* We're about to store pointers into the middle of our string. */
2541 if (!js_MakeStringImmutable(cx
, rdata
.repstr
))
2543 rdata
.dollarEnd
= rdata
.repstr
->chars() + rdata
.repstr
->length();
2544 rdata
.dollar
= js_strchr_limit(rdata
.repstr
->chars(), '$',
2548 if (!rdata
.g
.init(argc
, vp
))
2552 * Unlike its |String.prototype| brethren, |replace| doesn't convert
2553 * its input to a regular expression. (Even if it contains metachars.)
2555 * However, if the user invokes our (non-standard) |flags| argument
2556 * extension then we revert to creating a regular expression. Note that
2557 * this is observable behavior through the side-effect mutation of the
2561 const FlatMatch
*fm
= rdata
.g
.tryFlatMatch(rdata
.str
, optarg
, argc
, false);
2563 JS_ASSERT_IF(!rdata
.g
.hasRegExpPair(), argc
> optarg
);
2564 return str_replace_regexp(cx
, argc
, vp
, rdata
);
2567 if (fm
->match() < 0) {
2568 vp
->setString(rdata
.str
);
2573 return str_replace_flat_lambda(cx
, argc
, vp
, rdata
, *fm
);
2576 * Note: we could optimize the text.length == pattern.length case if we wanted,
2577 * even in the presence of dollar metachars.
2580 return BuildDollarReplacement(cx
, rdata
.str
, rdata
.repstr
, rdata
.dollar
, *fm
, vp
);
2582 return BuildFlatReplacement(cx
, rdata
.str
, rdata
.repstr
, *fm
, vp
);
2586 * Subroutine used by str_split to find the next split point in str, starting
2587 * at offset *ip and looking either for the separator substring given by sep, or
2588 * for the next re match. In the re case, return the matched separator in *sep,
2589 * and the possibly updated offset in *ip.
2591 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2592 * separator occurrence if found, or str->length if no separator is found.
2595 find_split(JSContext
*cx
, RegExpStatics
*res
, JSString
*str
, js::RegExp
*re
, jsint
*ip
,
2603 * Stop if past end of string. If at end of string, we will compare the
2604 * null char stored there (by js_NewString*) to sep->chars[j] in the while
2605 * loop at the end of this function, so that
2607 * "ab,".split(',') => ["ab", ""]
2609 * and the resulting array converts back to the string "ab," for symmetry.
2610 * However, we ape Perl and do this only if there is a sufficiently large
2611 * limit argument (see str_split).
2614 length
= str
->length();
2615 if ((size_t)i
> length
)
2618 chars
= str
->chars();
2621 * Match a regular expression against the separator at or above index i.
2622 * Call js_ExecuteRegExp with true for the test argument. On successful
2623 * match, get the separator from cx->regExpStatics.lastMatch.
2630 /* JS1.2 deviated from Perl by never matching at end of string. */
2632 if (!re
->execute(cx
, res
, str
, &index
, true, &rval
))
2634 if (!rval
.isTrue()) {
2635 /* Mismatch: ensure our caller advances i past end of string. */
2641 res
->getLastMatch(sep
);
2642 if (sep
->length
== 0) {
2644 * Empty string match: never split on an empty match at the start
2645 * of a find_split cycle. Same rule as for an empty global match
2650 * "Bump-along" to avoid sticking at an empty match, but don't
2651 * bump past end of string -- our caller must do that by adding
2652 * sep->length to our return value.
2654 if ((size_t)i
== length
)
2659 if ((size_t)i
== length
) {
2661 * If there was a trivial zero-length match at the end of the
2662 * split, then we shouldn't output the matched string at the end
2663 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2668 JS_ASSERT((size_t)i
>= sep
->length
);
2669 return i
- sep
->length
;
2673 * Special case: if sep is the empty string, split str into one character
2674 * substrings. Let our caller worry about whether to split once at end of
2675 * string into an empty substring.
2677 if (sep
->length
== 0)
2678 return ((size_t)i
== length
) ? -1 : i
+ 1;
2681 * Now that we know sep is non-empty, search starting at i in str for an
2682 * occurrence of all of sep's chars. If we find them, return the index of
2683 * the first separator char. Otherwise, return length.
2685 jsint match
= StringMatch(chars
+ i
, length
- i
, sep
->chars
, sep
->length
);
2686 return match
== -1 ? length
: match
+ i
;
2690 str_split(JSContext
*cx
, uintN argc
, Value
*vp
)
2693 NORMALIZE_THIS(cx
, vp
, str
);
2696 Value v
= StringValue(str
);
2697 JSObject
*aobj
= js_NewArrayObject(cx
, 1, &v
);
2700 vp
->setObject(*aobj
);
2705 JSSubString
*sep
, tmp
;
2706 if (VALUE_IS_REGEXP(cx
, vp
[2])) {
2707 re
= static_cast<RegExp
*>(vp
[2].toObject().getPrivate());
2710 /* Set a magic value so we can detect a successful re match. */
2714 JSString
*str2
= js_ValueToString(cx
, vp
[2]);
2717 vp
[2].setString(str2
);
2720 * Point sep at a local copy of str2's header because find_split
2721 * will modify sep->length.
2723 str2
->getCharsAndLength(tmp
.chars
, tmp
.length
);
2728 /* Use the second argument as the split limit, if given. */
2729 uint32 limit
= 0; /* Avoid warning. */
2730 bool limited
= (argc
> 1) && !vp
[3].isUndefined();
2733 if (!ValueToNumber(cx
, vp
[3], &d
))
2736 /* Clamp limit between 0 and 1 + string length. */
2737 limit
= js_DoubleToECMAUint32(d
);
2738 if (limit
> str
->length())
2739 limit
= 1 + str
->length();
2742 AutoValueVector
splits(cx
);
2744 RegExpStatics
*res
= cx
->regExpStatics();
2747 while ((j
= find_split(cx
, res
, str
, re
, &i
, sep
)) >= 0) {
2748 if (limited
&& len
>= limit
)
2751 JSString
*sub
= js_NewDependentString(cx
, str
, i
, size_t(j
- i
));
2752 if (!sub
|| !splits
.append(StringValue(sub
)))
2757 * Imitate perl's feature of including parenthesized substrings that
2758 * matched part of the delimiter in the new array, after the split
2759 * substring that was delimited.
2761 if (re
&& sep
->chars
) {
2762 for (uintN num
= 0; num
< res
->parenCount(); num
++) {
2763 if (limited
&& len
>= limit
)
2766 res
->getParen(num
+ 1, &parsub
);
2767 sub
= js_NewStringCopyN(cx
, parsub
.chars
, parsub
.length
);
2768 if (!sub
|| !splits
.append(StringValue(sub
)))
2774 i
= j
+ sep
->length
;
2780 JSObject
*aobj
= js_NewArrayObject(cx
, splits
.length(), splits
.begin());
2783 vp
->setObject(*aobj
);
2787 #if JS_HAS_PERL_SUBSTR
2789 str_substr(JSContext
*cx
, uintN argc
, Value
*vp
)
2793 jsdouble length
, begin
, end
;
2795 NORMALIZE_THIS(cx
, vp
, str
);
2797 if (!ValueToNumber(cx
, vp
[2], &d
))
2799 length
= str
->length();
2800 begin
= js_DoubleToInteger(d
);
2805 } else if (begin
> length
) {
2809 if (argc
== 1 || vp
[3].isUndefined()) {
2812 if (!ValueToNumber(cx
, vp
[3], &d
))
2814 end
= js_DoubleToInteger(d
);
2822 str
= js_NewDependentString(cx
, str
,
2824 (size_t)(end
- begin
));
2831 #endif /* JS_HAS_PERL_SUBSTR */
2834 * Python-esque sequence operations.
2837 str_concat(JSContext
*cx
, uintN argc
, Value
*vp
)
2839 JSString
*str
, *str2
;
2843 NORMALIZE_THIS(cx
, vp
, str
);
2845 /* Set vp (aka rval) early to handle the argc == 0 case. */
2848 for (i
= 0, argv
= vp
+ 2; i
< argc
; i
++) {
2849 str2
= js_ValueToString(cx
, argv
[i
]);
2852 argv
[i
].setString(str2
);
2854 str
= js_ConcatStrings(cx
, str
, str2
);
2864 str_slice(JSContext
*cx
, uintN argc
, Value
*vp
)
2866 if (argc
== 1 && vp
[1].isString() && vp
[2].isInt32()) {
2867 size_t begin
, end
, length
;
2869 JSString
*str
= vp
[1].toString();
2870 begin
= vp
[2].toInt32();
2871 end
= str
->length();
2873 length
= end
- begin
;
2875 str
= cx
->runtime
->emptyString
;
2878 ? JSString::getUnitString(cx
, str
, begin
)
2879 : js_NewDependentString(cx
, str
, begin
, length
);
2889 NORMALIZE_THIS(cx
, vp
, str
);
2892 double begin
, end
, length
;
2894 if (!ValueToNumber(cx
, vp
[2], &begin
))
2896 begin
= js_DoubleToInteger(begin
);
2897 length
= str
->length();
2902 } else if (begin
> length
) {
2906 if (argc
== 1 || vp
[3].isUndefined()) {
2909 if (!ValueToNumber(cx
, vp
[3], &end
))
2911 end
= js_DoubleToInteger(end
);
2916 } else if (end
> length
) {
2923 str
= js_NewDependentString(cx
, str
,
2925 (size_t)(end
- begin
));
2933 #if JS_HAS_STR_HTML_HELPERS
2935 * HTML composition aids.
2938 tagify(JSContext
*cx
, const char *begin
, JSString
*param
, const char *end
,
2943 size_t beglen
, endlen
, parlen
, taglen
;
2946 NORMALIZE_THIS(cx
, vp
, str
);
2951 beglen
= strlen(begin
);
2952 taglen
= 1 + beglen
+ 1; /* '<begin' + '>' */
2953 parlen
= 0; /* Avoid warning. */
2955 parlen
= param
->length();
2956 taglen
+= 2 + parlen
+ 1; /* '="param"' */
2958 endlen
= strlen(end
);
2959 taglen
+= str
->length() + 2 + endlen
+ 1; /* 'str</end>' */
2961 if (taglen
>= ~(size_t)0 / sizeof(jschar
)) {
2962 js_ReportAllocationOverflow(cx
);
2966 tagbuf
= (jschar
*) cx
->malloc((taglen
+ 1) * sizeof(jschar
));
2972 for (i
= 0; i
< beglen
; i
++)
2973 tagbuf
[j
++] = (jschar
)begin
[i
];
2977 js_strncpy(&tagbuf
[j
], param
->chars(), parlen
);
2982 js_strncpy(&tagbuf
[j
], str
->chars(), str
->length());
2986 for (i
= 0; i
< endlen
; i
++)
2987 tagbuf
[j
++] = (jschar
)end
[i
];
2989 JS_ASSERT(j
== taglen
);
2992 str
= js_NewString(cx
, tagbuf
, taglen
);
2994 js_free((char *)tagbuf
);
3002 tagify_value(JSContext
*cx
, uintN argc
, Value
*vp
,
3003 const char *begin
, const char *end
)
3007 param
= ArgToRootedString(cx
, argc
, vp
, 0);
3010 return tagify(cx
, begin
, param
, end
, vp
);
3014 str_bold(JSContext
*cx
, uintN argc
, Value
*vp
)
3016 return tagify(cx
, "b", NULL
, NULL
, vp
);
3020 str_italics(JSContext
*cx
, uintN argc
, Value
*vp
)
3022 return tagify(cx
, "i", NULL
, NULL
, vp
);
3026 str_fixed(JSContext
*cx
, uintN argc
, Value
*vp
)
3028 return tagify(cx
, "tt", NULL
, NULL
, vp
);
3032 str_fontsize(JSContext
*cx
, uintN argc
, Value
*vp
)
3034 return tagify_value(cx
, argc
, vp
, "font size", "font");
3038 str_fontcolor(JSContext
*cx
, uintN argc
, Value
*vp
)
3040 return tagify_value(cx
, argc
, vp
, "font color", "font");
3044 str_link(JSContext
*cx
, uintN argc
, Value
*vp
)
3046 return tagify_value(cx
, argc
, vp
, "a href", "a");
3050 str_anchor(JSContext
*cx
, uintN argc
, Value
*vp
)
3052 return tagify_value(cx
, argc
, vp
, "a name", "a");
3056 str_strike(JSContext
*cx
, uintN argc
, Value
*vp
)
3058 return tagify(cx
, "strike", NULL
, NULL
, vp
);
3062 str_small(JSContext
*cx
, uintN argc
, Value
*vp
)
3064 return tagify(cx
, "small", NULL
, NULL
, vp
);
3068 str_big(JSContext
*cx
, uintN argc
, Value
*vp
)
3070 return tagify(cx
, "big", NULL
, NULL
, vp
);
3074 str_blink(JSContext
*cx
, uintN argc
, Value
*vp
)
3076 return tagify(cx
, "blink", NULL
, NULL
, vp
);
3080 str_sup(JSContext
*cx
, uintN argc
, Value
*vp
)
3082 return tagify(cx
, "sup", NULL
, NULL
, vp
);
3086 str_sub(JSContext
*cx
, uintN argc
, Value
*vp
)
3088 return tagify(cx
, "sub", NULL
, NULL
, vp
);
3090 #endif /* JS_HAS_STR_HTML_HELPERS */
3094 js_String_getelem(JSContext
* cx
, JSString
* str
, int32 i
)
3096 if ((size_t)i
>= str
->length())
3098 return JSString::getUnitString(cx
, str
, size_t(i
));
3102 JS_DEFINE_TRCINFO_1(str_concat
,
3103 (3, (extern, STRING_RETRY
, js_ConcatStrings
, CONTEXT
, THIS_STRING
, STRING
,
3104 1, nanojit::ACCSET_NONE
)))
3106 static const uint16 GENERIC_PRIMITIVE
= JSFUN_GENERIC_NATIVE
| JSFUN_PRIMITIVE_THIS
;
3108 static JSFunctionSpec string_methods
[] = {
3110 JS_FN("quote", str_quote
, 0,GENERIC_PRIMITIVE
),
3111 JS_FN(js_toSource_str
, str_toSource
, 0,JSFUN_PRIMITIVE_THIS
),
3114 /* Java-like methods. */
3115 JS_FN(js_toString_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3116 JS_FN(js_valueOf_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3117 JS_FN(js_toJSON_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3118 JS_FN("substring", str_substring
, 2,GENERIC_PRIMITIVE
),
3119 JS_FN("toLowerCase", str_toLowerCase
, 0,GENERIC_PRIMITIVE
),
3120 JS_FN("toUpperCase", str_toUpperCase
, 0,GENERIC_PRIMITIVE
),
3121 JS_FN("charAt", js_str_charAt
, 1,GENERIC_PRIMITIVE
),
3122 JS_FN("charCodeAt", js_str_charCodeAt
, 1,GENERIC_PRIMITIVE
),
3123 JS_FN("indexOf", str_indexOf
, 1,GENERIC_PRIMITIVE
),
3124 JS_FN("lastIndexOf", str_lastIndexOf
, 1,GENERIC_PRIMITIVE
),
3125 JS_FN("trim", str_trim
, 0,GENERIC_PRIMITIVE
),
3126 JS_FN("trimLeft", str_trimLeft
, 0,GENERIC_PRIMITIVE
),
3127 JS_FN("trimRight", str_trimRight
, 0,GENERIC_PRIMITIVE
),
3128 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase
, 0,GENERIC_PRIMITIVE
),
3129 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase
, 0,GENERIC_PRIMITIVE
),
3130 JS_FN("localeCompare", str_localeCompare
, 1,GENERIC_PRIMITIVE
),
3132 /* Perl-ish methods (search is actually Python-esque). */
3133 JS_FN("match", str_match
, 1,GENERIC_PRIMITIVE
),
3134 JS_FN("search", str_search
, 1,GENERIC_PRIMITIVE
),
3135 JS_FN("replace", str_replace
, 2,GENERIC_PRIMITIVE
),
3136 JS_FN("split", str_split
, 2,GENERIC_PRIMITIVE
),
3137 #if JS_HAS_PERL_SUBSTR
3138 JS_FN("substr", str_substr
, 2,GENERIC_PRIMITIVE
),
3141 /* Python-esque sequence methods. */
3142 JS_TN("concat", str_concat
, 1,GENERIC_PRIMITIVE
, &str_concat_trcinfo
),
3143 JS_FN("slice", str_slice
, 2,GENERIC_PRIMITIVE
),
3145 /* HTML string methods. */
3146 #if JS_HAS_STR_HTML_HELPERS
3147 JS_FN("bold", str_bold
, 0,JSFUN_PRIMITIVE_THIS
),
3148 JS_FN("italics", str_italics
, 0,JSFUN_PRIMITIVE_THIS
),
3149 JS_FN("fixed", str_fixed
, 0,JSFUN_PRIMITIVE_THIS
),
3150 JS_FN("fontsize", str_fontsize
, 1,JSFUN_PRIMITIVE_THIS
),
3151 JS_FN("fontcolor", str_fontcolor
, 1,JSFUN_PRIMITIVE_THIS
),
3152 JS_FN("link", str_link
, 1,JSFUN_PRIMITIVE_THIS
),
3153 JS_FN("anchor", str_anchor
, 1,JSFUN_PRIMITIVE_THIS
),
3154 JS_FN("strike", str_strike
, 0,JSFUN_PRIMITIVE_THIS
),
3155 JS_FN("small", str_small
, 0,JSFUN_PRIMITIVE_THIS
),
3156 JS_FN("big", str_big
, 0,JSFUN_PRIMITIVE_THIS
),
3157 JS_FN("blink", str_blink
, 0,JSFUN_PRIMITIVE_THIS
),
3158 JS_FN("sup", str_sup
, 0,JSFUN_PRIMITIVE_THIS
),
3159 JS_FN("sub", str_sub
, 0,JSFUN_PRIMITIVE_THIS
),
3166 * Set up some tools to make it easier to generate large tables. After constant
3167 * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3168 * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3169 * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3172 #define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
3173 #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
3174 #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
3175 #define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
3176 #define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
3177 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3179 #define R3(n) R2(n), R2((n) + (1 << 2))
3180 #define R7(n) R6(n), R6((n) + (1 << 6))
3183 * Declare unit strings. Pack the string data itself into the mInlineChars
3184 * place in the header.
3187 JSString::FLAT | JSString::ATOMIZED | (1 << JSString::FLAGS_LENGTH_SHIFT),\
3188 { (jschar *)(((char *)(unitStringTable + (c))) + \
3189 offsetof(JSString, mInlineStorage)) }, \
3195 #pragma pack(push, 8)
3198 const JSString
JSString::unitStringTable
[]
3200 __attribute__ ((aligned (8)))
3213 * Declare length-2 strings. We only store strings where both characters are
3214 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3215 * the lowercase letters, and the next 26 are the uppercase letters.
3217 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
3218 (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
3219 (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
3220 JSString::INVALID_SMALL_CHAR)
3222 #define R TO_SMALL_CHAR
3224 const JSString::SmallChar
JSString::toSmallChar
[] = { R7(0) };
3229 * This is used when we generate our table of short strings, so the compiler is
3230 * happier if we use |c| as few times as possible.
3232 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
3233 (c) < 36 ? 'a' - 10 : \
3235 #define R FROM_SMALL_CHAR
3237 const jschar
JSString::fromSmallChar
[] = { R6(0) };
3242 * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3243 * where the upper 6 bits is the first character and the lower 6 bits is the
3247 JSString::FLAT | JSString::ATOMIZED | (2 << JSString::FLAGS_LENGTH_SHIFT),\
3248 { (jschar *)(((char *)(length2StringTable + (c))) + \
3249 offsetof(JSString, mInlineStorage)) }, \
3250 { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3255 #pragma pack(push, 8)
3258 const JSString
JSString::length2StringTable
[]
3260 __attribute__ ((aligned (8)))
3272 #define R(c) FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3f), 0x00
3274 const char JSString::deflatedLength2StringTable
[] = { R12(0) };
3279 * Declare int strings. Only int strings from 100 to 255 actually have to be
3280 * generated, since the rest are either unit strings or length-2 strings. To
3281 * avoid the runtime cost of figuring out where to look for the string for a
3282 * particular integer, we precompute a table of JSString*s which refer to the
3283 * correct location of the int string.
3286 JSString::FLAT | JSString::ATOMIZED | (3 << JSString::FLAGS_LENGTH_SHIFT),\
3287 { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \
3288 offsetof(JSString, mInlineStorage)) }, \
3289 { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3292 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3297 #pragma pack(push, 8)
3300 const JSString
JSString::hundredStringTable
[]
3302 __attribute__ ((aligned (8)))
3304 = { R7(100), /* 100 through 227 */
3305 R4(100 + (1 << 7)), /* 228 through 243 */
3306 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3307 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3312 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \
3313 (c) < 100 ? JSString::length2StringTable + \
3314 ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
3315 TO_SMALL_CHAR(((c) % 10) + '0') : \
3316 JSString::hundredStringTable + ((c) - 100))
3318 const JSString
*const JSString::intStringTable
[] = { R8(0) };
3328 #define R(c) ((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00
3330 const char JSString::deflatedIntStringTable
[] = {
3331 R7(100), /* 100 through 227 */
3332 R4(100 + (1 << 7)), /* 228 through 243 */
3333 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3334 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3348 /* Static table for common UTF8 encoding */
3349 #define U8(c) char(((c) >> 6) | 0xc0), char(((c) & 0x3f) | 0x80), 0
3350 #define U(c) U8(c), U8(c+1), U8(c+2), U8(c+3), U8(c+4), U8(c+5), U8(c+6), U8(c+7)
3352 const char JSString::deflatedUnitStringTable
[] = {
3353 U(0x80), U(0x88), U(0x90), U(0x98), U(0xa0), U(0xa8), U(0xb0), U(0xb8),
3354 U(0xc0), U(0xc8), U(0xd0), U(0xd8), U(0xe0), U(0xe8), U(0xf0), U(0xf8)
3361 js_String(JSContext
*cx
, uintN argc
, Value
*vp
)
3363 Value
*argv
= vp
+ 2;
3367 str
= js_ValueToString(cx
, argv
[0]);
3371 str
= cx
->runtime
->emptyString
;
3374 if (IsConstructing(vp
)) {
3375 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_StringClass
);
3378 obj
->setPrimitiveThis(StringValue(str
));
3379 vp
->setObject(*obj
);
3387 str_fromCharCode(JSContext
*cx
, uintN argc
, Value
*vp
)
3395 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
3398 if (!ValueToUint16(cx
, argv
[0], &code
))
3400 if (code
< UNIT_STRING_LIMIT
) {
3401 str
= JSString::unitString(code
);
3407 argv
[0].setInt32(code
);
3409 chars
= (jschar
*) cx
->malloc((argc
+ 1) * sizeof(jschar
));
3412 for (i
= 0; i
< argc
; i
++) {
3414 if (!ValueToUint16(cx
, argv
[i
], &code
)) {
3418 chars
[i
] = (jschar
)code
;
3421 str
= js_NewString(cx
, chars
, argc
);
3431 static JSString
* FASTCALL
3432 String_fromCharCode(JSContext
* cx
, int32 i
)
3434 JS_ASSERT(JS_ON_TRACE(cx
));
3435 jschar c
= (jschar
)i
;
3436 if (c
< UNIT_STRING_LIMIT
)
3437 return JSString::unitString(c
);
3438 return js_NewStringCopyN(cx
, &c
, 1);
3442 JS_DEFINE_TRCINFO_1(str_fromCharCode
,
3443 (2, (static, STRING_RETRY
, String_fromCharCode
, CONTEXT
, INT32
, 1, nanojit::ACCSET_NONE
)))
3445 static JSFunctionSpec string_static_methods
[] = {
3446 JS_TN("fromCharCode", str_fromCharCode
, 1, 0, &str_fromCharCode_trcinfo
),
3451 js_InitStringClass(JSContext
*cx
, JSObject
*obj
)
3455 /* Define the escape, unescape functions in the global object. */
3456 if (!JS_DefineFunctions(cx
, obj
, string_functions
))
3459 proto
= js_InitClass(cx
, obj
, NULL
, &js_StringClass
, js_String
, 1,
3460 NULL
, string_methods
,
3461 NULL
, string_static_methods
);
3464 proto
->setPrimitiveThis(StringValue(cx
->runtime
->emptyString
));
3465 if (!js_DefineNativeProperty(cx
, proto
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
3466 UndefinedValue(), NULL
, NULL
,
3467 JSPROP_READONLY
| JSPROP_PERMANENT
| JSPROP_SHARED
, 0, 0,
3476 js_NewString(JSContext
*cx
, jschar
*chars
, size_t length
)
3480 if (length
> JSString::MAX_LENGTH
) {
3481 if (JS_ON_TRACE(cx
)) {
3483 * If we can't leave the trace, signal OOM condition, otherwise
3484 * exit from trace before throwing.
3486 if (!CanLeaveTrace(cx
))
3491 js_ReportAllocationOverflow(cx
);
3495 str
= js_NewGCString(cx
);
3498 str
->initFlat(chars
, length
);
3501 JSRuntime
*rt
= cx
->runtime
;
3502 JS_RUNTIME_METER(rt
, liveStrings
);
3503 JS_RUNTIME_METER(rt
, totalStrings
);
3504 JS_LOCK_RUNTIME_VOID(rt
,
3505 (rt
->lengthSum
+= (double)length
,
3506 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3512 static JS_ALWAYS_INLINE JSString
*
3513 NewShortString(JSContext
*cx
, const jschar
*chars
, size_t length
)
3515 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3516 JSShortString
*str
= js_NewGCShortString(cx
);
3519 jschar
*storage
= str
->init(length
);
3520 js_short_strncpy(storage
, chars
, length
);
3521 storage
[length
] = 0;
3522 return str
->header();
3526 NewShortString(JSContext
*cx
, const char *chars
, size_t length
)
3528 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3529 JSShortString
*str
= js_NewGCShortString(cx
);
3532 jschar
*storage
= str
->init(length
);
3534 if (js_CStringsAreUTF8
) {
3536 size_t oldLength
= length
;
3538 if (!js_InflateStringToBuffer(cx
, chars
, length
, storage
, &length
))
3540 JS_ASSERT(length
<= oldLength
);
3541 storage
[length
] = 0;
3542 str
->resetLength(length
);
3545 jschar
*p
= storage
;
3547 *p
++ = jschar(*chars
++);
3550 return str
->header();
3553 static const size_t sMinWasteSize
= 16;
3556 js_NewStringFromCharBuffer(JSContext
*cx
, JSCharBuffer
&cb
)
3559 return ATOM_TO_STRING(cx
->runtime
->atomState
.emptyAtom
);
3561 size_t length
= cb
.length();
3563 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH
< JSCharBuffer::InlineLength
);
3564 if (JSShortString::fitsIntoShortString(length
))
3565 return NewShortString(cx
, cb
.begin(), length
);
3567 if (!cb
.append('\0'))
3570 size_t capacity
= cb
.capacity();
3572 jschar
*buf
= cb
.extractRawBuffer();
3576 /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3577 JS_ASSERT(capacity
>= length
);
3578 if (capacity
> sMinWasteSize
&& capacity
- length
> (length
>> 2)) {
3579 size_t bytes
= sizeof(jschar
) * (length
+ 1);
3580 jschar
*tmp
= (jschar
*)cx
->realloc(buf
, bytes
);
3588 JSString
*str
= js_NewString(cx
, buf
, length
);
3595 js_NewDependentString(JSContext
*cx
, JSString
*base
, size_t start
,
3601 return cx
->runtime
->emptyString
;
3603 if (start
== 0 && length
== base
->length())
3606 jschar
*chars
= base
->chars() + start
;
3608 JSString
*staticStr
= JSString::lookupStaticString(chars
, length
);
3612 /* Try to avoid long chains of dependent strings. */
3613 while (base
->isDependent())
3614 base
= base
->dependentBase();
3616 JS_ASSERT(base
->isFlat());
3618 ds
= js_NewGCString(cx
);
3621 ds
->initDependent(base
, chars
, length
);
3624 JSRuntime
*rt
= cx
->runtime
;
3625 JS_RUNTIME_METER(rt
, liveDependentStrings
);
3626 JS_RUNTIME_METER(rt
, totalDependentStrings
);
3627 JS_RUNTIME_METER(rt
, liveStrings
);
3628 JS_RUNTIME_METER(rt
, totalStrings
);
3629 JS_LOCK_RUNTIME_VOID(rt
,
3630 (rt
->strdepLengthSum
+= (double)length
,
3631 rt
->strdepLengthSquaredSum
+= (double)length
* (double)length
));
3632 JS_LOCK_RUNTIME_VOID(rt
,
3633 (rt
->lengthSum
+= (double)length
,
3634 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3643 void printJSStringStats(JSRuntime
*rt
)
3647 mean
= JS_MeanAndStdDev(rt
->totalStrings
, rt
->lengthSum
,
3648 rt
->lengthSquaredSum
, &sigma
);
3650 fprintf(stderr
, "%lu total strings, mean length %g (sigma %g)\n",
3651 (unsigned long)rt
->totalStrings
, mean
, sigma
);
3653 mean
= JS_MeanAndStdDev(rt
->totalDependentStrings
, rt
->strdepLengthSum
,
3654 rt
->strdepLengthSquaredSum
, &sigma
);
3656 fprintf(stderr
, "%lu total dependent strings, mean length %g (sigma %g)\n",
3657 (unsigned long)rt
->totalDependentStrings
, mean
, sigma
);
3662 js_NewStringCopyN(JSContext
*cx
, const jschar
*s
, size_t n
)
3664 if (JSShortString::fitsIntoShortString(n
))
3665 return NewShortString(cx
, s
, n
);
3670 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
3673 js_strncpy(news
, s
, n
);
3675 str
= js_NewString(cx
, news
, n
);
3682 js_NewStringCopyN(JSContext
*cx
, const char *s
, size_t n
)
3684 if (JSShortString::fitsIntoShortString(n
))
3685 return NewShortString(cx
, s
, n
);
3686 return JS_NewStringCopyN(cx
, s
, n
);
3690 js_NewStringCopyZ(JSContext
*cx
, const jschar
*s
)
3698 if (JSShortString::fitsIntoShortString(n
))
3699 return NewShortString(cx
, s
, n
);
3701 m
= (n
+ 1) * sizeof(jschar
);
3702 news
= (jschar
*) cx
->malloc(m
);
3706 str
= js_NewString(cx
, news
, n
);
3713 js_NewStringCopyZ(JSContext
*cx
, const char *s
)
3715 return js_NewStringCopyN(cx
, s
, strlen(s
));
3719 js_ValueToPrintable(JSContext
*cx
, const Value
&v
, JSAutoByteString
*bytes
, bool asSource
)
3723 str
= (asSource
? js_ValueToSource
: js_ValueToString
)(cx
, v
);
3726 str
= js_QuoteString(cx
, str
, 0);
3729 return bytes
->encode(cx
, str
);
3733 js_ValueToString(JSContext
*cx
, const Value
&arg
)
3736 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3742 } else if (v
.isInt32()) {
3743 str
= js_IntToString(cx
, v
.toInt32());
3744 } else if (v
.isDouble()) {
3745 str
= js_NumberToString(cx
, v
.toDouble());
3746 } else if (v
.isBoolean()) {
3747 str
= js_BooleanToString(cx
, v
.toBoolean());
3748 } else if (v
.isNull()) {
3749 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
3751 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
3756 static inline JSBool
3757 AppendAtom(JSAtom
*atom
, JSCharBuffer
&cb
)
3759 JSString
*str
= ATOM_TO_STRING(atom
);
3760 const jschar
*chars
;
3762 str
->getCharsAndLength(chars
, length
);
3763 return cb
.append(chars
, length
);
3766 /* This function implements E-262-3 section 9.8, toString. */
3768 js_ValueToCharBuffer(JSContext
*cx
, const Value
&arg
, JSCharBuffer
&cb
)
3771 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3775 const jschar
*chars
;
3777 v
.toString()->getCharsAndLength(chars
, length
);
3778 return cb
.append(chars
, length
);
3781 return js_NumberValueToCharBuffer(cx
, v
, cb
);
3783 return js_BooleanToCharBuffer(cx
, v
.toBoolean(), cb
);
3785 return AppendAtom(cx
->runtime
->atomState
.nullAtom
, cb
);
3786 JS_ASSERT(v
.isUndefined());
3787 return AppendAtom(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
], cb
);
3790 JS_FRIEND_API(JSString
*)
3791 js_ValueToSource(JSContext
*cx
, const Value
&v
)
3793 if (v
.isUndefined())
3794 return ATOM_TO_STRING(cx
->runtime
->atomState
.void0Atom
);
3796 return js_QuoteString(cx
, v
.toString(), '"');
3797 if (v
.isPrimitive()) {
3798 /* Special case to preserve negative zero, _contra_ toString. */
3799 if (v
.isDouble() && JSDOUBLE_IS_NEGZERO(v
.toDouble())) {
3800 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3801 static const jschar js_negzero_ucNstr
[] = {'-', '0'};
3803 return js_NewStringCopyN(cx
, js_negzero_ucNstr
, 2);
3805 return js_ValueToString(cx
, v
);
3808 JSAtom
*atom
= cx
->runtime
->atomState
.toSourceAtom
;
3809 AutoValueRooter
tvr(cx
);
3810 if (!js_TryMethod(cx
, &v
.toObject(), atom
, 0, NULL
, tvr
.addr()))
3812 return js_ValueToString(cx
, tvr
.value());
3816 * str is not necessarily a GC thing here.
3819 js_HashString(JSString
*str
)
3825 str
->getCharsAndLength(s
, n
);
3826 for (h
= 0; n
; s
++, n
--)
3827 h
= JS_ROTATE_LEFT32(h
, 4) ^ *s
;
3832 * str is not necessarily a GC thing here.
3835 js_EqualStrings(JSString
*str1
, JSString
*str2
)
3838 const jschar
*s1
, *s2
;
3843 /* Fast case: pointer equality could be a quick win. */
3848 if (n
!= str2
->length())
3854 s1
= str1
->chars(), s2
= str2
->chars();
3863 JS_DEFINE_CALLINFO_2(extern, BOOL
, js_EqualStrings
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3866 js_CompareStrings(JSString
*str1
, JSString
*str2
)
3868 size_t l1
, l2
, n
, i
;
3869 const jschar
*s1
, *s2
;
3875 /* Fast case: pointer equality could be a quick win. */
3879 str1
->getCharsAndLength(s1
, l1
);
3880 str2
->getCharsAndLength(s2
, l2
);
3882 for (i
= 0; i
< n
; i
++) {
3883 cmp
= s1
[i
] - s2
[i
];
3887 return (intN
)(l1
- l2
);
3889 JS_DEFINE_CALLINFO_2(extern, INT32
, js_CompareStrings
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3894 MatchStringAndAscii(JSString
*str
, const char *asciiBytes
)
3896 size_t length
= strlen(asciiBytes
);
3898 for (size_t i
= 0; i
!= length
; ++i
)
3899 JS_ASSERT(unsigned(asciiBytes
[i
]) <= 127);
3901 if (length
!= str
->length())
3903 const jschar
*chars
= str
->chars();
3904 for (size_t i
= 0; i
!= length
; ++i
) {
3905 if (unsigned(asciiBytes
[i
]) != unsigned(chars
[i
]))
3916 js_strlen(const jschar
*s
)
3920 for (t
= s
; *t
!= 0; t
++)
3922 return (size_t)(t
- s
);
3926 js_strchr(const jschar
*s
, jschar c
)
3937 js_strchr_limit(const jschar
*s
, jschar c
, const jschar
*limit
)
3948 js_InflateString(JSContext
*cx
, const char *bytes
, size_t *lengthp
)
3950 size_t nbytes
, nchars
, i
;
3957 if (js_CStringsAreUTF8
) {
3958 if (!js_InflateStringToBuffer(cx
, bytes
, nbytes
, NULL
, &nchars
))
3960 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof (jschar
));
3966 js_InflateStringToBuffer(cx
, bytes
, nbytes
, chars
, &nchars
);
3970 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof(jschar
));
3973 for (i
= 0; i
< nchars
; i
++)
3974 chars
[i
] = (unsigned char) bytes
[i
];
3982 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3990 * May be called with null cx by js_GetStringBytes, see below.
3993 js_DeflateString(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4001 if (js_CStringsAreUTF8
) {
4002 nbytes
= js_GetDeflatedStringLength(cx
, chars
, nchars
);
4003 if (nbytes
== (size_t) -1)
4005 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
4011 js_DeflateStringToBuffer(cx
, chars
, nchars
, bytes
, &nbytes
);
4015 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
4018 for (i
= 0; i
< nbytes
; i
++)
4019 bytes
[i
] = (char) chars
[i
];
4026 js_GetDeflatedStringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4028 if (!js_CStringsAreUTF8
)
4031 return js_GetDeflatedUTF8StringLength(cx
, chars
, nchars
);
4035 * May be called with null cx through js_GetStringBytes, see below.
4038 js_GetDeflatedUTF8StringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4046 for (end
= chars
+ nchars
; chars
!= end
; chars
++) {
4050 if (0xD800 <= c
&& c
<= 0xDFFF) {
4051 /* Surrogate pair. */
4054 /* nbytes sets 1 length since this is surrogate pair. */
4056 if (c
>= 0xDC00 || chars
== end
)
4059 if (c2
< 0xDC00 || c2
> 0xDFFF)
4061 c
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4074 JS_snprintf(buffer
, 10, "0x%x", c
);
4075 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
4076 NULL
, JSMSG_BAD_SURROGATE_CHAR
, buffer
);
4082 js_DeflateStringToBuffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4083 char *dst
, size_t *dstlenp
)
4088 if (!js_CStringsAreUTF8
) {
4089 if (srclen
> dstlen
) {
4090 for (i
= 0; i
< dstlen
; i
++)
4091 dst
[i
] = (char) src
[i
];
4093 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4094 JSMSG_BUFFER_TOO_SMALL
);
4098 for (i
= 0; i
< srclen
; i
++)
4099 dst
[i
] = (char) src
[i
];
4104 return js_DeflateStringToUTF8Buffer(cx
, src
, srclen
, dst
, dstlenp
);
4108 js_DeflateStringToUTF8Buffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4109 char *dst
, size_t *dstlenp
)
4111 size_t dstlen
, i
, origDstlen
, utf8Len
;
4117 origDstlen
= dstlen
;
4121 if ((c
>= 0xDC00) && (c
<= 0xDFFF))
4123 if (c
< 0xD800 || c
> 0xDBFF) {
4129 if ((c2
< 0xDC00) || (c2
> 0xDFFF))
4133 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4136 /* no encoding necessary - performance hack */
4138 goto bufferTooSmall
;
4142 utf8Len
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
4143 if (utf8Len
> dstlen
)
4144 goto bufferTooSmall
;
4145 for (i
= 0; i
< utf8Len
; i
++)
4146 *dst
++ = (char) utf8buf
[i
];
4150 *dstlenp
= (origDstlen
- dstlen
);
4154 *dstlenp
= (origDstlen
- dstlen
);
4155 /* Delegate error reporting to the measurement function. */
4157 js_GetDeflatedStringLength(cx
, src
- 1, srclen
+ 1);
4161 *dstlenp
= (origDstlen
- dstlen
);
4163 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4164 JSMSG_BUFFER_TOO_SMALL
);
4170 js_InflateStringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4171 jschar
*dst
, size_t *dstlenp
)
4175 if (!js_CStringsAreUTF8
) {
4178 if (srclen
> dstlen
) {
4179 for (i
= 0; i
< dstlen
; i
++)
4180 dst
[i
] = (unsigned char) src
[i
];
4182 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4183 JSMSG_BUFFER_TOO_SMALL
);
4187 for (i
= 0; i
< srclen
; i
++)
4188 dst
[i
] = (unsigned char) src
[i
];
4194 return js_InflateUTF8StringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
4198 js_InflateUTF8StringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4199 jschar
*dst
, size_t *dstlenp
)
4201 size_t dstlen
, origDstlen
, offset
, j
, n
;
4204 dstlen
= dst
? *dstlenp
: (size_t) -1;
4205 origDstlen
= dstlen
;
4212 while (v
& (0x80 >> n
))
4215 goto bufferTooSmall
;
4216 if (n
== 1 || n
> 4)
4218 for (j
= 1; j
< n
; j
++) {
4219 if ((src
[j
] & 0xC0) != 0x80)
4222 v
= Utf8ToOneUcs4Char((uint8
*)src
, n
);
4225 if (v
> 0xFFFFF || dstlen
< 2) {
4226 *dstlenp
= (origDstlen
- dstlen
);
4229 JS_snprintf(buffer
, 10, "0x%x", v
+ 0x10000);
4230 JS_ReportErrorFlagsAndNumber(cx
,
4232 js_GetErrorMessage
, NULL
,
4233 JSMSG_UTF8_CHAR_TOO_LARGE
,
4239 *dst
++ = (jschar
)((v
>> 10) + 0xD800);
4240 v
= (jschar
)((v
& 0x3FF) + 0xDC00);
4246 goto bufferTooSmall
;
4248 *dst
++ = (jschar
) v
;
4254 *dstlenp
= (origDstlen
- dstlen
);
4258 *dstlenp
= (origDstlen
- dstlen
);
4261 JS_snprintf(buffer
, 10, "%d", offset
);
4262 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
4263 js_GetErrorMessage
, NULL
,
4264 JSMSG_MALFORMED_UTF8_CHAR
,
4270 *dstlenp
= (origDstlen
- dstlen
);
4272 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4273 JSMSG_BUFFER_TOO_SMALL
);
4280 DeflatedStringCache::DeflatedStringCache()
4282 #ifdef JS_THREADSAFE
4288 DeflatedStringCache::init()
4290 #ifdef JS_THREADSAFE
4292 lock
= JS_NEW_LOCK();
4298 * Make room for 2K deflated strings that a typical browser session
4301 return map
.init(2048);
4304 DeflatedStringCache::~DeflatedStringCache()
4306 #ifdef JS_THREADSAFE
4308 JS_DESTROY_LOCK(lock
);
4313 DeflatedStringCache::sweep(JSContext
*cx
)
4316 * We must take a lock even during the GC as JS_GetFunctionName can be
4317 * called outside the request.
4319 JS_ACQUIRE_LOCK(lock
);
4321 for (Map::Enum
e(map
); !e
.empty(); e
.popFront()) {
4322 JSString
*str
= e
.front().key
;
4323 if (IsAboutToBeFinalized(str
)) {
4324 char *bytes
= e
.front().value
;
4328 * We cannot use cx->free here as bytes may come from the
4329 * embedding that calls JS_NewString(cx, bytes, length). Those
4330 * bytes may not be allocated via js_malloc and may not have
4331 * space for the background free list.
4337 JS_RELEASE_LOCK(lock
);
4341 DeflatedStringCache::getBytes(JSString
*str
)
4343 JS_ACQUIRE_LOCK(lock
);
4344 Map::AddPtr p
= map
.lookupForAdd(str
);
4345 char *bytes
= p
? p
->value
: NULL
;
4346 JS_RELEASE_LOCK(lock
);
4351 bytes
= js_DeflateString(NULL
, str
->chars(), str
->length());
4356 * In the single-threaded case we use the add method as js_DeflateString
4357 * cannot mutate the map. In particular, it cannot run the GC that may
4358 * delete entries from the map. But the JS_THREADSAFE version requires to
4359 * deal with other threads adding the entries to the map.
4361 char *bytesToFree
= NULL
;
4363 #ifdef JS_THREADSAFE
4364 JS_ACQUIRE_LOCK(lock
);
4365 ok
= map
.relookupOrAdd(p
, str
, bytes
);
4366 if (ok
&& p
->value
!= bytes
) {
4367 /* Some other thread has asked for str bytes .*/
4368 JS_ASSERT(!strcmp(p
->value
, bytes
));
4369 bytesToFree
= bytes
;
4372 JS_RELEASE_LOCK(lock
);
4373 #else /* !JS_THREADSAFE */
4374 ok
= map
.add(p
, str
, bytes
);
4377 bytesToFree
= bytes
;
4382 js_free(bytesToFree
);
4386 } /* namespace js */
4389 js_GetStringBytes(JSAtom
*atom
)
4391 JSString
*str
= ATOM_TO_STRING(atom
);
4392 if (JSString::isUnitString(str
)) {
4394 #ifdef IS_LITTLE_ENDIAN
4395 /* Unit string data is {c, 0, 0, 0} so we can just cast. */
4396 bytes
= (char *)str
->chars();
4398 /* Unit string data is {0, c, 0, 0} so we can point into the middle. */
4399 bytes
= (char *)str
->chars() + 1;
4401 return ((*bytes
& 0x80) && js_CStringsAreUTF8
)
4402 ? JSString::deflatedUnitStringTable
+ ((*bytes
& 0x7f) * 3)
4407 * We must burn some space on deflated int strings and length-2 strings
4408 * to preserve static allocation (which is to say, JSRuntime independence).
4410 if (JSString::isLength2String(str
))
4411 return JSString::deflatedLength2StringTable
+ ((str
- JSString::length2StringTable
) * 3);
4413 if (JSString::isHundredString(str
)) {
4415 * We handled the 1 and 2-digit number cases already, so we know that
4416 * str is between 100 and 255.
4418 return JSString::deflatedIntStringTable
+ ((str
- JSString::hundredStringTable
) * 4);
4421 return GetGCThingRuntime(str
)->deflatedStringCache
->getBytes(str
);
4425 * From java.lang.Character.java:
4427 * The character properties are currently encoded into 32 bits in the
4430 * 10 bits signed offset used for converting case
4431 * 1 bit if 1, adding the signed offset converts the character to
4433 * 1 bit if 1, subtracting the signed offset converts the character to
4435 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
4436 * 3 bits 0 may not be part of an identifier
4437 * 1 ignorable control; may continue a Unicode identifier or JS
4439 * 2 may continue a JS identifier but not a Unicode identifier
4441 * 3 may continue a Unicode identifier or JS identifier
4442 * 4 is a JS whitespace character
4443 * 5 may start or continue a JS identifier;
4444 * may continue but not start a Unicode identifier (_)
4445 * 6 may start or continue a JS identifier but not a Unicode
4447 * 7 may start or continue a Unicode identifier or JS identifier
4449 * 5, 6, 7 may start a JS identifier
4450 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
4451 * 7 may start a Unicode identifier
4452 * 1, 3, 5, 7 may continue a Unicode identifier
4453 * 1 is ignorable within an identifier
4454 * 4 is JS whitespace
4455 * 2 bits 0 this character has no numeric property
4456 * 1 adding the digit offset to the character code and then
4457 * masking with 0x1F will produce the desired numeric value
4458 * 2 this character has a "strange" numeric value
4459 * 3 a JS supradecimal digit: adding the digit offset to the
4460 * character code, then masking with 0x1F, then adding 10
4461 * will produce the desired numeric value
4462 * 5 bits digit offset
4463 * 1 bit XML 1.0 name start character
4464 * 1 bit XML 1.0 name character
4465 * 2 bits reserved for future use
4466 * 5 bits character type
4469 /* The X table has 1024 entries for a total of 1024 bytes. */
4471 const uint8 js_X
[] = {
4472 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
4473 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
4474 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
4475 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
4476 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
4477 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
4478 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
4479 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
4480 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
4481 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
4482 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
4483 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
4484 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
4485 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
4486 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
4487 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
4488 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
4489 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
4490 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
4491 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
4492 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
4493 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
4494 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
4495 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
4496 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
4497 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
4498 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
4499 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
4500 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
4501 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
4502 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
4503 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
4504 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
4505 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
4506 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
4507 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
4508 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
4509 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
4510 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
4511 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
4512 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
4513 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
4514 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
4515 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
4516 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
4517 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
4518 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
4519 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
4520 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
4521 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
4522 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
4523 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
4524 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
4525 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
4526 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
4527 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
4528 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
4529 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
4530 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
4531 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
4532 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
4533 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
4534 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
4535 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
4536 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
4537 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
4538 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
4539 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
4540 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
4541 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
4542 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
4543 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
4544 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
4545 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
4546 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
4547 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
4548 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
4549 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
4550 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
4551 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
4552 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
4553 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
4554 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
4555 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
4556 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
4557 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
4558 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
4559 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
4560 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
4561 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
4562 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
4563 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
4564 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
4565 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
4566 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
4567 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
4568 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
4569 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
4570 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
4571 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
4572 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
4573 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
4574 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
4575 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
4576 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
4577 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
4578 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
4579 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
4580 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
4581 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
4582 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
4583 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
4584 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
4585 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
4586 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
4587 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
4588 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
4589 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
4590 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
4591 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
4592 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
4593 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
4594 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
4595 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
4596 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
4597 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
4598 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
4599 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
4602 /* The Y table has 7808 entries for a total of 7808 bytes. */
4604 const uint8 js_Y
[] = {
4605 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4606 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
4607 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4608 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4609 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
4610 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
4611 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
4612 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
4613 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4614 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4615 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4616 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
4617 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4618 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4619 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4620 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
4621 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4622 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4623 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4624 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4625 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
4626 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
4627 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
4628 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
4629 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4630 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4631 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
4632 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
4633 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4634 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4635 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
4636 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
4637 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4638 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4639 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4640 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4641 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4642 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4643 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
4644 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
4645 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
4646 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
4647 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4648 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4649 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4650 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4651 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4652 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
4653 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
4654 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
4655 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
4656 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
4657 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
4658 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
4659 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
4660 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
4661 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
4662 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
4663 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
4664 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
4665 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4666 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4667 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
4668 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
4669 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4670 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4671 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4672 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4673 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4674 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4675 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4676 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4677 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4678 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4679 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
4680 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
4681 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
4682 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
4683 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
4684 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
4685 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
4686 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
4687 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
4688 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4689 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4690 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
4691 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
4692 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
4693 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4694 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
4695 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4696 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
4697 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
4698 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
4699 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4700 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4701 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4702 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4703 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4704 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4705 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4706 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4707 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4708 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4709 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
4710 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4711 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4712 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4713 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
4714 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4715 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
4716 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
4717 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
4718 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
4719 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4720 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4721 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
4722 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
4723 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4724 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4725 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
4726 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
4727 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
4728 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
4729 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
4730 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
4731 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
4732 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
4733 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
4734 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
4735 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4736 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4737 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4738 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4739 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4740 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4741 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4742 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4743 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
4744 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
4745 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4746 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4747 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4748 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4749 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
4750 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
4751 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4752 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4753 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4754 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4755 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4756 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4757 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
4758 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
4759 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4760 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4761 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4762 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
4763 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
4764 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
4765 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4766 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4767 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4768 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4769 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4770 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4771 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4772 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4773 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4774 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4775 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
4776 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
4777 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4778 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4779 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4780 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4781 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
4782 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
4783 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4784 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4785 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
4786 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4787 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4788 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
4789 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
4790 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4791 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4792 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4793 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4794 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
4795 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
4796 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4797 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4798 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
4799 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4800 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
4801 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4802 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4803 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4804 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
4805 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4806 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
4807 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
4808 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
4809 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
4810 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
4811 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4812 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4813 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4814 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4815 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4816 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4817 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4818 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4819 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4820 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4821 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4822 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4823 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4824 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4825 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4826 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4827 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4828 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4829 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4830 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4831 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4832 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4833 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4834 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4835 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4836 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4837 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4838 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4839 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4840 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4841 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4842 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4843 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4844 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
4845 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4846 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4847 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4848 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4849 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4850 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4851 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4852 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4853 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4854 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4855 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4856 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4857 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4858 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4859 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4860 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4861 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4862 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4863 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4864 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4865 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4866 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4867 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4868 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4869 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4870 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4871 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4872 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4873 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4874 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4875 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4876 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4877 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4878 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4879 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4880 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4881 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4882 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4883 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4884 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4885 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4886 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4887 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4888 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4889 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4890 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4891 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4892 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4893 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4894 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4895 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4896 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4897 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4898 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4899 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4900 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4901 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4902 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4903 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4904 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4905 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4906 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4907 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4908 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4909 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4910 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4911 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4912 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4913 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4914 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4915 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4916 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4917 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4918 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4919 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4920 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4921 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4922 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4923 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4924 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4925 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4926 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4927 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4928 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4929 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4930 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4931 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4932 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4933 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4934 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4935 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4936 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4937 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4938 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4939 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4940 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4941 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4942 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4943 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4944 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4945 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4946 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4947 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4948 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4949 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4950 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4951 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4952 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4953 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4954 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4955 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4956 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4957 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4958 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4959 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4960 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4961 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4962 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4963 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4964 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4965 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4966 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4967 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4968 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4969 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4970 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4971 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4972 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
4973 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4974 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4975 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4976 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4977 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4978 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4979 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4980 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4981 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4982 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4983 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4984 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4985 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4986 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
4987 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4988 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4989 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4990 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4991 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4992 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4993 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4994 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4995 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4996 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4997 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4998 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4999 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
5000 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
5001 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
5002 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
5003 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
5004 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
5005 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
5006 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
5007 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
5008 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
5009 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5010 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5011 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5012 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5013 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
5014 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
5015 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
5016 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
5017 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
5018 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
5019 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
5020 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
5021 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5022 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5023 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5024 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5025 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5026 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
5027 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
5028 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
5029 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
5030 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
5031 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
5032 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5033 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5034 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
5035 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5036 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
5037 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5038 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5039 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5040 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5041 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5042 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5043 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5044 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5045 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
5046 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
5047 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5048 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5049 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5050 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5051 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
5052 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
5053 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5054 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5055 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5056 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5057 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5058 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5059 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5060 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5061 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5062 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5063 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5064 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
5065 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5066 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5067 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5068 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5069 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5070 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5071 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5072 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5073 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
5074 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5075 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5076 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5077 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5078 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5079 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5080 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5081 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5082 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5083 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5084 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
5085 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5086 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5087 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5088 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5089 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5090 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5091 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5092 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5093 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5094 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5095 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
5096 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
5097 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5098 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5099 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5100 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5101 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5102 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5103 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5104 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5105 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5106 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5107 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5108 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
5109 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5110 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5111 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
5112 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
5113 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5114 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5115 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5116 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5117 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
5118 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
5119 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
5120 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
5121 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
5122 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
5123 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
5124 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
5125 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5126 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5127 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5128 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5129 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5130 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5131 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
5132 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
5133 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
5134 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
5135 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
5136 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
5137 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
5138 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
5139 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
5140 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
5141 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
5142 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
5143 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
5144 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
5145 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
5146 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
5147 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
5148 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
5149 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
5150 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5151 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5152 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5153 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5154 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
5155 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
5156 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
5157 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
5158 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
5159 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5160 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5161 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
5162 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
5163 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5164 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5165 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5166 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5167 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
5168 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
5169 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
5170 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5171 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5172 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5173 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
5174 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
5175 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
5176 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
5177 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
5178 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
5179 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
5180 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
5181 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5182 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5183 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
5184 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
5185 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
5186 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
5187 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
5188 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
5189 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
5190 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
5191 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
5192 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5193 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5194 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5195 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5196 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5197 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5198 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5199 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
5200 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5201 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5202 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
5203 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5204 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5205 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5206 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5207 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5208 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5209 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5210 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5211 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5212 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5213 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5214 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5215 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5216 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5217 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5218 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5219 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
5220 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
5221 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
5222 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
5223 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5224 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5225 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
5226 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
5227 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5228 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5229 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5230 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5231 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5232 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5233 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5234 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5235 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5236 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
5237 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5238 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5239 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5240 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5241 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
5242 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5243 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5244 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5245 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
5246 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
5247 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5248 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5249 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5250 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5251 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
5252 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
5253 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
5254 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5255 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5256 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
5257 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5258 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5259 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
5260 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
5261 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5262 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5263 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5264 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5265 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5266 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
5267 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5268 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5269 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5270 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5271 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5272 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5273 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5274 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5275 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5276 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5277 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5278 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5279 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
5280 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
5281 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5282 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5283 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5284 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5285 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5286 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5287 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5288 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5289 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5290 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5291 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5292 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5293 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5294 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5295 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
5296 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
5297 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5298 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5299 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5300 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5301 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
5302 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
5303 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5304 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5305 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5306 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5307 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5308 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5309 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5310 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
5311 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
5312 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
5313 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5314 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
5315 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
5316 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
5317 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
5318 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
5319 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
5320 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5321 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5322 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5323 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5324 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
5325 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
5326 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
5327 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
5328 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
5329 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
5330 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
5331 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
5332 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
5333 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5334 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5335 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5336 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5337 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5338 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5339 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5340 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5341 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5342 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5343 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
5344 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
5345 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5346 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5347 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5348 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5349 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5350 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5351 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5352 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5353 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5354 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5355 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5356 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
5357 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
5358 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5359 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5360 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5361 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5362 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
5363 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5364 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5365 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
5366 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
5367 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
5368 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
5369 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5370 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5371 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5372 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5373 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5374 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5375 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5376 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
5377 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
5378 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
5379 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5380 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5381 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
5382 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5383 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5384 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5385 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5386 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5387 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5388 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
5389 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
5390 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
5391 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5392 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5393 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5394 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5395 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5396 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5397 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5398 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
5399 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5400 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5401 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5402 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5403 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5404 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
5405 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5406 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5407 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5408 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5409 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5410 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5411 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
5412 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
5413 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5414 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5415 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5416 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
5417 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5418 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5419 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5420 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
5421 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5422 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5423 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5424 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5425 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
5426 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5427 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5428 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5429 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5430 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5431 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5432 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5433 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
5434 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5435 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5436 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5437 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5438 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5439 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5440 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5441 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5442 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5443 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5444 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5445 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5446 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5447 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5448 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5449 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5450 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5451 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5452 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5453 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5454 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5455 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5456 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5457 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5458 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
5459 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5460 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5461 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
5462 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
5463 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
5464 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
5465 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
5466 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
5467 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
5468 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
5469 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
5470 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5471 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5472 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5473 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5474 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5475 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5476 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5477 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5478 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5479 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5480 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5481 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5482 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5483 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
5484 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
5485 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5486 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5487 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
5488 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5489 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5490 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5491 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5492 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5493 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5494 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5495 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5496 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5497 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5498 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5499 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5500 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
5501 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5502 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5503 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5504 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5505 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5506 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5507 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5508 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5509 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5510 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5511 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
5512 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5513 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5514 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5515 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5516 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5517 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5518 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5519 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5520 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5521 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5522 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5523 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5524 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
5525 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5526 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5527 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5528 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5529 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
5530 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5531 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
5532 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
5533 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
5534 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
5535 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
5536 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
5537 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
5538 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
5539 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
5540 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
5541 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5542 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5543 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5544 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5545 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5546 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5547 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5548 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
5549 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
5550 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
5551 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
5552 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
5553 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5554 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5555 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5556 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
5557 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5558 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5559 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5560 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
5561 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
5562 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5563 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5564 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5565 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5566 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5567 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5568 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
5569 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5570 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5571 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5572 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
5573 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5574 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5575 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5576 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
5577 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
5578 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
5579 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
5580 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
5583 /* The A table has 124 entries for a total of 496 bytes. */
5585 const uint32 js_A
[] = {
5586 0x0001000F, /* 0 Cc, ignorable */
5587 0x0004000F, /* 1 Cc, whitespace */
5588 0x0004000C, /* 2 Zs, whitespace */
5589 0x00000018, /* 3 Po */
5590 0x0006001A, /* 4 Sc, currency */
5591 0x00000015, /* 5 Ps */
5592 0x00000016, /* 6 Pe */
5593 0x00000019, /* 7 Sm */
5594 0x00000014, /* 8 Pd */
5595 0x00036089, /* 9 Nd, identifier part, decimal 16 */
5596 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
5597 0x0000001B, /* 11 Sk */
5598 0x00050017, /* 12 Pc, underscore */
5599 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5600 0x0000000C, /* 14 Zs */
5601 0x0000001C, /* 15 So */
5602 0x00070182, /* 16 Ll, identifier start */
5603 0x0000600B, /* 17 No, decimal 16 */
5604 0x0000500B, /* 18 No, decimal 8 */
5605 0x0000800B, /* 19 No, strange */
5606 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
5607 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
5608 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
5609 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
5610 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
5611 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
5612 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
5613 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
5614 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
5615 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
5616 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
5617 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
5618 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
5619 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
5620 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
5621 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
5622 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
5623 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
5624 0x00070181, /* 38 Lu, identifier start */
5625 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
5626 0x00070185, /* 40 Lo, identifier start */
5627 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
5628 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
5629 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
5630 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5631 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
5632 0x00000000, /* 46 unassigned */
5633 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
5634 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
5635 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
5636 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
5637 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
5638 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
5639 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
5640 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
5641 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
5642 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
5643 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
5644 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
5645 0x00070084, /* 59 Lm, identifier start */
5646 0x00030086, /* 60 Mn, identifier part */
5647 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
5648 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
5649 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
5650 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
5651 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
5652 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
5653 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
5654 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
5655 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
5656 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
5657 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
5658 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
5659 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
5660 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
5661 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
5662 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
5663 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
5664 0x00034089, /* 78 Nd, identifier part, decimal 0 */
5665 0x00000087, /* 79 Me */
5666 0x00030088, /* 80 Mc, identifier part */
5667 0x00037489, /* 81 Nd, identifier part, decimal 26 */
5668 0x00005A0B, /* 82 No, decimal 13 */
5669 0x00006E0B, /* 83 No, decimal 23 */
5670 0x0000740B, /* 84 No, decimal 26 */
5671 0x0000000B, /* 85 No */
5672 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
5673 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
5674 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
5675 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
5676 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
5677 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
5678 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
5679 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
5680 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
5681 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
5682 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
5683 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
5684 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
5685 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
5686 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
5687 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
5688 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
5689 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
5690 0x00010010, /* 104 Cf, ignorable */
5691 0x0004000D, /* 105 Zl, whitespace */
5692 0x0004000E, /* 106 Zp, whitespace */
5693 0x0000400B, /* 107 No, decimal 0 */
5694 0x0000440B, /* 108 No, decimal 2 */
5695 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
5696 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
5697 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5698 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
5699 0x0007818A, /* 113 Nl, identifier start, strange */
5700 0x0000420B, /* 114 No, decimal 1 */
5701 0x0000720B, /* 115 No, decimal 25 */
5702 0x06A0001C, /* 116 So, hasLower (add 26) */
5703 0x0690001C, /* 117 So, hasUpper (subtract 26) */
5704 0x00006C0B, /* 118 No, decimal 22 */
5705 0x0000560B, /* 119 No, decimal 11 */
5706 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
5707 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
5708 0x00000013, /* 122 Cs */
5709 0x00000012 /* 123 Co */
5712 const jschar js_uriReservedPlusPound_ucstr
[] =
5713 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5714 const jschar js_uriUnescaped_ucstr
[] =
5715 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5716 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5717 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5718 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5719 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5720 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5723 * This table allows efficient testing for the regular expression \w which is
5724 * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5726 const bool js_alnum
[] = {
5727 /* 0 1 2 3 4 5 5 7 8 9 */
5728 /* 0 */ false, false, false, false, false, false, false, false, false, false,
5729 /* 1 */ false, false, false, false, false, false, false, false, false, false,
5730 /* 2 */ false, false, false, false, false, false, false, false, false, false,
5731 /* 3 */ false, false, false, false, false, false, false, false, false, false,
5732 /* 4 */ false, false, false, false, false, false, false, false, true, true,
5733 /* 5 */ true, true, true, true, true, true, true, true, false, false,
5734 /* 6 */ false, false, false, false, false, true, true, true, true, true,
5735 /* 7 */ true, true, true, true, true, true, true, true, true, true,
5736 /* 8 */ true, true, true, true, true, true, true, true, true, true,
5737 /* 9 */ true, false, false, false, false, true, false, true, true, true,
5738 /* 10 */ true, true, true, true, true, true, true, true, true, true,
5739 /* 11 */ true, true, true, true, true, true, true, true, true, true,
5740 /* 12 */ true, true, true, false, false, false, false, false
5743 #define URI_CHUNK 64U
5746 TransferBufferToString(JSContext
*cx
, JSCharBuffer
&cb
, Value
*rval
)
5748 JSString
*str
= js_NewStringFromCharBuffer(cx
, cb
);
5751 rval
->setString(str
);
5756 * ECMA 3, 15.1.3 URI Handling Function Properties
5758 * The following are implementations of the algorithms
5759 * given in the ECMA specification for the hidden functions
5760 * 'Encode' and 'Decode'.
5763 Encode(JSContext
*cx
, JSString
*str
, const jschar
*unescapedSet
,
5764 const jschar
*unescapedSet2
, Value
*rval
)
5766 size_t length
, j
, k
, L
;
5767 JSCharBuffer
cb(cx
);
5768 const jschar
*chars
;
5773 static const char HexDigits
[] = "0123456789ABCDEF"; /* NB: uppercase */
5775 str
->getCharsAndLength(chars
, length
);
5777 rval
->setString(cx
->runtime
->emptyString
);
5781 /* From this point the control must goto bad on failures. */
5784 for (k
= 0; k
< length
; k
++) {
5786 if (js_strchr(unescapedSet
, c
) ||
5787 (unescapedSet2
&& js_strchr(unescapedSet2
, c
))) {
5791 if ((c
>= 0xDC00) && (c
<= 0xDFFF)) {
5792 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5793 JSMSG_BAD_URI
, NULL
);
5796 if (c
< 0xD800 || c
> 0xDBFF) {
5801 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5802 JSMSG_BAD_URI
, NULL
);
5806 if ((c2
< 0xDC00) || (c2
> 0xDFFF)) {
5807 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5808 JSMSG_BAD_URI
, NULL
);
5811 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
5813 L
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
5814 for (j
= 0; j
< L
; j
++) {
5815 hexBuf
[1] = HexDigits
[utf8buf
[j
] >> 4];
5816 hexBuf
[2] = HexDigits
[utf8buf
[j
] & 0xf];
5817 if (!cb
.append(hexBuf
, 3))
5823 return TransferBufferToString(cx
, cb
, rval
);
5827 Decode(JSContext
*cx
, JSString
*str
, const jschar
*reservedSet
, Value
*rval
)
5829 size_t length
, start
, k
;
5830 JSCharBuffer
cb(cx
);
5831 const jschar
*chars
;
5838 str
->getCharsAndLength(chars
, length
);
5840 rval
->setString(cx
->runtime
->emptyString
);
5844 /* From this point the control must goto bad on failures. */
5845 for (k
= 0; k
< length
; k
++) {
5849 if ((k
+ 2) >= length
)
5850 goto report_bad_uri
;
5851 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5852 goto report_bad_uri
;
5853 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5859 while (B
& (0x80 >> n
))
5861 if (n
== 1 || n
> 4)
5862 goto report_bad_uri
;
5863 octets
[0] = (uint8
)B
;
5864 if (k
+ 3 * (n
- 1) >= length
)
5865 goto report_bad_uri
;
5866 for (j
= 1; j
< n
; j
++) {
5868 if (chars
[k
] != '%')
5869 goto report_bad_uri
;
5870 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5871 goto report_bad_uri
;
5872 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5873 if ((B
& 0xC0) != 0x80)
5874 goto report_bad_uri
;
5876 octets
[j
] = (char)B
;
5878 v
= Utf8ToOneUcs4Char(octets
, n
);
5882 goto report_bad_uri
;
5883 c
= (jschar
)((v
& 0x3FF) + 0xDC00);
5884 H
= (jschar
)((v
>> 10) + 0xD800);
5891 if (js_strchr(reservedSet
, c
)) {
5892 if (!cb
.append(chars
+ start
, k
- start
+ 1))
5904 return TransferBufferToString(cx
, cb
, rval
);
5907 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_URI
);
5914 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5918 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5921 return Decode(cx
, str
, js_uriReservedPlusPound_ucstr
, vp
);
5925 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5929 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5932 return Decode(cx
, str
, js_empty_ucstr
, vp
);
5936 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5940 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5943 return Encode(cx
, str
, js_uriReservedPlusPound_ucstr
, js_uriUnescaped_ucstr
,
5948 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5952 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5955 return Encode(cx
, str
, js_uriUnescaped_ucstr
, NULL
, vp
);
5959 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5960 * least 4 bytes long. Return the number of UTF-8 bytes of data written.
5963 js_OneUcs4ToUtf8Char(uint8
*utf8Buffer
, uint32 ucs4Char
)
5967 JS_ASSERT(ucs4Char
<= 0x10FFFF);
5968 if (ucs4Char
< 0x80) {
5969 *utf8Buffer
= (uint8
)ucs4Char
;
5972 uint32 a
= ucs4Char
>> 11;
5980 utf8Buffer
[i
] = (uint8
)((ucs4Char
& 0x3F) | 0x80);
5983 *utf8Buffer
= (uint8
)(0x100 - (1 << (8-utf8Length
)) + ucs4Char
);
5989 * Convert a utf8 character sequence into a UCS-4 character and return that
5990 * character. It is assumed that the caller already checked that the sequence
5994 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
)
5998 /* from Unicode 3.1, non-shortest form is illegal */
5999 static const uint32 minucs4Table
[] = {
6000 0x00000080, 0x00000800, 0x00010000
6003 JS_ASSERT(utf8Length
>= 1 && utf8Length
<= 4);
6004 if (utf8Length
== 1) {
6005 ucs4Char
= *utf8Buffer
;
6006 JS_ASSERT(!(ucs4Char
& 0x80));
6008 JS_ASSERT((*utf8Buffer
& (0x100 - (1 << (7-utf8Length
)))) ==
6009 (0x100 - (1 << (8-utf8Length
))));
6010 ucs4Char
= *utf8Buffer
++ & ((1<<(7-utf8Length
))-1);
6011 minucs4Char
= minucs4Table
[utf8Length
-2];
6012 while (--utf8Length
) {
6013 JS_ASSERT((*utf8Buffer
& 0xC0) == 0x80);
6014 ucs4Char
= ucs4Char
<<6 | (*utf8Buffer
++ & 0x3F);
6016 if (JS_UNLIKELY(ucs4Char
< minucs4Char
)) {
6017 ucs4Char
= OVERLONG_UTF8
;
6018 } else if (ucs4Char
== 0xFFFE || ucs4Char
== 0xFFFF) {
6028 PutEscapedStringImpl(char *buffer
, size_t bufferSize
, FILE *fp
, JSString
*str
, uint32 quote
)
6030 const jschar
*chars
, *charsEnd
;
6034 uintN u
, hex
, shift
;
6036 STOP
, FIRST_QUOTE
, LAST_QUOTE
, CHARS
, ESCAPE_START
, ESCAPE_MORE
6039 JS_ASSERT(quote
== 0 || quote
== '\'' || quote
== '"');
6040 JS_ASSERT_IF(!buffer
, bufferSize
== 0);
6041 JS_ASSERT_IF(fp
, !buffer
);
6043 if (bufferSize
== 0)
6048 str
->getCharsAndEnd(chars
, charsEnd
);
6050 state
= FIRST_QUOTE
;
6054 c
= 0; /* to quell GCC warnings */
6071 if (chars
== charsEnd
) {
6078 escape
= strchr(js_EscapeMap
, (int)u
);
6087 if (u
== quote
|| u
== '\\')
6090 } else if (u
< 0x100) {
6105 state
= ESCAPE_START
;
6108 JS_ASSERT(' ' <= u
&& u
< 127);
6110 state
= ESCAPE_MORE
;
6118 u
= 0xF & (hex
>> shift
);
6119 c
= (char)(u
+ (u
< 10 ? '0' : 'A' - 10));
6123 JS_ASSERT(n
<= bufferSize
);
6124 if (n
!= bufferSize
) {
6131 if (fputc(c
, fp
) < 0)
6142 } /* namespace js */