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
);
92 JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT
== 8);
93 JSStringFinalizeOp str_finalizers
[JS_EXTERNAL_STRING_LIMIT
] = {
94 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
98 js_GetStringChars(JSContext
*cx
, JSString
*str
)
100 if (!js_MakeStringImmutable(cx
, str
))
102 return str
->flatChars();
114 * This can be called from any string in the rope, so first traverse to the
118 while (topNode
->isInteriorNode())
119 topNode
= topNode
->interiorNodeParent();
122 size_t length
= topNode
->length();
125 capacity
= topNode
->topNodeCapacity();
126 chars
= (jschar
*) topNode
->topNodeBuffer();
129 * To make the traversal simpler, convert the top node to be marked as an
130 * interior node with a NULL parent, so that we end up at NULL when we are
131 * done processing it.
133 topNode
->convertToInteriorNode(NULL
);
134 JSString
*str
= topNode
, *next
;
138 * Traverse the tree, making each interior string dependent on the resulting
142 switch (str
->ropeTraversalCount()) {
144 next
= str
->ropeLeft();
147 * We know the "offset" field for the new dependent string now, but
148 * not later, so store it early. We have to be careful with this:
149 * mLeft is replaced by mOffset.
151 str
->startTraversalConversion(chars
, pos
);
152 str
->ropeIncrementTraversalCount();
153 if (next
->isInteriorNode()) {
156 js_strncpy(chars
+ pos
, next
->chars(), next
->length());
157 pos
+= next
->length();
161 next
= str
->ropeRight();
162 str
->ropeIncrementTraversalCount();
163 if (next
->isInteriorNode()) {
166 js_strncpy(chars
+ pos
, next
->chars(), next
->length());
167 pos
+= next
->length();
171 next
= str
->interiorNodeParent();
172 /* Make the string a dependent string dependent with the right fields. */
173 str
->finishTraversalConversion(topNode
, chars
, pos
);
177 JS_NOT_REACHED("bad traversal count");
181 JS_ASSERT(pos
== length
);
182 /* Set null terminator. */
184 topNode
->initFlatMutable(chars
, pos
, capacity
);
190 js_Flatten(JSString
* str
)
195 JS_DEFINE_CALLINFO_1(extern, INT32
, js_Flatten
, STRING
, 0, nanojit::ACCSET_STORE_ANY
)
197 #endif /* !JS_TRACER */
199 static JS_ALWAYS_INLINE
size_t
200 RopeAllocSize(const size_t length
, size_t *capacity
)
202 static const size_t ROPE_DOUBLING_MAX
= 1024 * 1024;
205 size_t minCap
= (length
+ 1) * sizeof(jschar
);
208 * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
209 * next power of 2. This is similar to what we do with arrays; see
210 * JSObject::ensureDenseArrayElements.
212 if (length
> ROPE_DOUBLING_MAX
)
213 size
= minCap
+ (minCap
/ 8);
215 size
= 1 << (JS_CeilingLog2(minCap
));
216 *capacity
= (size
/ sizeof(jschar
)) - 1;
217 JS_ASSERT(size
>= sizeof(JSRopeBufferInfo
));
221 static JS_ALWAYS_INLINE JSRopeBufferInfo
*
222 ObtainRopeBuffer(JSContext
*cx
, bool usingLeft
, bool usingRight
,
223 JSRopeBufferInfo
*sourceBuffer
, size_t length
,
224 JSString
*left
, JSString
*right
)
226 JSRopeBufferInfo
*buf
;
230 * We need to survive a GC upon failure and in case creating a new
231 * string header triggers a GC, but we've broken the invariant that
232 * rope top nodes always point to freeable JSRopeBufferInfo
233 * objects, so make them point to NULL.
236 left
->nullifyTopNodeBuffer();
238 right
->nullifyTopNodeBuffer();
241 * Try to reuse sourceBuffer. If it's not suitable, free it and create a
244 if (length
<= sourceBuffer
->capacity
) {
247 size_t allocSize
= RopeAllocSize(length
, &capacity
);
248 cx
->free(sourceBuffer
);
249 buf
= (JSRopeBufferInfo
*) cx
->malloc(allocSize
);
252 buf
->capacity
= capacity
;
257 static JS_ALWAYS_INLINE JSString
*
258 FinishConcat(JSContext
*cx
, bool usingLeft
, bool usingRight
,
259 JSString
*left
, JSString
*right
, size_t length
,
260 JSRopeBufferInfo
*buf
)
262 JSString
*res
= js_NewGCString(cx
);
267 res
->initTopNode(left
, right
, length
, buf
);
269 left
->convertToInteriorNode(res
);
271 right
->convertToInteriorNode(res
);
275 JSString
* JS_FASTCALL
276 js_ConcatStrings(JSContext
*cx
, JSString
*left
, JSString
*right
)
278 size_t length
, leftLen
, rightLen
;
279 bool leftRopeTop
, rightRopeTop
;
281 leftLen
= left
->length();
284 rightLen
= right
->length();
288 length
= leftLen
+ rightLen
;
290 if (JSShortString::fitsIntoShortString(length
)) {
291 JSShortString
*shortStr
= js_NewGCShortString(cx
);
295 jschar
*buf
= shortStr
->init(length
);
296 js_short_strncpy(buf
, left
->chars(), leftLen
);
297 js_short_strncpy(buf
+ leftLen
, right
->chars(), rightLen
);
299 return shortStr
->header();
303 * We need to enforce a tree structure in ropes: every node needs to have a
304 * unique parent. So, we can't have the left or right child be in the middle
305 * of a rope tree. One potential solution is to traverse the subtree for the
306 * argument string and create a new flat string, but that would add
307 * complexity and is a rare case, so we simply flatten the entire rope that
308 * contains it. The case where left and right are part of the same rope is
309 * handled implicitly.
311 if (left
->isInteriorNode())
313 if (right
->isInteriorNode())
316 if (left
->isMutable() && !right
->isRope() &&
317 left
->flatCapacity() >= length
) {
318 JS_ASSERT(left
->isFlat());
321 * If left has enough unused space at the end of its buffer that we can
322 * fit the entire new string there, just write there.
324 jschar
*chars
= left
->chars();
325 js_strncpy(chars
+ leftLen
, right
->chars(), rightLen
);
327 JSString
*res
= js_NewString(cx
, chars
, length
);
330 res
->initFlatMutable(chars
, length
, left
->flatCapacity());
331 left
->initDependent(res
, res
->flatChars(), leftLen
);
335 if (length
> JSString::MAX_LENGTH
) {
336 if (JS_ON_TRACE(cx
)) {
337 if (!CanLeaveTrace(cx
))
341 js_ReportAllocationOverflow(cx
);
345 leftRopeTop
= left
->isTopNode();
346 rightRopeTop
= right
->isTopNode();
349 * To make traversal more manageable, we enforce that, unless the children
350 * are leaves, the two children of a rope node must be distinct.
352 if (left
== right
&& leftRopeTop
) {
355 rightRopeTop
= false;
356 JS_ASSERT(leftLen
= left
->length());
357 JS_ASSERT(rightLen
= right
->length());
358 JS_ASSERT(!left
->isTopNode());
359 JS_ASSERT(!right
->isTopNode());
363 * There are 4 cases, based on whether on whether the left or right is a
364 * rope or non-rope string.
366 JSRopeBufferInfo
*buf
= NULL
;
369 /* Left child is a rope. */
370 JSRopeBufferInfo
*leftBuf
= left
->topNodeBuffer();
372 /* If both children are ropes, steal the larger buffer. */
373 if (JS_UNLIKELY(rightRopeTop
)) {
374 JSRopeBufferInfo
*rightBuf
= right
->topNodeBuffer();
376 /* Put the larger buffer into 'leftBuf'. */
377 if (leftBuf
->capacity
>= rightBuf
->capacity
) {
385 buf
= ObtainRopeBuffer(cx
, true, rightRopeTop
, leftBuf
, length
, left
, right
);
388 } else if (JS_UNLIKELY(rightRopeTop
)) {
389 /* Right child is a rope: steal its buffer if big enough. */
390 JSRopeBufferInfo
*rightBuf
= right
->topNodeBuffer();
392 buf
= ObtainRopeBuffer(cx
, false, true, rightBuf
, length
, left
, right
);
396 /* Neither child is a rope: need to make a new buffer. */
398 size_t allocSize
= RopeAllocSize(length
, &capacity
);
399 buf
= (JSRopeBufferInfo
*) cx
->malloc(allocSize
);
402 buf
->capacity
= capacity
;
405 return FinishConcat(cx
, leftRopeTop
, rightRopeTop
, left
, right
, length
, buf
);
409 JSString::undepend(JSContext
*cx
)
417 n
= dependentLength();
418 size
= (n
+ 1) * sizeof(jschar
);
419 s
= (jschar
*) cx
->malloc(size
);
423 js_strncpy(s
, dependentChars(), n
);
429 JSRuntime
*rt
= cx
->runtime
;
430 JS_RUNTIME_UNMETER(rt
, liveDependentStrings
);
431 JS_RUNTIME_UNMETER(rt
, totalDependentStrings
);
432 JS_LOCK_RUNTIME_VOID(rt
,
433 (rt
->strdepLengthSum
-= (double)n
,
434 rt
->strdepLengthSquaredSum
-= (double)n
* (double)n
));
443 js_MakeStringImmutable(JSContext
*cx
, JSString
*str
)
446 * Flattening a rope may result in a dependent string, so we need to flatten
447 * before undepending the string.
449 str
->ensureNotRope();
450 if (!str
->ensureNotDependent(cx
)) {
451 JS_RUNTIME_METER(cx
->runtime
, badUndependStrings
);
454 str
->flatClearMutable();
459 ArgToRootedString(JSContext
*cx
, uintN argc
, Value
*vp
, uintN arg
)
462 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
465 if (vp
->isObject() && !DefaultValue(cx
, &vp
->toObject(), JSTYPE_STRING
, vp
))
469 if (vp
->isString()) {
470 str
= vp
->toString();
471 } else if (vp
->isBoolean()) {
472 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.booleanAtoms
[
473 (int)vp
->toBoolean()]);
474 } else if (vp
->isNull()) {
475 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
476 } else if (vp
->isUndefined()) {
477 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
480 str
= js_NumberToString(cx
, vp
->toNumber());
488 * Forward declarations for URI encode/decode and helper routines
491 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
494 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
497 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
500 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
502 static const uint32 OVERLONG_UTF8
= UINT32_MAX
;
505 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
);
508 * Contributions from the String class to the set of methods defined for the
509 * global object. escape and unescape used to be defined in the Mocha library,
510 * but as ECMA decided to spec them, they've been moved to the core engine
511 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
512 * characters by unescape.)
516 * Stuff to emulate the old libmocha escape, which took a second argument
517 * giving the type of escape to perform. Retained for compatibility, and
518 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
521 #define URL_XALPHAS ((uint8) 1)
522 #define URL_XPALPHAS ((uint8) 2)
523 #define URL_PATH ((uint8) 4)
525 static const uint8 urlCharType
[256] =
526 /* Bit 0 xalpha -- the alphas
527 * Bit 1 xpalpha -- as xalpha but
528 * converts spaces to plus and plus to %20
529 * Bit 2 ... path -- as xalphas but doesn't escape '/'
531 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
532 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
533 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
534 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
535 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
536 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
537 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
538 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
539 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
542 /* This matches the ECMA escape set when mask is 7 (default.) */
544 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
546 /* See ECMA-262 Edition 3 B.2.1 */
548 js_str_escape(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
, Value
*rval
)
551 size_t i
, ni
, length
, newlength
;
557 const char digits
[] = {'0', '1', '2', '3', '4', '5', '6', '7',
558 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
560 mask
= URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
;
562 if (!ValueToNumber(cx
, argv
[1], &d
))
564 if (!JSDOUBLE_IS_FINITE(d
) ||
565 (mask
= (jsint
)d
) != d
||
566 mask
& ~(URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
))
569 JS_snprintf(numBuf
, sizeof numBuf
, "%lx", (unsigned long) mask
);
570 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
571 JSMSG_BAD_STRING_MASK
, numBuf
);
576 str
= ArgToRootedString(cx
, argc
, argv
- 2, 0);
580 str
->getCharsAndLength(chars
, length
);
583 /* Take a first pass and see how big the result string will need to be. */
584 for (i
= 0; i
< length
; i
++) {
585 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
))
588 if (mask
== URL_XPALPHAS
&& ch
== ' ')
589 continue; /* The character will be encoded as '+' */
590 newlength
+= 2; /* The character will be encoded as %XX */
592 newlength
+= 5; /* The character will be encoded as %uXXXX */
596 * This overflow test works because newlength is incremented by at
597 * most 5 on each iteration.
599 if (newlength
< length
) {
600 js_ReportAllocationOverflow(cx
);
605 if (newlength
>= ~(size_t)0 / sizeof(jschar
)) {
606 js_ReportAllocationOverflow(cx
);
610 newchars
= (jschar
*) cx
->malloc((newlength
+ 1) * sizeof(jschar
));
613 for (i
= 0, ni
= 0; i
< length
; i
++) {
614 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
)) {
616 } else if (ch
< 256) {
617 if (mask
== URL_XPALPHAS
&& ch
== ' ') {
618 newchars
[ni
++] = '+'; /* convert spaces to pluses */
620 newchars
[ni
++] = '%';
621 newchars
[ni
++] = digits
[ch
>> 4];
622 newchars
[ni
++] = digits
[ch
& 0xF];
625 newchars
[ni
++] = '%';
626 newchars
[ni
++] = 'u';
627 newchars
[ni
++] = digits
[ch
>> 12];
628 newchars
[ni
++] = digits
[(ch
& 0xF00) >> 8];
629 newchars
[ni
++] = digits
[(ch
& 0xF0) >> 4];
630 newchars
[ni
++] = digits
[ch
& 0xF];
633 JS_ASSERT(ni
== newlength
);
634 newchars
[newlength
] = 0;
636 str
= js_NewString(cx
, newchars
, newlength
);
641 rval
->setString(str
);
647 str_escape(JSContext
*cx
, uintN argc
, Value
*vp
)
649 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
650 return obj
&& js_str_escape(cx
, obj
, argc
, vp
+ 2, vp
);
653 /* See ECMA-262 Edition 3 B.2.2 */
655 str_unescape(JSContext
*cx
, uintN argc
, Value
*vp
)
658 size_t i
, ni
, length
;
663 str
= ArgToRootedString(cx
, argc
, vp
, 0);
667 str
->getCharsAndLength(chars
, length
);
669 /* Don't bother allocating less space for the new string. */
670 newchars
= (jschar
*) cx
->malloc((length
+ 1) * sizeof(jschar
));
677 if (i
+ 1 < length
&&
678 JS7_ISHEX(chars
[i
]) && JS7_ISHEX(chars
[i
+ 1]))
680 ch
= JS7_UNHEX(chars
[i
]) * 16 + JS7_UNHEX(chars
[i
+ 1]);
682 } else if (i
+ 4 < length
&& chars
[i
] == 'u' &&
683 JS7_ISHEX(chars
[i
+ 1]) && JS7_ISHEX(chars
[i
+ 2]) &&
684 JS7_ISHEX(chars
[i
+ 3]) && JS7_ISHEX(chars
[i
+ 4]))
686 ch
= (((((JS7_UNHEX(chars
[i
+ 1]) << 4)
687 + JS7_UNHEX(chars
[i
+ 2])) << 4)
688 + JS7_UNHEX(chars
[i
+ 3])) << 4)
689 + JS7_UNHEX(chars
[i
+ 4]);
697 str
= js_NewString(cx
, newchars
, ni
);
708 str_uneval(JSContext
*cx
, uintN argc
, Value
*vp
)
712 str
= js_ValueToSource(cx
, argc
!= 0 ? vp
[2] : UndefinedValue());
720 const char js_escape_str
[] = "escape";
721 const char js_unescape_str
[] = "unescape";
723 const char js_uneval_str
[] = "uneval";
725 const char js_decodeURI_str
[] = "decodeURI";
726 const char js_encodeURI_str
[] = "encodeURI";
727 const char js_decodeURIComponent_str
[] = "decodeURIComponent";
728 const char js_encodeURIComponent_str
[] = "encodeURIComponent";
730 static JSFunctionSpec string_functions
[] = {
731 JS_FN(js_escape_str
, str_escape
, 1,0),
732 JS_FN(js_unescape_str
, str_unescape
, 1,0),
734 JS_FN(js_uneval_str
, str_uneval
, 1,0),
736 JS_FN(js_decodeURI_str
, str_decodeURI
, 1,0),
737 JS_FN(js_encodeURI_str
, str_encodeURI
, 1,0),
738 JS_FN(js_decodeURIComponent_str
, str_decodeURI_Component
, 1,0),
739 JS_FN(js_encodeURIComponent_str
, str_encodeURI_Component
, 1,0),
744 jschar js_empty_ucstr
[] = {0};
745 JSSubString js_EmptySubString
= {0, js_empty_ucstr
};
748 str_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
752 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
753 if (obj
->getClass() == &js_StringClass
) {
754 /* Follow ECMA-262 by fetching intrinsic length of our string. */
755 str
= obj
->getPrimitiveThis().toString();
757 /* Preserve compatibility: convert obj to a string primitive. */
758 str
= js_ValueToString(cx
, ObjectValue(*obj
));
763 vp
->setInt32(str
->length());
769 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
772 str_enumerate(JSContext
*cx
, JSObject
*obj
)
774 JSString
*str
, *str1
;
777 str
= obj
->getPrimitiveThis().toString();
779 length
= str
->length();
780 for (i
= 0; i
< length
; i
++) {
781 str1
= js_NewDependentString(cx
, str
, i
, 1);
784 if (!obj
->defineProperty(cx
, INT_TO_JSID(i
), StringValue(str1
),
785 PropertyStub
, PropertyStub
,
786 STRING_ELEMENT_ATTRS
)) {
791 return obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
792 UndefinedValue(), NULL
, NULL
,
793 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_SHARED
);
797 str_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
800 if (!JSID_IS_INT(id
))
803 JSString
*str
= obj
->getPrimitiveThis().toString();
805 jsint slot
= JSID_TO_INT(id
);
806 if ((size_t)slot
< str
->length()) {
807 JSString
*str1
= JSString::getUnitString(cx
, str
, size_t(slot
));
810 if (!obj
->defineProperty(cx
, id
, StringValue(str1
), NULL
, NULL
,
811 STRING_ELEMENT_ATTRS
)) {
819 Class js_StringClass
= {
821 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE
|
822 JSCLASS_HAS_CACHED_PROTO(JSProto_String
),
823 PropertyStub
, /* addProperty */
824 PropertyStub
, /* delProperty */
826 PropertyStub
, /* setProperty */
828 (JSResolveOp
)str_resolve
,
832 #define NORMALIZE_THIS(cx,vp,str) \
834 if (vp[1].isString()) { \
835 str = vp[1].toString(); \
837 str = NormalizeThis(cx, vp); \
844 NormalizeThis(JSContext
*cx
, Value
*vp
)
846 if (vp
[1].isNullOrUndefined() && !ComputeThisFromVp(cx
, vp
))
850 * String.prototype.{toString,toSource,valueOf} throw a TypeError if the
851 * this-argument is not a string or a String object. So those methods use
852 * js::GetPrimitiveThis which provides that behavior.
854 * By standard, the rest of the String methods must ToString the
855 * this-argument rather than throw a TypeError. So those methods use
856 * NORMALIZE_THIS (and thus NormalizeThis) instead.
858 if (vp
[1].isObject()) {
859 JSObject
*obj
= &vp
[1].toObject();
860 if (obj
->getClass() == &js_StringClass
) {
861 vp
[1] = obj
->getPrimitiveThis();
862 return vp
[1].toString();
866 JSString
*str
= js_ValueToString(cx
, vp
[1]);
869 vp
[1].setString(str
);
876 * String.prototype.quote is generic (as are most string methods), unlike
877 * toSource, toString, and valueOf.
880 str_quote(JSContext
*cx
, uintN argc
, Value
*vp
)
884 NORMALIZE_THIS(cx
, vp
, str
);
885 str
= js_QuoteString(cx
, str
, '"');
893 str_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
896 if (!GetPrimitiveThis(cx
, vp
, &str
))
899 str
= js_QuoteString(cx
, str
, '"');
904 size_t j
= JS_snprintf(buf
, sizeof buf
, "(new String(");
908 str
->getCharsAndLength(s
, k
);
910 size_t n
= j
+ k
+ 2;
911 jschar
*t
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
916 for (i
= 0; i
< j
; i
++)
918 for (j
= 0; j
< k
; i
++, j
++)
924 str
= js_NewString(cx
, t
, n
);
933 #endif /* JS_HAS_TOSOURCE */
936 js_str_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
939 if (!GetPrimitiveThis(cx
, vp
, &str
))
946 * Java-like string native methods.
950 SubstringTail(JSContext
*cx
, JSString
*str
, jsdouble length
, jsdouble begin
, jsdouble end
)
954 else if (begin
> length
)
959 else if (end
> length
)
962 /* ECMA emulates old JDK1.0 java.lang.String.substring. */
963 jsdouble tmp
= begin
;
968 return js_NewDependentString(cx
, str
, (size_t)begin
, (size_t)(end
- begin
));
972 str_substring(JSContext
*cx
, uintN argc
, Value
*vp
)
976 jsdouble length
, begin
, end
;
978 NORMALIZE_THIS(cx
, vp
, str
);
980 if (!ValueToNumber(cx
, vp
[2], &d
))
982 length
= str
->length();
983 begin
= js_DoubleToInteger(d
);
984 if (argc
== 1 || vp
[3].isUndefined()) {
987 if (!ValueToNumber(cx
, vp
[3], &d
))
989 end
= js_DoubleToInteger(d
);
992 str
= SubstringTail(cx
, str
, length
, begin
, end
);
1000 JSString
* JS_FASTCALL
1001 js_toLowerCase(JSContext
*cx
, JSString
*str
)
1007 str
->getCharsAndLength(s
, n
);
1008 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
1011 for (i
= 0; i
< n
; i
++)
1012 news
[i
] = JS_TOLOWER(s
[i
]);
1014 str
= js_NewString(cx
, news
, n
);
1023 str_toLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1027 NORMALIZE_THIS(cx
, vp
, str
);
1028 str
= js_toLowerCase(cx
, str
);
1036 str_toLocaleLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1041 * Forcefully ignore the first (or any) argument and return toLowerCase(),
1042 * ECMA has reserved that argument, presumably for defining the locale.
1044 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToLowerCase
) {
1045 NORMALIZE_THIS(cx
, vp
, str
);
1046 return cx
->localeCallbacks
->localeToLowerCase(cx
, str
, Jsvalify(vp
));
1048 return str_toLowerCase(cx
, 0, vp
);
1051 JSString
* JS_FASTCALL
1052 js_toUpperCase(JSContext
*cx
, JSString
*str
)
1058 str
->getCharsAndLength(s
, n
);
1059 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
1062 for (i
= 0; i
< n
; i
++)
1063 news
[i
] = JS_TOUPPER(s
[i
]);
1065 str
= js_NewString(cx
, news
, n
);
1074 str_toUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1078 NORMALIZE_THIS(cx
, vp
, str
);
1079 str
= js_toUpperCase(cx
, str
);
1087 str_toLocaleUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
1092 * Forcefully ignore the first (or any) argument and return toUpperCase(),
1093 * ECMA has reserved that argument, presumably for defining the locale.
1095 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUpperCase
) {
1096 NORMALIZE_THIS(cx
, vp
, str
);
1097 return cx
->localeCallbacks
->localeToUpperCase(cx
, str
, Jsvalify(vp
));
1099 return str_toUpperCase(cx
, 0, vp
);
1103 str_localeCompare(JSContext
*cx
, uintN argc
, Value
*vp
)
1105 JSString
*str
, *thatStr
;
1107 NORMALIZE_THIS(cx
, vp
, str
);
1111 thatStr
= js_ValueToString(cx
, vp
[2]);
1114 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeCompare
) {
1115 vp
[2].setString(thatStr
);
1116 return cx
->localeCallbacks
->localeCompare(cx
, str
, thatStr
, Jsvalify(vp
));
1118 vp
->setInt32(js_CompareStrings(str
, thatStr
));
1124 js_str_charAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1130 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1131 str
= vp
[1].toString();
1132 i
= vp
[2].toInt32();
1133 if ((size_t)i
>= str
->length())
1136 NORMALIZE_THIS(cx
, vp
, str
);
1141 if (!ValueToNumber(cx
, vp
[2], &d
))
1143 d
= js_DoubleToInteger(d
);
1146 if (d
< 0 || str
->length() <= d
)
1151 str
= JSString::getUnitString(cx
, str
, size_t(i
));
1158 vp
->setString(cx
->runtime
->emptyString
);
1163 js_str_charCodeAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1169 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1170 str
= vp
[1].toString();
1171 i
= vp
[2].toInt32();
1172 if ((size_t)i
>= str
->length())
1175 NORMALIZE_THIS(cx
, vp
, str
);
1180 if (!ValueToNumber(cx
, vp
[2], &d
))
1182 d
= js_DoubleToInteger(d
);
1185 if (d
< 0 || str
->length() <= d
)
1190 vp
->setInt32(str
->chars()[i
]);
1194 vp
->setDouble(js_NaN
);
1199 js_BoyerMooreHorspool(const jschar
*text
, jsuint textlen
,
1200 const jschar
*pat
, jsuint patlen
)
1202 uint8 skip
[sBMHCharSetSize
];
1204 JS_ASSERT(0 < patlen
&& patlen
<= sBMHPatLenMax
);
1205 for (jsuint i
= 0; i
< sBMHCharSetSize
; i
++)
1206 skip
[i
] = (uint8
)patlen
;
1207 jsuint m
= patlen
- 1;
1208 for (jsuint i
= 0; i
< m
; i
++) {
1210 if (c
>= sBMHCharSetSize
)
1211 return sBMHBadPattern
;
1212 skip
[c
] = (uint8
)(m
- i
);
1217 k
+= ((c
= text
[k
]) >= sBMHCharSetSize
) ? patlen
: skip
[c
]) {
1218 for (jsuint i
= k
, j
= m
; ; i
--, j
--) {
1219 if (text
[i
] != pat
[j
])
1222 return static_cast<jsint
>(i
); /* safe: max string size */
1229 typedef jsuint Extent
;
1230 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*, jsuint patlen
) {
1231 return (patlen
- 1) * sizeof(jschar
);
1233 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1234 return memcmp(p
, t
, extent
) == 0;
1239 typedef const jschar
*Extent
;
1240 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*pat
, jsuint patlen
) {
1241 return pat
+ patlen
;
1243 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1244 for (; p
!= extent
; ++p
, ++t
) {
1252 template <class InnerMatch
>
1254 UnrolledMatch(const jschar
*text
, jsuint textlen
, const jschar
*pat
, jsuint patlen
)
1256 JS_ASSERT(patlen
> 0 && textlen
> 0);
1257 const jschar
*textend
= text
+ textlen
- (patlen
- 1);
1258 const jschar p0
= *pat
;
1259 const jschar
*const patNext
= pat
+ 1;
1260 const typename
InnerMatch::Extent extent
= InnerMatch::computeExtent(pat
, patlen
);
1263 const jschar
*t
= text
;
1264 switch ((textend
- t
) & 7) {
1265 case 0: if (*t
++ == p0
) { fixup
= 8; goto match
; }
1266 case 7: if (*t
++ == p0
) { fixup
= 7; goto match
; }
1267 case 6: if (*t
++ == p0
) { fixup
= 6; goto match
; }
1268 case 5: if (*t
++ == p0
) { fixup
= 5; goto match
; }
1269 case 4: if (*t
++ == p0
) { fixup
= 4; goto match
; }
1270 case 3: if (*t
++ == p0
) { fixup
= 3; goto match
; }
1271 case 2: if (*t
++ == p0
) { fixup
= 2; goto match
; }
1272 case 1: if (*t
++ == p0
) { fixup
= 1; goto match
; }
1274 while (t
!= textend
) {
1275 if (t
[0] == p0
) { t
+= 1; fixup
= 8; goto match
; }
1276 if (t
[1] == p0
) { t
+= 2; fixup
= 7; goto match
; }
1277 if (t
[2] == p0
) { t
+= 3; fixup
= 6; goto match
; }
1278 if (t
[3] == p0
) { t
+= 4; fixup
= 5; goto match
; }
1279 if (t
[4] == p0
) { t
+= 5; fixup
= 4; goto match
; }
1280 if (t
[5] == p0
) { t
+= 6; fixup
= 3; goto match
; }
1281 if (t
[6] == p0
) { t
+= 7; fixup
= 2; goto match
; }
1282 if (t
[7] == p0
) { t
+= 8; fixup
= 1; goto match
; }
1288 if (!InnerMatch::match(patNext
, t
, extent
))
1290 return t
- text
- 1;
1293 } while (--fixup
> 0);
1298 static JS_ALWAYS_INLINE jsint
1299 StringMatch(const jschar
*text
, jsuint textlen
,
1300 const jschar
*pat
, jsuint patlen
)
1304 if (textlen
< patlen
)
1307 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1309 * Given enough registers, the unrolled loop below is faster than the
1310 * following loop. 32-bit x86 does not have enough registers.
1313 const jschar p0
= *pat
;
1314 for (const jschar
*c
= text
, *end
= text
+ textlen
; c
!= end
; ++c
) {
1323 * If the text or pattern string is short, BMH will be more expensive than
1324 * the basic linear scan due to initialization cost and a more complex loop
1325 * body. While the correct threshold is input-dependent, we can make a few
1326 * conservative observations:
1327 * - When |textlen| is "big enough", the initialization time will be
1328 * proportionally small, so the worst-case slowdown is minimized.
1329 * - When |patlen| is "too small", even the best case for BMH will be
1330 * slower than a simple scan for large |textlen| due to the more complex
1332 * From this, the values for "big enough" and "too small" are determined
1333 * empirically. See bug 526348.
1335 if (textlen
>= 512 && patlen
>= 11 && patlen
<= sBMHPatLenMax
) {
1336 jsint index
= js_BoyerMooreHorspool(text
, textlen
, pat
, patlen
);
1337 if (index
!= sBMHBadPattern
)
1342 * For big patterns with large potential overlap we want the SIMD-optimized
1343 * speed of memcmp. For small patterns, a simple loop is faster.
1345 * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1348 #if !defined(__linux__)
1349 patlen
> 128 ? UnrolledMatch
<MemCmp
>(text
, textlen
, pat
, patlen
)
1352 UnrolledMatch
<ManualCmp
>(text
, textlen
, pat
, patlen
);
1355 static const size_t sRopeMatchThresholdRatioLog2
= 5;
1358 RopeMatch(JSString
*textstr
, const jschar
*pat
, jsuint patlen
)
1360 JS_ASSERT(textstr
->isTopNode());
1364 if (textstr
->length() < patlen
)
1368 * List of leaf nodes in the rope. If we run out of memory when trying to
1369 * append to this list, we can still fall back to StringMatch, so use the
1370 * system allocator so we don't report OOM in that case.
1372 Vector
<JSString
*, 16, SystemAllocPolicy
> strs
;
1375 * We don't want to do rope matching if there is a poor node-to-char ratio,
1376 * since this means spending a lot of time in the match loop below. We also
1377 * need to build the list of leaf nodes. Do both here: iterate over the
1378 * nodes so long as there are not too many.
1380 size_t textstrlen
= textstr
->length();
1381 size_t threshold
= textstrlen
>> sRopeMatchThresholdRatioLog2
;
1382 JSRopeLeafIterator
iter(textstr
);
1383 for (JSString
*str
= iter
.init(); str
; str
= iter
.next()) {
1384 if (threshold
-- == 0 || !strs
.append(str
))
1385 return StringMatch(textstr
->chars(), textstrlen
, pat
, patlen
);
1388 /* Absolute offset from the beginning of the logical string textstr. */
1391 // TODO: consider branching to a simple loop if patlen == 1
1393 for (JSString
**outerp
= strs
.begin(); outerp
!= strs
.end(); ++outerp
) {
1394 /* First try to match without spanning two nodes. */
1395 const jschar
*chars
;
1397 (*outerp
)->getCharsAndLength(chars
, len
);
1398 jsint matchResult
= StringMatch(chars
, len
, pat
, patlen
);
1399 if (matchResult
!= -1)
1400 return pos
+ matchResult
;
1402 /* Test the overlap. */
1403 JSString
**innerp
= outerp
;
1406 * Start searching at the first place where StringMatch wouldn't have
1409 const jschar
*const text
= chars
+ (patlen
> len
? 0 : len
- patlen
+ 1);
1410 const jschar
*const textend
= chars
+ len
;
1411 const jschar p0
= *pat
;
1412 const jschar
*const p1
= pat
+ 1;
1413 const jschar
*const patend
= pat
+ patlen
;
1414 for (const jschar
*t
= text
; t
!= textend
; ) {
1417 const jschar
*ttend
= textend
;
1418 for (const jschar
*pp
= p1
, *tt
= t
; pp
!= patend
; ++pp
, ++tt
) {
1419 while (tt
== ttend
) {
1420 if (++innerp
== strs
.end())
1422 (*innerp
)->getCharsAndEnd(tt
, ttend
);
1425 goto break_continue
;
1429 return pos
+ (t
- chars
) - 1; /* -1 because of *t++ above */
1441 str_indexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1445 NORMALIZE_THIS(cx
, vp
, str
);
1447 JSString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1451 const jschar
*text
= str
->chars();
1452 jsuint textlen
= str
->length();
1453 const jschar
*pat
= patstr
->chars();
1454 jsuint patlen
= patstr
->length();
1458 if (vp
[3].isInt32()) {
1459 jsint i
= vp
[3].toInt32();
1462 } else if (jsuint(i
) > textlen
) {
1472 if (!ValueToNumber(cx
, vp
[3], &d
))
1474 d
= js_DoubleToInteger(d
);
1477 } else if (d
> textlen
) {
1490 jsint match
= StringMatch(text
, textlen
, pat
, patlen
);
1491 vp
->setInt32((match
== -1) ? -1 : start
+ match
);
1496 str_lastIndexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1498 JSString
*str
, *str2
;
1499 const jschar
*text
, *pat
;
1500 jsint i
, j
, textlen
, patlen
;
1503 NORMALIZE_THIS(cx
, vp
, str
);
1504 text
= str
->chars();
1505 textlen
= (jsint
) str
->length();
1507 if (argc
!= 0 && vp
[2].isString()) {
1508 str2
= vp
[2].toString();
1510 str2
= ArgToRootedString(cx
, argc
, vp
, 0);
1514 pat
= str2
->chars();
1515 patlen
= (jsint
) str2
->length();
1517 i
= textlen
- patlen
; // Start searching here
1524 if (vp
[3].isInt32()) {
1525 j
= vp
[3].toInt32();
1531 if (!ValueToNumber(cx
, vp
[3], &d
))
1533 if (!JSDOUBLE_IS_NaN(d
)) {
1534 d
= js_DoubleToInteger(d
);
1548 const jschar
*t
= text
+ i
;
1549 const jschar
*textend
= text
- 1;
1550 const jschar p0
= *pat
;
1551 const jschar
*patNext
= pat
+ 1;
1552 const jschar
*patEnd
= pat
+ patlen
;
1554 for (; t
!= textend
; --t
) {
1556 const jschar
*t1
= t
+ 1;
1557 for (const jschar
*p1
= patNext
; p1
!= patEnd
; ++p1
, ++t1
) {
1559 goto break_continue
;
1561 vp
->setInt32(t
- text
);
1572 js_TrimString(JSContext
*cx
, Value
*vp
, JSBool trimLeft
, JSBool trimRight
)
1575 const jschar
*chars
;
1576 size_t length
, begin
, end
;
1578 NORMALIZE_THIS(cx
, vp
, str
);
1579 str
->getCharsAndLength(chars
, length
);
1584 while (begin
< length
&& JS_ISSPACE(chars
[begin
]))
1589 while (end
> begin
&& JS_ISSPACE(chars
[end
-1]))
1593 str
= js_NewDependentString(cx
, str
, begin
, end
- begin
);
1602 str_trim(JSContext
*cx
, uintN argc
, Value
*vp
)
1604 return js_TrimString(cx
, vp
, JS_TRUE
, JS_TRUE
);
1608 str_trimLeft(JSContext
*cx
, uintN argc
, Value
*vp
)
1610 return js_TrimString(cx
, vp
, JS_TRUE
, JS_FALSE
);
1614 str_trimRight(JSContext
*cx
, uintN argc
, Value
*vp
)
1616 return js_TrimString(cx
, vp
, JS_FALSE
, JS_TRUE
);
1620 * Perl-inspired string functions.
1623 /* Result of a successfully performed flat match. */
1631 friend class RegExpGuard
;
1634 FlatMatch() : patstr(NULL
) {} /* Old GCC wants this initialization. */
1635 JSString
*pattern() const { return patstr
; }
1636 size_t patternLength() const { return patlen
; }
1639 * @note The match is -1 when the match is performed successfully,
1640 * but no match is found.
1642 int32
match() const { return match_
; }
1645 /* A regexp and optional associated object. */
1651 explicit RegExpPair(RegExp
*re
): re_(re
) {}
1652 friend class RegExpGuard
;
1655 /* @note May be null. */
1656 JSObject
*reobj() const { return reobj_
; }
1657 RegExp
&re() const { JS_ASSERT(re_
); return *re_
; }
1661 * RegExpGuard factors logic out of String regexp operations.
1663 * @param optarg Indicates in which argument position RegExp
1664 * flags will be found, if present. This is a Mozilla
1665 * extension and not part of any ECMA spec.
1669 RegExpGuard(const RegExpGuard
&);
1670 void operator=(const RegExpGuard
&);
1677 * Upper bound on the number of characters we are willing to potentially
1678 * waste on searching for RegExp meta-characters.
1680 static const size_t MAX_FLAT_PAT_LEN
= 256;
1682 static JSString
*flattenPattern(JSContext
*cx
, JSString
*patstr
) {
1683 JSCharBuffer
cb(cx
);
1684 if (!cb
.reserve(patstr
->length()))
1687 static const jschar ESCAPE_CHAR
= '\\';
1688 const jschar
*chars
= patstr
->chars();
1689 size_t len
= patstr
->length();
1690 for (const jschar
*it
= chars
; it
!= chars
+ len
; ++it
) {
1691 if (RegExp::isMetaChar(*it
)) {
1692 if (!cb
.append(ESCAPE_CHAR
) || !cb
.append(*it
))
1695 if (!cb
.append(*it
))
1699 return js_NewStringFromCharBuffer(cx
, cb
);
1703 explicit RegExpGuard(JSContext
*cx
) : cx(cx
), rep(NULL
) {}
1707 rep
.re_
->decref(cx
);
1710 /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1712 init(uintN argc
, Value
*vp
)
1714 if (argc
!= 0 && VALUE_IS_REGEXP(cx
, vp
[2])) {
1715 rep
.reobj_
= &vp
[2].toObject();
1716 rep
.re_
= RegExp::extractFrom(rep
.reobj_
);
1717 rep
.re_
->incref(cx
);
1719 fm
.patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1727 * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1728 * pattern string, or a lengthy pattern string can thwart this process.
1730 * @param checkMetaChars Look for regexp metachars in the pattern string.
1731 * @return Whether flat matching could be used.
1734 tryFlatMatch(JSString
*textstr
, uintN optarg
, uintN argc
, bool checkMetaChars
= true)
1739 fm
.patstr
->getCharsAndLength(fm
.pat
, fm
.patlen
);
1744 if (checkMetaChars
&&
1745 (fm
.patlen
> MAX_FLAT_PAT_LEN
|| RegExp::hasMetaChars(fm
.pat
, fm
.patlen
))) {
1750 * textstr could be a rope, so we want to avoid flattening it for as
1753 if (textstr
->isTopNode()) {
1754 fm
.match_
= RopeMatch(textstr
, fm
.pat
, fm
.patlen
);
1758 textstr
->getCharsAndLength(text
, textlen
);
1759 fm
.match_
= StringMatch(text
, textlen
, fm
.pat
, fm
.patlen
);
1764 /* If the pattern is not already a regular expression, make it so. */
1766 normalizeRegExp(bool flat
, uintN optarg
, uintN argc
, Value
*vp
)
1768 /* If we don't have a RegExp, build RegExp from pattern string. */
1773 if (optarg
< argc
) {
1774 opt
= js_ValueToString(cx
, vp
[2 + optarg
]);
1783 patstr
= flattenPattern(cx
, fm
.patstr
);
1791 rep
.re_
= RegExp::createFlagged(cx
, patstr
, opt
);
1799 bool hasRegExpPair() const { return rep
.re_
; }
1803 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1804 static JS_ALWAYS_INLINE
bool
1805 Matched(bool test
, const Value
&v
)
1807 return test
? v
.isTrue() : !v
.isNull();
1810 typedef bool (*DoMatchCallback
)(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *data
);
1813 * BitOR-ing these flags allows the DoMatch caller to control when how the
1814 * RegExp engine is called and when callbacks are fired.
1816 enum MatchControlFlags
{
1817 TEST_GLOBAL_BIT
= 0x1, /* use RegExp.test for global regexps */
1818 TEST_SINGLE_BIT
= 0x2, /* use RegExp.test for non-global regexps */
1819 CALLBACK_ON_SINGLE_BIT
= 0x4, /* fire callback on non-global match */
1821 MATCH_ARGS
= TEST_GLOBAL_BIT
,
1822 MATCHALL_ARGS
= CALLBACK_ON_SINGLE_BIT
,
1823 REPLACE_ARGS
= TEST_GLOBAL_BIT
| TEST_SINGLE_BIT
| CALLBACK_ON_SINGLE_BIT
1826 /* Factor out looping and matching logic. */
1828 DoMatch(JSContext
*cx
, RegExpStatics
*res
, Value
*vp
, JSString
*str
, const RegExpPair
&rep
,
1829 DoMatchCallback callback
, void *data
, MatchControlFlags flags
)
1831 RegExp
&re
= rep
.re();
1833 /* global matching ('g') */
1834 bool testGlobal
= flags
& TEST_GLOBAL_BIT
;
1836 rep
.reobj()->zeroRegExpLastIndex();
1837 for (size_t count
= 0, i
= 0, length
= str
->length(); i
<= length
; ++count
) {
1838 if (!re
.execute(cx
, res
, str
, &i
, testGlobal
, vp
))
1840 if (!Matched(testGlobal
, *vp
))
1842 if (!callback(cx
, res
, count
, data
))
1844 if (!res
->matched())
1849 bool testSingle
= !!(flags
& TEST_SINGLE_BIT
),
1850 callbackOnSingle
= !!(flags
& CALLBACK_ON_SINGLE_BIT
);
1852 if (!re
.execute(cx
, res
, str
, &i
, testSingle
, vp
))
1854 if (callbackOnSingle
&& Matched(testSingle
, *vp
) && !callback(cx
, res
, 0, data
))
1861 BuildFlatMatchArray(JSContext
*cx
, JSString
*textstr
, const FlatMatch
&fm
, Value
*vp
)
1863 if (fm
.match() < 0) {
1868 /* For this non-global match, produce a RegExp.exec-style array. */
1869 JSObject
*obj
= js_NewSlowArrayObject(cx
);
1872 vp
->setObject(*obj
);
1874 return obj
->defineProperty(cx
, INT_TO_JSID(0), StringValue(fm
.pattern())) &&
1875 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.indexAtom
),
1876 Int32Value(fm
.match())) &&
1877 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.inputAtom
),
1878 StringValue(textstr
));
1881 typedef JSObject
**MatchArgType
;
1884 * DoMatch will only callback on global matches, hence this function builds
1885 * only the "array of matches" returned by match on global regexps.
1888 MatchCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
1890 JS_ASSERT(count
<= JSID_INT_MAX
); /* by max string length */
1892 JSObject
*&arrayobj
= *static_cast<MatchArgType
>(p
);
1894 arrayobj
= js_NewArrayObject(cx
, 0, NULL
);
1900 if (!res
->createLastMatch(cx
, &v
))
1903 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
1904 return !!arrayobj
->setProperty(cx
, INT_TO_JSID(count
), &v
, false);
1908 str_match(JSContext
*cx
, uintN argc
, Value
*vp
)
1911 NORMALIZE_THIS(cx
, vp
, str
);
1914 if (!g
.init(argc
, vp
))
1916 if (const FlatMatch
*fm
= g
.tryFlatMatch(str
, 1, argc
))
1917 return BuildFlatMatchArray(cx
, str
, *fm
, vp
);
1919 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1923 AutoObjectRooter
array(cx
);
1924 MatchArgType arg
= array
.addr();
1925 RegExpStatics
*res
= cx
->regExpStatics();
1926 if (!DoMatch(cx
, res
, vp
, str
, *rep
, MatchCallback
, arg
, MATCH_ARGS
))
1929 /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1930 if (rep
->re().global())
1931 vp
->setObjectOrNull(array
.object());
1936 str_search(JSContext
*cx
, uintN argc
, Value
*vp
)
1939 NORMALIZE_THIS(cx
, vp
, str
);
1942 if (!g
.init(argc
, vp
))
1944 if (const FlatMatch
*fm
= g
.tryFlatMatch(str
, 1, argc
)) {
1945 vp
->setInt32(fm
->match());
1948 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1952 RegExpStatics
*res
= cx
->regExpStatics();
1954 if (!rep
->re().execute(cx
, res
, str
, &i
, true, vp
))
1958 vp
->setInt32(res
->matchStart());
1966 ReplaceData(JSContext
*cx
)
1970 JSString
*str
; /* 'this' parameter object as a string */
1971 RegExpGuard g
; /* regexp parameter object and private data */
1972 JSObject
*lambda
; /* replacement function object or null */
1973 JSObject
*elembase
; /* object for function(a){return b[a]} replace */
1974 JSString
*repstr
; /* replacement string */
1975 jschar
*dollar
; /* null or pointer to first $ in repstr */
1976 jschar
*dollarEnd
; /* limit pointer for js_strchr_limit */
1977 jsint index
; /* index in result of next replacement */
1978 jsint leftIndex
; /* left context index in str->chars */
1979 JSSubString dollarStr
; /* for "$$" InterpretDollar result */
1980 bool calledBack
; /* record whether callback has been called */
1981 InvokeSessionGuard session
; /* arguments for repeated lambda Invoke call */
1982 InvokeArgsGuard singleShot
; /* arguments for single lambda Invoke call */
1983 JSCharBuffer cb
; /* buffer built during DoMatch */
1987 InterpretDollar(JSContext
*cx
, RegExpStatics
*res
, jschar
*dp
, jschar
*ep
, ReplaceData
&rdata
,
1988 JSSubString
*out
, size_t *skip
)
1990 JS_ASSERT(*dp
== '$');
1992 /* If there is only a dollar, bail now */
1996 /* Interpret all Perl match-induced dollar variables. */
1998 if (JS7_ISDEC(dc
)) {
1999 /* ECMA-262 Edition 3: 1-9 or 01-99 */
2000 uintN num
= JS7_UNDEC(dc
);
2001 if (num
> res
->getParenCount())
2004 jschar
*cp
= dp
+ 2;
2005 if (cp
< ep
&& (dc
= *cp
, JS7_ISDEC(dc
))) {
2006 uintN tmp
= 10 * num
+ JS7_UNDEC(dc
);
2007 if (tmp
<= res
->getParenCount()) {
2015 /* Adjust num from 1 $n-origin to 0 array-index-origin. */
2018 if (num
< res
->getParenCount())
2019 res
->getParen(num
, out
);
2021 *out
= js_EmptySubString
;
2028 rdata
.dollarStr
.chars
= dp
;
2029 rdata
.dollarStr
.length
= 1;
2030 *out
= rdata
.dollarStr
;
2033 res
->getLastMatch(out
);
2036 res
->getLastParen(out
);
2039 res
->getLeftContext(out
);
2042 res
->getRightContext(out
);
2049 FindReplaceLength(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, size_t *sizep
)
2051 JSObject
*base
= rdata
.elembase
;
2054 * The base object is used when replace was passed a lambda which looks like
2055 * 'function(a) { return b[a]; }' for the base object b. b will not change
2056 * in the course of the replace unless we end up making a scripted call due
2057 * to accessing a scripted getter or a value with a scripted toString.
2059 JS_ASSERT(rdata
.lambda
);
2060 JS_ASSERT(!base
->getOps()->lookupProperty
);
2061 JS_ASSERT(!base
->getOps()->getProperty
);
2064 if (!res
->createLastMatch(cx
, &match
))
2066 JSString
*str
= match
.toString();
2069 if (str
->isAtomized()) {
2070 atom
= STRING_TO_ATOM(str
);
2072 atom
= js_AtomizeString(cx
, str
, 0);
2076 jsid id
= ATOM_TO_JSID(atom
);
2079 JSProperty
*prop
= NULL
;
2080 if (js_LookupPropertyWithFlags(cx
, base
, id
, JSRESOLVE_QUALIFIED
, &holder
, &prop
) < 0)
2083 /* Only handle the case where the property exists and is on this object. */
2084 if (prop
&& holder
== base
) {
2085 Shape
*shape
= (Shape
*) prop
;
2086 if (shape
->slot
!= SHAPE_INVALID_SLOT
&& shape
->hasDefaultGetter()) {
2087 Value value
= base
->getSlot(shape
->slot
);
2088 if (value
.isString()) {
2089 rdata
.repstr
= value
.toString();
2090 *sizep
= rdata
.repstr
->length();
2097 * Couldn't handle this property, fall through and despecialize to the
2098 * general lambda case.
2100 rdata
.elembase
= NULL
;
2103 JSObject
*lambda
= rdata
.lambda
;
2106 * In the lambda case, not only do we find the replacement string's
2107 * length, we compute repstr and return it via rdata for use within
2108 * DoReplace. The lambda is called with arguments ($&, $1, $2, ...,
2109 * index, input), i.e., all the properties of a regexp match array.
2110 * For $&, etc., we must create string jsvals from cx->regExpStatics.
2111 * We grab up stack space to keep the newborn strings GC-rooted.
2113 uintN p
= res
->getParenCount();
2114 uintN argc
= 1 + p
+ 2;
2116 InvokeSessionGuard
&session
= rdata
.session
;
2117 if (!session
.started()) {
2118 Value lambdav
= ObjectValue(*lambda
);
2119 if (!session
.start(cx
, lambdav
, UndefinedValue(), argc
))
2123 PreserveRegExpStatics
staticsGuard(res
);
2124 if (!staticsGuard
.init(cx
))
2127 /* Push $&, $1, $2, ... */
2129 if (!res
->createLastMatch(cx
, &session
[argi
++]))
2132 for (size_t i
= 0; i
< res
->getParenCount(); ++i
) {
2133 if (!res
->createParen(cx
, i
, &session
[argi
++]))
2137 /* Push match index and input string. */
2138 session
[argi
++].setInt32(res
->matchStart());
2139 session
[argi
].setString(rdata
.str
);
2141 if (!session
.invoke(cx
))
2144 /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2145 rdata
.repstr
= ValueToString_TestForStringInline(cx
, session
.rval());
2149 *sizep
= rdata
.repstr
->length();
2153 JSString
*repstr
= rdata
.repstr
;
2154 size_t replen
= repstr
->length();
2155 for (jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2158 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2159 replen
+= sub
.length
- skip
;
2170 DoReplace(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, jschar
*chars
)
2172 JSString
*repstr
= rdata
.repstr
;
2174 jschar
*bp
= cp
= repstr
->chars();
2175 for (jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2176 size_t len
= dp
- cp
;
2177 js_strncpy(chars
, cp
, len
);
2183 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2185 js_strncpy(chars
, sub
.chars
, len
);
2193 js_strncpy(chars
, cp
, repstr
->length() - (cp
- bp
));
2197 ReplaceCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
2199 ReplaceData
&rdata
= *static_cast<ReplaceData
*>(p
);
2201 rdata
.calledBack
= true;
2202 JSString
*str
= rdata
.str
;
2203 size_t leftoff
= rdata
.leftIndex
;
2204 const jschar
*left
= str
->chars() + leftoff
;
2205 size_t leftlen
= res
->matchStart() - leftoff
;
2206 rdata
.leftIndex
= res
->matchLimit();
2208 size_t replen
= 0; /* silence 'unused' warning */
2209 if (!FindReplaceLength(cx
, res
, rdata
, &replen
))
2212 size_t growth
= leftlen
+ replen
;
2213 if (!rdata
.cb
.growByUninitialized(growth
))
2216 jschar
*chars
= rdata
.cb
.begin() + rdata
.index
;
2217 rdata
.index
+= growth
;
2218 js_strncpy(chars
, left
, leftlen
);
2220 DoReplace(cx
, res
, rdata
, chars
);
2225 BuildFlatReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2226 const FlatMatch
&fm
, Value
*vp
)
2228 JSRopeBuilder
builder(cx
);
2229 size_t match
= fm
.match(); /* Avoid signed/unsigned warnings. */
2230 size_t matchEnd
= match
+ fm
.patternLength();
2232 if (textstr
->isTopNode()) {
2234 * If we are replacing over a rope, avoid flattening it by iterating
2235 * through it, building a new rope.
2237 JSRopeLeafIterator
iter(textstr
);
2239 for (JSString
*str
= iter
.init(); str
; str
= iter
.next()) {
2240 size_t len
= str
->length();
2241 size_t strEnd
= pos
+ len
;
2242 if (pos
< matchEnd
&& strEnd
> match
) {
2244 * We need to special-case any part of the rope that overlaps
2245 * with the replacement string.
2249 * If this part of the rope overlaps with the left side of
2250 * the pattern, then it must be the only one to overlap with
2251 * the first character in the pattern, so we include the
2252 * replacement string here.
2254 JSString
*leftSide
= js_NewDependentString(cx
, str
, 0, match
- pos
);
2256 !builder
.append(leftSide
) ||
2257 !builder
.append(repstr
)) {
2263 * If str runs off the end of the matched string, append the
2266 if (strEnd
> matchEnd
) {
2267 JSString
*rightSide
= js_NewDependentString(cx
, str
, matchEnd
- pos
,
2269 if (!rightSide
|| !builder
.append(rightSide
))
2273 if (!builder
.append(str
))
2276 pos
+= str
->length();
2279 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, match
);
2282 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, match
+ fm
.patternLength(),
2283 textstr
->length() - match
- fm
.patternLength());
2285 !builder
.append(leftSide
) ||
2286 !builder
.append(repstr
) ||
2287 !builder
.append(rightSide
)) {
2292 vp
->setString(builder
.getStr());
2297 * Perform a linear-scan dollar substitution on the replacement text,
2298 * constructing a result string that looks like:
2300 * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2303 BuildDollarReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2304 const jschar
*firstDollar
, const FlatMatch
&fm
, Value
*vp
)
2306 JS_ASSERT(repstr
->chars() <= firstDollar
&& firstDollar
< repstr
->chars() + repstr
->length());
2307 size_t matchStart
= fm
.match();
2308 size_t matchLimit
= matchStart
+ fm
.patternLength();
2309 JSCharBuffer
newReplaceChars(cx
);
2314 * len(newstr) >= len(orig) - len(match) + len(replacement)
2316 * Note that dollar vars _could_ make the resulting text smaller than this.
2318 if (!newReplaceChars
.reserve(textstr
->length() - fm
.patternLength() + repstr
->length()))
2321 /* Move the pre-dollar chunk in bulk. */
2322 JS_ALWAYS_TRUE(newReplaceChars
.append(repstr
->chars(), firstDollar
));
2324 /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2325 #define ENSURE(__cond) if (!(__cond)) return false;
2326 const jschar
*repstrLimit
= repstr
->chars() + repstr
->length();
2327 for (const jschar
*it
= firstDollar
; it
< repstrLimit
; ++it
) {
2328 if (*it
!= '$' || it
== repstrLimit
- 1) {
2329 ENSURE(newReplaceChars
.append(*it
));
2333 switch (*(it
+ 1)) {
2334 case '$': /* Eat one of the dollars. */
2335 ENSURE(newReplaceChars
.append(*it
));
2338 ENSURE(newReplaceChars
.append(textstr
->chars() + matchStart
,
2339 textstr
->chars() + matchLimit
));
2342 ENSURE(newReplaceChars
.append(textstr
->chars(), textstr
->chars() + matchStart
));
2345 ENSURE(newReplaceChars
.append(textstr
->chars() + matchLimit
,
2346 textstr
->chars() + textstr
->length()));
2348 default: /* The dollar we saw was not special (no matter what its mother told it). */
2349 ENSURE(newReplaceChars
.append(*it
));
2352 ++it
; /* We always eat an extra char in the above switch. */
2355 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, matchStart
);
2358 JSString
*newReplace
= js_NewStringFromCharBuffer(cx
, newReplaceChars
);
2361 JS_ASSERT(textstr
->length() >= matchLimit
);
2362 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, matchLimit
,
2363 textstr
->length() - matchLimit
);
2366 JSRopeBuilder
builder(cx
);
2367 ENSURE(builder
.append(leftSide
) &&
2368 builder
.append(newReplace
) &&
2369 builder
.append(rightSide
));
2372 vp
->setString(builder
.getStr());
2377 str_replace_regexp(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
)
2379 const RegExpPair
*rep
= rdata
.g
.normalizeRegExp(true, 2, argc
, vp
);
2384 rdata
.leftIndex
= 0;
2385 rdata
.calledBack
= false;
2387 RegExpStatics
*res
= cx
->regExpStatics();
2388 if (!DoMatch(cx
, res
, vp
, rdata
.str
, *rep
, ReplaceCallback
, &rdata
, REPLACE_ARGS
))
2391 if (!rdata
.calledBack
) {
2392 /* Didn't match, so the string is unmodified. */
2393 vp
->setString(rdata
.str
);
2398 res
->getRightContext(&sub
);
2399 if (!rdata
.cb
.append(sub
.chars
, sub
.length
))
2402 JSString
*retstr
= js_NewStringFromCharBuffer(cx
, rdata
.cb
);
2406 vp
->setString(retstr
);
2411 str_replace_flat_lambda(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
,
2412 const FlatMatch
&fm
)
2414 JS_ASSERT(fm
.match() >= 0);
2417 JSString
*matchStr
= js_NewDependentString(cx
, rdata
.str
, fm
.match(), fm
.patternLength());
2421 /* lambda(matchStr, matchStart, textstr) */
2422 static const uint32 lambdaArgc
= 3;
2423 if (!cx
->stack().pushInvokeArgs(cx
, lambdaArgc
, &rdata
.singleShot
))
2426 CallArgs
&args
= rdata
.singleShot
;
2427 args
.callee().setObject(*rdata
.lambda
);
2428 args
.thisv().setUndefined();
2430 Value
*sp
= args
.argv();
2431 sp
[0].setString(matchStr
);
2432 sp
[1].setInt32(fm
.match());
2433 sp
[2].setString(rdata
.str
);
2435 if (!Invoke(cx
, rdata
.singleShot
, 0))
2438 JSString
*repstr
= js_ValueToString(cx
, args
.rval());
2442 JSString
*leftSide
= js_NewDependentString(cx
, rdata
.str
, 0, fm
.match());
2446 size_t matchLimit
= fm
.match() + fm
.patternLength();
2447 JSString
*rightSide
= js_NewDependentString(cx
, rdata
.str
, matchLimit
,
2448 rdata
.str
->length() - matchLimit
);
2452 JSRopeBuilder
builder(cx
);
2453 if (!(builder
.append(leftSide
) &&
2454 builder
.append(repstr
) &&
2455 builder
.append(rightSide
))) {
2459 vp
->setString(builder
.getStr());
2464 js::str_replace(JSContext
*cx
, uintN argc
, Value
*vp
)
2466 ReplaceData
rdata(cx
);
2467 NORMALIZE_THIS(cx
, vp
, rdata
.str
);
2468 static const uint32 optarg
= 2;
2470 /* Extract replacement string/function. */
2471 if (argc
>= optarg
&& js_IsCallable(vp
[3])) {
2472 rdata
.lambda
= &vp
[3].toObject();
2473 rdata
.elembase
= NULL
;
2474 rdata
.repstr
= NULL
;
2475 rdata
.dollar
= rdata
.dollarEnd
= NULL
;
2477 if (rdata
.lambda
->isFunction()) {
2478 JSFunction
*fun
= rdata
.lambda
->getFunctionPrivate();
2479 if (fun
->isInterpreted()) {
2481 * Pattern match the script to check if it is is indexing into a
2482 * particular object, e.g. 'function(a) { return b[a]; }'. Avoid
2483 * calling the script in such cases, which are used by javascript
2484 * packers (particularly the popular Dean Edwards packer) to efficiently
2485 * encode large scripts. We only handle the code patterns generated
2486 * by such packers here.
2488 JSScript
*script
= fun
->u
.i
.script
;
2489 jsbytecode
*pc
= script
->code
;
2491 Value table
= UndefinedValue();
2492 if (JSOp(*pc
) == JSOP_GETFCSLOT
) {
2493 table
= rdata
.lambda
->getFlatClosureUpvar(GET_UINT16(pc
));
2494 pc
+= JSOP_GETFCSLOT_LENGTH
;
2497 if (table
.isObject() &&
2498 JSOp(*pc
) == JSOP_GETARG
&& GET_SLOTNO(pc
) == 0 &&
2499 JSOp(*(pc
+ JSOP_GETARG_LENGTH
)) == JSOP_GETELEM
&&
2500 JSOp(*(pc
+ JSOP_GETARG_LENGTH
+ JSOP_GETELEM_LENGTH
)) == JSOP_RETURN
) {
2501 Class
*clasp
= table
.toObject().getClass();
2502 if (clasp
->isNative() &&
2503 !clasp
->ops
.lookupProperty
&&
2504 !clasp
->ops
.getProperty
) {
2505 rdata
.elembase
= &table
.toObject();
2511 rdata
.lambda
= NULL
;
2512 rdata
.elembase
= NULL
;
2513 rdata
.repstr
= ArgToRootedString(cx
, argc
, vp
, 1);
2517 /* We're about to store pointers into the middle of our string. */
2518 if (!js_MakeStringImmutable(cx
, rdata
.repstr
))
2520 rdata
.dollarEnd
= rdata
.repstr
->chars() + rdata
.repstr
->length();
2521 rdata
.dollar
= js_strchr_limit(rdata
.repstr
->chars(), '$',
2525 if (!rdata
.g
.init(argc
, vp
))
2529 * Unlike its |String.prototype| brethren, |replace| doesn't convert
2530 * its input to a regular expression. (Even if it contains metachars.)
2532 * However, if the user invokes our (non-standard) |flags| argument
2533 * extension then we revert to creating a regular expression. Note that
2534 * this is observable behavior through the side-effect mutation of the
2538 const FlatMatch
*fm
= rdata
.g
.tryFlatMatch(rdata
.str
, optarg
, argc
, false);
2540 JS_ASSERT_IF(!rdata
.g
.hasRegExpPair(), argc
> optarg
);
2541 return str_replace_regexp(cx
, argc
, vp
, rdata
);
2544 if (fm
->match() < 0) {
2545 vp
->setString(rdata
.str
);
2550 return str_replace_flat_lambda(cx
, argc
, vp
, rdata
, *fm
);
2553 * Note: we could optimize the text.length == pattern.length case if we wanted,
2554 * even in the presence of dollar metachars.
2557 return BuildDollarReplacement(cx
, rdata
.str
, rdata
.repstr
, rdata
.dollar
, *fm
, vp
);
2559 return BuildFlatReplacement(cx
, rdata
.str
, rdata
.repstr
, *fm
, vp
);
2563 * Subroutine used by str_split to find the next split point in str, starting
2564 * at offset *ip and looking either for the separator substring given by sep, or
2565 * for the next re match. In the re case, return the matched separator in *sep,
2566 * and the possibly updated offset in *ip.
2568 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2569 * separator occurrence if found, or str->length if no separator is found.
2572 find_split(JSContext
*cx
, RegExpStatics
*res
, JSString
*str
, js::RegExp
*re
, jsint
*ip
,
2580 * Stop if past end of string. If at end of string, we will compare the
2581 * null char stored there (by js_NewString*) to sep->chars[j] in the while
2582 * loop at the end of this function, so that
2584 * "ab,".split(',') => ["ab", ""]
2586 * and the resulting array converts back to the string "ab," for symmetry.
2587 * However, we ape Perl and do this only if there is a sufficiently large
2588 * limit argument (see str_split).
2591 length
= str
->length();
2592 if ((size_t)i
> length
)
2595 chars
= str
->chars();
2598 * Match a regular expression against the separator at or above index i.
2599 * Call js_ExecuteRegExp with true for the test argument. On successful
2600 * match, get the separator from cx->regExpStatics.lastMatch.
2607 /* JS1.2 deviated from Perl by never matching at end of string. */
2609 if (!re
->execute(cx
, res
, str
, &index
, true, &rval
))
2611 if (!rval
.isTrue()) {
2612 /* Mismatch: ensure our caller advances i past end of string. */
2618 res
->getLastMatch(sep
);
2619 if (sep
->length
== 0) {
2621 * Empty string match: never split on an empty match at the start
2622 * of a find_split cycle. Same rule as for an empty global match
2627 * "Bump-along" to avoid sticking at an empty match, but don't
2628 * bump past end of string -- our caller must do that by adding
2629 * sep->length to our return value.
2631 if ((size_t)i
== length
)
2636 if ((size_t)i
== length
) {
2638 * If there was a trivial zero-length match at the end of the
2639 * split, then we shouldn't output the matched string at the end
2640 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2645 JS_ASSERT((size_t)i
>= sep
->length
);
2646 return i
- sep
->length
;
2650 * Special case: if sep is the empty string, split str into one character
2651 * substrings. Let our caller worry about whether to split once at end of
2652 * string into an empty substring.
2654 if (sep
->length
== 0)
2655 return ((size_t)i
== length
) ? -1 : i
+ 1;
2658 * Now that we know sep is non-empty, search starting at i in str for an
2659 * occurrence of all of sep's chars. If we find them, return the index of
2660 * the first separator char. Otherwise, return length.
2662 jsint match
= StringMatch(chars
+ i
, length
- i
, sep
->chars
, sep
->length
);
2663 return match
== -1 ? length
: match
+ i
;
2667 str_split(JSContext
*cx
, uintN argc
, Value
*vp
)
2670 NORMALIZE_THIS(cx
, vp
, str
);
2673 Value v
= StringValue(str
);
2674 JSObject
*aobj
= js_NewArrayObject(cx
, 1, &v
);
2677 vp
->setObject(*aobj
);
2682 JSSubString
*sep
, tmp
;
2683 if (VALUE_IS_REGEXP(cx
, vp
[2])) {
2684 re
= static_cast<RegExp
*>(vp
[2].toObject().getPrivate());
2687 /* Set a magic value so we can detect a successful re match. */
2691 JSString
*str2
= js_ValueToString(cx
, vp
[2]);
2694 vp
[2].setString(str2
);
2697 * Point sep at a local copy of str2's header because find_split
2698 * will modify sep->length.
2700 str2
->getCharsAndLength(tmp
.chars
, tmp
.length
);
2705 /* Use the second argument as the split limit, if given. */
2706 uint32 limit
= 0; /* Avoid warning. */
2707 bool limited
= (argc
> 1) && !vp
[3].isUndefined();
2710 if (!ValueToNumber(cx
, vp
[3], &d
))
2713 /* Clamp limit between 0 and 1 + string length. */
2714 limit
= js_DoubleToECMAUint32(d
);
2715 if (limit
> str
->length())
2716 limit
= 1 + str
->length();
2719 AutoValueVector
splits(cx
);
2721 RegExpStatics
*res
= cx
->regExpStatics();
2724 while ((j
= find_split(cx
, res
, str
, re
, &i
, sep
)) >= 0) {
2725 if (limited
&& len
>= limit
)
2728 JSString
*sub
= js_NewDependentString(cx
, str
, i
, size_t(j
- i
));
2729 if (!sub
|| !splits
.append(StringValue(sub
)))
2734 * Imitate perl's feature of including parenthesized substrings that
2735 * matched part of the delimiter in the new array, after the split
2736 * substring that was delimited.
2738 if (re
&& sep
->chars
) {
2739 for (uintN num
= 0; num
< res
->getParenCount(); num
++) {
2740 if (limited
&& len
>= limit
)
2743 res
->getParen(num
, &parsub
);
2744 sub
= js_NewStringCopyN(cx
, parsub
.chars
, parsub
.length
);
2745 if (!sub
|| !splits
.append(StringValue(sub
)))
2751 i
= j
+ sep
->length
;
2757 JSObject
*aobj
= js_NewArrayObject(cx
, splits
.length(), splits
.begin());
2760 vp
->setObject(*aobj
);
2764 #if JS_HAS_PERL_SUBSTR
2766 str_substr(JSContext
*cx
, uintN argc
, Value
*vp
)
2770 jsdouble length
, begin
, end
;
2772 NORMALIZE_THIS(cx
, vp
, str
);
2774 if (!ValueToNumber(cx
, vp
[2], &d
))
2776 length
= str
->length();
2777 begin
= js_DoubleToInteger(d
);
2782 } else if (begin
> length
) {
2786 if (argc
== 1 || vp
[3].isUndefined()) {
2789 if (!ValueToNumber(cx
, vp
[3], &d
))
2791 end
= js_DoubleToInteger(d
);
2799 str
= js_NewDependentString(cx
, str
,
2801 (size_t)(end
- begin
));
2808 #endif /* JS_HAS_PERL_SUBSTR */
2811 * Python-esque sequence operations.
2814 str_concat(JSContext
*cx
, uintN argc
, Value
*vp
)
2816 JSString
*str
, *str2
;
2820 NORMALIZE_THIS(cx
, vp
, str
);
2822 /* Set vp (aka rval) early to handle the argc == 0 case. */
2825 for (i
= 0, argv
= vp
+ 2; i
< argc
; i
++) {
2826 str2
= js_ValueToString(cx
, argv
[i
]);
2829 argv
[i
].setString(str2
);
2831 str
= js_ConcatStrings(cx
, str
, str2
);
2841 str_slice(JSContext
*cx
, uintN argc
, Value
*vp
)
2843 if (argc
== 1 && vp
[1].isString() && vp
[2].isInt32()) {
2844 size_t begin
, end
, length
;
2846 JSString
*str
= vp
[1].toString();
2847 begin
= vp
[2].toInt32();
2848 end
= str
->length();
2850 length
= end
- begin
;
2852 str
= cx
->runtime
->emptyString
;
2855 ? JSString::getUnitString(cx
, str
, begin
)
2856 : js_NewDependentString(cx
, str
, begin
, length
);
2866 NORMALIZE_THIS(cx
, vp
, str
);
2869 double begin
, end
, length
;
2871 if (!ValueToNumber(cx
, vp
[2], &begin
))
2873 begin
= js_DoubleToInteger(begin
);
2874 length
= str
->length();
2879 } else if (begin
> length
) {
2883 if (argc
== 1 || vp
[3].isUndefined()) {
2886 if (!ValueToNumber(cx
, vp
[3], &end
))
2888 end
= js_DoubleToInteger(end
);
2893 } else if (end
> length
) {
2900 str
= js_NewDependentString(cx
, str
,
2902 (size_t)(end
- begin
));
2910 #if JS_HAS_STR_HTML_HELPERS
2912 * HTML composition aids.
2915 tagify(JSContext
*cx
, const char *begin
, JSString
*param
, const char *end
,
2920 size_t beglen
, endlen
, parlen
, taglen
;
2923 NORMALIZE_THIS(cx
, vp
, str
);
2928 beglen
= strlen(begin
);
2929 taglen
= 1 + beglen
+ 1; /* '<begin' + '>' */
2930 parlen
= 0; /* Avoid warning. */
2932 parlen
= param
->length();
2933 taglen
+= 2 + parlen
+ 1; /* '="param"' */
2935 endlen
= strlen(end
);
2936 taglen
+= str
->length() + 2 + endlen
+ 1; /* 'str</end>' */
2938 if (taglen
>= ~(size_t)0 / sizeof(jschar
)) {
2939 js_ReportAllocationOverflow(cx
);
2943 tagbuf
= (jschar
*) cx
->malloc((taglen
+ 1) * sizeof(jschar
));
2949 for (i
= 0; i
< beglen
; i
++)
2950 tagbuf
[j
++] = (jschar
)begin
[i
];
2954 js_strncpy(&tagbuf
[j
], param
->chars(), parlen
);
2959 js_strncpy(&tagbuf
[j
], str
->chars(), str
->length());
2963 for (i
= 0; i
< endlen
; i
++)
2964 tagbuf
[j
++] = (jschar
)end
[i
];
2966 JS_ASSERT(j
== taglen
);
2969 str
= js_NewString(cx
, tagbuf
, taglen
);
2971 js_free((char *)tagbuf
);
2979 tagify_value(JSContext
*cx
, uintN argc
, Value
*vp
,
2980 const char *begin
, const char *end
)
2984 param
= ArgToRootedString(cx
, argc
, vp
, 0);
2987 return tagify(cx
, begin
, param
, end
, vp
);
2991 str_bold(JSContext
*cx
, uintN argc
, Value
*vp
)
2993 return tagify(cx
, "b", NULL
, NULL
, vp
);
2997 str_italics(JSContext
*cx
, uintN argc
, Value
*vp
)
2999 return tagify(cx
, "i", NULL
, NULL
, vp
);
3003 str_fixed(JSContext
*cx
, uintN argc
, Value
*vp
)
3005 return tagify(cx
, "tt", NULL
, NULL
, vp
);
3009 str_fontsize(JSContext
*cx
, uintN argc
, Value
*vp
)
3011 return tagify_value(cx
, argc
, vp
, "font size", "font");
3015 str_fontcolor(JSContext
*cx
, uintN argc
, Value
*vp
)
3017 return tagify_value(cx
, argc
, vp
, "font color", "font");
3021 str_link(JSContext
*cx
, uintN argc
, Value
*vp
)
3023 return tagify_value(cx
, argc
, vp
, "a href", "a");
3027 str_anchor(JSContext
*cx
, uintN argc
, Value
*vp
)
3029 return tagify_value(cx
, argc
, vp
, "a name", "a");
3033 str_strike(JSContext
*cx
, uintN argc
, Value
*vp
)
3035 return tagify(cx
, "strike", NULL
, NULL
, vp
);
3039 str_small(JSContext
*cx
, uintN argc
, Value
*vp
)
3041 return tagify(cx
, "small", NULL
, NULL
, vp
);
3045 str_big(JSContext
*cx
, uintN argc
, Value
*vp
)
3047 return tagify(cx
, "big", NULL
, NULL
, vp
);
3051 str_blink(JSContext
*cx
, uintN argc
, Value
*vp
)
3053 return tagify(cx
, "blink", NULL
, NULL
, vp
);
3057 str_sup(JSContext
*cx
, uintN argc
, Value
*vp
)
3059 return tagify(cx
, "sup", NULL
, NULL
, vp
);
3063 str_sub(JSContext
*cx
, uintN argc
, Value
*vp
)
3065 return tagify(cx
, "sub", NULL
, NULL
, vp
);
3067 #endif /* JS_HAS_STR_HTML_HELPERS */
3071 js_String_getelem(JSContext
* cx
, JSString
* str
, int32 i
)
3073 if ((size_t)i
>= str
->length())
3075 return JSString::getUnitString(cx
, str
, size_t(i
));
3079 JS_DEFINE_TRCINFO_1(str_concat
,
3080 (3, (extern, STRING_RETRY
, js_ConcatStrings
, CONTEXT
, THIS_STRING
, STRING
,
3081 1, nanojit::ACCSET_NONE
)))
3083 static const uint16 GENERIC_PRIMITIVE
= JSFUN_GENERIC_NATIVE
| JSFUN_PRIMITIVE_THIS
;
3085 static JSFunctionSpec string_methods
[] = {
3087 JS_FN("quote", str_quote
, 0,GENERIC_PRIMITIVE
),
3088 JS_FN(js_toSource_str
, str_toSource
, 0,JSFUN_PRIMITIVE_THIS
),
3091 /* Java-like methods. */
3092 JS_FN(js_toString_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3093 JS_FN(js_valueOf_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3094 JS_FN(js_toJSON_str
, js_str_toString
, 0,JSFUN_PRIMITIVE_THIS
),
3095 JS_FN("substring", str_substring
, 2,GENERIC_PRIMITIVE
),
3096 JS_FN("toLowerCase", str_toLowerCase
, 0,GENERIC_PRIMITIVE
),
3097 JS_FN("toUpperCase", str_toUpperCase
, 0,GENERIC_PRIMITIVE
),
3098 JS_FN("charAt", js_str_charAt
, 1,GENERIC_PRIMITIVE
),
3099 JS_FN("charCodeAt", js_str_charCodeAt
, 1,GENERIC_PRIMITIVE
),
3100 JS_FN("indexOf", str_indexOf
, 1,GENERIC_PRIMITIVE
),
3101 JS_FN("lastIndexOf", str_lastIndexOf
, 1,GENERIC_PRIMITIVE
),
3102 JS_FN("trim", str_trim
, 0,GENERIC_PRIMITIVE
),
3103 JS_FN("trimLeft", str_trimLeft
, 0,GENERIC_PRIMITIVE
),
3104 JS_FN("trimRight", str_trimRight
, 0,GENERIC_PRIMITIVE
),
3105 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase
, 0,GENERIC_PRIMITIVE
),
3106 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase
, 0,GENERIC_PRIMITIVE
),
3107 JS_FN("localeCompare", str_localeCompare
, 1,GENERIC_PRIMITIVE
),
3109 /* Perl-ish methods (search is actually Python-esque). */
3110 JS_FN("match", str_match
, 1,GENERIC_PRIMITIVE
),
3111 JS_FN("search", str_search
, 1,GENERIC_PRIMITIVE
),
3112 JS_FN("replace", str_replace
, 2,GENERIC_PRIMITIVE
),
3113 JS_FN("split", str_split
, 2,GENERIC_PRIMITIVE
),
3114 #if JS_HAS_PERL_SUBSTR
3115 JS_FN("substr", str_substr
, 2,GENERIC_PRIMITIVE
),
3118 /* Python-esque sequence methods. */
3119 JS_TN("concat", str_concat
, 1,GENERIC_PRIMITIVE
, &str_concat_trcinfo
),
3120 JS_FN("slice", str_slice
, 2,GENERIC_PRIMITIVE
),
3122 /* HTML string methods. */
3123 #if JS_HAS_STR_HTML_HELPERS
3124 JS_FN("bold", str_bold
, 0,JSFUN_PRIMITIVE_THIS
),
3125 JS_FN("italics", str_italics
, 0,JSFUN_PRIMITIVE_THIS
),
3126 JS_FN("fixed", str_fixed
, 0,JSFUN_PRIMITIVE_THIS
),
3127 JS_FN("fontsize", str_fontsize
, 1,JSFUN_PRIMITIVE_THIS
),
3128 JS_FN("fontcolor", str_fontcolor
, 1,JSFUN_PRIMITIVE_THIS
),
3129 JS_FN("link", str_link
, 1,JSFUN_PRIMITIVE_THIS
),
3130 JS_FN("anchor", str_anchor
, 1,JSFUN_PRIMITIVE_THIS
),
3131 JS_FN("strike", str_strike
, 0,JSFUN_PRIMITIVE_THIS
),
3132 JS_FN("small", str_small
, 0,JSFUN_PRIMITIVE_THIS
),
3133 JS_FN("big", str_big
, 0,JSFUN_PRIMITIVE_THIS
),
3134 JS_FN("blink", str_blink
, 0,JSFUN_PRIMITIVE_THIS
),
3135 JS_FN("sup", str_sup
, 0,JSFUN_PRIMITIVE_THIS
),
3136 JS_FN("sub", str_sub
, 0,JSFUN_PRIMITIVE_THIS
),
3143 * Set up some tools to make it easier to generate large tables. After constant
3144 * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3145 * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3146 * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3149 #define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
3150 #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
3151 #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
3152 #define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
3153 #define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
3154 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3156 #define R3(n) R2(n), R2((n) + (1 << 2))
3157 #define R7(n) R6(n), R6((n) + (1 << 6))
3160 * Declare unit strings. Pack the string data itself into the mInlineChars
3161 * place in the header.
3164 JSString::FLAT | JSString::ATOMIZED | (1 << JSString::FLAGS_LENGTH_SHIFT),\
3165 { (jschar *)(((char *)(unitStringTable + (c))) + \
3166 offsetof(JSString, mInlineStorage)) }, \
3172 #pragma pack(push, 8)
3175 const JSString
JSString::unitStringTable
[]
3177 __attribute__ ((aligned (8)))
3190 * Declare length-2 strings. We only store strings where both characters are
3191 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3192 * the lowercase letters, and the next 26 are the uppercase letters.
3194 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
3195 (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
3196 (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
3197 JSString::INVALID_SMALL_CHAR)
3199 #define R TO_SMALL_CHAR
3201 const JSString::SmallChar
JSString::toSmallChar
[] = { R7(0) };
3206 * This is used when we generate our table of short strings, so the compiler is
3207 * happier if we use |c| as few times as possible.
3209 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
3210 (c) < 36 ? 'a' - 10 : \
3212 #define R FROM_SMALL_CHAR
3214 const jschar
JSString::fromSmallChar
[] = { R6(0) };
3219 * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3220 * where the upper 6 bits is the first character and the lower 6 bits is the
3224 JSString::FLAT | JSString::ATOMIZED | (2 << JSString::FLAGS_LENGTH_SHIFT),\
3225 { (jschar *)(((char *)(length2StringTable + (c))) + \
3226 offsetof(JSString, mInlineStorage)) }, \
3227 { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3232 #pragma pack(push, 8)
3235 const JSString
JSString::length2StringTable
[]
3237 __attribute__ ((aligned (8)))
3249 #define R(c) FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3f), 0x00
3251 const char JSString::deflatedLength2StringTable
[] = { R12(0) };
3256 * Declare int strings. Only int strings from 100 to 255 actually have to be
3257 * generated, since the rest are either unit strings or length-2 strings. To
3258 * avoid the runtime cost of figuring out where to look for the string for a
3259 * particular integer, we precompute a table of JSString*s which refer to the
3260 * correct location of the int string.
3263 JSString::FLAT | JSString::ATOMIZED | (3 << JSString::FLAGS_LENGTH_SHIFT),\
3264 { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \
3265 offsetof(JSString, mInlineStorage)) }, \
3266 { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3269 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3274 #pragma pack(push, 8)
3277 const JSString
JSString::hundredStringTable
[]
3279 __attribute__ ((aligned (8)))
3281 = { R7(100), /* 100 through 227 */
3282 R4(100 + (1 << 7)), /* 228 through 243 */
3283 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3284 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3289 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \
3290 (c) < 100 ? JSString::length2StringTable + \
3291 ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
3292 TO_SMALL_CHAR(((c) % 10) + '0') : \
3293 JSString::hundredStringTable + ((c) - 100))
3295 const JSString
*const JSString::intStringTable
[] = { R8(0) };
3305 #define R(c) ((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00
3307 const char JSString::deflatedIntStringTable
[] = {
3308 R7(100), /* 100 through 227 */
3309 R4(100 + (1 << 7)), /* 228 through 243 */
3310 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3311 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3325 /* Static table for common UTF8 encoding */
3326 #define U8(c) char(((c) >> 6) | 0xc0), char(((c) & 0x3f) | 0x80), 0
3327 #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)
3329 const char JSString::deflatedUnitStringTable
[] = {
3330 U(0x80), U(0x88), U(0x90), U(0x98), U(0xa0), U(0xa8), U(0xb0), U(0xb8),
3331 U(0xc0), U(0xc8), U(0xd0), U(0xd8), U(0xe0), U(0xe8), U(0xf0), U(0xf8)
3338 js_String(JSContext
*cx
, uintN argc
, Value
*vp
)
3340 Value
*argv
= vp
+ 2;
3344 str
= js_ValueToString(cx
, argv
[0]);
3348 str
= cx
->runtime
->emptyString
;
3351 if (IsConstructing(vp
)) {
3352 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_StringClass
);
3355 obj
->setPrimitiveThis(StringValue(str
));
3356 vp
->setObject(*obj
);
3364 str_fromCharCode(JSContext
*cx
, uintN argc
, Value
*vp
)
3372 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
3375 if (!ValueToUint16(cx
, argv
[0], &code
))
3377 if (code
< UNIT_STRING_LIMIT
) {
3378 str
= JSString::unitString(code
);
3384 argv
[0].setInt32(code
);
3386 chars
= (jschar
*) cx
->malloc((argc
+ 1) * sizeof(jschar
));
3389 for (i
= 0; i
< argc
; i
++) {
3391 if (!ValueToUint16(cx
, argv
[i
], &code
)) {
3395 chars
[i
] = (jschar
)code
;
3398 str
= js_NewString(cx
, chars
, argc
);
3408 static JSString
* FASTCALL
3409 String_fromCharCode(JSContext
* cx
, int32 i
)
3411 JS_ASSERT(JS_ON_TRACE(cx
));
3412 jschar c
= (jschar
)i
;
3413 if (c
< UNIT_STRING_LIMIT
)
3414 return JSString::unitString(c
);
3415 return js_NewStringCopyN(cx
, &c
, 1);
3419 JS_DEFINE_TRCINFO_1(str_fromCharCode
,
3420 (2, (static, STRING_RETRY
, String_fromCharCode
, CONTEXT
, INT32
, 1, nanojit::ACCSET_NONE
)))
3422 static JSFunctionSpec string_static_methods
[] = {
3423 JS_TN("fromCharCode", str_fromCharCode
, 1, 0, &str_fromCharCode_trcinfo
),
3428 js_InitStringClass(JSContext
*cx
, JSObject
*obj
)
3432 /* Define the escape, unescape functions in the global object. */
3433 if (!JS_DefineFunctions(cx
, obj
, string_functions
))
3436 proto
= js_InitClass(cx
, obj
, NULL
, &js_StringClass
, js_String
, 1,
3437 NULL
, string_methods
,
3438 NULL
, string_static_methods
);
3441 proto
->setPrimitiveThis(StringValue(cx
->runtime
->emptyString
));
3442 if (!js_DefineNativeProperty(cx
, proto
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
3443 UndefinedValue(), NULL
, NULL
,
3444 JSPROP_READONLY
| JSPROP_PERMANENT
| JSPROP_SHARED
, 0, 0,
3453 js_NewString(JSContext
*cx
, jschar
*chars
, size_t length
)
3457 if (length
> JSString::MAX_LENGTH
) {
3458 if (JS_ON_TRACE(cx
)) {
3460 * If we can't leave the trace, signal OOM condition, otherwise
3461 * exit from trace before throwing.
3463 if (!CanLeaveTrace(cx
))
3468 js_ReportAllocationOverflow(cx
);
3472 str
= js_NewGCString(cx
);
3475 str
->initFlat(chars
, length
);
3478 JSRuntime
*rt
= cx
->runtime
;
3479 JS_RUNTIME_METER(rt
, liveStrings
);
3480 JS_RUNTIME_METER(rt
, totalStrings
);
3481 JS_LOCK_RUNTIME_VOID(rt
,
3482 (rt
->lengthSum
+= (double)length
,
3483 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3489 static JS_ALWAYS_INLINE JSString
*
3490 NewShortString(JSContext
*cx
, const jschar
*chars
, size_t length
)
3492 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3493 JSShortString
*str
= js_NewGCShortString(cx
);
3496 jschar
*storage
= str
->init(length
);
3497 js_short_strncpy(storage
, chars
, length
);
3498 storage
[length
] = 0;
3499 return str
->header();
3503 NewShortString(JSContext
*cx
, const char *chars
, size_t length
)
3505 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3506 JSShortString
*str
= js_NewGCShortString(cx
);
3509 jschar
*storage
= str
->init(length
);
3511 if (js_CStringsAreUTF8
) {
3513 size_t oldLength
= length
;
3515 if (!js_InflateStringToBuffer(cx
, chars
, length
, storage
, &length
))
3517 JS_ASSERT(length
<= oldLength
);
3518 storage
[length
] = 0;
3519 str
->resetLength(length
);
3522 jschar
*p
= storage
;
3524 *p
++ = jschar(*chars
++);
3527 return str
->header();
3530 static const size_t sMinWasteSize
= 16;
3533 js_NewStringFromCharBuffer(JSContext
*cx
, JSCharBuffer
&cb
)
3536 return ATOM_TO_STRING(cx
->runtime
->atomState
.emptyAtom
);
3538 size_t length
= cb
.length();
3540 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH
< JSCharBuffer::InlineLength
);
3541 if (JSShortString::fitsIntoShortString(length
))
3542 return NewShortString(cx
, cb
.begin(), length
);
3544 if (!cb
.append('\0'))
3547 size_t capacity
= cb
.capacity();
3549 jschar
*buf
= cb
.extractRawBuffer();
3553 /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3554 JS_ASSERT(capacity
>= length
);
3555 if (capacity
> sMinWasteSize
&& capacity
- length
> (length
>> 2)) {
3556 size_t bytes
= sizeof(jschar
) * (length
+ 1);
3557 jschar
*tmp
= (jschar
*)cx
->realloc(buf
, bytes
);
3565 JSString
*str
= js_NewString(cx
, buf
, length
);
3572 js_NewDependentString(JSContext
*cx
, JSString
*base
, size_t start
,
3578 return cx
->runtime
->emptyString
;
3580 if (start
== 0 && length
== base
->length())
3583 jschar
*chars
= base
->chars() + start
;
3585 JSString
*staticStr
= JSString::lookupStaticString(chars
, length
);
3589 /* Try to avoid long chains of dependent strings. */
3590 while (base
->isDependent())
3591 base
= base
->dependentBase();
3593 JS_ASSERT(base
->isFlat());
3595 ds
= js_NewGCString(cx
);
3598 ds
->initDependent(base
, chars
, length
);
3601 JSRuntime
*rt
= cx
->runtime
;
3602 JS_RUNTIME_METER(rt
, liveDependentStrings
);
3603 JS_RUNTIME_METER(rt
, totalDependentStrings
);
3604 JS_RUNTIME_METER(rt
, liveStrings
);
3605 JS_RUNTIME_METER(rt
, totalStrings
);
3606 JS_LOCK_RUNTIME_VOID(rt
,
3607 (rt
->strdepLengthSum
+= (double)length
,
3608 rt
->strdepLengthSquaredSum
+= (double)length
* (double)length
));
3609 JS_LOCK_RUNTIME_VOID(rt
,
3610 (rt
->lengthSum
+= (double)length
,
3611 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3620 void printJSStringStats(JSRuntime
*rt
)
3624 mean
= JS_MeanAndStdDev(rt
->totalStrings
, rt
->lengthSum
,
3625 rt
->lengthSquaredSum
, &sigma
);
3627 fprintf(stderr
, "%lu total strings, mean length %g (sigma %g)\n",
3628 (unsigned long)rt
->totalStrings
, mean
, sigma
);
3630 mean
= JS_MeanAndStdDev(rt
->totalDependentStrings
, rt
->strdepLengthSum
,
3631 rt
->strdepLengthSquaredSum
, &sigma
);
3633 fprintf(stderr
, "%lu total dependent strings, mean length %g (sigma %g)\n",
3634 (unsigned long)rt
->totalDependentStrings
, mean
, sigma
);
3639 js_NewStringCopyN(JSContext
*cx
, const jschar
*s
, size_t n
)
3641 if (JSShortString::fitsIntoShortString(n
))
3642 return NewShortString(cx
, s
, n
);
3647 news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
3650 js_strncpy(news
, s
, n
);
3652 str
= js_NewString(cx
, news
, n
);
3659 js_NewStringCopyN(JSContext
*cx
, const char *s
, size_t n
)
3661 if (JSShortString::fitsIntoShortString(n
))
3662 return NewShortString(cx
, s
, n
);
3663 return JS_NewStringCopyN(cx
, s
, n
);
3667 js_NewStringCopyZ(JSContext
*cx
, const jschar
*s
)
3675 if (JSShortString::fitsIntoShortString(n
))
3676 return NewShortString(cx
, s
, n
);
3678 m
= (n
+ 1) * sizeof(jschar
);
3679 news
= (jschar
*) cx
->malloc(m
);
3683 str
= js_NewString(cx
, news
, n
);
3690 js_NewStringCopyZ(JSContext
*cx
, const char *s
)
3692 return js_NewStringCopyN(cx
, s
, strlen(s
));
3695 JS_FRIEND_API(const char *)
3696 js_ValueToPrintable(JSContext
*cx
, const Value
&v
, JSValueToStringFun v2sfun
)
3700 str
= v2sfun(cx
, v
);
3703 str
= js_QuoteString(cx
, str
, 0);
3706 return js_GetStringBytes(cx
, str
);
3710 js_ValueToString(JSContext
*cx
, const Value
&arg
)
3713 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3719 } else if (v
.isInt32()) {
3720 str
= js_NumberToString(cx
, v
.toInt32());
3721 } else if (v
.isDouble()) {
3722 str
= js_NumberToString(cx
, v
.toDouble());
3723 } else if (v
.isBoolean()) {
3724 str
= js_BooleanToString(cx
, v
.toBoolean());
3725 } else if (v
.isNull()) {
3726 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
3728 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
3733 static inline JSBool
3734 AppendAtom(JSAtom
*atom
, JSCharBuffer
&cb
)
3736 JSString
*str
= ATOM_TO_STRING(atom
);
3737 const jschar
*chars
;
3739 str
->getCharsAndLength(chars
, length
);
3740 return cb
.append(chars
, length
);
3743 /* This function implements E-262-3 section 9.8, toString. */
3745 js_ValueToCharBuffer(JSContext
*cx
, const Value
&arg
, JSCharBuffer
&cb
)
3748 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3752 const jschar
*chars
;
3754 v
.toString()->getCharsAndLength(chars
, length
);
3755 return cb
.append(chars
, length
);
3758 return js_NumberValueToCharBuffer(cx
, v
, cb
);
3760 return js_BooleanToCharBuffer(cx
, v
.toBoolean(), cb
);
3762 return AppendAtom(cx
->runtime
->atomState
.nullAtom
, cb
);
3763 JS_ASSERT(v
.isUndefined());
3764 return AppendAtom(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
], cb
);
3767 JS_FRIEND_API(JSString
*)
3768 js_ValueToSource(JSContext
*cx
, const Value
&v
)
3770 if (v
.isUndefined())
3771 return ATOM_TO_STRING(cx
->runtime
->atomState
.void0Atom
);
3773 return js_QuoteString(cx
, v
.toString(), '"');
3774 if (v
.isPrimitive()) {
3775 /* Special case to preserve negative zero, _contra_ toString. */
3776 if (v
.isDouble() && JSDOUBLE_IS_NEGZERO(v
.toDouble())) {
3777 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3778 static const jschar js_negzero_ucNstr
[] = {'-', '0'};
3780 return js_NewStringCopyN(cx
, js_negzero_ucNstr
, 2);
3782 return js_ValueToString(cx
, v
);
3785 JSAtom
*atom
= cx
->runtime
->atomState
.toSourceAtom
;
3786 AutoValueRooter
tvr(cx
);
3787 if (!js_TryMethod(cx
, &v
.toObject(), atom
, 0, NULL
, tvr
.addr()))
3789 return js_ValueToString(cx
, tvr
.value());
3793 * str is not necessarily a GC thing here.
3796 js_HashString(JSString
*str
)
3802 str
->getCharsAndLength(s
, n
);
3803 for (h
= 0; n
; s
++, n
--)
3804 h
= JS_ROTATE_LEFT32(h
, 4) ^ *s
;
3809 * str is not necessarily a GC thing here.
3812 js_EqualStrings(JSString
*str1
, JSString
*str2
)
3815 const jschar
*s1
, *s2
;
3820 /* Fast case: pointer equality could be a quick win. */
3825 if (n
!= str2
->length())
3831 s1
= str1
->chars(), s2
= str2
->chars();
3840 JS_DEFINE_CALLINFO_2(extern, BOOL
, js_EqualStrings
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3843 js_CompareStrings(JSString
*str1
, JSString
*str2
)
3845 size_t l1
, l2
, n
, i
;
3846 const jschar
*s1
, *s2
;
3852 /* Fast case: pointer equality could be a quick win. */
3856 str1
->getCharsAndLength(s1
, l1
);
3857 str2
->getCharsAndLength(s2
, l2
);
3859 for (i
= 0; i
< n
; i
++) {
3860 cmp
= s1
[i
] - s2
[i
];
3864 return (intN
)(l1
- l2
);
3866 JS_DEFINE_CALLINFO_2(extern, INT32
, js_CompareStrings
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3869 js_strlen(const jschar
*s
)
3873 for (t
= s
; *t
!= 0; t
++)
3875 return (size_t)(t
- s
);
3879 js_strchr(const jschar
*s
, jschar c
)
3890 js_strchr_limit(const jschar
*s
, jschar c
, const jschar
*limit
)
3901 js_InflateString(JSContext
*cx
, const char *bytes
, size_t *lengthp
)
3903 size_t nbytes
, nchars
, i
;
3910 if (js_CStringsAreUTF8
) {
3911 if (!js_InflateStringToBuffer(cx
, bytes
, nbytes
, NULL
, &nchars
))
3913 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof (jschar
));
3919 js_InflateStringToBuffer(cx
, bytes
, nbytes
, chars
, &nchars
);
3923 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof(jschar
));
3926 for (i
= 0; i
< nchars
; i
++)
3927 chars
[i
] = (unsigned char) bytes
[i
];
3935 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3943 * May be called with null cx by js_GetStringBytes, see below.
3946 js_DeflateString(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3954 if (js_CStringsAreUTF8
) {
3955 nbytes
= js_GetDeflatedStringLength(cx
, chars
, nchars
);
3956 if (nbytes
== (size_t) -1)
3958 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3964 js_DeflateStringToBuffer(cx
, chars
, nchars
, bytes
, &nbytes
);
3968 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3971 for (i
= 0; i
< nbytes
; i
++)
3972 bytes
[i
] = (char) chars
[i
];
3979 js_GetDeflatedStringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3981 if (!js_CStringsAreUTF8
)
3984 return js_GetDeflatedUTF8StringLength(cx
, chars
, nchars
);
3988 * May be called with null cx through js_GetStringBytes, see below.
3991 js_GetDeflatedUTF8StringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3999 for (end
= chars
+ nchars
; chars
!= end
; chars
++) {
4003 if (0xD800 <= c
&& c
<= 0xDFFF) {
4004 /* Surrogate pair. */
4007 /* nbytes sets 1 length since this is surrogate pair. */
4009 if (c
>= 0xDC00 || chars
== end
)
4012 if (c2
< 0xDC00 || c2
> 0xDFFF)
4014 c
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4027 JS_snprintf(buffer
, 10, "0x%x", c
);
4028 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
4029 NULL
, JSMSG_BAD_SURROGATE_CHAR
, buffer
);
4035 js_DeflateStringToBuffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4036 char *dst
, size_t *dstlenp
)
4041 if (!js_CStringsAreUTF8
) {
4042 if (srclen
> dstlen
) {
4043 for (i
= 0; i
< dstlen
; i
++)
4044 dst
[i
] = (char) src
[i
];
4046 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4047 JSMSG_BUFFER_TOO_SMALL
);
4051 for (i
= 0; i
< srclen
; i
++)
4052 dst
[i
] = (char) src
[i
];
4057 return js_DeflateStringToUTF8Buffer(cx
, src
, srclen
, dst
, dstlenp
);
4061 js_DeflateStringToUTF8Buffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4062 char *dst
, size_t *dstlenp
)
4064 size_t dstlen
, i
, origDstlen
, utf8Len
;
4070 origDstlen
= dstlen
;
4074 if ((c
>= 0xDC00) && (c
<= 0xDFFF))
4076 if (c
< 0xD800 || c
> 0xDBFF) {
4082 if ((c2
< 0xDC00) || (c2
> 0xDFFF))
4086 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4089 /* no encoding necessary - performance hack */
4091 goto bufferTooSmall
;
4095 utf8Len
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
4096 if (utf8Len
> dstlen
)
4097 goto bufferTooSmall
;
4098 for (i
= 0; i
< utf8Len
; i
++)
4099 *dst
++ = (char) utf8buf
[i
];
4103 *dstlenp
= (origDstlen
- dstlen
);
4107 *dstlenp
= (origDstlen
- dstlen
);
4108 /* Delegate error reporting to the measurement function. */
4110 js_GetDeflatedStringLength(cx
, src
- 1, srclen
+ 1);
4114 *dstlenp
= (origDstlen
- dstlen
);
4116 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4117 JSMSG_BUFFER_TOO_SMALL
);
4123 js_InflateStringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4124 jschar
*dst
, size_t *dstlenp
)
4128 if (!js_CStringsAreUTF8
) {
4131 if (srclen
> dstlen
) {
4132 for (i
= 0; i
< dstlen
; i
++)
4133 dst
[i
] = (unsigned char) src
[i
];
4135 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4136 JSMSG_BUFFER_TOO_SMALL
);
4140 for (i
= 0; i
< srclen
; i
++)
4141 dst
[i
] = (unsigned char) src
[i
];
4147 return js_InflateUTF8StringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
4151 js_InflateUTF8StringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4152 jschar
*dst
, size_t *dstlenp
)
4154 size_t dstlen
, origDstlen
, offset
, j
, n
;
4157 dstlen
= dst
? *dstlenp
: (size_t) -1;
4158 origDstlen
= dstlen
;
4165 while (v
& (0x80 >> n
))
4168 goto bufferTooSmall
;
4169 if (n
== 1 || n
> 4)
4171 for (j
= 1; j
< n
; j
++) {
4172 if ((src
[j
] & 0xC0) != 0x80)
4175 v
= Utf8ToOneUcs4Char((uint8
*)src
, n
);
4178 if (v
> 0xFFFFF || dstlen
< 2) {
4179 *dstlenp
= (origDstlen
- dstlen
);
4182 JS_snprintf(buffer
, 10, "0x%x", v
+ 0x10000);
4183 JS_ReportErrorFlagsAndNumber(cx
,
4185 js_GetErrorMessage
, NULL
,
4186 JSMSG_UTF8_CHAR_TOO_LARGE
,
4192 *dst
++ = (jschar
)((v
>> 10) + 0xD800);
4193 v
= (jschar
)((v
& 0x3FF) + 0xDC00);
4199 goto bufferTooSmall
;
4201 *dst
++ = (jschar
) v
;
4207 *dstlenp
= (origDstlen
- dstlen
);
4211 *dstlenp
= (origDstlen
- dstlen
);
4214 JS_snprintf(buffer
, 10, "%d", offset
);
4215 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
4216 js_GetErrorMessage
, NULL
,
4217 JSMSG_MALFORMED_UTF8_CHAR
,
4223 *dstlenp
= (origDstlen
- dstlen
);
4225 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4226 JSMSG_BUFFER_TOO_SMALL
);
4233 DeflatedStringCache::DeflatedStringCache()
4235 #ifdef JS_THREADSAFE
4241 DeflatedStringCache::init()
4243 #ifdef JS_THREADSAFE
4245 lock
= JS_NEW_LOCK();
4251 * Make room for 2K deflated strings that a typical browser session
4254 return map
.init(2048);
4257 DeflatedStringCache::~DeflatedStringCache()
4259 #ifdef JS_THREADSAFE
4261 JS_DESTROY_LOCK(lock
);
4266 DeflatedStringCache::sweep(JSContext
*cx
)
4269 * We must take a lock even during the GC as JS_GetStringBytes() can be
4270 * called outside the request.
4272 JS_ACQUIRE_LOCK(lock
);
4274 for (Map::Enum
e(map
); !e
.empty(); e
.popFront()) {
4275 JSString
*str
= e
.front().key
;
4276 if (IsAboutToBeFinalized(str
)) {
4277 char *bytes
= e
.front().value
;
4281 * We cannot use cx->free here as bytes may come from the
4282 * embedding that calls JS_NewString(cx, bytes, length). Those
4283 * bytes may not be allocated via js_malloc and may not have
4284 * space for the background free list.
4290 JS_RELEASE_LOCK(lock
);
4294 DeflatedStringCache::remove(JSString
*str
)
4296 JS_ACQUIRE_LOCK(lock
);
4298 Map::Ptr p
= map
.lookup(str
);
4304 JS_RELEASE_LOCK(lock
);
4308 DeflatedStringCache::setBytes(JSContext
*cx
, JSString
*str
, char *bytes
)
4310 JS_ACQUIRE_LOCK(lock
);
4312 Map::AddPtr p
= map
.lookupForAdd(str
);
4314 bool ok
= map
.add(p
, str
, bytes
);
4316 JS_RELEASE_LOCK(lock
);
4319 js_ReportOutOfMemory(cx
);
4324 DeflatedStringCache::getBytes(JSContext
*cx
, JSString
*str
)
4326 JS_ACQUIRE_LOCK(lock
);
4327 Map::AddPtr p
= map
.lookupForAdd(str
);
4328 char *bytes
= p
? p
->value
: NULL
;
4329 JS_RELEASE_LOCK(lock
);
4334 bytes
= js_DeflateString(cx
, str
->chars(), str
->length());
4339 * In the single-threaded case we use the add method as js_DeflateString
4340 * cannot mutate the map. In particular, it cannot run the GC that may
4341 * delete entries from the map. But the JS_THREADSAFE version requires to
4342 * deal with other threads adding the entries to the map.
4344 char *bytesToFree
= NULL
;
4346 #ifdef JS_THREADSAFE
4347 JS_ACQUIRE_LOCK(lock
);
4348 ok
= map
.relookupOrAdd(p
, str
, bytes
);
4349 if (ok
&& p
->value
!= bytes
) {
4350 /* Some other thread has asked for str bytes .*/
4351 JS_ASSERT(!strcmp(p
->value
, bytes
));
4352 bytesToFree
= bytes
;
4355 JS_RELEASE_LOCK(lock
);
4356 #else /* !JS_THREADSAFE */
4357 ok
= map
.add(p
, str
, bytes
);
4360 bytesToFree
= bytes
;
4363 js_ReportOutOfMemory(cx
);
4368 cx
->free(bytesToFree
);
4370 js_free(bytesToFree
);
4375 } /* namespace js */
4378 js_GetStringBytes(JSContext
*cx
, JSString
*str
)
4383 if (JSString::isUnitString(str
)) {
4384 #ifdef IS_LITTLE_ENDIAN
4385 /* Unit string data is {c, 0, 0, 0} so we can just cast. */
4386 bytes
= (char *)str
->chars();
4388 /* Unit string data is {0, c, 0, 0} so we can point into the middle. */
4389 bytes
= (char *)str
->chars() + 1;
4391 return ((*bytes
& 0x80) && js_CStringsAreUTF8
)
4392 ? JSString::deflatedUnitStringTable
+ ((*bytes
& 0x7f) * 3)
4397 * We must burn some space on deflated int strings and length-2 strings
4398 * to preserve static allocation (which is to say, JSRuntime independence).
4400 if (JSString::isLength2String(str
))
4401 return JSString::deflatedLength2StringTable
+ ((str
- JSString::length2StringTable
) * 3);
4403 if (JSString::isHundredString(str
)) {
4405 * We handled the 1 and 2-digit number cases already, so we know that
4406 * str is between 100 and 255.
4408 return JSString::deflatedIntStringTable
+ ((str
- JSString::hundredStringTable
) * 4);
4414 /* JS_GetStringBytes calls us with null cx. */
4415 rt
= GetGCThingRuntime(str
);
4418 return rt
->deflatedStringCache
->getBytes(cx
, str
);
4422 * From java.lang.Character.java:
4424 * The character properties are currently encoded into 32 bits in the
4427 * 10 bits signed offset used for converting case
4428 * 1 bit if 1, adding the signed offset converts the character to
4430 * 1 bit if 1, subtracting the signed offset converts the character to
4432 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
4433 * 3 bits 0 may not be part of an identifier
4434 * 1 ignorable control; may continue a Unicode identifier or JS
4436 * 2 may continue a JS identifier but not a Unicode identifier
4438 * 3 may continue a Unicode identifier or JS identifier
4439 * 4 is a JS whitespace character
4440 * 5 may start or continue a JS identifier;
4441 * may continue but not start a Unicode identifier (_)
4442 * 6 may start or continue a JS identifier but not a Unicode
4444 * 7 may start or continue a Unicode identifier or JS identifier
4446 * 5, 6, 7 may start a JS identifier
4447 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
4448 * 7 may start a Unicode identifier
4449 * 1, 3, 5, 7 may continue a Unicode identifier
4450 * 1 is ignorable within an identifier
4451 * 4 is JS whitespace
4452 * 2 bits 0 this character has no numeric property
4453 * 1 adding the digit offset to the character code and then
4454 * masking with 0x1F will produce the desired numeric value
4455 * 2 this character has a "strange" numeric value
4456 * 3 a JS supradecimal digit: adding the digit offset to the
4457 * character code, then masking with 0x1F, then adding 10
4458 * will produce the desired numeric value
4459 * 5 bits digit offset
4460 * 1 bit XML 1.0 name start character
4461 * 1 bit XML 1.0 name character
4462 * 2 bits reserved for future use
4463 * 5 bits character type
4466 /* The X table has 1024 entries for a total of 1024 bytes. */
4468 const uint8 js_X
[] = {
4469 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
4470 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
4471 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
4472 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
4473 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
4474 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
4475 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
4476 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
4477 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
4478 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
4479 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
4480 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
4481 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
4482 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
4483 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
4484 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
4485 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
4486 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
4487 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
4488 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
4489 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
4490 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
4491 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
4492 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
4493 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
4494 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
4495 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
4496 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
4497 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
4498 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
4499 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
4500 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
4501 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
4502 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
4503 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
4504 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
4505 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
4506 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
4507 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
4508 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
4509 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
4510 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
4511 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
4512 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
4513 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
4514 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
4515 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
4516 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
4517 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
4518 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
4519 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
4520 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
4521 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
4522 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
4523 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
4524 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
4525 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
4526 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
4527 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
4528 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
4529 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
4530 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
4531 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
4532 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
4533 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
4534 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
4535 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
4536 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
4537 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
4538 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
4539 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
4540 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
4541 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
4542 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
4543 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
4544 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
4545 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
4546 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
4547 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
4548 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
4549 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
4550 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
4551 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
4552 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
4553 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
4554 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
4555 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
4556 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
4557 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
4558 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
4559 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
4560 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
4561 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
4562 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
4563 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
4564 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
4565 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
4566 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
4567 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
4568 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
4569 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
4570 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
4571 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
4572 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
4573 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
4574 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
4575 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
4576 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
4577 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
4578 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
4579 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
4580 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
4581 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
4582 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
4583 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
4584 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
4585 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
4586 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
4587 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
4588 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
4589 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
4590 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
4591 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
4592 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
4593 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
4594 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
4595 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
4596 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
4599 /* The Y table has 7808 entries for a total of 7808 bytes. */
4601 const uint8 js_Y
[] = {
4602 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4603 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
4604 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4605 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4606 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
4607 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
4608 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
4609 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
4610 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4611 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4612 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4613 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
4614 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4615 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4616 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4617 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
4618 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4619 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4620 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4621 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4622 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
4623 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
4624 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
4625 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
4626 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4627 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4628 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
4629 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
4630 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4631 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4632 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
4633 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
4634 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4635 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4636 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
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 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
4641 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
4642 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
4643 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
4644 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4645 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4646 23, 24, 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 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
4650 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
4651 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
4652 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
4653 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
4654 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
4655 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
4656 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
4657 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
4658 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
4659 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
4660 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
4661 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
4662 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4663 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4664 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
4665 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
4666 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4667 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4668 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4669 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4670 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4671 46, 46, 46, 46, 46, 46, 46, 46, /* 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, /* 9 */
4675 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4676 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
4677 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
4678 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
4679 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
4680 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
4681 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
4682 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
4683 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
4684 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
4685 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4686 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4687 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
4688 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
4689 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
4690 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4691 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
4692 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4693 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
4694 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
4695 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
4696 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4697 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4698 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4699 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4700 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
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, 46, 46, /* 13 */
4707 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4708 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4709 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4710 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
4711 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4712 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
4713 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
4714 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
4715 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
4716 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4717 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4718 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
4719 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
4720 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4721 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4722 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
4723 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
4724 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
4725 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
4726 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
4727 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
4728 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
4729 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
4730 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
4731 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
4732 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4733 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4734 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4735 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4736 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4737 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4738 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4739 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4740 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
4741 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
4742 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4743 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4744 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4745 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4746 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
4747 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
4748 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4749 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4750 23, 24, 23, 24, 23, 24, 23, 24, /* 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 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
4755 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
4756 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4757 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4758 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4759 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
4760 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
4761 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
4762 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4763 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4764 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
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, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4769 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4770 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4771 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4772 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
4773 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
4774 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4775 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4776 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4777 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4778 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
4779 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
4780 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4781 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4782 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
4783 60, 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, 3, 60, /* 22 */
4786 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
4787 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4788 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4789 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4790 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4791 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
4792 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
4793 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4794 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4795 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
4796 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4797 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
4798 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4799 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4800 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4801 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
4802 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4803 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
4804 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
4805 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
4806 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
4807 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
4808 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4809 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4810 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4811 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4812 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
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 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4818 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4819 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4820 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4821 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4822 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4823 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4824 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4825 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4826 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4827 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4828 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
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, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4835 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4836 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4837 40, 40, 40, 40, 40, 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, 46, 46, 60, 40, 80, 80, /* 29 */
4842 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4843 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4844 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4845 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4846 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4847 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4848 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4849 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4850 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4851 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4852 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4853 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4854 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4855 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4856 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4857 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4858 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4859 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4860 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4861 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4862 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4863 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4864 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4865 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4866 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4867 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4868 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4869 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4870 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4871 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4872 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4873 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4874 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4875 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4876 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4877 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4878 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4879 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4880 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4881 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4882 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4883 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4884 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4885 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4886 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4887 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4888 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4889 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4890 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4891 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4892 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4893 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4894 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4895 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4896 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4897 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4898 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4899 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4900 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4901 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4902 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4903 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4904 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4905 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4906 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4907 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4908 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4909 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4910 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4911 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4912 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4913 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4914 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4915 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4916 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4917 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4918 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4919 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4920 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4921 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4922 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4923 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4924 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4925 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4926 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4927 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4928 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4929 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4930 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4931 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4932 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4933 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4934 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4935 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4936 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4937 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4938 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4939 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4940 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4941 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4942 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4943 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4944 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4945 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4946 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4947 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4948 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4949 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4950 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4951 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4952 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4953 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4954 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4955 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4956 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4957 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4958 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4959 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4960 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4961 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4962 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4963 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4964 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4965 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4966 40, 40, 40, 40, 40, 40, 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, 46, 46, 46, 46, 80, 80, /* 45 */
4970 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4971 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4972 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4973 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4974 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4975 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4976 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4977 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4978 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4979 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4980 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4981 40, 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, 3, /* 47 */
4984 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4985 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4986 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4987 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4988 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4989 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4990 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4991 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4992 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4993 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4994 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4995 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4996 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
4997 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
4998 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
4999 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
5000 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
5001 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
5002 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
5003 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
5004 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
5005 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
5006 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5007 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5008 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5009 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
5010 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
5011 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
5012 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
5013 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
5014 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
5015 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
5016 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
5017 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
5018 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5019 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5020 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5021 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5022 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
5023 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
5024 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
5025 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
5026 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
5027 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
5028 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
5029 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5030 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5031 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
5032 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
5033 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
5034 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5035 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5036 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5037 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
5038 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5039 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5040 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5041 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
5042 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
5043 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
5044 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5045 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5046 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5047 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
5048 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
5049 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
5050 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5051 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
5052 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
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, /* 57 */
5059 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5060 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5061 40, 40, 46, 46, 46, 46, 46, 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, 40, 40, 40, 40, 40, 40, /* 57 */
5065 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
5066 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5067 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5068 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5069 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
5070 40, 40, 40, 46, 46, 46, 46, 46, /* 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, 40, 40, 40, 40, 40, /* 58 */
5074 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5075 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
5076 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
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, 46, 46, 46, 46, 46, 46, /* 59 */
5082 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5083 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
5084 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
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, /* 61 */
5091 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5092 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
5093 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
5094 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5095 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5096 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5097 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
5098 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5099 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
5100 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
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, 46, 46, 46, 46, 46, 46, /* 62 */
5106 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5107 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5108 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
5109 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
5110 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5111 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5112 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
5113 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
5114 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
5115 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
5116 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
5117 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
5118 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
5119 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
5120 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
5121 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
5122 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5123 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5124 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5125 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5126 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
5127 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
5128 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
5129 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
5130 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
5131 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
5132 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
5133 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
5134 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
5135 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
5136 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
5137 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
5138 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
5139 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
5140 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
5141 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
5142 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
5143 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
5144 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
5145 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
5146 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
5147 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5148 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5149 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5150 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
5151 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
5152 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
5153 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
5154 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
5155 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
5156 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5157 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5158 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
5159 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
5160 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5161 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5162 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5163 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5164 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
5165 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
5166 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
5167 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5168 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5169 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5170 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
5171 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
5172 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
5173 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
5174 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
5175 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
5176 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
5177 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
5178 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5179 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5180 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
5181 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
5182 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
5183 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
5184 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
5185 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
5186 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
5187 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
5188 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
5189 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5190 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5191 15, 15, 15, 15, 15, 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, /* 74 */
5195 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5196 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
5197 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5198 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5199 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
5200 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5201 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5202 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5203 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5204 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
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, /* 76 */
5211 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5212 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
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, 46, 46, 46, 46, 46, 46, /* 76 */
5217 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
5218 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
5219 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
5220 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5221 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5222 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
5223 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
5224 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5225 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5226 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5227 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5228 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
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, 46, 46, 46, 46, 46, /* 78 */
5234 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5235 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5236 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5237 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5238 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
5239 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5240 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5241 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5242 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
5243 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
5244 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5245 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5246 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5247 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5248 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
5249 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
5250 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
5251 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5252 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5253 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
5254 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5255 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5256 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
5257 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
5258 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5259 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5260 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5261 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5262 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5263 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
5264 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5265 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5266 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5267 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5268 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
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, /* 84 */
5275 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5276 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
5277 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
5278 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5279 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5280 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5281 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5282 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5283 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5284 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
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 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5289 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5290 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5291 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5292 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
5293 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
5294 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5295 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5296 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5297 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5298 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
5299 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
5300 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5301 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5302 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5303 46, 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 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5307 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
5308 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
5309 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
5310 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5311 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
5312 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
5313 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
5314 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
5315 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
5316 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
5317 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5318 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5319 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5320 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5321 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
5322 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
5323 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
5324 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
5325 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
5326 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
5327 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
5328 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
5329 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
5330 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5331 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5332 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5333 40, 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, /* 92 */
5339 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5340 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
5341 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
5342 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5343 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5344 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5345 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5346 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5347 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5348 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
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, 3, 59, 59, 59, 46, /* 93 */
5354 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
5355 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5356 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5357 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5358 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5359 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
5360 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5361 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5362 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
5363 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
5364 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
5365 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
5366 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5367 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5368 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5369 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5370 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5371 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5372 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5373 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
5374 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
5375 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
5376 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5377 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5378 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
5379 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5380 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5381 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5382 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5383 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5384 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5385 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
5386 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
5387 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
5388 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5389 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5390 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5391 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5392 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5393 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5394 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5395 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
5396 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5397 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5398 15, 15, 15, 15, 15, 15, 15, 15, /* 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, 46, /* 99 */
5402 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5403 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5404 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
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, 46, /* 100 */
5409 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
5410 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5411 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5412 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5413 15, 15, 15, 15, 15, 15, 46, 46, /* 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, 15, 15, /* 101 */
5417 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
5418 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5419 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5420 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5421 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5422 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
5423 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5424 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5425 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5426 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5427 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5428 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5429 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5430 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
5431 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5432 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5433 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5434 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5435 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5436 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
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 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5443 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5444 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
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 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5451 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5452 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
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, 46, 46, /* 106 */
5456 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5457 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5458 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
5459 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
5460 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
5461 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
5462 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
5463 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
5464 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
5465 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
5466 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
5467 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5468 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5469 40, 40, 40, 40, 40, 40, 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, /* 109 */
5475 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5476 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
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, 46, 46, 46, 46, 46, 46, /* 109 */
5481 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
5482 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5483 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5484 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
5485 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5486 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5487 40, 40, 40, 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, /* 111 */
5491 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5492 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
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, 5, 6, /* 111 */
5498 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5499 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5500 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5501 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5502 40, 40, 40, 40, 40, 40, 40, 40, /* 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, /* 113 */
5507 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5508 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
5509 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5510 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5511 40, 40, 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, /* 114 */
5515 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5516 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5517 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5518 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5519 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5520 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5521 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
5522 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5523 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5524 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5525 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5526 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
5527 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5528 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
5529 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
5530 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
5531 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
5532 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
5533 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
5534 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
5535 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
5536 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
5537 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
5538 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5539 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5540 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
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, 46, 46, 104, /* 117 */
5546 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
5547 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
5548 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
5549 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
5550 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5551 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5552 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5553 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
5554 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5555 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5556 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5557 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
5558 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
5559 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5560 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5561 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5562 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5563 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5564 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5565 40, 40, 40, 40, 40, 40, 59, 59, /* 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, 40, 40, /* 120 */
5569 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
5570 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5571 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5572 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5573 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
5574 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
5575 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
5576 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
5577 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
5580 /* The A table has 124 entries for a total of 496 bytes. */
5582 const uint32 js_A
[] = {
5583 0x0001000F, /* 0 Cc, ignorable */
5584 0x0004000F, /* 1 Cc, whitespace */
5585 0x0004000C, /* 2 Zs, whitespace */
5586 0x00000018, /* 3 Po */
5587 0x0006001A, /* 4 Sc, currency */
5588 0x00000015, /* 5 Ps */
5589 0x00000016, /* 6 Pe */
5590 0x00000019, /* 7 Sm */
5591 0x00000014, /* 8 Pd */
5592 0x00036089, /* 9 Nd, identifier part, decimal 16 */
5593 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
5594 0x0000001B, /* 11 Sk */
5595 0x00050017, /* 12 Pc, underscore */
5596 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5597 0x0000000C, /* 14 Zs */
5598 0x0000001C, /* 15 So */
5599 0x00070182, /* 16 Ll, identifier start */
5600 0x0000600B, /* 17 No, decimal 16 */
5601 0x0000500B, /* 18 No, decimal 8 */
5602 0x0000800B, /* 19 No, strange */
5603 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
5604 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
5605 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
5606 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
5607 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
5608 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
5609 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
5610 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
5611 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
5612 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
5613 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
5614 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
5615 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
5616 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
5617 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
5618 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
5619 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
5620 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
5621 0x00070181, /* 38 Lu, identifier start */
5622 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
5623 0x00070185, /* 40 Lo, identifier start */
5624 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
5625 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
5626 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
5627 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5628 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
5629 0x00000000, /* 46 unassigned */
5630 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
5631 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
5632 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
5633 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
5634 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
5635 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
5636 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
5637 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
5638 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
5639 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
5640 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
5641 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
5642 0x00070084, /* 59 Lm, identifier start */
5643 0x00030086, /* 60 Mn, identifier part */
5644 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
5645 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
5646 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
5647 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
5648 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
5649 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
5650 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
5651 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
5652 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
5653 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
5654 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
5655 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
5656 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
5657 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
5658 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
5659 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
5660 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
5661 0x00034089, /* 78 Nd, identifier part, decimal 0 */
5662 0x00000087, /* 79 Me */
5663 0x00030088, /* 80 Mc, identifier part */
5664 0x00037489, /* 81 Nd, identifier part, decimal 26 */
5665 0x00005A0B, /* 82 No, decimal 13 */
5666 0x00006E0B, /* 83 No, decimal 23 */
5667 0x0000740B, /* 84 No, decimal 26 */
5668 0x0000000B, /* 85 No */
5669 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
5670 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
5671 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
5672 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
5673 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
5674 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
5675 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
5676 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
5677 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
5678 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
5679 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
5680 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
5681 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
5682 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
5683 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
5684 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
5685 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
5686 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
5687 0x00010010, /* 104 Cf, ignorable */
5688 0x0004000D, /* 105 Zl, whitespace */
5689 0x0004000E, /* 106 Zp, whitespace */
5690 0x0000400B, /* 107 No, decimal 0 */
5691 0x0000440B, /* 108 No, decimal 2 */
5692 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
5693 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
5694 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5695 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
5696 0x0007818A, /* 113 Nl, identifier start, strange */
5697 0x0000420B, /* 114 No, decimal 1 */
5698 0x0000720B, /* 115 No, decimal 25 */
5699 0x06A0001C, /* 116 So, hasLower (add 26) */
5700 0x0690001C, /* 117 So, hasUpper (subtract 26) */
5701 0x00006C0B, /* 118 No, decimal 22 */
5702 0x0000560B, /* 119 No, decimal 11 */
5703 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
5704 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
5705 0x00000013, /* 122 Cs */
5706 0x00000012 /* 123 Co */
5709 const jschar js_uriReservedPlusPound_ucstr
[] =
5710 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5711 const jschar js_uriUnescaped_ucstr
[] =
5712 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5713 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5714 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5715 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5716 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5717 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5720 * This table allows efficient testing for the regular expression \w which is
5721 * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5723 const bool js_alnum
[] = {
5724 /* 0 1 2 3 4 5 5 7 8 9 */
5725 /* 0 */ false, false, false, false, false, false, false, false, false, false,
5726 /* 1 */ false, false, false, false, false, false, false, false, false, false,
5727 /* 2 */ false, false, false, false, false, false, false, false, false, false,
5728 /* 3 */ false, false, false, false, false, false, false, false, false, false,
5729 /* 4 */ false, false, false, false, false, false, false, false, true, true,
5730 /* 5 */ true, true, true, true, true, true, true, true, false, false,
5731 /* 6 */ false, false, false, false, false, true, true, true, true, true,
5732 /* 7 */ true, true, true, true, true, true, true, true, true, true,
5733 /* 8 */ true, true, true, true, true, true, true, true, true, true,
5734 /* 9 */ true, false, false, false, false, true, false, true, true, true,
5735 /* 10 */ true, true, true, true, true, true, true, true, true, true,
5736 /* 11 */ true, true, true, true, true, true, true, true, true, true,
5737 /* 12 */ true, true, true, false, false, false, false, false
5740 #define URI_CHUNK 64U
5743 TransferBufferToString(JSContext
*cx
, JSCharBuffer
&cb
, Value
*rval
)
5745 JSString
*str
= js_NewStringFromCharBuffer(cx
, cb
);
5748 rval
->setString(str
);
5753 * ECMA 3, 15.1.3 URI Handling Function Properties
5755 * The following are implementations of the algorithms
5756 * given in the ECMA specification for the hidden functions
5757 * 'Encode' and 'Decode'.
5760 Encode(JSContext
*cx
, JSString
*str
, const jschar
*unescapedSet
,
5761 const jschar
*unescapedSet2
, Value
*rval
)
5763 size_t length
, j
, k
, L
;
5764 JSCharBuffer
cb(cx
);
5765 const jschar
*chars
;
5770 static const char HexDigits
[] = "0123456789ABCDEF"; /* NB: uppercase */
5772 str
->getCharsAndLength(chars
, length
);
5774 rval
->setString(cx
->runtime
->emptyString
);
5778 /* From this point the control must goto bad on failures. */
5781 for (k
= 0; k
< length
; k
++) {
5783 if (js_strchr(unescapedSet
, c
) ||
5784 (unescapedSet2
&& js_strchr(unescapedSet2
, c
))) {
5788 if ((c
>= 0xDC00) && (c
<= 0xDFFF)) {
5789 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5790 JSMSG_BAD_URI
, NULL
);
5793 if (c
< 0xD800 || c
> 0xDBFF) {
5798 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5799 JSMSG_BAD_URI
, NULL
);
5803 if ((c2
< 0xDC00) || (c2
> 0xDFFF)) {
5804 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5805 JSMSG_BAD_URI
, NULL
);
5808 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
5810 L
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
5811 for (j
= 0; j
< L
; j
++) {
5812 hexBuf
[1] = HexDigits
[utf8buf
[j
] >> 4];
5813 hexBuf
[2] = HexDigits
[utf8buf
[j
] & 0xf];
5814 if (!cb
.append(hexBuf
, 3))
5820 return TransferBufferToString(cx
, cb
, rval
);
5824 Decode(JSContext
*cx
, JSString
*str
, const jschar
*reservedSet
, Value
*rval
)
5826 size_t length
, start
, k
;
5827 JSCharBuffer
cb(cx
);
5828 const jschar
*chars
;
5835 str
->getCharsAndLength(chars
, length
);
5837 rval
->setString(cx
->runtime
->emptyString
);
5841 /* From this point the control must goto bad on failures. */
5842 for (k
= 0; k
< length
; k
++) {
5846 if ((k
+ 2) >= length
)
5847 goto report_bad_uri
;
5848 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5849 goto report_bad_uri
;
5850 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5856 while (B
& (0x80 >> n
))
5858 if (n
== 1 || n
> 4)
5859 goto report_bad_uri
;
5860 octets
[0] = (uint8
)B
;
5861 if (k
+ 3 * (n
- 1) >= length
)
5862 goto report_bad_uri
;
5863 for (j
= 1; j
< n
; j
++) {
5865 if (chars
[k
] != '%')
5866 goto report_bad_uri
;
5867 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5868 goto report_bad_uri
;
5869 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5870 if ((B
& 0xC0) != 0x80)
5871 goto report_bad_uri
;
5873 octets
[j
] = (char)B
;
5875 v
= Utf8ToOneUcs4Char(octets
, n
);
5879 goto report_bad_uri
;
5880 c
= (jschar
)((v
& 0x3FF) + 0xDC00);
5881 H
= (jschar
)((v
>> 10) + 0xD800);
5888 if (js_strchr(reservedSet
, c
)) {
5889 if (!cb
.append(chars
+ start
, k
- start
+ 1))
5901 return TransferBufferToString(cx
, cb
, rval
);
5904 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_URI
);
5911 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5915 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5918 return Decode(cx
, str
, js_uriReservedPlusPound_ucstr
, vp
);
5922 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5926 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5929 return Decode(cx
, str
, js_empty_ucstr
, vp
);
5933 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5937 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5940 return Encode(cx
, str
, js_uriReservedPlusPound_ucstr
, js_uriUnescaped_ucstr
,
5945 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5949 str
= ArgToRootedString(cx
, argc
, vp
, 0);
5952 return Encode(cx
, str
, js_uriUnescaped_ucstr
, NULL
, vp
);
5956 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5957 * least 4 bytes long. Return the number of UTF-8 bytes of data written.
5960 js_OneUcs4ToUtf8Char(uint8
*utf8Buffer
, uint32 ucs4Char
)
5964 JS_ASSERT(ucs4Char
<= 0x10FFFF);
5965 if (ucs4Char
< 0x80) {
5966 *utf8Buffer
= (uint8
)ucs4Char
;
5969 uint32 a
= ucs4Char
>> 11;
5977 utf8Buffer
[i
] = (uint8
)((ucs4Char
& 0x3F) | 0x80);
5980 *utf8Buffer
= (uint8
)(0x100 - (1 << (8-utf8Length
)) + ucs4Char
);
5986 * Convert a utf8 character sequence into a UCS-4 character and return that
5987 * character. It is assumed that the caller already checked that the sequence
5991 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
)
5995 /* from Unicode 3.1, non-shortest form is illegal */
5996 static const uint32 minucs4Table
[] = {
5997 0x00000080, 0x00000800, 0x00010000
6000 JS_ASSERT(utf8Length
>= 1 && utf8Length
<= 4);
6001 if (utf8Length
== 1) {
6002 ucs4Char
= *utf8Buffer
;
6003 JS_ASSERT(!(ucs4Char
& 0x80));
6005 JS_ASSERT((*utf8Buffer
& (0x100 - (1 << (7-utf8Length
)))) ==
6006 (0x100 - (1 << (8-utf8Length
))));
6007 ucs4Char
= *utf8Buffer
++ & ((1<<(7-utf8Length
))-1);
6008 minucs4Char
= minucs4Table
[utf8Length
-2];
6009 while (--utf8Length
) {
6010 JS_ASSERT((*utf8Buffer
& 0xC0) == 0x80);
6011 ucs4Char
= ucs4Char
<<6 | (*utf8Buffer
++ & 0x3F);
6013 if (JS_UNLIKELY(ucs4Char
< minucs4Char
)) {
6014 ucs4Char
= OVERLONG_UTF8
;
6015 } else if (ucs4Char
== 0xFFFE || ucs4Char
== 0xFFFF) {
6022 #if defined DEBUG || defined JS_DUMP_CONSERVATIVE_GC_ROOTS
6024 JS_FRIEND_API(size_t)
6025 js_PutEscapedStringImpl(char *buffer
, size_t bufferSize
, FILE *fp
,
6026 JSString
*str
, uint32 quote
)
6028 const jschar
*chars
, *charsEnd
;
6032 uintN u
, hex
, shift
;
6034 STOP
, FIRST_QUOTE
, LAST_QUOTE
, CHARS
, ESCAPE_START
, ESCAPE_MORE
6037 JS_ASSERT(quote
== 0 || quote
== '\'' || quote
== '"');
6038 JS_ASSERT_IF(buffer
, bufferSize
!= 0);
6039 JS_ASSERT_IF(!buffer
, bufferSize
== 0);
6040 JS_ASSERT_IF(fp
, !buffer
);
6042 str
->getCharsAndEnd(chars
, charsEnd
);
6045 state
= FIRST_QUOTE
;
6049 c
= 0; /* to quell GCC warnings */
6066 if (chars
== charsEnd
) {
6073 escape
= strchr(js_EscapeMap
, (int)u
);
6082 if (u
== quote
|| u
== '\\')
6085 } else if (u
< 0x100) {
6100 state
= ESCAPE_START
;
6103 JS_ASSERT(' ' <= u
&& u
< 127);
6105 state
= ESCAPE_MORE
;
6113 u
= 0xF & (hex
>> shift
);
6114 c
= (char)(u
+ (u
< 10 ? '0' : 'A' - 10));
6118 if (n
== bufferSize
)