1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JS string type implementation.
44 * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
45 * native methods store strings (possibly newborn) converted from their 'this'
46 * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
47 * conversions at their index (argv[0], argv[1]). This is a legitimate method
48 * of rooting things that might lose their newborn root due to subsequent GC
49 * allocations in the same native method.
62 #include "jsbuiltins.h"
64 #include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */
73 #include "jsstaticcheck.h"
77 #include "jsversion.h"
79 #include "jscntxtinlines.h"
80 #include "jsinterpinlines.h"
81 #include "jsobjinlines.h"
82 #include "jsregexpinlines.h"
83 #include "jsstrinlines.h"
84 #include "jsautooplen.h" // generated headers last
87 using namespace js::gc
;
89 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH
) <= size_t(JSVAL_INT_MAX
));
90 JS_STATIC_ASSERT(JSString::MAX_LENGTH
<= JSVAL_INT_MAX
);
93 js_GetStringChars(JSContext
*cx
, JSString
*str
)
95 if (!js_MakeStringImmutable(cx
, str
))
97 return str
->flatChars();
100 static JS_ALWAYS_INLINE
size_t
101 RopeCapacityFor(size_t length
)
103 static const size_t ROPE_DOUBLING_MAX
= 1024 * 1024;
106 * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
107 * next power of 2. This is similar to what we do with arrays; see
108 * JSObject::ensureDenseArrayElements.
110 if (length
> ROPE_DOUBLING_MAX
)
111 return length
+ (length
/ 8);
112 return RoundUpPow2(length
);
115 static JS_ALWAYS_INLINE jschar
*
116 AllocChars(JSContext
*maybecx
, size_t wholeCapacity
)
118 /* +1 for the null char at the end. */
119 JS_STATIC_ASSERT(JSString::MAX_LENGTH
* sizeof(jschar
) < UINT32_MAX
);
120 size_t bytes
= (wholeCapacity
+ 1) * sizeof(jschar
);
122 return (jschar
*)maybecx
->malloc(bytes
);
123 return (jschar
*)js_malloc(bytes
);
127 JSString::flatten(JSContext
*maybecx
)
132 * Perform a depth-first dag traversal, splatting each node's characters
133 * into a contiguous buffer. Visit each rope node three times:
134 * 1. record position in the buffer and recurse into left child;
135 * 2. recurse into the right child;
136 * 3. transform the node into a dependent string.
137 * To avoid maintaining a stack, tree nodes are mutated to indicate how
138 * many times they have been visited. Since ropes can be dags, a node may
139 * be encountered multiple times during traversal. However, step 3 above
140 * leaves a valid dependent string, so everythings works out. This
141 * algorithm is homomorphic to TypedMarker(JSTracer *, JSString *).
143 * While ropes avoid all sorts of quadratic cases with string
144 * concatenation, they can't help when ropes are immediately flattened.
145 * One idiomatic case that we'd like to keep linear (and has traditionally
146 * been linear in SM and other JS engines) is:
153 * To do this, when the buffer for a to-be-flattened rope is allocated, the
154 * allocation size is rounded up. Then, if the resulting flat string is the
155 * left-hand side of a new rope that gets flattened and there is enough
156 * capacity, the rope is flattened into the same buffer, thereby avoiding
157 * copying the left-hand side. Clearing the 'extensible' bit turns off this
158 * optimization. This is necessary, e.g., when the JSAPI hands out the raw
159 * null-terminated char array of a flat string.
161 * N.B. This optimization can create chains of dependent strings.
163 const size_t wholeLength
= length();
164 size_t wholeCapacity
;
166 JSString
*str
= this;
169 if (u
.left
->isExtensible() && u
.left
->s
.capacity
>= wholeLength
) {
170 wholeCapacity
= u
.left
->s
.capacity
;
171 wholeChars
= const_cast<jschar
*>(u
.left
->u
.chars
);
172 pos
= wholeChars
+ u
.left
->length();
173 u
.left
->finishTraversalConversion(this, wholeChars
, pos
);
174 goto visit_right_child
;
177 wholeCapacity
= RopeCapacityFor(wholeLength
);
178 wholeChars
= AllocChars(maybecx
, wholeCapacity
);
183 maybecx
->runtime
->stringMemoryUsed
+= wholeLength
* 2;
186 JSString
*left
= str
->u
.left
; /* Read before clobbered. */
188 if (left
->isRope()) {
189 left
->s
.parent
= str
; /* Return to this when 'left' done, */
190 left
->lengthAndFlags
= 0x200; /* but goto visit_right_child. */
192 goto first_visit_node
;
194 size_t len
= left
->length();
195 PodCopy(pos
, left
->u
.chars
, len
);
199 JSString
*right
= str
->s
.right
;
200 if (right
->isRope()) {
201 right
->s
.parent
= str
; /* Return to this node when 'right' done, */
202 right
->lengthAndFlags
= 0x300; /* but goto finish_node. */
204 goto first_visit_node
;
206 size_t len
= right
->length();
207 PodCopy(pos
, right
->u
.chars
, len
);
212 JS_ASSERT(pos
== wholeChars
+ wholeLength
);
214 initFlatExtensible(wholeChars
, wholeLength
, wholeCapacity
);
217 size_t progress
= str
->lengthAndFlags
; /* Read before clobbered. */
218 JSString
*parent
= str
->s
.parent
;
219 str
->finishTraversalConversion(this, wholeChars
, pos
);
221 if (progress
== 0x200)
222 goto visit_right_child
;
227 JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT
== 8);
228 JSStringFinalizeOp
JSExternalString::str_finalizers
[JSExternalString::TYPE_LIMIT
] = {
229 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
235 js_Flatten(JSContext
*cx
, JSString
* str
)
237 return !!str
->flatten(cx
);
239 JS_DEFINE_CALLINFO_2(extern, BOOL
, js_Flatten
, CONTEXT
, STRING
, 0, nanojit::ACCSET_STORE_ANY
)
241 #endif /* !JS_TRACER */
243 JSString
* JS_FASTCALL
244 js_ConcatStrings(JSContext
*cx
, JSString
*left
, JSString
*right
)
246 size_t leftLen
= left
->length();
250 size_t rightLen
= right
->length();
254 size_t wholeLength
= leftLen
+ rightLen
;
256 if (JSShortString::fitsIntoShortString(wholeLength
)) {
257 JSShortString
*shortStr
= js_NewGCShortString(cx
);
260 const jschar
*leftChars
= left
->getChars(cx
);
263 const jschar
*rightChars
= right
->getChars(cx
);
267 jschar
*buf
= shortStr
->init(wholeLength
);
268 js_short_strncpy(buf
, leftChars
, leftLen
);
269 js_short_strncpy(buf
+ leftLen
, rightChars
, rightLen
);
270 buf
[wholeLength
] = 0;
271 return shortStr
->header();
274 if (wholeLength
> JSString::MAX_LENGTH
) {
275 if (JS_ON_TRACE(cx
)) {
276 if (!CanLeaveTrace(cx
))
280 js_ReportAllocationOverflow(cx
);
284 JSString
*newRoot
= js_NewGCString(cx
);
288 newRoot
->initRopeNode(left
, right
, wholeLength
);
293 JSString::undepend(JSContext
*cx
)
298 if (!ensureLinear(cx
))
302 n
= dependentLength();
303 size
= (n
+ 1) * sizeof(jschar
);
304 s
= (jschar
*) cx
->malloc(size
);
308 cx
->runtime
->stringMemoryUsed
+= size
;
309 js_strncpy(s
, dependentChars(), n
);
315 JSRuntime
*rt
= cx
->runtime
;
316 JS_RUNTIME_UNMETER(rt
, liveDependentStrings
);
317 JS_RUNTIME_UNMETER(rt
, totalDependentStrings
);
318 JS_LOCK_RUNTIME_VOID(rt
,
319 (rt
->strdepLengthSum
-= (double)n
,
320 rt
->strdepLengthSquaredSum
-= (double)n
* (double)n
));
329 js_MakeStringImmutable(JSContext
*cx
, JSString
*str
)
332 * Flattening a rope may result in a dependent string, so we need to flatten
333 * before undepending the string.
335 if (!str
->isFlat() && !str
->undepend(cx
)) {
336 JS_RUNTIME_METER(cx
->runtime
, badUndependStrings
);
339 str
->flatClearExtensible();
343 static JSLinearString
*
344 ArgToRootedString(JSContext
*cx
, uintN argc
, Value
*vp
, uintN arg
)
347 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
350 if (vp
->isObject() && !DefaultValue(cx
, &vp
->toObject(), JSTYPE_STRING
, vp
))
354 if (vp
->isString()) {
355 str
= vp
->toString()->ensureLinear(cx
);
356 } else if (vp
->isBoolean()) {
357 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.booleanAtoms
[
358 (int)vp
->toBoolean()]);
359 } else if (vp
->isNull()) {
360 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
361 } else if (vp
->isUndefined()) {
362 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
365 str
= NumberToString(cx
, vp
->toNumber());
374 * Forward declarations for URI encode/decode and helper routines
377 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
380 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
383 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
386 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
388 static const uint32 OVERLONG_UTF8
= UINT32_MAX
;
391 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
);
394 * Contributions from the String class to the set of methods defined for the
395 * global object. escape and unescape used to be defined in the Mocha library,
396 * but as ECMA decided to spec them, they've been moved to the core engine
397 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
398 * characters by unescape.)
402 * Stuff to emulate the old libmocha escape, which took a second argument
403 * giving the type of escape to perform. Retained for compatibility, and
404 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
407 #define URL_XALPHAS ((uint8) 1)
408 #define URL_XPALPHAS ((uint8) 2)
409 #define URL_PATH ((uint8) 4)
411 static const uint8 urlCharType
[256] =
412 /* Bit 0 xalpha -- the alphas
413 * Bit 1 xpalpha -- as xalpha but
414 * converts spaces to plus and plus to %20
415 * Bit 2 ... path -- as xalphas but doesn't escape '/'
417 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
418 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
419 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
420 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
421 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
422 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
423 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
424 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
425 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
428 /* This matches the ECMA escape set when mask is 7 (default.) */
430 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
432 /* See ECMA-262 Edition 3 B.2.1 */
434 js_str_escape(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
, Value
*rval
)
436 const char digits
[] = {'0', '1', '2', '3', '4', '5', '6', '7',
437 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
439 jsint mask
= URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
;
442 if (!ValueToNumber(cx
, argv
[1], &d
))
444 if (!JSDOUBLE_IS_FINITE(d
) ||
445 (mask
= (jsint
)d
) != d
||
446 mask
& ~(URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
))
449 JS_snprintf(numBuf
, sizeof numBuf
, "%lx", (unsigned long) mask
);
450 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
451 JSMSG_BAD_STRING_MASK
, numBuf
);
456 JSLinearString
*str
= ArgToRootedString(cx
, argc
, argv
- 2, 0);
460 size_t length
= str
->length();
461 const jschar
*chars
= str
->chars();
463 /* Take a first pass and see how big the result string will need to be. */
464 size_t newlength
= length
;
465 for (size_t i
= 0; i
< length
; i
++) {
467 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
))
470 if (mask
== URL_XPALPHAS
&& ch
== ' ')
471 continue; /* The character will be encoded as '+' */
472 newlength
+= 2; /* The character will be encoded as %XX */
474 newlength
+= 5; /* The character will be encoded as %uXXXX */
478 * This overflow test works because newlength is incremented by at
479 * most 5 on each iteration.
481 if (newlength
< length
) {
482 js_ReportAllocationOverflow(cx
);
487 if (newlength
>= ~(size_t)0 / sizeof(jschar
)) {
488 js_ReportAllocationOverflow(cx
);
492 jschar
*newchars
= (jschar
*) cx
->malloc((newlength
+ 1) * sizeof(jschar
));
496 for (i
= 0, ni
= 0; i
< length
; i
++) {
498 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
)) {
500 } else if (ch
< 256) {
501 if (mask
== URL_XPALPHAS
&& ch
== ' ') {
502 newchars
[ni
++] = '+'; /* convert spaces to pluses */
504 newchars
[ni
++] = '%';
505 newchars
[ni
++] = digits
[ch
>> 4];
506 newchars
[ni
++] = digits
[ch
& 0xF];
509 newchars
[ni
++] = '%';
510 newchars
[ni
++] = 'u';
511 newchars
[ni
++] = digits
[ch
>> 12];
512 newchars
[ni
++] = digits
[(ch
& 0xF00) >> 8];
513 newchars
[ni
++] = digits
[(ch
& 0xF0) >> 4];
514 newchars
[ni
++] = digits
[ch
& 0xF];
517 JS_ASSERT(ni
== newlength
);
518 newchars
[newlength
] = 0;
520 JSString
*retstr
= js_NewString(cx
, newchars
, newlength
);
525 rval
->setString(retstr
);
531 str_escape(JSContext
*cx
, uintN argc
, Value
*vp
)
533 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
534 return obj
&& js_str_escape(cx
, obj
, argc
, vp
+ 2, vp
);
537 /* See ECMA-262 Edition 3 B.2.2 */
539 str_unescape(JSContext
*cx
, uintN argc
, Value
*vp
)
541 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
545 size_t length
= str
->length();
546 const jschar
*chars
= str
->chars();
548 /* Don't bother allocating less space for the new string. */
549 jschar
*newchars
= (jschar
*) cx
->malloc((length
+ 1) * sizeof(jschar
));
552 size_t ni
= 0, i
= 0;
554 jschar ch
= chars
[i
++];
556 if (i
+ 1 < length
&&
557 JS7_ISHEX(chars
[i
]) && JS7_ISHEX(chars
[i
+ 1]))
559 ch
= JS7_UNHEX(chars
[i
]) * 16 + JS7_UNHEX(chars
[i
+ 1]);
561 } else if (i
+ 4 < length
&& chars
[i
] == 'u' &&
562 JS7_ISHEX(chars
[i
+ 1]) && JS7_ISHEX(chars
[i
+ 2]) &&
563 JS7_ISHEX(chars
[i
+ 3]) && JS7_ISHEX(chars
[i
+ 4]))
565 ch
= (((((JS7_UNHEX(chars
[i
+ 1]) << 4)
566 + JS7_UNHEX(chars
[i
+ 2])) << 4)
567 + JS7_UNHEX(chars
[i
+ 3])) << 4)
568 + JS7_UNHEX(chars
[i
+ 4]);
576 JSString
*retstr
= js_NewString(cx
, newchars
, ni
);
581 vp
->setString(retstr
);
587 str_uneval(JSContext
*cx
, uintN argc
, Value
*vp
)
591 str
= js_ValueToSource(cx
, argc
!= 0 ? vp
[2] : UndefinedValue());
599 const char js_escape_str
[] = "escape";
600 const char js_unescape_str
[] = "unescape";
602 const char js_uneval_str
[] = "uneval";
604 const char js_decodeURI_str
[] = "decodeURI";
605 const char js_encodeURI_str
[] = "encodeURI";
606 const char js_decodeURIComponent_str
[] = "decodeURIComponent";
607 const char js_encodeURIComponent_str
[] = "encodeURIComponent";
609 static JSFunctionSpec string_functions
[] = {
610 JS_FN(js_escape_str
, str_escape
, 1,0),
611 JS_FN(js_unescape_str
, str_unescape
, 1,0),
613 JS_FN(js_uneval_str
, str_uneval
, 1,0),
615 JS_FN(js_decodeURI_str
, str_decodeURI
, 1,0),
616 JS_FN(js_encodeURI_str
, str_encodeURI
, 1,0),
617 JS_FN(js_decodeURIComponent_str
, str_decodeURI_Component
, 1,0),
618 JS_FN(js_encodeURIComponent_str
, str_encodeURI_Component
, 1,0),
623 jschar js_empty_ucstr
[] = {0};
624 JSSubString js_EmptySubString
= {0, js_empty_ucstr
};
627 str_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
631 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
632 if (obj
->getClass() == &js_StringClass
) {
633 /* Follow ECMA-262 by fetching intrinsic length of our string. */
634 str
= obj
->getPrimitiveThis().toString();
636 /* Preserve compatibility: convert obj to a string primitive. */
637 str
= js_ValueToString(cx
, ObjectValue(*obj
));
642 vp
->setInt32(str
->length());
648 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
651 str_enumerate(JSContext
*cx
, JSObject
*obj
)
653 JSString
*str
, *str1
;
656 str
= obj
->getPrimitiveThis().toString();
658 length
= str
->length();
659 for (i
= 0; i
< length
; i
++) {
660 str1
= js_NewDependentString(cx
, str
, i
, 1);
663 if (!obj
->defineProperty(cx
, INT_TO_JSID(i
), StringValue(str1
),
664 PropertyStub
, PropertyStub
,
665 STRING_ELEMENT_ATTRS
)) {
670 return obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
671 UndefinedValue(), NULL
, NULL
,
672 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_SHARED
);
676 str_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
679 if (!JSID_IS_INT(id
))
682 JSString
*str
= obj
->getPrimitiveThis().toString();
684 jsint slot
= JSID_TO_INT(id
);
685 if ((size_t)slot
< str
->length()) {
686 JSString
*str1
= JSString::getUnitString(cx
, str
, size_t(slot
));
689 if (!obj
->defineProperty(cx
, id
, StringValue(str1
), NULL
, NULL
,
690 STRING_ELEMENT_ATTRS
)) {
698 Class js_StringClass
= {
700 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE
|
701 JSCLASS_HAS_CACHED_PROTO(JSProto_String
),
702 PropertyStub
, /* addProperty */
703 PropertyStub
, /* delProperty */
705 PropertyStub
, /* setProperty */
707 (JSResolveOp
)str_resolve
,
711 #define NORMALIZE_THIS(cx,vp,str) \
713 if (vp[1].isString()) { \
714 str = vp[1].toString(); \
716 str = NormalizeThis(cx, vp); \
723 NormalizeThis(JSContext
*cx
, Value
*vp
)
725 if (vp
[1].isNullOrUndefined() && !ComputeThisFromVp(cx
, vp
))
729 * String.prototype.{toString,toSource,valueOf} throw a TypeError if the
730 * this-argument is not a string or a String object. So those methods use
731 * js::GetPrimitiveThis which provides that behavior.
733 * By standard, the rest of the String methods must ToString the
734 * this-argument rather than throw a TypeError. So those methods use
735 * NORMALIZE_THIS (and thus NormalizeThis) instead.
737 if (vp
[1].isObject()) {
738 JSObject
*obj
= &vp
[1].toObject();
739 if (obj
->getClass() == &js_StringClass
) {
740 vp
[1] = obj
->getPrimitiveThis();
741 return vp
[1].toString();
745 JSString
*str
= js_ValueToString(cx
, vp
[1]);
748 vp
[1].setString(str
);
755 * String.prototype.quote is generic (as are most string methods), unlike
756 * toSource, toString, and valueOf.
759 str_quote(JSContext
*cx
, uintN argc
, Value
*vp
)
763 NORMALIZE_THIS(cx
, vp
, str
);
764 str
= js_QuoteString(cx
, str
, '"');
772 str_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
775 if (!GetPrimitiveThis(cx
, vp
, &str
))
778 str
= js_QuoteString(cx
, str
, '"');
783 size_t j
= JS_snprintf(buf
, sizeof buf
, "(new String(");
785 size_t k
= str
->length();
786 const jschar
*s
= str
->getChars(cx
);
790 size_t n
= j
+ k
+ 2;
791 jschar
*t
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
796 for (i
= 0; i
< j
; i
++)
798 for (j
= 0; j
< k
; i
++, j
++)
804 str
= js_NewString(cx
, t
, n
);
813 #endif /* JS_HAS_TOSOURCE */
816 js_str_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
819 if (!GetPrimitiveThis(cx
, vp
, &str
))
826 * Java-like string native methods.
829 JS_ALWAYS_INLINE
bool
830 ValueToIntegerRange(JSContext
*cx
, const Value
&v
, int32
*out
)
837 if (!ValueToNumber(cx
, v
, &d
))
840 d
= js_DoubleToInteger(d
);
843 else if (d
< INT32_MIN
)
853 str_substring(JSContext
*cx
, uintN argc
, Value
*vp
)
856 int32 length
, begin
, end
;
858 NORMALIZE_THIS(cx
, vp
, str
);
861 end
= length
= int32(str
->length());
863 if (!ValueToIntegerRange(cx
, vp
[2], &begin
))
868 else if (begin
> length
)
871 if (argc
> 1 && !vp
[3].isUndefined()) {
872 if (!ValueToIntegerRange(cx
, vp
[3], &end
))
888 str
= js_NewDependentString(cx
, str
, size_t(begin
), size_t(end
- begin
));
897 JSString
* JS_FASTCALL
898 js_toLowerCase(JSContext
*cx
, JSString
*str
)
900 size_t n
= str
->length();
901 const jschar
*s
= str
->getChars(cx
);
905 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
908 for (size_t i
= 0; i
< n
; i
++)
909 news
[i
] = JS_TOLOWER(s
[i
]);
911 str
= js_NewString(cx
, news
, n
);
920 str_toLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
924 NORMALIZE_THIS(cx
, vp
, str
);
925 str
= js_toLowerCase(cx
, str
);
933 str_toLocaleLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
938 * Forcefully ignore the first (or any) argument and return toLowerCase(),
939 * ECMA has reserved that argument, presumably for defining the locale.
941 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToLowerCase
) {
942 NORMALIZE_THIS(cx
, vp
, str
);
943 return cx
->localeCallbacks
->localeToLowerCase(cx
, str
, Jsvalify(vp
));
945 return str_toLowerCase(cx
, 0, vp
);
948 JSString
* JS_FASTCALL
949 js_toUpperCase(JSContext
*cx
, JSString
*str
)
951 size_t n
= str
->length();
952 const jschar
*s
= str
->getChars(cx
);
955 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
958 for (size_t i
= 0; i
< n
; i
++)
959 news
[i
] = JS_TOUPPER(s
[i
]);
961 str
= js_NewString(cx
, news
, n
);
970 str_toUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
974 NORMALIZE_THIS(cx
, vp
, str
);
975 str
= js_toUpperCase(cx
, str
);
983 str_toLocaleUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
988 * Forcefully ignore the first (or any) argument and return toUpperCase(),
989 * ECMA has reserved that argument, presumably for defining the locale.
991 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUpperCase
) {
992 NORMALIZE_THIS(cx
, vp
, str
);
993 return cx
->localeCallbacks
->localeToUpperCase(cx
, str
, Jsvalify(vp
));
995 return str_toUpperCase(cx
, 0, vp
);
999 str_localeCompare(JSContext
*cx
, uintN argc
, Value
*vp
)
1001 JSString
*str
, *thatStr
;
1003 NORMALIZE_THIS(cx
, vp
, str
);
1007 thatStr
= js_ValueToString(cx
, vp
[2]);
1010 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeCompare
) {
1011 vp
[2].setString(thatStr
);
1012 return cx
->localeCallbacks
->localeCompare(cx
, str
, thatStr
, Jsvalify(vp
));
1015 if (!CompareStrings(cx
, str
, thatStr
, &result
))
1017 vp
->setInt32(result
);
1023 js_str_charAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1029 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1030 str
= vp
[1].toString();
1031 i
= vp
[2].toInt32();
1032 if ((size_t)i
>= str
->length())
1035 NORMALIZE_THIS(cx
, vp
, str
);
1040 if (!ValueToNumber(cx
, vp
[2], &d
))
1042 d
= js_DoubleToInteger(d
);
1045 if (d
< 0 || str
->length() <= d
)
1050 str
= JSString::getUnitString(cx
, str
, size_t(i
));
1057 vp
->setString(cx
->runtime
->emptyString
);
1062 js_str_charCodeAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1066 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1067 str
= vp
[1].toString();
1068 i
= vp
[2].toInt32();
1069 if ((size_t)i
>= str
->length())
1072 NORMALIZE_THIS(cx
, vp
, str
);
1078 if (!ValueToNumber(cx
, vp
[2], &d
))
1080 d
= js_DoubleToInteger(d
);
1083 if (d
< 0 || str
->length() <= d
)
1088 const jschar
*chars
;
1089 chars
= str
->getChars(cx
);
1093 vp
->setInt32(chars
[i
]);
1097 vp
->setDouble(js_NaN
);
1102 js_BoyerMooreHorspool(const jschar
*text
, jsuint textlen
,
1103 const jschar
*pat
, jsuint patlen
)
1105 uint8 skip
[sBMHCharSetSize
];
1107 JS_ASSERT(0 < patlen
&& patlen
<= sBMHPatLenMax
);
1108 for (jsuint i
= 0; i
< sBMHCharSetSize
; i
++)
1109 skip
[i
] = (uint8
)patlen
;
1110 jsuint m
= patlen
- 1;
1111 for (jsuint i
= 0; i
< m
; i
++) {
1113 if (c
>= sBMHCharSetSize
)
1114 return sBMHBadPattern
;
1115 skip
[c
] = (uint8
)(m
- i
);
1120 k
+= ((c
= text
[k
]) >= sBMHCharSetSize
) ? patlen
: skip
[c
]) {
1121 for (jsuint i
= k
, j
= m
; ; i
--, j
--) {
1122 if (text
[i
] != pat
[j
])
1125 return static_cast<jsint
>(i
); /* safe: max string size */
1132 typedef jsuint Extent
;
1133 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*, jsuint patlen
) {
1134 return (patlen
- 1) * sizeof(jschar
);
1136 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1137 return memcmp(p
, t
, extent
) == 0;
1142 typedef const jschar
*Extent
;
1143 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*pat
, jsuint patlen
) {
1144 return pat
+ patlen
;
1146 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1147 for (; p
!= extent
; ++p
, ++t
) {
1155 template <class InnerMatch
>
1157 UnrolledMatch(const jschar
*text
, jsuint textlen
, const jschar
*pat
, jsuint patlen
)
1159 JS_ASSERT(patlen
> 0 && textlen
> 0);
1160 const jschar
*textend
= text
+ textlen
- (patlen
- 1);
1161 const jschar p0
= *pat
;
1162 const jschar
*const patNext
= pat
+ 1;
1163 const typename
InnerMatch::Extent extent
= InnerMatch::computeExtent(pat
, patlen
);
1166 const jschar
*t
= text
;
1167 switch ((textend
- t
) & 7) {
1168 case 0: if (*t
++ == p0
) { fixup
= 8; goto match
; }
1169 case 7: if (*t
++ == p0
) { fixup
= 7; goto match
; }
1170 case 6: if (*t
++ == p0
) { fixup
= 6; goto match
; }
1171 case 5: if (*t
++ == p0
) { fixup
= 5; goto match
; }
1172 case 4: if (*t
++ == p0
) { fixup
= 4; goto match
; }
1173 case 3: if (*t
++ == p0
) { fixup
= 3; goto match
; }
1174 case 2: if (*t
++ == p0
) { fixup
= 2; goto match
; }
1175 case 1: if (*t
++ == p0
) { fixup
= 1; goto match
; }
1177 while (t
!= textend
) {
1178 if (t
[0] == p0
) { t
+= 1; fixup
= 8; goto match
; }
1179 if (t
[1] == p0
) { t
+= 2; fixup
= 7; goto match
; }
1180 if (t
[2] == p0
) { t
+= 3; fixup
= 6; goto match
; }
1181 if (t
[3] == p0
) { t
+= 4; fixup
= 5; goto match
; }
1182 if (t
[4] == p0
) { t
+= 5; fixup
= 4; goto match
; }
1183 if (t
[5] == p0
) { t
+= 6; fixup
= 3; goto match
; }
1184 if (t
[6] == p0
) { t
+= 7; fixup
= 2; goto match
; }
1185 if (t
[7] == p0
) { t
+= 8; fixup
= 1; goto match
; }
1191 if (!InnerMatch::match(patNext
, t
, extent
))
1193 return t
- text
- 1;
1196 } while (--fixup
> 0);
1201 static JS_ALWAYS_INLINE jsint
1202 StringMatch(const jschar
*text
, jsuint textlen
,
1203 const jschar
*pat
, jsuint patlen
)
1207 if (textlen
< patlen
)
1210 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1212 * Given enough registers, the unrolled loop below is faster than the
1213 * following loop. 32-bit x86 does not have enough registers.
1216 const jschar p0
= *pat
;
1217 for (const jschar
*c
= text
, *end
= text
+ textlen
; c
!= end
; ++c
) {
1226 * If the text or pattern string is short, BMH will be more expensive than
1227 * the basic linear scan due to initialization cost and a more complex loop
1228 * body. While the correct threshold is input-dependent, we can make a few
1229 * conservative observations:
1230 * - When |textlen| is "big enough", the initialization time will be
1231 * proportionally small, so the worst-case slowdown is minimized.
1232 * - When |patlen| is "too small", even the best case for BMH will be
1233 * slower than a simple scan for large |textlen| due to the more complex
1235 * From this, the values for "big enough" and "too small" are determined
1236 * empirically. See bug 526348.
1238 if (textlen
>= 512 && patlen
>= 11 && patlen
<= sBMHPatLenMax
) {
1239 jsint index
= js_BoyerMooreHorspool(text
, textlen
, pat
, patlen
);
1240 if (index
!= sBMHBadPattern
)
1245 * For big patterns with large potential overlap we want the SIMD-optimized
1246 * speed of memcmp. For small patterns, a simple loop is faster.
1248 * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1251 #if !defined(__linux__)
1252 patlen
> 128 ? UnrolledMatch
<MemCmp
>(text
, textlen
, pat
, patlen
)
1255 UnrolledMatch
<ManualCmp
>(text
, textlen
, pat
, patlen
);
1258 static const size_t sRopeMatchThresholdRatioLog2
= 5;
1261 * RopeMatch takes the text to search, the patern to search for in the text.
1262 * RopeMatch returns false on OOM and otherwise returns the match index through
1263 * the 'match' outparam (-1 for not found).
1266 RopeMatch(JSContext
*cx
, JSString
*textstr
, const jschar
*pat
, jsuint patlen
, jsint
*match
)
1268 JS_ASSERT(textstr
->isRope());
1274 if (textstr
->length() < patlen
) {
1280 * List of leaf nodes in the rope. If we run out of memory when trying to
1281 * append to this list, we can still fall back to StringMatch, so use the
1282 * system allocator so we don't report OOM in that case.
1284 Vector
<JSString
*, 16, SystemAllocPolicy
> strs
;
1287 * We don't want to do rope matching if there is a poor node-to-char ratio,
1288 * since this means spending a lot of time in the match loop below. We also
1289 * need to build the list of leaf nodes. Do both here: iterate over the
1290 * nodes so long as there are not too many.
1293 size_t textstrlen
= textstr
->length();
1294 size_t threshold
= textstrlen
>> sRopeMatchThresholdRatioLog2
;
1295 StringSegmentRange
r(cx
);
1296 if (!r
.init(textstr
))
1298 while (!r
.empty()) {
1299 if (threshold
-- == 0 || !strs
.append(r
.front())) {
1300 const jschar
*chars
= textstr
->getChars(cx
);
1303 *match
= StringMatch(chars
, textstrlen
, pat
, patlen
);
1311 /* Absolute offset from the beginning of the logical string textstr. */
1314 // TODO: consider branching to a simple loop if patlen == 1
1316 for (JSString
**outerp
= strs
.begin(); outerp
!= strs
.end(); ++outerp
) {
1317 /* First try to match without spanning two nodes. */
1318 JSString
*outer
= *outerp
;
1319 const jschar
*chars
= outer
->nonRopeChars();
1320 size_t len
= outer
->length();
1321 jsint matchResult
= StringMatch(chars
, len
, pat
, patlen
);
1322 if (matchResult
!= -1) {
1323 *match
= pos
+ matchResult
;
1327 /* Test the overlap. */
1328 JSString
**innerp
= outerp
;
1331 * Start searching at the first place where StringMatch wouldn't have
1334 const jschar
*const text
= chars
+ (patlen
> len
? 0 : len
- patlen
+ 1);
1335 const jschar
*const textend
= chars
+ len
;
1336 const jschar p0
= *pat
;
1337 const jschar
*const p1
= pat
+ 1;
1338 const jschar
*const patend
= pat
+ patlen
;
1339 for (const jschar
*t
= text
; t
!= textend
; ) {
1342 const jschar
*ttend
= textend
;
1343 for (const jschar
*pp
= p1
, *tt
= t
; pp
!= patend
; ++pp
, ++tt
) {
1344 while (tt
== ttend
) {
1345 if (++innerp
== strs
.end()) {
1349 JSString
*inner
= *innerp
;
1350 tt
= inner
->nonRopeChars();
1351 ttend
= tt
+ inner
->length();
1354 goto break_continue
;
1358 *match
= pos
+ (t
- chars
) - 1; /* -1 because of *t++ above */
1372 str_indexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1376 NORMALIZE_THIS(cx
, vp
, str
);
1378 JSLinearString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1382 jsuint textlen
= str
->length();
1383 const jschar
*text
= str
->getChars(cx
);
1387 jsuint patlen
= patstr
->length();
1388 const jschar
*pat
= patstr
->chars();
1392 if (vp
[3].isInt32()) {
1393 jsint i
= vp
[3].toInt32();
1396 } else if (jsuint(i
) > textlen
) {
1406 if (!ValueToNumber(cx
, vp
[3], &d
))
1408 d
= js_DoubleToInteger(d
);
1411 } else if (d
> textlen
) {
1424 jsint match
= StringMatch(text
, textlen
, pat
, patlen
);
1425 vp
->setInt32((match
== -1) ? -1 : start
+ match
);
1430 str_lastIndexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1433 NORMALIZE_THIS(cx
, vp
, textstr
);
1434 size_t textlen
= textstr
->length();
1435 const jschar
*text
= textstr
->getChars(cx
);
1439 JSLinearString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1443 size_t patlen
= patstr
->length();
1444 const jschar
*pat
= patstr
->chars();
1446 jsint i
= textlen
- patlen
; // Start searching here
1453 if (vp
[3].isInt32()) {
1454 jsint j
= vp
[3].toInt32();
1461 if (!ValueToNumber(cx
, vp
[3], &d
))
1463 if (!JSDOUBLE_IS_NaN(d
)) {
1464 d
= js_DoubleToInteger(d
);
1478 const jschar
*t
= text
+ i
;
1479 const jschar
*textend
= text
- 1;
1480 const jschar p0
= *pat
;
1481 const jschar
*patNext
= pat
+ 1;
1482 const jschar
*patEnd
= pat
+ patlen
;
1484 for (; t
!= textend
; --t
) {
1486 const jschar
*t1
= t
+ 1;
1487 for (const jschar
*p1
= patNext
; p1
!= patEnd
; ++p1
, ++t1
) {
1489 goto break_continue
;
1491 vp
->setInt32(t
- text
);
1502 js_TrimString(JSContext
*cx
, Value
*vp
, JSBool trimLeft
, JSBool trimRight
)
1505 NORMALIZE_THIS(cx
, vp
, str
);
1506 size_t length
= str
->length();
1507 const jschar
*chars
= str
->getChars(cx
);
1512 size_t end
= length
;
1515 while (begin
< length
&& JS_ISSPACE(chars
[begin
]))
1520 while (end
> begin
&& JS_ISSPACE(chars
[end
-1]))
1524 str
= js_NewDependentString(cx
, str
, begin
, end
- begin
);
1533 str_trim(JSContext
*cx
, uintN argc
, Value
*vp
)
1535 return js_TrimString(cx
, vp
, JS_TRUE
, JS_TRUE
);
1539 str_trimLeft(JSContext
*cx
, uintN argc
, Value
*vp
)
1541 return js_TrimString(cx
, vp
, JS_TRUE
, JS_FALSE
);
1545 str_trimRight(JSContext
*cx
, uintN argc
, Value
*vp
)
1547 return js_TrimString(cx
, vp
, JS_FALSE
, JS_TRUE
);
1551 * Perl-inspired string functions.
1554 /* Result of a successfully performed flat match. */
1557 JSLinearString
*patstr
;
1562 friend class RegExpGuard
;
1565 FlatMatch() : patstr(NULL
) {} /* Old GCC wants this initialization. */
1566 JSString
*pattern() const { return patstr
; }
1567 size_t patternLength() const { return patlen
; }
1570 * Note: The match is -1 when the match is performed successfully,
1571 * but no match is found.
1573 int32
match() const { return match_
; }
1576 /* A regexp and optional associated object. */
1579 AutoRefCount
<RegExp
> arc
;
1583 explicit RegExpPair(RegExpPair
&);
1586 explicit RegExpPair(JSContext
*cx
, RegExp
*re
) : arc(cx
, re
), re_(re
) {}
1588 void reset(JSObject
&reobj
) {
1590 re_
= RegExp::extractFrom(&reobj
);
1595 void reset(RegExp
&re
) {
1601 /* Note: May be null. */
1602 JSObject
*reobj() const { return reobj_
; }
1603 RegExp
&re() const { JS_ASSERT(re_
); return *re_
; }
1604 bool hasRegExp() const { return !!re_
; }
1608 * RegExpGuard factors logic out of String regexp operations.
1610 * @param optarg Indicates in which argument position RegExp
1611 * flags will be found, if present. This is a Mozilla
1612 * extension and not part of any ECMA spec.
1616 RegExpGuard(const RegExpGuard
&);
1617 void operator=(const RegExpGuard
&);
1624 * Upper bound on the number of characters we are willing to potentially
1625 * waste on searching for RegExp meta-characters.
1627 static const size_t MAX_FLAT_PAT_LEN
= 256;
1629 static JSString
*flattenPattern(JSContext
*cx
, JSLinearString
*patstr
) {
1630 StringBuffer
sb(cx
);
1631 if (!sb
.reserve(patstr
->length()))
1634 static const jschar ESCAPE_CHAR
= '\\';
1635 const jschar
*chars
= patstr
->chars();
1636 size_t len
= patstr
->length();
1637 for (const jschar
*it
= chars
; it
!= chars
+ len
; ++it
) {
1638 if (RegExp::isMetaChar(*it
)) {
1639 if (!sb
.append(ESCAPE_CHAR
) || !sb
.append(*it
))
1642 if (!sb
.append(*it
))
1646 return sb
.finishString();
1650 explicit RegExpGuard(JSContext
*cx
) : cx(cx
), rep(cx
, NULL
) {}
1653 /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1655 init(uintN argc
, Value
*vp
)
1657 if (argc
!= 0 && VALUE_IS_REGEXP(cx
, vp
[2])) {
1658 rep
.reset(vp
[2].toObject());
1660 fm
.patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1668 * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1669 * pattern string, or a lengthy pattern string can thwart this process.
1671 * @param checkMetaChars Look for regexp metachars in the pattern string.
1672 * @return Whether flat matching could be used.
1674 * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->isExceptionPending().
1677 tryFlatMatch(JSContext
*cx
, JSString
*textstr
, uintN optarg
, uintN argc
,
1678 bool checkMetaChars
= true)
1680 if (rep
.hasRegExp())
1683 fm
.pat
= fm
.patstr
->chars();
1684 fm
.patlen
= fm
.patstr
->length();
1689 if (checkMetaChars
&&
1690 (fm
.patlen
> MAX_FLAT_PAT_LEN
|| RegExp::hasMetaChars(fm
.pat
, fm
.patlen
))) {
1695 * textstr could be a rope, so we want to avoid flattening it for as
1698 if (textstr
->isRope()) {
1699 if (!RopeMatch(cx
, textstr
, fm
.pat
, fm
.patlen
, &fm
.match_
))
1702 const jschar
*text
= textstr
->nonRopeChars();
1703 size_t textlen
= textstr
->length();
1704 fm
.match_
= StringMatch(text
, textlen
, fm
.pat
, fm
.patlen
);
1709 /* If the pattern is not already a regular expression, make it so. */
1711 normalizeRegExp(bool flat
, uintN optarg
, uintN argc
, Value
*vp
)
1713 if (rep
.hasRegExp())
1716 /* Build RegExp from pattern string. */
1718 if (optarg
< argc
) {
1719 opt
= js_ValueToString(cx
, vp
[2 + optarg
]);
1728 patstr
= flattenPattern(cx
, fm
.patstr
);
1736 RegExp
*re
= RegExp::createFlagged(cx
, patstr
, opt
);
1744 bool hasRegExpPair() const { return rep
.hasRegExp(); }
1748 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1749 static JS_ALWAYS_INLINE
bool
1750 Matched(bool test
, const Value
&v
)
1752 return test
? v
.isTrue() : !v
.isNull();
1755 typedef bool (*DoMatchCallback
)(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *data
);
1758 * BitOR-ing these flags allows the DoMatch caller to control when how the
1759 * RegExp engine is called and when callbacks are fired.
1761 enum MatchControlFlags
{
1762 TEST_GLOBAL_BIT
= 0x1, /* use RegExp.test for global regexps */
1763 TEST_SINGLE_BIT
= 0x2, /* use RegExp.test for non-global regexps */
1764 CALLBACK_ON_SINGLE_BIT
= 0x4, /* fire callback on non-global match */
1766 MATCH_ARGS
= TEST_GLOBAL_BIT
,
1767 MATCHALL_ARGS
= CALLBACK_ON_SINGLE_BIT
,
1768 REPLACE_ARGS
= TEST_GLOBAL_BIT
| TEST_SINGLE_BIT
| CALLBACK_ON_SINGLE_BIT
1771 /* Factor out looping and matching logic. */
1773 DoMatch(JSContext
*cx
, RegExpStatics
*res
, Value
*vp
, JSString
*str
, const RegExpPair
&rep
,
1774 DoMatchCallback callback
, void *data
, MatchControlFlags flags
)
1776 RegExp
&re
= rep
.re();
1778 /* global matching ('g') */
1779 bool testGlobal
= flags
& TEST_GLOBAL_BIT
;
1781 rep
.reobj()->zeroRegExpLastIndex();
1782 for (size_t count
= 0, i
= 0, length
= str
->length(); i
<= length
; ++count
) {
1783 if (!re
.execute(cx
, res
, str
, &i
, testGlobal
, vp
))
1785 if (!Matched(testGlobal
, *vp
))
1787 if (!callback(cx
, res
, count
, data
))
1789 if (!res
->matched())
1794 bool testSingle
= !!(flags
& TEST_SINGLE_BIT
),
1795 callbackOnSingle
= !!(flags
& CALLBACK_ON_SINGLE_BIT
);
1797 if (!re
.execute(cx
, res
, str
, &i
, testSingle
, vp
))
1799 if (callbackOnSingle
&& Matched(testSingle
, *vp
) && !callback(cx
, res
, 0, data
))
1806 BuildFlatMatchArray(JSContext
*cx
, JSString
*textstr
, const FlatMatch
&fm
, Value
*vp
)
1808 if (fm
.match() < 0) {
1813 /* For this non-global match, produce a RegExp.exec-style array. */
1814 JSObject
*obj
= NewSlowEmptyArray(cx
);
1817 vp
->setObject(*obj
);
1819 return obj
->defineProperty(cx
, INT_TO_JSID(0), StringValue(fm
.pattern())) &&
1820 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.indexAtom
),
1821 Int32Value(fm
.match())) &&
1822 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.inputAtom
),
1823 StringValue(textstr
));
1826 typedef JSObject
**MatchArgType
;
1829 * DoMatch will only callback on global matches, hence this function builds
1830 * only the "array of matches" returned by match on global regexps.
1833 MatchCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
1835 JS_ASSERT(count
<= JSID_INT_MAX
); /* by max string length */
1837 JSObject
*&arrayobj
= *static_cast<MatchArgType
>(p
);
1839 arrayobj
= NewDenseEmptyArray(cx
);
1845 if (!res
->createLastMatch(cx
, &v
))
1848 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
1849 return !!arrayobj
->setProperty(cx
, INT_TO_JSID(count
), &v
, false);
1853 str_match(JSContext
*cx
, uintN argc
, Value
*vp
)
1856 NORMALIZE_THIS(cx
, vp
, str
);
1859 if (!g
.init(argc
, vp
))
1861 if (const FlatMatch
*fm
= g
.tryFlatMatch(cx
, str
, 1, argc
))
1862 return BuildFlatMatchArray(cx
, str
, *fm
, vp
);
1863 if (cx
->isExceptionPending()) /* from tryFlatMatch */
1866 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1870 AutoObjectRooter
array(cx
);
1871 MatchArgType arg
= array
.addr();
1872 RegExpStatics
*res
= cx
->regExpStatics();
1873 if (!DoMatch(cx
, res
, vp
, str
, *rep
, MatchCallback
, arg
, MATCH_ARGS
))
1876 /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1877 if (rep
->re().global())
1878 vp
->setObjectOrNull(array
.object());
1883 str_search(JSContext
*cx
, uintN argc
, Value
*vp
)
1886 NORMALIZE_THIS(cx
, vp
, str
);
1889 if (!g
.init(argc
, vp
))
1891 if (const FlatMatch
*fm
= g
.tryFlatMatch(cx
, str
, 1, argc
)) {
1892 vp
->setInt32(fm
->match());
1895 if (cx
->isExceptionPending()) /* from tryFlatMatch */
1897 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1901 RegExpStatics
*res
= cx
->regExpStatics();
1903 if (!rep
->re().execute(cx
, res
, str
, &i
, true, vp
))
1907 vp
->setInt32(res
->matchStart());
1915 ReplaceData(JSContext
*cx
)
1919 JSString
*str
; /* 'this' parameter object as a string */
1920 RegExpGuard g
; /* regexp parameter object and private data */
1921 JSObject
*lambda
; /* replacement function object or null */
1922 JSObject
*elembase
; /* object for function(a){return b[a]} replace */
1923 JSLinearString
*repstr
; /* replacement string */
1924 const jschar
*dollar
; /* null or pointer to first $ in repstr */
1925 const jschar
*dollarEnd
; /* limit pointer for js_strchr_limit */
1926 jsint leftIndex
; /* left context index in str->chars */
1927 JSSubString dollarStr
; /* for "$$" InterpretDollar result */
1928 bool calledBack
; /* record whether callback has been called */
1929 InvokeSessionGuard session
; /* arguments for repeated lambda Invoke call */
1930 InvokeArgsGuard singleShot
; /* arguments for single lambda Invoke call */
1931 StringBuffer sb
; /* buffer built during DoMatch */
1935 InterpretDollar(JSContext
*cx
, RegExpStatics
*res
, const jschar
*dp
, const jschar
*ep
,
1936 ReplaceData
&rdata
, JSSubString
*out
, size_t *skip
)
1938 JS_ASSERT(*dp
== '$');
1940 /* If there is only a dollar, bail now */
1944 /* Interpret all Perl match-induced dollar variables. */
1946 if (JS7_ISDEC(dc
)) {
1947 /* ECMA-262 Edition 3: 1-9 or 01-99 */
1948 uintN num
= JS7_UNDEC(dc
);
1949 if (num
> res
->parenCount())
1952 const jschar
*cp
= dp
+ 2;
1953 if (cp
< ep
&& (dc
= *cp
, JS7_ISDEC(dc
))) {
1954 uintN tmp
= 10 * num
+ JS7_UNDEC(dc
);
1955 if (tmp
<= res
->parenCount()) {
1965 JS_ASSERT(num
<= res
->parenCount());
1968 * Note: we index to get the paren with the (1-indexed) pair
1969 * number, as opposed to a (0-indexed) paren number.
1971 res
->getParen(num
, out
);
1978 rdata
.dollarStr
.chars
= dp
;
1979 rdata
.dollarStr
.length
= 1;
1980 *out
= rdata
.dollarStr
;
1983 res
->getLastMatch(out
);
1986 res
->getLastParen(out
);
1989 res
->getLeftContext(out
);
1992 res
->getRightContext(out
);
1999 FindReplaceLength(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, size_t *sizep
)
2001 JSObject
*base
= rdata
.elembase
;
2004 * The base object is used when replace was passed a lambda which looks like
2005 * 'function(a) { return b[a]; }' for the base object b. b will not change
2006 * in the course of the replace unless we end up making a scripted call due
2007 * to accessing a scripted getter or a value with a scripted toString.
2009 JS_ASSERT(rdata
.lambda
);
2010 JS_ASSERT(!base
->getOps()->lookupProperty
);
2011 JS_ASSERT(!base
->getOps()->getProperty
);
2014 if (!res
->createLastMatch(cx
, &match
))
2016 JSString
*str
= match
.toString();
2019 if (str
->isAtomized()) {
2020 atom
= STRING_TO_ATOM(str
);
2022 atom
= js_AtomizeString(cx
, str
, 0);
2026 jsid id
= ATOM_TO_JSID(atom
);
2029 JSProperty
*prop
= NULL
;
2030 if (js_LookupPropertyWithFlags(cx
, base
, id
, JSRESOLVE_QUALIFIED
, &holder
, &prop
) < 0)
2033 /* Only handle the case where the property exists and is on this object. */
2034 if (prop
&& holder
== base
) {
2035 Shape
*shape
= (Shape
*) prop
;
2036 if (shape
->slot
!= SHAPE_INVALID_SLOT
&& shape
->hasDefaultGetter()) {
2037 Value value
= base
->getSlot(shape
->slot
);
2038 if (value
.isString()) {
2039 rdata
.repstr
= value
.toString()->ensureLinear(cx
);
2042 *sizep
= rdata
.repstr
->length();
2049 * Couldn't handle this property, fall through and despecialize to the
2050 * general lambda case.
2052 rdata
.elembase
= NULL
;
2055 JSObject
*lambda
= rdata
.lambda
;
2058 * In the lambda case, not only do we find the replacement string's
2059 * length, we compute repstr and return it via rdata for use within
2060 * DoReplace. The lambda is called with arguments ($&, $1, $2, ...,
2061 * index, input), i.e., all the properties of a regexp match array.
2062 * For $&, etc., we must create string jsvals from cx->regExpStatics.
2063 * We grab up stack space to keep the newborn strings GC-rooted.
2065 uintN p
= res
->parenCount();
2066 uintN argc
= 1 + p
+ 2;
2068 InvokeSessionGuard
&session
= rdata
.session
;
2069 if (!session
.started()) {
2070 Value lambdav
= ObjectValue(*lambda
);
2071 if (!session
.start(cx
, lambdav
, UndefinedValue(), argc
))
2075 PreserveRegExpStatics
staticsGuard(res
);
2076 if (!staticsGuard
.init(cx
))
2079 /* Push $&, $1, $2, ... */
2081 if (!res
->createLastMatch(cx
, &session
[argi
++]))
2084 for (size_t i
= 0; i
< res
->parenCount(); ++i
) {
2085 if (!res
->createParen(cx
, i
+ 1, &session
[argi
++]))
2089 /* Push match index and input string. */
2090 session
[argi
++].setInt32(res
->matchStart());
2091 session
[argi
].setString(rdata
.str
);
2093 if (!session
.invoke(cx
))
2096 /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2097 JSString
*repstr
= ValueToString_TestForStringInline(cx
, session
.rval());
2100 rdata
.repstr
= repstr
->ensureLinear(cx
);
2103 *sizep
= rdata
.repstr
->length();
2107 JSString
*repstr
= rdata
.repstr
;
2108 size_t replen
= repstr
->length();
2109 for (const jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
;
2110 dp
= js_strchr_limit(dp
, '$', ep
)) {
2113 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2114 replen
+= sub
.length
- skip
;
2125 * Precondition: |rdata.sb| already has necessary growth space reserved (as
2126 * derived from FindReplaceLength).
2129 DoReplace(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
)
2131 JSLinearString
*repstr
= rdata
.repstr
;
2133 const jschar
*bp
= cp
= repstr
->chars();
2135 const jschar
*dp
= rdata
.dollar
;
2136 const jschar
*ep
= rdata
.dollarEnd
;
2137 for (; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2138 /* Move one of the constant portions of the replacement value. */
2139 size_t len
= dp
- cp
;
2140 JS_ALWAYS_TRUE(rdata
.sb
.append(cp
, len
));
2145 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2147 JS_ALWAYS_TRUE(rdata
.sb
.append(sub
.chars
, len
));
2154 JS_ALWAYS_TRUE(rdata
.sb
.append(cp
, repstr
->length() - (cp
- bp
)));
2158 ReplaceRegExpCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
2160 ReplaceData
&rdata
= *static_cast<ReplaceData
*>(p
);
2162 rdata
.calledBack
= true;
2163 JSLinearString
*str
= rdata
.str
->assertIsLinear(); /* flattened for regexp */
2164 size_t leftoff
= rdata
.leftIndex
;
2165 const jschar
*left
= str
->chars() + leftoff
;
2166 size_t leftlen
= res
->matchStart() - leftoff
;
2167 rdata
.leftIndex
= res
->matchLimit();
2169 size_t replen
= 0; /* silence 'unused' warning */
2170 if (!FindReplaceLength(cx
, res
, rdata
, &replen
))
2173 size_t growth
= leftlen
+ replen
;
2174 if (!rdata
.sb
.reserve(rdata
.sb
.length() + growth
))
2176 JS_ALWAYS_TRUE(rdata
.sb
.append(left
, leftlen
)); /* skipped-over portion of the search value */
2177 DoReplace(cx
, res
, rdata
);
2182 BuildFlatReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2183 const FlatMatch
&fm
, Value
*vp
)
2185 RopeBuilder
builder(cx
);
2186 size_t match
= fm
.match();
2187 size_t matchEnd
= match
+ fm
.patternLength();
2189 if (textstr
->isRope()) {
2191 * If we are replacing over a rope, avoid flattening it by iterating
2192 * through it, building a new rope.
2194 StringSegmentRange
r(cx
);
2195 if (!r
.init(textstr
))
2198 while (!r
.empty()) {
2199 JSString
*str
= r
.front();
2200 size_t len
= str
->length();
2201 size_t strEnd
= pos
+ len
;
2202 if (pos
< matchEnd
&& strEnd
> match
) {
2204 * We need to special-case any part of the rope that overlaps
2205 * with the replacement string.
2209 * If this part of the rope overlaps with the left side of
2210 * the pattern, then it must be the only one to overlap with
2211 * the first character in the pattern, so we include the
2212 * replacement string here.
2214 JSString
*leftSide
= js_NewDependentString(cx
, str
, 0, match
- pos
);
2216 !builder
.append(leftSide
) ||
2217 !builder
.append(repstr
)) {
2223 * If str runs off the end of the matched string, append the
2226 if (strEnd
> matchEnd
) {
2227 JSString
*rightSide
= js_NewDependentString(cx
, str
, matchEnd
- pos
,
2229 if (!rightSide
|| !builder
.append(rightSide
))
2233 if (!builder
.append(str
))
2236 pos
+= str
->length();
2241 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, match
);
2244 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, match
+ fm
.patternLength(),
2245 textstr
->length() - match
- fm
.patternLength());
2247 !builder
.append(leftSide
) ||
2248 !builder
.append(repstr
) ||
2249 !builder
.append(rightSide
)) {
2254 vp
->setString(builder
.result());
2259 * Perform a linear-scan dollar substitution on the replacement text,
2260 * constructing a result string that looks like:
2262 * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2265 BuildDollarReplacement(JSContext
*cx
, JSString
*textstrArg
, JSLinearString
*repstr
,
2266 const jschar
*firstDollar
, const FlatMatch
&fm
, Value
*vp
)
2268 JSLinearString
*textstr
= textstrArg
->ensureLinear(cx
);
2272 JS_ASSERT(repstr
->chars() <= firstDollar
&& firstDollar
< repstr
->chars() + repstr
->length());
2273 size_t matchStart
= fm
.match();
2274 size_t matchLimit
= matchStart
+ fm
.patternLength();
2279 * len(newstr) >= len(orig) - len(match) + len(replacement)
2281 * Note that dollar vars _could_ make the resulting text smaller than this.
2283 StringBuffer
newReplaceChars(cx
);
2284 if (!newReplaceChars
.reserve(textstr
->length() - fm
.patternLength() + repstr
->length()))
2287 /* Move the pre-dollar chunk in bulk. */
2288 JS_ALWAYS_TRUE(newReplaceChars
.append(repstr
->chars(), firstDollar
));
2290 /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2291 #define ENSURE(__cond) if (!(__cond)) return false;
2292 const jschar
*repstrLimit
= repstr
->chars() + repstr
->length();
2293 for (const jschar
*it
= firstDollar
; it
< repstrLimit
; ++it
) {
2294 if (*it
!= '$' || it
== repstrLimit
- 1) {
2295 ENSURE(newReplaceChars
.append(*it
));
2299 switch (*(it
+ 1)) {
2300 case '$': /* Eat one of the dollars. */
2301 ENSURE(newReplaceChars
.append(*it
));
2304 ENSURE(newReplaceChars
.append(textstr
->chars() + matchStart
,
2305 textstr
->chars() + matchLimit
));
2308 ENSURE(newReplaceChars
.append(textstr
->chars(), textstr
->chars() + matchStart
));
2311 ENSURE(newReplaceChars
.append(textstr
->chars() + matchLimit
,
2312 textstr
->chars() + textstr
->length()));
2314 default: /* The dollar we saw was not special (no matter what its mother told it). */
2315 ENSURE(newReplaceChars
.append(*it
));
2318 ++it
; /* We always eat an extra char in the above switch. */
2321 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, matchStart
);
2324 JSString
*newReplace
= newReplaceChars
.finishString();
2327 JS_ASSERT(textstr
->length() >= matchLimit
);
2328 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, matchLimit
,
2329 textstr
->length() - matchLimit
);
2332 RopeBuilder
builder(cx
);
2333 ENSURE(builder
.append(leftSide
) &&
2334 builder
.append(newReplace
) &&
2335 builder
.append(rightSide
));
2338 vp
->setString(builder
.result());
2343 str_replace_regexp(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
)
2345 const RegExpPair
*rep
= rdata
.g
.normalizeRegExp(true, 2, argc
, vp
);
2349 rdata
.leftIndex
= 0;
2350 rdata
.calledBack
= false;
2352 RegExpStatics
*res
= cx
->regExpStatics();
2353 if (!DoMatch(cx
, res
, vp
, rdata
.str
, *rep
, ReplaceRegExpCallback
, &rdata
, REPLACE_ARGS
))
2356 if (!rdata
.calledBack
) {
2357 /* Didn't match, so the string is unmodified. */
2358 vp
->setString(rdata
.str
);
2363 res
->getRightContext(&sub
);
2364 if (!rdata
.sb
.append(sub
.chars
, sub
.length
))
2367 JSString
*retstr
= rdata
.sb
.finishString();
2371 vp
->setString(retstr
);
2376 str_replace_flat_lambda(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
,
2377 const FlatMatch
&fm
)
2379 JS_ASSERT(fm
.match() >= 0);
2382 JSString
*matchStr
= js_NewDependentString(cx
, rdata
.str
, fm
.match(), fm
.patternLength());
2386 /* lambda(matchStr, matchStart, textstr) */
2387 static const uint32 lambdaArgc
= 3;
2388 if (!cx
->stack().pushInvokeArgs(cx
, lambdaArgc
, &rdata
.singleShot
))
2391 CallArgs
&args
= rdata
.singleShot
;
2392 args
.callee().setObject(*rdata
.lambda
);
2393 args
.thisv().setUndefined();
2395 Value
*sp
= args
.argv();
2396 sp
[0].setString(matchStr
);
2397 sp
[1].setInt32(fm
.match());
2398 sp
[2].setString(rdata
.str
);
2400 if (!Invoke(cx
, rdata
.singleShot
, 0))
2403 JSString
*repstr
= js_ValueToString(cx
, args
.rval());
2407 JSString
*leftSide
= js_NewDependentString(cx
, rdata
.str
, 0, fm
.match());
2411 size_t matchLimit
= fm
.match() + fm
.patternLength();
2412 JSString
*rightSide
= js_NewDependentString(cx
, rdata
.str
, matchLimit
,
2413 rdata
.str
->length() - matchLimit
);
2417 RopeBuilder
builder(cx
);
2418 if (!(builder
.append(leftSide
) &&
2419 builder
.append(repstr
) &&
2420 builder
.append(rightSide
))) {
2424 vp
->setString(builder
.result());
2429 js::str_replace(JSContext
*cx
, uintN argc
, Value
*vp
)
2431 ReplaceData
rdata(cx
);
2432 NORMALIZE_THIS(cx
, vp
, rdata
.str
);
2433 static const uint32 optarg
= 2;
2435 /* Extract replacement string/function. */
2436 if (argc
>= optarg
&& js_IsCallable(vp
[3])) {
2437 rdata
.lambda
= &vp
[3].toObject();
2438 rdata
.elembase
= NULL
;
2439 rdata
.repstr
= NULL
;
2440 rdata
.dollar
= rdata
.dollarEnd
= NULL
;
2442 if (rdata
.lambda
->isFunction()) {
2443 JSFunction
*fun
= rdata
.lambda
->getFunctionPrivate();
2444 if (fun
->isInterpreted()) {
2446 * Pattern match the script to check if it is is indexing into a
2447 * particular object, e.g. 'function(a) { return b[a]; }'. Avoid
2448 * calling the script in such cases, which are used by javascript
2449 * packers (particularly the popular Dean Edwards packer) to efficiently
2450 * encode large scripts. We only handle the code patterns generated
2451 * by such packers here.
2453 JSScript
*script
= fun
->u
.i
.script
;
2454 jsbytecode
*pc
= script
->code
;
2456 Value table
= UndefinedValue();
2457 if (JSOp(*pc
) == JSOP_GETFCSLOT
) {
2458 table
= rdata
.lambda
->getFlatClosureUpvar(GET_UINT16(pc
));
2459 pc
+= JSOP_GETFCSLOT_LENGTH
;
2462 if (table
.isObject() &&
2463 JSOp(*pc
) == JSOP_GETARG
&& GET_SLOTNO(pc
) == 0 &&
2464 JSOp(*(pc
+ JSOP_GETARG_LENGTH
)) == JSOP_GETELEM
&&
2465 JSOp(*(pc
+ JSOP_GETARG_LENGTH
+ JSOP_GETELEM_LENGTH
)) == JSOP_RETURN
) {
2466 Class
*clasp
= table
.toObject().getClass();
2467 if (clasp
->isNative() &&
2468 !clasp
->ops
.lookupProperty
&&
2469 !clasp
->ops
.getProperty
) {
2470 rdata
.elembase
= &table
.toObject();
2476 rdata
.lambda
= NULL
;
2477 rdata
.elembase
= NULL
;
2478 rdata
.repstr
= ArgToRootedString(cx
, argc
, vp
, 1);
2482 /* We're about to store pointers into the middle of our string. */
2483 if (!js_MakeStringImmutable(cx
, rdata
.repstr
))
2485 rdata
.dollarEnd
= rdata
.repstr
->chars() + rdata
.repstr
->length();
2486 rdata
.dollar
= js_strchr_limit(rdata
.repstr
->chars(), '$',
2490 if (!rdata
.g
.init(argc
, vp
))
2494 * Unlike its |String.prototype| brethren, |replace| doesn't convert
2495 * its input to a regular expression. (Even if it contains metachars.)
2497 * However, if the user invokes our (non-standard) |flags| argument
2498 * extension then we revert to creating a regular expression. Note that
2499 * this is observable behavior through the side-effect mutation of the
2503 const FlatMatch
*fm
= rdata
.g
.tryFlatMatch(cx
, rdata
.str
, optarg
, argc
, false);
2505 if (cx
->isExceptionPending()) /* oom in RopeMatch in tryFlatMatch */
2507 JS_ASSERT_IF(!rdata
.g
.hasRegExpPair(), argc
> optarg
);
2508 return str_replace_regexp(cx
, argc
, vp
, rdata
);
2511 if (fm
->match() < 0) {
2512 vp
->setString(rdata
.str
);
2517 return str_replace_flat_lambda(cx
, argc
, vp
, rdata
, *fm
);
2520 * Note: we could optimize the text.length == pattern.length case if we wanted,
2521 * even in the presence of dollar metachars.
2524 return BuildDollarReplacement(cx
, rdata
.str
, rdata
.repstr
, rdata
.dollar
, *fm
, vp
);
2526 return BuildFlatReplacement(cx
, rdata
.str
, rdata
.repstr
, *fm
, vp
);
2530 * Subroutine used by str_split to find the next split point in str, starting
2531 * at offset *ip and looking either for the separator substring given by sep, or
2532 * for the next re match. In the re case, return the matched separator in *sep,
2533 * and the possibly updated offset in *ip.
2535 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2536 * separator occurrence if found, or str->length if no separator is found.
2539 find_split(JSContext
*cx
, RegExpStatics
*res
, JSString
*str
, js::RegExp
*re
, jsint
*ip
,
2543 * Stop if past end of string. If at end of string, we will compare the
2544 * null char stored there (by js_NewString*) to sep->chars[j] in the while
2545 * loop at the end of this function, so that
2547 * "ab,".split(',') => ["ab", ""]
2549 * and the resulting array converts back to the string "ab," for symmetry.
2550 * However, we ape Perl and do this only if there is a sufficiently large
2551 * limit argument (see str_split).
2554 size_t length
= str
->length();
2555 if ((size_t)i
> length
)
2558 const jschar
*chars
= str
->getChars(cx
);
2563 * Match a regular expression against the separator at or above index i.
2564 * Call js_ExecuteRegExp with true for the test argument. On successful
2565 * match, get the separator from cx->regExpStatics.lastMatch.
2572 /* JS1.2 deviated from Perl by never matching at end of string. */
2574 if (!re
->execute(cx
, res
, str
, &index
, true, &rval
))
2576 if (!rval
.isTrue()) {
2577 /* Mismatch: ensure our caller advances i past end of string. */
2583 res
->getLastMatch(sep
);
2584 if (sep
->length
== 0) {
2586 * Empty string match: never split on an empty match at the start
2587 * of a find_split cycle. Same rule as for an empty global match
2592 * "Bump-along" to avoid sticking at an empty match, but don't
2593 * bump past end of string -- our caller must do that by adding
2594 * sep->length to our return value.
2596 if ((size_t)i
== length
)
2601 if ((size_t)i
== length
) {
2603 * If there was a trivial zero-length match at the end of the
2604 * split, then we shouldn't output the matched string at the end
2605 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2610 JS_ASSERT((size_t)i
>= sep
->length
);
2611 return i
- sep
->length
;
2615 * Special case: if sep is the empty string, split str into one character
2616 * substrings. Let our caller worry about whether to split once at end of
2617 * string into an empty substring.
2619 if (sep
->length
== 0)
2620 return ((size_t)i
== length
) ? -1 : i
+ 1;
2623 * Now that we know sep is non-empty, search starting at i in str for an
2624 * occurrence of all of sep's chars. If we find them, return the index of
2625 * the first separator char. Otherwise, return length.
2627 jsint match
= StringMatch(chars
+ i
, length
- i
, sep
->chars
, sep
->length
);
2628 return match
== -1 ? length
: match
+ i
;
2632 str_split(JSContext
*cx
, uintN argc
, Value
*vp
)
2635 NORMALIZE_THIS(cx
, vp
, str
);
2638 Value v
= StringValue(str
);
2639 JSObject
*aobj
= NewDenseCopiedArray(cx
, 1, &v
);
2642 vp
->setObject(*aobj
);
2647 JSSubString
*sep
, tmp
;
2648 if (VALUE_IS_REGEXP(cx
, vp
[2])) {
2649 re
= static_cast<RegExp
*>(vp
[2].toObject().getPrivate());
2652 /* Set a magic value so we can detect a successful re match. */
2656 JSString
*sepstr
= js_ValueToString(cx
, vp
[2]);
2659 vp
[2].setString(sepstr
);
2662 * Point sep at a local copy of sepstr's header because find_split
2663 * will modify sep->length.
2665 tmp
.length
= sepstr
->length();
2666 tmp
.chars
= sepstr
->getChars(cx
);
2673 /* Use the second argument as the split limit, if given. */
2674 uint32 limit
= 0; /* Avoid warning. */
2675 bool limited
= (argc
> 1) && !vp
[3].isUndefined();
2678 if (!ValueToNumber(cx
, vp
[3], &d
))
2681 /* Clamp limit between 0 and 1 + string length. */
2682 limit
= js_DoubleToECMAUint32(d
);
2683 if (limit
> str
->length())
2684 limit
= 1 + str
->length();
2687 AutoValueVector
splits(cx
);
2689 RegExpStatics
*res
= cx
->regExpStatics();
2692 while ((j
= find_split(cx
, res
, str
, re
, &i
, sep
)) >= 0) {
2693 if (limited
&& len
>= limit
)
2696 JSString
*sub
= js_NewDependentString(cx
, str
, i
, size_t(j
- i
));
2697 if (!sub
|| !splits
.append(StringValue(sub
)))
2702 * Imitate perl's feature of including parenthesized substrings that
2703 * matched part of the delimiter in the new array, after the split
2704 * substring that was delimited.
2706 if (re
&& sep
->chars
) {
2707 for (uintN num
= 0; num
< res
->parenCount(); num
++) {
2708 if (limited
&& len
>= limit
)
2711 res
->getParen(num
+ 1, &parsub
);
2712 sub
= js_NewStringCopyN(cx
, parsub
.chars
, parsub
.length
);
2713 if (!sub
|| !splits
.append(StringValue(sub
)))
2719 i
= j
+ sep
->length
;
2725 JSObject
*aobj
= NewDenseCopiedArray(cx
, splits
.length(), splits
.begin());
2728 vp
->setObject(*aobj
);
2732 #if JS_HAS_PERL_SUBSTR
2734 str_substr(JSContext
*cx
, uintN argc
, Value
*vp
)
2737 int32 length
, len
, begin
;
2739 NORMALIZE_THIS(cx
, vp
, str
);
2742 length
= int32(str
->length());
2743 if (!ValueToIntegerRange(cx
, vp
[2], &begin
))
2746 if (begin
>= length
) {
2747 str
= cx
->runtime
->emptyString
;
2751 begin
+= length
; /* length + INT_MIN will always be less then 0 */
2756 if (argc
== 1 || vp
[3].isUndefined()) {
2757 len
= length
- begin
;
2759 if (!ValueToIntegerRange(cx
, vp
[3], &len
))
2763 str
= cx
->runtime
->emptyString
;
2767 if (uint32(length
) < uint32(begin
+ len
))
2768 len
= length
- begin
;
2771 str
= js_NewDependentString(cx
, str
, size_t(begin
), size_t(len
));
2780 #endif /* JS_HAS_PERL_SUBSTR */
2783 * Python-esque sequence operations.
2786 str_concat(JSContext
*cx
, uintN argc
, Value
*vp
)
2788 JSString
*str
, *str2
;
2792 NORMALIZE_THIS(cx
, vp
, str
);
2794 /* Set vp (aka rval) early to handle the argc == 0 case. */
2797 for (i
= 0, argv
= vp
+ 2; i
< argc
; i
++) {
2798 str2
= js_ValueToString(cx
, argv
[i
]);
2801 argv
[i
].setString(str2
);
2803 str
= js_ConcatStrings(cx
, str
, str2
);
2813 str_slice(JSContext
*cx
, uintN argc
, Value
*vp
)
2815 if (argc
== 1 && vp
[1].isString() && vp
[2].isInt32()) {
2816 size_t begin
, end
, length
;
2818 JSString
*str
= vp
[1].toString();
2819 begin
= vp
[2].toInt32();
2820 end
= str
->length();
2822 length
= end
- begin
;
2824 str
= cx
->runtime
->emptyString
;
2827 ? JSString::getUnitString(cx
, str
, begin
)
2828 : js_NewDependentString(cx
, str
, begin
, length
);
2838 NORMALIZE_THIS(cx
, vp
, str
);
2841 double begin
, end
, length
;
2843 if (!ValueToNumber(cx
, vp
[2], &begin
))
2845 begin
= js_DoubleToInteger(begin
);
2846 length
= str
->length();
2851 } else if (begin
> length
) {
2855 if (argc
== 1 || vp
[3].isUndefined()) {
2858 if (!ValueToNumber(cx
, vp
[3], &end
))
2860 end
= js_DoubleToInteger(end
);
2865 } else if (end
> length
) {
2872 str
= js_NewDependentString(cx
, str
,
2874 (size_t)(end
- begin
));
2882 #if JS_HAS_STR_HTML_HELPERS
2884 * HTML composition aids.
2887 tagify(JSContext
*cx
, const char *begin
, JSLinearString
*param
, const char *end
,
2891 NORMALIZE_THIS(cx
, vp
, thisstr
);
2892 JSLinearString
*str
= thisstr
->ensureLinear(cx
);
2899 size_t beglen
= strlen(begin
);
2900 size_t taglen
= 1 + beglen
+ 1; /* '<begin' + '>' */
2901 size_t parlen
= 0; /* Avoid warning. */
2903 parlen
= param
->length();
2904 taglen
+= 2 + parlen
+ 1; /* '="param"' */
2906 size_t endlen
= strlen(end
);
2907 taglen
+= str
->length() + 2 + endlen
+ 1; /* 'str</end>' */
2909 if (taglen
>= ~(size_t)0 / sizeof(jschar
)) {
2910 js_ReportAllocationOverflow(cx
);
2914 jschar
*tagbuf
= (jschar
*) cx
->malloc((taglen
+ 1) * sizeof(jschar
));
2920 for (size_t i
= 0; i
< beglen
; i
++)
2921 tagbuf
[j
++] = (jschar
)begin
[i
];
2925 js_strncpy(&tagbuf
[j
], param
->chars(), parlen
);
2931 js_strncpy(&tagbuf
[j
], str
->chars(), str
->length());
2935 for (size_t i
= 0; i
< endlen
; i
++)
2936 tagbuf
[j
++] = (jschar
)end
[i
];
2938 JS_ASSERT(j
== taglen
);
2941 JSString
*retstr
= js_NewString(cx
, tagbuf
, taglen
);
2943 js_free((char *)tagbuf
);
2946 vp
->setString(retstr
);
2951 tagify_value(JSContext
*cx
, uintN argc
, Value
*vp
,
2952 const char *begin
, const char *end
)
2954 JSLinearString
*param
= ArgToRootedString(cx
, argc
, vp
, 0);
2957 return tagify(cx
, begin
, param
, end
, vp
);
2961 str_bold(JSContext
*cx
, uintN argc
, Value
*vp
)
2963 return tagify(cx
, "b", NULL
, NULL
, vp
);
2967 str_italics(JSContext
*cx
, uintN argc
, Value
*vp
)
2969 return tagify(cx
, "i", NULL
, NULL
, vp
);
2973 str_fixed(JSContext
*cx
, uintN argc
, Value
*vp
)
2975 return tagify(cx
, "tt", NULL
, NULL
, vp
);
2979 str_fontsize(JSContext
*cx
, uintN argc
, Value
*vp
)
2981 return tagify_value(cx
, argc
, vp
, "font size", "font");
2985 str_fontcolor(JSContext
*cx
, uintN argc
, Value
*vp
)
2987 return tagify_value(cx
, argc
, vp
, "font color", "font");
2991 str_link(JSContext
*cx
, uintN argc
, Value
*vp
)
2993 return tagify_value(cx
, argc
, vp
, "a href", "a");
2997 str_anchor(JSContext
*cx
, uintN argc
, Value
*vp
)
2999 return tagify_value(cx
, argc
, vp
, "a name", "a");
3003 str_strike(JSContext
*cx
, uintN argc
, Value
*vp
)
3005 return tagify(cx
, "strike", NULL
, NULL
, vp
);
3009 str_small(JSContext
*cx
, uintN argc
, Value
*vp
)
3011 return tagify(cx
, "small", NULL
, NULL
, vp
);
3015 str_big(JSContext
*cx
, uintN argc
, Value
*vp
)
3017 return tagify(cx
, "big", NULL
, NULL
, vp
);
3021 str_blink(JSContext
*cx
, uintN argc
, Value
*vp
)
3023 return tagify(cx
, "blink", NULL
, NULL
, vp
);
3027 str_sup(JSContext
*cx
, uintN argc
, Value
*vp
)
3029 return tagify(cx
, "sup", NULL
, NULL
, vp
);
3033 str_sub(JSContext
*cx
, uintN argc
, Value
*vp
)
3035 return tagify(cx
, "sub", NULL
, NULL
, vp
);
3037 #endif /* JS_HAS_STR_HTML_HELPERS */
3041 js_String_getelem(JSContext
* cx
, JSString
* str
, int32 i
)
3043 if ((size_t)i
>= str
->length())
3045 return JSString::getUnitString(cx
, str
, size_t(i
));
3049 JS_DEFINE_TRCINFO_1(str_concat
,
3050 (3, (extern, STRING_RETRY
, js_ConcatStrings
, CONTEXT
, THIS_STRING
, STRING
,
3051 1, nanojit::ACCSET_NONE
)))
3053 static JSFunctionSpec string_methods
[] = {
3055 JS_FN("quote", str_quote
, 0,JSFUN_GENERIC_NATIVE
),
3056 JS_FN(js_toSource_str
, str_toSource
, 0,0),
3059 /* Java-like methods. */
3060 JS_FN(js_toString_str
, js_str_toString
, 0,0),
3061 JS_FN(js_valueOf_str
, js_str_toString
, 0,0),
3062 JS_FN(js_toJSON_str
, js_str_toString
, 0,0),
3063 JS_FN("substring", str_substring
, 2,JSFUN_GENERIC_NATIVE
),
3064 JS_FN("toLowerCase", str_toLowerCase
, 0,JSFUN_GENERIC_NATIVE
),
3065 JS_FN("toUpperCase", str_toUpperCase
, 0,JSFUN_GENERIC_NATIVE
),
3066 JS_FN("charAt", js_str_charAt
, 1,JSFUN_GENERIC_NATIVE
),
3067 JS_FN("charCodeAt", js_str_charCodeAt
, 1,JSFUN_GENERIC_NATIVE
),
3068 JS_FN("indexOf", str_indexOf
, 1,JSFUN_GENERIC_NATIVE
),
3069 JS_FN("lastIndexOf", str_lastIndexOf
, 1,JSFUN_GENERIC_NATIVE
),
3070 JS_FN("trim", str_trim
, 0,JSFUN_GENERIC_NATIVE
),
3071 JS_FN("trimLeft", str_trimLeft
, 0,JSFUN_GENERIC_NATIVE
),
3072 JS_FN("trimRight", str_trimRight
, 0,JSFUN_GENERIC_NATIVE
),
3073 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase
, 0,JSFUN_GENERIC_NATIVE
),
3074 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase
, 0,JSFUN_GENERIC_NATIVE
),
3075 JS_FN("localeCompare", str_localeCompare
, 1,JSFUN_GENERIC_NATIVE
),
3077 /* Perl-ish methods (search is actually Python-esque). */
3078 JS_FN("match", str_match
, 1,JSFUN_GENERIC_NATIVE
),
3079 JS_FN("search", str_search
, 1,JSFUN_GENERIC_NATIVE
),
3080 JS_FN("replace", str_replace
, 2,JSFUN_GENERIC_NATIVE
),
3081 JS_FN("split", str_split
, 2,JSFUN_GENERIC_NATIVE
),
3082 #if JS_HAS_PERL_SUBSTR
3083 JS_FN("substr", str_substr
, 2,JSFUN_GENERIC_NATIVE
),
3086 /* Python-esque sequence methods. */
3087 JS_TN("concat", str_concat
, 1,JSFUN_GENERIC_NATIVE
, &str_concat_trcinfo
),
3088 JS_FN("slice", str_slice
, 2,JSFUN_GENERIC_NATIVE
),
3090 /* HTML string methods. */
3091 #if JS_HAS_STR_HTML_HELPERS
3092 JS_FN("bold", str_bold
, 0,0),
3093 JS_FN("italics", str_italics
, 0,0),
3094 JS_FN("fixed", str_fixed
, 0,0),
3095 JS_FN("fontsize", str_fontsize
, 1,0),
3096 JS_FN("fontcolor", str_fontcolor
, 1,0),
3097 JS_FN("link", str_link
, 1,0),
3098 JS_FN("anchor", str_anchor
, 1,0),
3099 JS_FN("strike", str_strike
, 0,0),
3100 JS_FN("small", str_small
, 0,0),
3101 JS_FN("big", str_big
, 0,0),
3102 JS_FN("blink", str_blink
, 0,0),
3103 JS_FN("sup", str_sup
, 0,0),
3104 JS_FN("sub", str_sub
, 0,0),
3111 * Set up some tools to make it easier to generate large tables. After constant
3112 * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3113 * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3114 * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3117 #define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
3118 #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
3119 #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
3120 #define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
3121 #define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
3122 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3124 #define R3(n) R2(n), R2((n) + (1 << 2))
3125 #define R7(n) R6(n), R6((n) + (1 << 6))
3127 #define BUILD_LENGTH_AND_FLAGS(length, flags) \
3128 (((length) << JSString::LENGTH_SHIFT) | (flags))
3131 * Declare unit strings. Pack the string data itself into the mInlineChars
3132 * place in the header.
3135 BUILD_LENGTH_AND_FLAGS(1, JSString::FLAT | JSString::ATOMIZED), \
3136 { (jschar *)(((char *)(unitStringTable + (c))) + \
3137 offsetof(JSString, inlineStorage)) }, \
3143 #pragma pack(push, 8)
3146 const JSString
JSString::unitStringTable
[]
3148 __attribute__ ((aligned (8)))
3161 * Declare length-2 strings. We only store strings where both characters are
3162 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3163 * the lowercase letters, and the next 26 are the uppercase letters.
3165 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
3166 (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
3167 (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
3168 JSString::INVALID_SMALL_CHAR)
3170 #define R TO_SMALL_CHAR
3172 const JSString::SmallChar
JSString::toSmallChar
[] = { R7(0) };
3177 * This is used when we generate our table of short strings, so the compiler is
3178 * happier if we use |c| as few times as possible.
3180 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
3181 (c) < 36 ? 'a' - 10 : \
3183 #define R FROM_SMALL_CHAR
3185 const jschar
JSString::fromSmallChar
[] = { R6(0) };
3190 * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3191 * where the upper 6 bits is the first character and the lower 6 bits is the
3195 BUILD_LENGTH_AND_FLAGS(2, JSString::FLAT | JSString::ATOMIZED), \
3196 { (jschar *)(((char *)(length2StringTable + (c))) + \
3197 offsetof(JSString, inlineStorage)) }, \
3198 { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3203 #pragma pack(push, 8)
3206 const JSString
JSString::length2StringTable
[]
3208 __attribute__ ((aligned (8)))
3221 * Declare int strings. Only int strings from 100 to 255 actually have to be
3222 * generated, since the rest are either unit strings or length-2 strings. To
3223 * avoid the runtime cost of figuring out where to look for the string for a
3224 * particular integer, we precompute a table of JSString*s which refer to the
3225 * correct location of the int string.
3228 BUILD_LENGTH_AND_FLAGS(3, JSString::FLAT | JSString::ATOMIZED), \
3229 { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \
3230 offsetof(JSString, inlineStorage)) }, \
3231 { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3234 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3239 #pragma pack(push, 8)
3242 const JSString
JSString::hundredStringTable
[]
3244 __attribute__ ((aligned (8)))
3246 = { R7(100), /* 100 through 227 */
3247 R4(100 + (1 << 7)), /* 228 through 243 */
3248 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3249 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3254 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \
3255 (c) < 100 ? JSString::length2StringTable + \
3256 ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
3257 TO_SMALL_CHAR(((c) % 10) + '0') : \
3258 JSString::hundredStringTable + ((c) - 100))
3260 const JSString
*const JSString::intStringTable
[] = { R8(0) };
3281 js_String(JSContext
*cx
, uintN argc
, Value
*vp
)
3283 Value
*argv
= vp
+ 2;
3287 str
= js_ValueToString(cx
, argv
[0]);
3291 str
= cx
->runtime
->emptyString
;
3294 if (IsConstructing(vp
)) {
3295 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_StringClass
);
3298 obj
->setPrimitiveThis(StringValue(str
));
3299 vp
->setObject(*obj
);
3307 str_fromCharCode(JSContext
*cx
, uintN argc
, Value
*vp
)
3315 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
3318 if (!ValueToUint16(cx
, argv
[0], &code
))
3320 if (code
< UNIT_STRING_LIMIT
) {
3321 str
= JSString::unitString(code
);
3327 argv
[0].setInt32(code
);
3329 chars
= (jschar
*) cx
->malloc((argc
+ 1) * sizeof(jschar
));
3332 for (i
= 0; i
< argc
; i
++) {
3334 if (!ValueToUint16(cx
, argv
[i
], &code
)) {
3338 chars
[i
] = (jschar
)code
;
3341 str
= js_NewString(cx
, chars
, argc
);
3351 static JSString
* FASTCALL
3352 String_fromCharCode(JSContext
* cx
, int32 i
)
3354 JS_ASSERT(JS_ON_TRACE(cx
));
3355 jschar c
= (jschar
)i
;
3356 if (c
< UNIT_STRING_LIMIT
)
3357 return JSString::unitString(c
);
3358 return js_NewStringCopyN(cx
, &c
, 1);
3362 JS_DEFINE_TRCINFO_1(str_fromCharCode
,
3363 (2, (static, STRING_RETRY
, String_fromCharCode
, CONTEXT
, INT32
, 1, nanojit::ACCSET_NONE
)))
3365 static JSFunctionSpec string_static_methods
[] = {
3366 JS_TN("fromCharCode", str_fromCharCode
, 1, 0, &str_fromCharCode_trcinfo
),
3371 js_InitStringClass(JSContext
*cx
, JSObject
*obj
)
3375 /* Define the escape, unescape functions in the global object. */
3376 if (!JS_DefineFunctions(cx
, obj
, string_functions
))
3379 proto
= js_InitClass(cx
, obj
, NULL
, &js_StringClass
, js_String
, 1,
3380 NULL
, string_methods
,
3381 NULL
, string_static_methods
);
3384 proto
->setPrimitiveThis(StringValue(cx
->runtime
->emptyString
));
3385 if (!js_DefineNativeProperty(cx
, proto
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
3386 UndefinedValue(), NULL
, NULL
,
3387 JSPROP_READONLY
| JSPROP_PERMANENT
| JSPROP_SHARED
, 0, 0,
3396 js_NewString(JSContext
*cx
, jschar
*chars
, size_t length
)
3400 if (length
> JSString::MAX_LENGTH
) {
3401 if (JS_ON_TRACE(cx
)) {
3403 * If we can't leave the trace, signal OOM condition, otherwise
3404 * exit from trace before throwing.
3406 if (!CanLeaveTrace(cx
))
3411 js_ReportAllocationOverflow(cx
);
3415 str
= js_NewGCString(cx
);
3418 str
->initFlat(chars
, length
);
3419 cx
->runtime
->stringMemoryUsed
+= length
* 2;
3422 JSRuntime
*rt
= cx
->runtime
;
3423 JS_RUNTIME_METER(rt
, liveStrings
);
3424 JS_RUNTIME_METER(rt
, totalStrings
);
3425 JS_LOCK_RUNTIME_VOID(rt
,
3426 (rt
->lengthSum
+= (double)length
,
3427 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3430 return str
->assertIsFlat();
3433 static JS_ALWAYS_INLINE JSFlatString
*
3434 NewShortString(JSContext
*cx
, const jschar
*chars
, size_t length
)
3436 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3437 JSShortString
*str
= js_NewGCShortString(cx
);
3440 jschar
*storage
= str
->init(length
);
3441 js_short_strncpy(storage
, chars
, length
);
3442 storage
[length
] = 0;
3443 return str
->header()->assertIsFlat();
3446 static JSFlatString
*
3447 NewShortString(JSContext
*cx
, const char *chars
, size_t length
)
3449 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3450 JSShortString
*str
= js_NewGCShortString(cx
);
3453 jschar
*storage
= str
->init(length
);
3455 if (js_CStringsAreUTF8
) {
3457 size_t oldLength
= length
;
3459 if (!js_InflateStringToBuffer(cx
, chars
, length
, storage
, &length
))
3461 JS_ASSERT(length
<= oldLength
);
3462 storage
[length
] = 0;
3463 str
->resetLength(length
);
3466 jschar
*p
= storage
;
3468 *p
++ = (unsigned char)*chars
++;
3471 return str
->header()->assertIsFlat();
3474 static const size_t sMinWasteSize
= 16;
3477 StringBuffer::finishString()
3479 JSContext
*cx
= context();
3481 return ATOM_TO_STRING(cx
->runtime
->atomState
.emptyAtom
);
3483 size_t length
= cb
.length();
3484 if (!checkLength(length
))
3487 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH
< CharBuffer::InlineLength
);
3488 if (JSShortString::fitsIntoShortString(length
))
3489 return NewShortString(cx
, cb
.begin(), length
);
3491 if (!cb
.append('\0'))
3494 size_t capacity
= cb
.capacity();
3496 jschar
*buf
= cb
.extractRawBuffer();
3500 /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3501 JS_ASSERT(capacity
>= length
);
3502 if (capacity
> sMinWasteSize
&& capacity
- length
> (length
>> 2)) {
3503 size_t bytes
= sizeof(jschar
) * (length
+ 1);
3504 jschar
*tmp
= (jschar
*)cx
->realloc(buf
, bytes
);
3512 JSFlatString
*str
= js_NewString(cx
, buf
, length
);
3519 js_NewDependentString(JSContext
*cx
, JSString
*baseArg
, size_t start
,
3525 return cx
->runtime
->emptyString
;
3527 JSLinearString
*base
= baseArg
->ensureLinear(cx
);
3531 if (start
== 0 && length
== base
->length())
3534 const jschar
*chars
= base
->chars() + start
;
3536 JSLinearString
*staticStr
= JSString::lookupStaticString(chars
, length
);
3540 /* Try to avoid long chains of dependent strings. */
3541 while (base
->isDependent())
3542 base
= base
->dependentBase();
3544 JS_ASSERT(base
->isFlat());
3546 ds
= js_NewGCString(cx
);
3549 ds
->initDependent(base
, chars
, length
);
3552 JSRuntime
*rt
= cx
->runtime
;
3553 JS_RUNTIME_METER(rt
, liveDependentStrings
);
3554 JS_RUNTIME_METER(rt
, totalDependentStrings
);
3555 JS_RUNTIME_METER(rt
, liveStrings
);
3556 JS_RUNTIME_METER(rt
, totalStrings
);
3557 JS_LOCK_RUNTIME_VOID(rt
,
3558 (rt
->strdepLengthSum
+= (double)length
,
3559 rt
->strdepLengthSquaredSum
+= (double)length
* (double)length
));
3560 JS_LOCK_RUNTIME_VOID(rt
,
3561 (rt
->lengthSum
+= (double)length
,
3562 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3565 return ds
->assertIsLinear();
3571 void printJSStringStats(JSRuntime
*rt
)
3575 mean
= JS_MeanAndStdDev(rt
->totalStrings
, rt
->lengthSum
,
3576 rt
->lengthSquaredSum
, &sigma
);
3578 fprintf(stderr
, "%lu total strings, mean length %g (sigma %g)\n",
3579 (unsigned long)rt
->totalStrings
, mean
, sigma
);
3581 mean
= JS_MeanAndStdDev(rt
->totalDependentStrings
, rt
->strdepLengthSum
,
3582 rt
->strdepLengthSquaredSum
, &sigma
);
3584 fprintf(stderr
, "%lu total dependent strings, mean length %g (sigma %g)\n",
3585 (unsigned long)rt
->totalDependentStrings
, mean
, sigma
);
3590 js_NewStringCopyN(JSContext
*cx
, const jschar
*s
, size_t n
)
3592 if (JSShortString::fitsIntoShortString(n
))
3593 return NewShortString(cx
, s
, n
);
3595 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
3598 js_strncpy(news
, s
, n
);
3600 JSFlatString
*str
= js_NewString(cx
, news
, n
);
3607 js_NewStringCopyN(JSContext
*cx
, const char *s
, size_t n
)
3609 if (JSShortString::fitsIntoShortString(n
))
3610 return NewShortString(cx
, s
, n
);
3612 jschar
*chars
= js_InflateString(cx
, s
, &n
);
3615 JSFlatString
*str
= js_NewString(cx
, chars
, n
);
3622 js_NewStringCopyZ(JSContext
*cx
, const jschar
*s
)
3624 size_t n
= js_strlen(s
);
3625 if (JSShortString::fitsIntoShortString(n
))
3626 return NewShortString(cx
, s
, n
);
3628 size_t m
= (n
+ 1) * sizeof(jschar
);
3629 jschar
*news
= (jschar
*) cx
->malloc(m
);
3633 JSFlatString
*str
= js_NewString(cx
, news
, n
);
3640 js_NewStringCopyZ(JSContext
*cx
, const char *s
)
3642 return js_NewStringCopyN(cx
, s
, strlen(s
));
3646 js_ValueToPrintable(JSContext
*cx
, const Value
&v
, JSAutoByteString
*bytes
, bool asSource
)
3650 str
= (asSource
? js_ValueToSource
: js_ValueToString
)(cx
, v
);
3653 str
= js_QuoteString(cx
, str
, 0);
3656 return bytes
->encode(cx
, str
);
3660 js_ValueToString(JSContext
*cx
, const Value
&arg
)
3663 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3669 } else if (v
.isInt32()) {
3670 str
= js_IntToString(cx
, v
.toInt32());
3671 } else if (v
.isDouble()) {
3672 str
= js_NumberToString(cx
, v
.toDouble());
3673 } else if (v
.isBoolean()) {
3674 str
= js_BooleanToString(cx
, v
.toBoolean());
3675 } else if (v
.isNull()) {
3676 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
3678 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
3683 /* This function implements E-262-3 section 9.8, toString. */
3685 js::ValueToStringBuffer(JSContext
*cx
, const Value
&arg
, StringBuffer
&sb
)
3688 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3692 JSString
*str
= v
.toString();
3693 size_t length
= str
->length();
3694 const jschar
*chars
= str
->getChars(cx
);
3697 return sb
.append(chars
, length
);
3700 return NumberValueToStringBuffer(cx
, v
, sb
);
3702 return BooleanToStringBuffer(cx
, v
.toBoolean(), sb
);
3704 return sb
.append(cx
->runtime
->atomState
.nullAtom
);
3705 JS_ASSERT(v
.isUndefined());
3706 return sb
.append(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
3709 JS_FRIEND_API(JSString
*)
3710 js_ValueToSource(JSContext
*cx
, const Value
&v
)
3712 if (v
.isUndefined())
3713 return ATOM_TO_STRING(cx
->runtime
->atomState
.void0Atom
);
3715 return js_QuoteString(cx
, v
.toString(), '"');
3716 if (v
.isPrimitive()) {
3717 /* Special case to preserve negative zero, _contra_ toString. */
3718 if (v
.isDouble() && JSDOUBLE_IS_NEGZERO(v
.toDouble())) {
3719 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3720 static const jschar js_negzero_ucNstr
[] = {'-', '0'};
3722 return js_NewStringCopyN(cx
, js_negzero_ucNstr
, 2);
3724 return js_ValueToString(cx
, v
);
3727 JSAtom
*atom
= cx
->runtime
->atomState
.toSourceAtom
;
3728 AutoValueRooter
tvr(cx
);
3729 if (!js_TryMethod(cx
, &v
.toObject(), atom
, 0, NULL
, tvr
.addr()))
3731 return js_ValueToString(cx
, tvr
.value());
3737 * str is not necessarily a GC thing here.
3739 static JS_ALWAYS_INLINE
bool
3740 EqualStringsTail(JSLinearString
*str1
, size_t length1
, JSLinearString
*str2
)
3742 const jschar
*s1
= str1
->chars();
3743 const jschar
*s1end
= s1
+ length1
;
3744 const jschar
*s2
= str2
->chars();
3750 } while (s1
!= s1end
);
3756 EqualStrings(JSContext
*cx
, JSString
*str1
, JSString
*str2
, JSBool
*result
)
3763 size_t length1
= str1
->length();
3764 if (length1
!= str2
->length()) {
3774 JSLinearString
*linear1
= str1
->ensureLinear(cx
);
3777 JSLinearString
*linear2
= str2
->ensureLinear(cx
);
3781 *result
= EqualStringsTail(linear1
, length1
, linear2
);
3786 EqualStrings(JSLinearString
*str1
, JSLinearString
*str2
)
3791 size_t length1
= str1
->length();
3792 if (length1
!= str2
->length())
3798 return EqualStringsTail(str1
, length1
, str2
);
3801 } /* namespace js */
3804 js_EqualStringsOnTrace(JSContext
*cx
, JSString
*str1
, JSString
*str2
)
3807 return EqualStrings(cx
, str1
, str2
, &result
) ? result
: JS_NEITHER
;
3809 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_EqualStringsOnTrace
,
3810 CONTEXT
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3815 CompareStringsImpl(JSContext
*cx
, JSString
*str1
, JSString
*str2
, int32
*result
)
3825 size_t l1
= str1
->length();
3826 const jschar
*s1
= str1
->getChars(cx
);
3830 size_t l2
= str2
->length();
3831 const jschar
*s2
= str2
->getChars(cx
);
3835 size_t n
= JS_MIN(l1
, l2
);
3836 for (size_t i
= 0; i
< n
; i
++) {
3837 if (int32 cmp
= s1
[i
] - s2
[i
]) {
3842 *result
= (int32
)(l1
- l2
);
3847 CompareStrings(JSContext
*cx
, JSString
*str1
, JSString
*str2
, int32
*result
)
3849 return CompareStringsImpl(cx
, str1
, str2
, result
);
3852 } /* namespace js */
3855 js_CompareStringsOnTrace(JSContext
*cx
, JSString
*str1
, JSString
*str2
)
3858 if (!CompareStringsImpl(cx
, str1
, str2
, &result
))
3860 JS_ASSERT(result
!= INT32_MIN
);
3863 JS_DEFINE_CALLINFO_3(extern, INT32
, js_CompareStringsOnTrace
,
3864 CONTEXT
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3869 StringEqualsAscii(JSLinearString
*str
, const char *asciiBytes
)
3871 size_t length
= strlen(asciiBytes
);
3873 for (size_t i
= 0; i
!= length
; ++i
)
3874 JS_ASSERT(unsigned(asciiBytes
[i
]) <= 127);
3876 if (length
!= str
->length())
3878 const jschar
*chars
= str
->chars();
3879 for (size_t i
= 0; i
!= length
; ++i
) {
3880 if (unsigned(asciiBytes
[i
]) != unsigned(chars
[i
]))
3889 js_strlen(const jschar
*s
)
3893 for (t
= s
; *t
!= 0; t
++)
3895 return (size_t)(t
- s
);
3899 js_strchr(const jschar
*s
, jschar c
)
3910 js_strchr_limit(const jschar
*s
, jschar c
, const jschar
*limit
)
3921 js_InflateString(JSContext
*cx
, const char *bytes
, size_t *lengthp
)
3923 size_t nbytes
, nchars
, i
;
3930 if (js_CStringsAreUTF8
) {
3931 if (!js_InflateStringToBuffer(cx
, bytes
, nbytes
, NULL
, &nchars
))
3933 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof (jschar
));
3939 js_InflateStringToBuffer(cx
, bytes
, nbytes
, chars
, &nchars
);
3943 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof(jschar
));
3946 for (i
= 0; i
< nchars
; i
++)
3947 chars
[i
] = (unsigned char) bytes
[i
];
3955 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3963 * May be called with null cx.
3966 js_DeflateString(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3974 if (js_CStringsAreUTF8
) {
3975 nbytes
= js_GetDeflatedStringLength(cx
, chars
, nchars
);
3976 if (nbytes
== (size_t) -1)
3978 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3984 js_DeflateStringToBuffer(cx
, chars
, nchars
, bytes
, &nbytes
);
3988 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3991 for (i
= 0; i
< nbytes
; i
++)
3992 bytes
[i
] = (char) chars
[i
];
3999 js_GetDeflatedStringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4001 if (!js_CStringsAreUTF8
)
4004 return js_GetDeflatedUTF8StringLength(cx
, chars
, nchars
);
4008 * May be called with null cx through public API, see below.
4011 js_GetDeflatedUTF8StringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4019 for (end
= chars
+ nchars
; chars
!= end
; chars
++) {
4023 if (0xD800 <= c
&& c
<= 0xDFFF) {
4024 /* Surrogate pair. */
4027 /* nbytes sets 1 length since this is surrogate pair. */
4029 if (c
>= 0xDC00 || chars
== end
)
4032 if (c2
< 0xDC00 || c2
> 0xDFFF)
4034 c
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4047 JS_snprintf(buffer
, 10, "0x%x", c
);
4048 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
4049 NULL
, JSMSG_BAD_SURROGATE_CHAR
, buffer
);
4055 js_DeflateStringToBuffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4056 char *dst
, size_t *dstlenp
)
4061 if (!js_CStringsAreUTF8
) {
4062 if (srclen
> dstlen
) {
4063 for (i
= 0; i
< dstlen
; i
++)
4064 dst
[i
] = (char) src
[i
];
4066 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4067 JSMSG_BUFFER_TOO_SMALL
);
4071 for (i
= 0; i
< srclen
; i
++)
4072 dst
[i
] = (char) src
[i
];
4077 return js_DeflateStringToUTF8Buffer(cx
, src
, srclen
, dst
, dstlenp
);
4081 js_DeflateStringToUTF8Buffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4082 char *dst
, size_t *dstlenp
)
4084 size_t dstlen
, i
, origDstlen
, utf8Len
;
4090 origDstlen
= dstlen
;
4094 if ((c
>= 0xDC00) && (c
<= 0xDFFF))
4096 if (c
< 0xD800 || c
> 0xDBFF) {
4102 if ((c2
< 0xDC00) || (c2
> 0xDFFF))
4106 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4109 /* no encoding necessary - performance hack */
4111 goto bufferTooSmall
;
4115 utf8Len
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
4116 if (utf8Len
> dstlen
)
4117 goto bufferTooSmall
;
4118 for (i
= 0; i
< utf8Len
; i
++)
4119 *dst
++ = (char) utf8buf
[i
];
4123 *dstlenp
= (origDstlen
- dstlen
);
4127 *dstlenp
= (origDstlen
- dstlen
);
4128 /* Delegate error reporting to the measurement function. */
4130 js_GetDeflatedStringLength(cx
, src
- 1, srclen
+ 1);
4134 *dstlenp
= (origDstlen
- dstlen
);
4136 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4137 JSMSG_BUFFER_TOO_SMALL
);
4143 js_InflateStringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4144 jschar
*dst
, size_t *dstlenp
)
4148 if (!js_CStringsAreUTF8
) {
4151 if (srclen
> dstlen
) {
4152 for (i
= 0; i
< dstlen
; i
++)
4153 dst
[i
] = (unsigned char) src
[i
];
4155 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4156 JSMSG_BUFFER_TOO_SMALL
);
4160 for (i
= 0; i
< srclen
; i
++)
4161 dst
[i
] = (unsigned char) src
[i
];
4167 return js_InflateUTF8StringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
4171 js_InflateUTF8StringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4172 jschar
*dst
, size_t *dstlenp
)
4174 size_t dstlen
, origDstlen
, offset
, j
, n
;
4177 dstlen
= dst
? *dstlenp
: (size_t) -1;
4178 origDstlen
= dstlen
;
4185 while (v
& (0x80 >> n
))
4188 goto bufferTooSmall
;
4189 if (n
== 1 || n
> 4)
4191 for (j
= 1; j
< n
; j
++) {
4192 if ((src
[j
] & 0xC0) != 0x80)
4195 v
= Utf8ToOneUcs4Char((uint8
*)src
, n
);
4198 if (v
> 0xFFFFF || dstlen
< 2) {
4199 *dstlenp
= (origDstlen
- dstlen
);
4202 JS_snprintf(buffer
, 10, "0x%x", v
+ 0x10000);
4203 JS_ReportErrorFlagsAndNumber(cx
,
4205 js_GetErrorMessage
, NULL
,
4206 JSMSG_UTF8_CHAR_TOO_LARGE
,
4212 *dst
++ = (jschar
)((v
>> 10) + 0xD800);
4213 v
= (jschar
)((v
& 0x3FF) + 0xDC00);
4219 goto bufferTooSmall
;
4221 *dst
++ = (jschar
) v
;
4227 *dstlenp
= (origDstlen
- dstlen
);
4231 *dstlenp
= (origDstlen
- dstlen
);
4234 JS_snprintf(buffer
, 10, "%d", offset
);
4235 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
4236 js_GetErrorMessage
, NULL
,
4237 JSMSG_MALFORMED_UTF8_CHAR
,
4243 *dstlenp
= (origDstlen
- dstlen
);
4245 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4246 JSMSG_BUFFER_TOO_SMALL
);
4252 * From java.lang.Character.java:
4254 * The character properties are currently encoded into 32 bits in the
4257 * 10 bits signed offset used for converting case
4258 * 1 bit if 1, adding the signed offset converts the character to
4260 * 1 bit if 1, subtracting the signed offset converts the character to
4262 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
4263 * 3 bits 0 may not be part of an identifier
4264 * 1 ignorable control; may continue a Unicode identifier or JS
4266 * 2 may continue a JS identifier but not a Unicode identifier
4268 * 3 may continue a Unicode identifier or JS identifier
4269 * 4 is a JS whitespace character
4270 * 5 may start or continue a JS identifier;
4271 * may continue but not start a Unicode identifier (_)
4272 * 6 may start or continue a JS identifier but not a Unicode
4274 * 7 may start or continue a Unicode identifier or JS identifier
4276 * 5, 6, 7 may start a JS identifier
4277 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
4278 * 7 may start a Unicode identifier
4279 * 1, 3, 5, 7 may continue a Unicode identifier
4280 * 1 is ignorable within an identifier
4281 * 4 is JS whitespace
4282 * 2 bits 0 this character has no numeric property
4283 * 1 adding the digit offset to the character code and then
4284 * masking with 0x1F will produce the desired numeric value
4285 * 2 this character has a "strange" numeric value
4286 * 3 a JS supradecimal digit: adding the digit offset to the
4287 * character code, then masking with 0x1F, then adding 10
4288 * will produce the desired numeric value
4289 * 5 bits digit offset
4290 * 1 bit XML 1.0 name start character
4291 * 1 bit XML 1.0 name character
4292 * 2 bits reserved for future use
4293 * 5 bits character type
4296 /* The X table has 1024 entries for a total of 1024 bytes. */
4298 const uint8 js_X
[] = {
4299 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
4300 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
4301 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
4302 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
4303 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
4304 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
4305 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
4306 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
4307 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
4308 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
4309 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
4310 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
4311 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
4312 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
4313 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
4314 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
4315 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
4316 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
4317 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
4318 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
4319 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
4320 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
4321 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
4322 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
4323 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
4324 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
4325 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
4326 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
4327 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
4328 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
4329 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
4330 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
4331 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
4332 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
4333 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
4334 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
4335 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
4336 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
4337 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
4338 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
4339 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
4340 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
4341 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
4342 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
4343 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
4344 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
4345 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
4346 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
4347 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
4348 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
4349 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
4350 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
4351 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
4352 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
4353 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
4354 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
4355 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
4356 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
4357 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
4358 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
4359 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
4360 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
4361 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
4362 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
4363 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
4364 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
4365 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
4366 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
4367 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
4368 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
4369 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
4370 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
4371 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
4372 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
4373 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
4374 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
4375 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
4376 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
4377 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
4378 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
4379 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
4380 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
4381 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
4382 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
4383 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
4384 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
4385 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
4386 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
4387 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
4388 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
4389 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
4390 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
4391 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
4392 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
4393 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
4394 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
4395 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
4396 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
4397 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
4398 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
4399 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
4400 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
4401 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
4402 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
4403 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
4404 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
4405 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
4406 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
4407 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
4408 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
4409 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
4410 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
4411 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
4412 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
4413 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
4414 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
4415 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
4416 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
4417 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
4418 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
4419 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
4420 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
4421 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
4422 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
4423 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
4424 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
4425 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
4426 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
4429 /* The Y table has 7808 entries for a total of 7808 bytes. */
4431 const uint8 js_Y
[] = {
4432 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4433 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
4434 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4435 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4436 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
4437 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
4438 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
4439 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
4440 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4441 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4442 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4443 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
4444 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4445 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4446 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4447 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
4448 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4449 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4450 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4451 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4452 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
4453 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
4454 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
4455 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
4456 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4457 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4458 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
4459 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
4460 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4461 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4462 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
4463 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
4464 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4465 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4466 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4467 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4468 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4469 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4470 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
4471 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
4472 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
4473 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
4474 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4475 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4476 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4477 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4478 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4479 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
4480 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
4481 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
4482 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
4483 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
4484 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
4485 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
4486 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
4487 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
4488 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
4489 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
4490 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
4491 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
4492 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4493 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4494 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
4495 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
4496 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4497 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4498 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4499 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4500 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4501 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4502 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4503 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4504 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4505 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4506 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
4507 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
4508 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
4509 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
4510 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
4511 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
4512 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
4513 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
4514 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
4515 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4516 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4517 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
4518 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
4519 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
4520 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4521 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
4522 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4523 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
4524 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
4525 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
4526 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4527 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4528 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4529 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4530 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4531 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4532 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4533 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4534 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4535 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4536 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
4537 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4538 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4539 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4540 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
4541 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4542 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
4543 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
4544 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
4545 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
4546 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4547 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4548 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
4549 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
4550 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4551 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4552 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
4553 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
4554 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
4555 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
4556 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
4557 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
4558 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
4559 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
4560 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
4561 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
4562 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4563 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4564 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4565 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4566 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4567 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4568 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4569 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4570 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
4571 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
4572 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4573 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4574 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4575 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4576 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
4577 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
4578 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4579 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4580 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4581 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4582 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4583 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4584 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
4585 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
4586 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4587 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4588 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4589 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
4590 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
4591 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
4592 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4593 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4594 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4595 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4596 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4597 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4598 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4599 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4600 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4601 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4602 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
4603 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
4604 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4605 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4606 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4607 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4608 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
4609 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
4610 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4611 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4612 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
4613 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4614 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4615 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
4616 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
4617 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4618 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4619 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4620 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4621 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
4622 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
4623 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4624 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4625 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
4626 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4627 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
4628 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4629 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4630 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4631 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
4632 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4633 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
4634 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
4635 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
4636 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
4637 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
4638 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4639 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4640 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4641 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4642 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4643 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4644 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4645 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4646 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4647 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4648 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4649 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4650 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4651 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4652 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4653 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4654 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4655 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4656 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4657 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4658 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4659 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4660 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4661 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4662 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4663 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4664 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4665 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4666 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4667 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4668 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4669 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4670 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4671 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
4672 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4673 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4674 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4675 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4676 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4677 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4678 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4679 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4680 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4681 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4682 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4683 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4684 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4685 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4686 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4687 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4688 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4689 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4690 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4691 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4692 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4693 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4694 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4695 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4696 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4697 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4698 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4699 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4700 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4701 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4702 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4703 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4704 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4705 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4706 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4707 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4708 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4709 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4710 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4711 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4712 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4713 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4714 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4715 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4716 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4717 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4718 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4719 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4720 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4721 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4722 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4723 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4724 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4725 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4726 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4727 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4728 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4729 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4730 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4731 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4732 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4733 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4734 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4735 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4736 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4737 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4738 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4739 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4740 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4741 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4742 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4743 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4744 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4745 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4746 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4747 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4748 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4749 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4750 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4751 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4752 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4753 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4754 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4755 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4756 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4757 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4758 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4759 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4760 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4761 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4762 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4763 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4764 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4765 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4766 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4767 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4768 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4769 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4770 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4771 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4772 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4773 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4774 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4775 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4776 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4777 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4778 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4779 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4780 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4781 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4782 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4783 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4784 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4785 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4786 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4787 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4788 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4789 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4790 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4791 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4792 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4793 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4794 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4795 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4796 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4797 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4798 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4799 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
4800 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4801 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4802 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4803 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4804 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4805 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4806 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4807 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4808 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4809 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4810 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4811 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4812 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4813 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
4814 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4815 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4816 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4817 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4818 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4819 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4820 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4821 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4822 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4823 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4824 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4825 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4826 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
4827 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
4828 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
4829 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
4830 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
4831 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
4832 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
4833 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
4834 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
4835 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
4836 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4837 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4838 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4839 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4840 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
4841 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
4842 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
4843 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
4844 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
4845 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
4846 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
4847 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
4848 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4849 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4850 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4851 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4852 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4853 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
4854 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
4855 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
4856 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
4857 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
4858 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
4859 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4860 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4861 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
4862 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4863 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
4864 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4865 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4866 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4867 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4868 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4869 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4870 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4871 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4872 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
4873 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
4874 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4875 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4876 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4877 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4878 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
4879 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
4880 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4881 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4882 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4883 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4884 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4885 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4886 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4887 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4888 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4889 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4890 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4891 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
4892 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4893 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4894 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4895 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4896 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4897 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4898 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4899 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4900 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
4901 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4902 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4903 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4904 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4905 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4906 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4907 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4908 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4909 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4910 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4911 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
4912 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4913 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4914 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4915 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4916 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4917 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4918 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4919 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4920 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4921 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4922 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
4923 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
4924 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4925 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4926 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4927 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4928 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4929 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4930 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4931 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4932 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4933 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4934 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4935 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
4936 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4937 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4938 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
4939 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
4940 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4941 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4942 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4943 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4944 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
4945 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
4946 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
4947 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
4948 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
4949 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
4950 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
4951 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
4952 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4953 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4954 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4955 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4956 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4957 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4958 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
4959 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
4960 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
4961 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
4962 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
4963 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
4964 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
4965 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
4966 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
4967 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
4968 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
4969 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
4970 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
4971 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
4972 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4973 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
4974 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4975 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
4976 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
4977 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4978 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4979 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4980 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4981 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
4982 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
4983 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
4984 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
4985 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
4986 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4987 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4988 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
4989 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
4990 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4991 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4992 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4993 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4994 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
4995 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
4996 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
4997 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4998 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4999 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5000 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
5001 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
5002 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
5003 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
5004 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
5005 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
5006 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
5007 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
5008 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5009 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5010 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
5011 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
5012 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
5013 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
5014 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
5015 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
5016 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
5017 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
5018 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
5019 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5020 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5021 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5022 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5023 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5024 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5025 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5026 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
5027 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5028 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5029 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
5030 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5031 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5032 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5033 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5034 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5035 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5036 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5037 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5038 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5039 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5040 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5041 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5042 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5043 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5044 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5045 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5046 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
5047 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
5048 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
5049 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
5050 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5051 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5052 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
5053 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
5054 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5055 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5056 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5057 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5058 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5059 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5060 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5061 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5062 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5063 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
5064 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5065 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5066 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5067 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5068 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
5069 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5070 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5071 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5072 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
5073 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
5074 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5075 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5076 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5077 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5078 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
5079 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
5080 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
5081 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5082 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5083 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
5084 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5085 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5086 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
5087 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
5088 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5089 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5090 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5091 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5092 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5093 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
5094 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5095 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5096 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5097 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5098 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5099 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5100 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5101 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5102 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5103 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5104 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5105 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5106 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
5107 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
5108 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5109 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5110 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5111 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5112 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5113 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5114 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5115 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5116 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5117 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5118 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5119 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5120 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5121 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5122 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
5123 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
5124 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5125 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5126 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5127 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5128 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
5129 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
5130 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5131 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5132 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5133 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5134 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5135 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5136 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5137 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
5138 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
5139 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
5140 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5141 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
5142 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
5143 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
5144 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
5145 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
5146 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
5147 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5148 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5149 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5150 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5151 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
5152 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
5153 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
5154 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
5155 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
5156 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
5157 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
5158 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
5159 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
5160 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5161 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5162 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5163 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5164 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5165 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5166 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5167 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5168 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5169 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5170 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
5171 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
5172 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5173 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5174 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5175 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5176 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5177 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5178 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5179 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5180 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5181 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5182 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5183 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
5184 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
5185 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5186 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5187 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5188 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5189 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
5190 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5191 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5192 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
5193 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
5194 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
5195 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
5196 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5197 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5198 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5199 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5200 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5201 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5202 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5203 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
5204 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
5205 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
5206 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5207 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5208 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
5209 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5210 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5211 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5212 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5213 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5214 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5215 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
5216 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
5217 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
5218 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5219 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5220 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5221 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5222 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5223 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5224 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5225 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
5226 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5227 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5228 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5229 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5230 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5231 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
5232 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5233 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5234 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5235 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5236 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5237 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5238 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
5239 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
5240 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5241 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5242 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5243 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
5244 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5245 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5246 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5247 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
5248 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5249 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5250 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5251 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5252 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
5253 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5254 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5255 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5256 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5257 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5258 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5259 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5260 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
5261 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5262 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5263 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5264 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5265 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5266 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5267 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5268 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5269 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5270 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5271 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5272 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5273 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5274 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5275 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5276 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5277 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5278 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5279 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5280 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5281 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5282 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5283 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5284 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5285 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
5286 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5287 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5288 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
5289 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
5290 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
5291 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
5292 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
5293 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
5294 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
5295 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
5296 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
5297 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5298 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5299 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5300 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5301 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5302 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5303 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5304 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5305 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5306 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5307 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5308 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5309 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5310 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
5311 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
5312 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5313 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5314 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
5315 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5316 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5317 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5318 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5319 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5320 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5321 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5322 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5323 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5324 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5325 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5326 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5327 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
5328 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5329 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5330 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5331 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5332 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5333 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5334 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5335 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5336 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5337 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5338 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
5339 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5340 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5341 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5342 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5343 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5344 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5345 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5346 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5347 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5348 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5349 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5350 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5351 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
5352 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5353 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5354 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5355 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5356 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
5357 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5358 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
5359 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
5360 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
5361 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
5362 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
5363 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
5364 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
5365 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
5366 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
5367 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
5368 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5369 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5370 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5371 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5372 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5373 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5374 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5375 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
5376 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
5377 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
5378 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
5379 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
5380 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5381 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5382 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5383 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
5384 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5385 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5386 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5387 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
5388 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
5389 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5390 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5391 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5392 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5393 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5394 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5395 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
5396 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5397 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5398 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5399 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
5400 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5401 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5402 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5403 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
5404 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
5405 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
5406 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
5407 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
5410 /* The A table has 124 entries for a total of 496 bytes. */
5412 const uint32 js_A
[] = {
5413 0x0001000F, /* 0 Cc, ignorable */
5414 0x0004000F, /* 1 Cc, whitespace */
5415 0x0004000C, /* 2 Zs, whitespace */
5416 0x00000018, /* 3 Po */
5417 0x0006001A, /* 4 Sc, currency */
5418 0x00000015, /* 5 Ps */
5419 0x00000016, /* 6 Pe */
5420 0x00000019, /* 7 Sm */
5421 0x00000014, /* 8 Pd */
5422 0x00036089, /* 9 Nd, identifier part, decimal 16 */
5423 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
5424 0x0000001B, /* 11 Sk */
5425 0x00050017, /* 12 Pc, underscore */
5426 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5427 0x0000000C, /* 14 Zs */
5428 0x0000001C, /* 15 So */
5429 0x00070182, /* 16 Ll, identifier start */
5430 0x0000600B, /* 17 No, decimal 16 */
5431 0x0000500B, /* 18 No, decimal 8 */
5432 0x0000800B, /* 19 No, strange */
5433 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
5434 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
5435 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
5436 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
5437 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
5438 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
5439 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
5440 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
5441 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
5442 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
5443 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
5444 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
5445 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
5446 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
5447 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
5448 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
5449 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
5450 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
5451 0x00070181, /* 38 Lu, identifier start */
5452 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
5453 0x00070185, /* 40 Lo, identifier start */
5454 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
5455 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
5456 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
5457 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5458 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
5459 0x00000000, /* 46 unassigned */
5460 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
5461 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
5462 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
5463 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
5464 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
5465 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
5466 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
5467 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
5468 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
5469 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
5470 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
5471 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
5472 0x00070084, /* 59 Lm, identifier start */
5473 0x00030086, /* 60 Mn, identifier part */
5474 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
5475 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
5476 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
5477 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
5478 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
5479 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
5480 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
5481 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
5482 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
5483 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
5484 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
5485 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
5486 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
5487 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
5488 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
5489 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
5490 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
5491 0x00034089, /* 78 Nd, identifier part, decimal 0 */
5492 0x00000087, /* 79 Me */
5493 0x00030088, /* 80 Mc, identifier part */
5494 0x00037489, /* 81 Nd, identifier part, decimal 26 */
5495 0x00005A0B, /* 82 No, decimal 13 */
5496 0x00006E0B, /* 83 No, decimal 23 */
5497 0x0000740B, /* 84 No, decimal 26 */
5498 0x0000000B, /* 85 No */
5499 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
5500 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
5501 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
5502 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
5503 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
5504 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
5505 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
5506 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
5507 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
5508 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
5509 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
5510 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
5511 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
5512 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
5513 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
5514 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
5515 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
5516 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
5517 0x00010010, /* 104 Cf, ignorable */
5518 0x0004000D, /* 105 Zl, whitespace */
5519 0x0004000E, /* 106 Zp, whitespace */
5520 0x0000400B, /* 107 No, decimal 0 */
5521 0x0000440B, /* 108 No, decimal 2 */
5522 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
5523 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
5524 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5525 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
5526 0x0007818A, /* 113 Nl, identifier start, strange */
5527 0x0000420B, /* 114 No, decimal 1 */
5528 0x0000720B, /* 115 No, decimal 25 */
5529 0x06A0001C, /* 116 So, hasLower (add 26) */
5530 0x0690001C, /* 117 So, hasUpper (subtract 26) */
5531 0x00006C0B, /* 118 No, decimal 22 */
5532 0x0000560B, /* 119 No, decimal 11 */
5533 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
5534 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
5535 0x00000013, /* 122 Cs */
5536 0x00000012 /* 123 Co */
5539 const jschar js_uriReservedPlusPound_ucstr
[] =
5540 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5541 const jschar js_uriUnescaped_ucstr
[] =
5542 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5543 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5544 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5545 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5546 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5547 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5550 * This table allows efficient testing for the regular expression \w which is
5551 * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5553 const bool js_alnum
[] = {
5554 /* 0 1 2 3 4 5 5 7 8 9 */
5555 /* 0 */ false, false, false, false, false, false, false, false, false, false,
5556 /* 1 */ false, false, false, false, false, false, false, false, false, false,
5557 /* 2 */ false, false, false, false, false, false, false, false, false, false,
5558 /* 3 */ false, false, false, false, false, false, false, false, false, false,
5559 /* 4 */ false, false, false, false, false, false, false, false, true, true,
5560 /* 5 */ true, true, true, true, true, true, true, true, false, false,
5561 /* 6 */ false, false, false, false, false, true, true, true, true, true,
5562 /* 7 */ true, true, true, true, true, true, true, true, true, true,
5563 /* 8 */ true, true, true, true, true, true, true, true, true, true,
5564 /* 9 */ true, false, false, false, false, true, false, true, true, true,
5565 /* 10 */ true, true, true, true, true, true, true, true, true, true,
5566 /* 11 */ true, true, true, true, true, true, true, true, true, true,
5567 /* 12 */ true, true, true, false, false, false, false, false
5570 #define URI_CHUNK 64U
5573 TransferBufferToString(JSContext
*cx
, StringBuffer
&sb
, Value
*rval
)
5575 JSString
*str
= sb
.finishString();
5578 rval
->setString(str
);
5583 * ECMA 3, 15.1.3 URI Handling Function Properties
5585 * The following are implementations of the algorithms
5586 * given in the ECMA specification for the hidden functions
5587 * 'Encode' and 'Decode'.
5590 Encode(JSContext
*cx
, JSString
*str
, const jschar
*unescapedSet
,
5591 const jschar
*unescapedSet2
, Value
*rval
)
5593 static const char HexDigits
[] = "0123456789ABCDEF"; /* NB: uppercase */
5595 size_t length
= str
->length();
5596 const jschar
*chars
= str
->getChars(cx
);
5601 rval
->setString(cx
->runtime
->emptyString
);
5605 StringBuffer
sb(cx
);
5609 for (size_t k
= 0; k
< length
; k
++) {
5610 jschar c
= chars
[k
];
5611 if (js_strchr(unescapedSet
, c
) ||
5612 (unescapedSet2
&& js_strchr(unescapedSet2
, c
))) {
5616 if ((c
>= 0xDC00) && (c
<= 0xDFFF)) {
5617 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5618 JSMSG_BAD_URI
, NULL
);
5622 if (c
< 0xD800 || c
> 0xDBFF) {
5627 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5628 JSMSG_BAD_URI
, NULL
);
5631 jschar c2
= chars
[k
];
5632 if ((c2
< 0xDC00) || (c2
> 0xDFFF)) {
5633 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5634 JSMSG_BAD_URI
, NULL
);
5637 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
5640 size_t L
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
5641 for (size_t j
= 0; j
< L
; j
++) {
5642 hexBuf
[1] = HexDigits
[utf8buf
[j
] >> 4];
5643 hexBuf
[2] = HexDigits
[utf8buf
[j
] & 0xf];
5644 if (!sb
.append(hexBuf
, 3))
5650 return TransferBufferToString(cx
, sb
, rval
);
5654 Decode(JSContext
*cx
, JSString
*str
, const jschar
*reservedSet
, Value
*rval
)
5656 size_t length
= str
->length();
5657 const jschar
*chars
= str
->getChars(cx
);
5662 rval
->setString(cx
->runtime
->emptyString
);
5666 StringBuffer
sb(cx
);
5667 for (size_t k
= 0; k
< length
; k
++) {
5668 jschar c
= chars
[k
];
5671 if ((k
+ 2) >= length
)
5672 goto report_bad_uri
;
5673 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5674 goto report_bad_uri
;
5675 jsuint B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5681 while (B
& (0x80 >> n
))
5683 if (n
== 1 || n
> 4)
5684 goto report_bad_uri
;
5686 octets
[0] = (uint8
)B
;
5687 if (k
+ 3 * (n
- 1) >= length
)
5688 goto report_bad_uri
;
5689 for (intN j
= 1; j
< n
; j
++) {
5691 if (chars
[k
] != '%')
5692 goto report_bad_uri
;
5693 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5694 goto report_bad_uri
;
5695 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5696 if ((B
& 0xC0) != 0x80)
5697 goto report_bad_uri
;
5699 octets
[j
] = (char)B
;
5701 uint32 v
= Utf8ToOneUcs4Char(octets
, n
);
5705 goto report_bad_uri
;
5706 c
= (jschar
)((v
& 0x3FF) + 0xDC00);
5707 jschar H
= (jschar
)((v
>> 10) + 0xD800);
5714 if (js_strchr(reservedSet
, c
)) {
5715 if (!sb
.append(chars
+ start
, k
- start
+ 1))
5727 return TransferBufferToString(cx
, sb
, rval
);
5730 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_URI
);
5737 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5739 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5742 return Decode(cx
, str
, js_uriReservedPlusPound_ucstr
, vp
);
5746 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5748 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5751 return Decode(cx
, str
, js_empty_ucstr
, vp
);
5755 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5757 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5760 return Encode(cx
, str
, js_uriReservedPlusPound_ucstr
, js_uriUnescaped_ucstr
,
5765 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5767 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5770 return Encode(cx
, str
, js_uriUnescaped_ucstr
, NULL
, vp
);
5774 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5775 * least 4 bytes long. Return the number of UTF-8 bytes of data written.
5778 js_OneUcs4ToUtf8Char(uint8
*utf8Buffer
, uint32 ucs4Char
)
5782 JS_ASSERT(ucs4Char
<= 0x10FFFF);
5783 if (ucs4Char
< 0x80) {
5784 *utf8Buffer
= (uint8
)ucs4Char
;
5787 uint32 a
= ucs4Char
>> 11;
5795 utf8Buffer
[i
] = (uint8
)((ucs4Char
& 0x3F) | 0x80);
5798 *utf8Buffer
= (uint8
)(0x100 - (1 << (8-utf8Length
)) + ucs4Char
);
5804 * Convert a utf8 character sequence into a UCS-4 character and return that
5805 * character. It is assumed that the caller already checked that the sequence
5809 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
)
5813 /* from Unicode 3.1, non-shortest form is illegal */
5814 static const uint32 minucs4Table
[] = {
5815 0x00000080, 0x00000800, 0x00010000
5818 JS_ASSERT(utf8Length
>= 1 && utf8Length
<= 4);
5819 if (utf8Length
== 1) {
5820 ucs4Char
= *utf8Buffer
;
5821 JS_ASSERT(!(ucs4Char
& 0x80));
5823 JS_ASSERT((*utf8Buffer
& (0x100 - (1 << (7-utf8Length
)))) ==
5824 (0x100 - (1 << (8-utf8Length
))));
5825 ucs4Char
= *utf8Buffer
++ & ((1<<(7-utf8Length
))-1);
5826 minucs4Char
= minucs4Table
[utf8Length
-2];
5827 while (--utf8Length
) {
5828 JS_ASSERT((*utf8Buffer
& 0xC0) == 0x80);
5829 ucs4Char
= ucs4Char
<<6 | (*utf8Buffer
++ & 0x3F);
5831 if (JS_UNLIKELY(ucs4Char
< minucs4Char
)) {
5832 ucs4Char
= OVERLONG_UTF8
;
5833 } else if (ucs4Char
== 0xFFFE || ucs4Char
== 0xFFFF) {
5843 PutEscapedStringImpl(char *buffer
, size_t bufferSize
, FILE *fp
, JSLinearString
*str
, uint32 quote
)
5846 STOP
, FIRST_QUOTE
, LAST_QUOTE
, CHARS
, ESCAPE_START
, ESCAPE_MORE
5849 JS_ASSERT(quote
== 0 || quote
== '\'' || quote
== '"');
5850 JS_ASSERT_IF(!buffer
, bufferSize
== 0);
5851 JS_ASSERT_IF(fp
, !buffer
);
5853 if (bufferSize
== 0)
5858 const jschar
*chars
= str
->chars();
5859 const jschar
*charsEnd
= chars
+ str
->length();
5861 state
= FIRST_QUOTE
;
5865 char c
= 0; /* to quell GCC warnings */
5882 if (chars
== charsEnd
) {
5889 const char *escape
= strchr(js_EscapeMap
, (int)u
);
5898 if (u
== quote
|| u
== '\\')
5901 } else if (u
< 0x100) {
5916 state
= ESCAPE_START
;
5919 JS_ASSERT(' ' <= u
&& u
< 127);
5921 state
= ESCAPE_MORE
;
5929 u
= 0xF & (hex
>> shift
);
5930 c
= (char)(u
+ (u
< 10 ? '0' : 'A' - 10));
5934 JS_ASSERT(n
<= bufferSize
);
5935 if (n
!= bufferSize
) {
5942 if (fputc(c
, fp
) < 0)
5953 } /* namespace js */