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 const size_t wholeLength
= length();
162 size_t wholeCapacity
;
164 JSString
*str
= this;
167 if (u
.left
->isExtensible() && u
.left
->s
.capacity
>= wholeLength
) {
168 wholeCapacity
= u
.left
->s
.capacity
;
169 wholeChars
= const_cast<jschar
*>(u
.left
->u
.chars
);
170 pos
= wholeChars
+ u
.left
->length();
171 u
.left
->finishTraversalConversion(this, wholeChars
, pos
);
172 goto visit_right_child
;
175 wholeCapacity
= RopeCapacityFor(wholeLength
);
176 wholeChars
= AllocChars(maybecx
, wholeCapacity
);
181 JSString
*left
= str
->u
.left
; /* Read before clobbered. */
183 if (left
->isRope()) {
184 left
->s
.parent
= str
; /* Return to this when 'left' done, */
185 left
->lengthAndFlags
= 0x200; /* but goto visit_right_child. */
187 goto first_visit_node
;
189 size_t len
= left
->length();
190 PodCopy(pos
, left
->u
.chars
, len
);
194 JSString
*right
= str
->s
.right
;
195 if (right
->isRope()) {
196 right
->s
.parent
= str
; /* Return to this node when 'right' done, */
197 right
->lengthAndFlags
= 0x300; /* but goto finish_node. */
199 goto first_visit_node
;
201 size_t len
= right
->length();
202 PodCopy(pos
, right
->u
.chars
, len
);
207 JS_ASSERT(pos
== wholeChars
+ wholeLength
);
209 initFlatExtensible(wholeChars
, wholeLength
, wholeCapacity
);
212 size_t progress
= str
->lengthAndFlags
; /* Read before clobbered. */
213 JSString
*parent
= str
->s
.parent
;
214 str
->finishTraversalConversion(this, wholeChars
, pos
);
216 if (progress
== 0x200)
217 goto visit_right_child
;
222 JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT
== 8);
223 JSStringFinalizeOp
JSExternalString::str_finalizers
[JSExternalString::TYPE_LIMIT
] = {
224 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
230 js_Flatten(JSContext
*cx
, JSString
* str
)
232 return !!str
->flatten(cx
);
234 JS_DEFINE_CALLINFO_2(extern, BOOL
, js_Flatten
, CONTEXT
, STRING
, 0, nanojit::ACCSET_STORE_ANY
)
236 #endif /* !JS_TRACER */
238 JSString
* JS_FASTCALL
239 js_ConcatStrings(JSContext
*cx
, JSString
*left
, JSString
*right
)
241 size_t leftLen
= left
->length();
245 size_t rightLen
= right
->length();
249 size_t wholeLength
= leftLen
+ rightLen
;
251 if (JSShortString::fitsIntoShortString(wholeLength
)) {
252 JSShortString
*shortStr
= js_NewGCShortString(cx
);
255 const jschar
*leftChars
= left
->getChars(cx
);
258 const jschar
*rightChars
= right
->getChars(cx
);
262 jschar
*buf
= shortStr
->init(wholeLength
);
263 js_short_strncpy(buf
, leftChars
, leftLen
);
264 js_short_strncpy(buf
+ leftLen
, rightChars
, rightLen
);
265 buf
[wholeLength
] = 0;
266 return shortStr
->header();
269 if (wholeLength
> JSString::MAX_LENGTH
) {
270 if (JS_ON_TRACE(cx
)) {
271 if (!CanLeaveTrace(cx
))
275 js_ReportAllocationOverflow(cx
);
279 JSString
*newRoot
= js_NewGCString(cx
);
283 newRoot
->initRopeNode(left
, right
, wholeLength
);
288 JSString::undepend(JSContext
*cx
)
293 if (!ensureLinear(cx
))
297 n
= dependentLength();
298 size
= (n
+ 1) * sizeof(jschar
);
299 s
= (jschar
*) cx
->malloc(size
);
303 js_strncpy(s
, dependentChars(), n
);
309 JSRuntime
*rt
= cx
->runtime
;
310 JS_RUNTIME_UNMETER(rt
, liveDependentStrings
);
311 JS_RUNTIME_UNMETER(rt
, totalDependentStrings
);
312 JS_LOCK_RUNTIME_VOID(rt
,
313 (rt
->strdepLengthSum
-= (double)n
,
314 rt
->strdepLengthSquaredSum
-= (double)n
* (double)n
));
323 js_MakeStringImmutable(JSContext
*cx
, JSString
*str
)
326 * Flattening a rope may result in a dependent string, so we need to flatten
327 * before undepending the string.
329 if (!str
->isFlat() && !str
->undepend(cx
)) {
330 JS_RUNTIME_METER(cx
->runtime
, badUndependStrings
);
333 str
->flatClearExtensible();
337 static JSLinearString
*
338 ArgToRootedString(JSContext
*cx
, uintN argc
, Value
*vp
, uintN arg
)
341 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
344 if (vp
->isObject() && !DefaultValue(cx
, &vp
->toObject(), JSTYPE_STRING
, vp
))
348 if (vp
->isString()) {
349 str
= vp
->toString()->ensureLinear(cx
);
350 } else if (vp
->isBoolean()) {
351 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.booleanAtoms
[
352 (int)vp
->toBoolean()]);
353 } else if (vp
->isNull()) {
354 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
355 } else if (vp
->isUndefined()) {
356 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
359 str
= NumberToString(cx
, vp
->toNumber());
368 * Forward declarations for URI encode/decode and helper routines
371 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
374 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
377 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
);
380 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
);
382 static const uint32 OVERLONG_UTF8
= UINT32_MAX
;
385 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
);
388 * Contributions from the String class to the set of methods defined for the
389 * global object. escape and unescape used to be defined in the Mocha library,
390 * but as ECMA decided to spec them, they've been moved to the core engine
391 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
392 * characters by unescape.)
396 * Stuff to emulate the old libmocha escape, which took a second argument
397 * giving the type of escape to perform. Retained for compatibility, and
398 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
401 #define URL_XALPHAS ((uint8) 1)
402 #define URL_XPALPHAS ((uint8) 2)
403 #define URL_PATH ((uint8) 4)
405 static const uint8 urlCharType
[256] =
406 /* Bit 0 xalpha -- the alphas
407 * Bit 1 xpalpha -- as xalpha but
408 * converts spaces to plus and plus to %20
409 * Bit 2 ... path -- as xalphas but doesn't escape '/'
411 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
412 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
413 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
414 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
415 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
416 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
417 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
418 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
419 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
422 /* This matches the ECMA escape set when mask is 7 (default.) */
424 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
426 /* See ECMA-262 Edition 3 B.2.1 */
428 js_str_escape(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
, Value
*rval
)
430 const char digits
[] = {'0', '1', '2', '3', '4', '5', '6', '7',
431 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
433 jsint mask
= URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
;
436 if (!ValueToNumber(cx
, argv
[1], &d
))
438 if (!JSDOUBLE_IS_FINITE(d
) ||
439 (mask
= (jsint
)d
) != d
||
440 mask
& ~(URL_XALPHAS
| URL_XPALPHAS
| URL_PATH
))
443 JS_snprintf(numBuf
, sizeof numBuf
, "%lx", (unsigned long) mask
);
444 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
445 JSMSG_BAD_STRING_MASK
, numBuf
);
450 JSLinearString
*str
= ArgToRootedString(cx
, argc
, argv
- 2, 0);
454 size_t length
= str
->length();
455 const jschar
*chars
= str
->chars();
457 /* Take a first pass and see how big the result string will need to be. */
458 size_t newlength
= length
;
459 for (size_t i
= 0; i
< length
; i
++) {
461 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
))
464 if (mask
== URL_XPALPHAS
&& ch
== ' ')
465 continue; /* The character will be encoded as '+' */
466 newlength
+= 2; /* The character will be encoded as %XX */
468 newlength
+= 5; /* The character will be encoded as %uXXXX */
472 * This overflow test works because newlength is incremented by at
473 * most 5 on each iteration.
475 if (newlength
< length
) {
476 js_ReportAllocationOverflow(cx
);
481 if (newlength
>= ~(size_t)0 / sizeof(jschar
)) {
482 js_ReportAllocationOverflow(cx
);
486 jschar
*newchars
= (jschar
*) cx
->malloc((newlength
+ 1) * sizeof(jschar
));
490 for (i
= 0, ni
= 0; i
< length
; i
++) {
492 if ((ch
= chars
[i
]) < 128 && IS_OK(ch
, mask
)) {
494 } else if (ch
< 256) {
495 if (mask
== URL_XPALPHAS
&& ch
== ' ') {
496 newchars
[ni
++] = '+'; /* convert spaces to pluses */
498 newchars
[ni
++] = '%';
499 newchars
[ni
++] = digits
[ch
>> 4];
500 newchars
[ni
++] = digits
[ch
& 0xF];
503 newchars
[ni
++] = '%';
504 newchars
[ni
++] = 'u';
505 newchars
[ni
++] = digits
[ch
>> 12];
506 newchars
[ni
++] = digits
[(ch
& 0xF00) >> 8];
507 newchars
[ni
++] = digits
[(ch
& 0xF0) >> 4];
508 newchars
[ni
++] = digits
[ch
& 0xF];
511 JS_ASSERT(ni
== newlength
);
512 newchars
[newlength
] = 0;
514 JSString
*retstr
= js_NewString(cx
, newchars
, newlength
);
519 rval
->setString(retstr
);
525 str_escape(JSContext
*cx
, uintN argc
, Value
*vp
)
527 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
528 return obj
&& js_str_escape(cx
, obj
, argc
, vp
+ 2, vp
);
531 /* See ECMA-262 Edition 3 B.2.2 */
533 str_unescape(JSContext
*cx
, uintN argc
, Value
*vp
)
535 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
539 size_t length
= str
->length();
540 const jschar
*chars
= str
->chars();
542 /* Don't bother allocating less space for the new string. */
543 jschar
*newchars
= (jschar
*) cx
->malloc((length
+ 1) * sizeof(jschar
));
546 size_t ni
= 0, i
= 0;
548 jschar ch
= chars
[i
++];
550 if (i
+ 1 < length
&&
551 JS7_ISHEX(chars
[i
]) && JS7_ISHEX(chars
[i
+ 1]))
553 ch
= JS7_UNHEX(chars
[i
]) * 16 + JS7_UNHEX(chars
[i
+ 1]);
555 } else if (i
+ 4 < length
&& chars
[i
] == 'u' &&
556 JS7_ISHEX(chars
[i
+ 1]) && JS7_ISHEX(chars
[i
+ 2]) &&
557 JS7_ISHEX(chars
[i
+ 3]) && JS7_ISHEX(chars
[i
+ 4]))
559 ch
= (((((JS7_UNHEX(chars
[i
+ 1]) << 4)
560 + JS7_UNHEX(chars
[i
+ 2])) << 4)
561 + JS7_UNHEX(chars
[i
+ 3])) << 4)
562 + JS7_UNHEX(chars
[i
+ 4]);
570 JSString
*retstr
= js_NewString(cx
, newchars
, ni
);
575 vp
->setString(retstr
);
581 str_uneval(JSContext
*cx
, uintN argc
, Value
*vp
)
585 str
= js_ValueToSource(cx
, argc
!= 0 ? vp
[2] : UndefinedValue());
593 const char js_escape_str
[] = "escape";
594 const char js_unescape_str
[] = "unescape";
596 const char js_uneval_str
[] = "uneval";
598 const char js_decodeURI_str
[] = "decodeURI";
599 const char js_encodeURI_str
[] = "encodeURI";
600 const char js_decodeURIComponent_str
[] = "decodeURIComponent";
601 const char js_encodeURIComponent_str
[] = "encodeURIComponent";
603 static JSFunctionSpec string_functions
[] = {
604 JS_FN(js_escape_str
, str_escape
, 1,0),
605 JS_FN(js_unescape_str
, str_unescape
, 1,0),
607 JS_FN(js_uneval_str
, str_uneval
, 1,0),
609 JS_FN(js_decodeURI_str
, str_decodeURI
, 1,0),
610 JS_FN(js_encodeURI_str
, str_encodeURI
, 1,0),
611 JS_FN(js_decodeURIComponent_str
, str_decodeURI_Component
, 1,0),
612 JS_FN(js_encodeURIComponent_str
, str_encodeURI_Component
, 1,0),
617 jschar js_empty_ucstr
[] = {0};
618 JSSubString js_EmptySubString
= {0, js_empty_ucstr
};
621 str_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
625 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
626 if (obj
->getClass() == &js_StringClass
) {
627 /* Follow ECMA-262 by fetching intrinsic length of our string. */
628 str
= obj
->getPrimitiveThis().toString();
630 /* Preserve compatibility: convert obj to a string primitive. */
631 str
= js_ValueToString(cx
, ObjectValue(*obj
));
636 vp
->setInt32(str
->length());
642 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
645 str_enumerate(JSContext
*cx
, JSObject
*obj
)
647 JSString
*str
, *str1
;
650 str
= obj
->getPrimitiveThis().toString();
652 length
= str
->length();
653 for (i
= 0; i
< length
; i
++) {
654 str1
= js_NewDependentString(cx
, str
, i
, 1);
657 if (!obj
->defineProperty(cx
, INT_TO_JSID(i
), StringValue(str1
),
658 PropertyStub
, PropertyStub
,
659 STRING_ELEMENT_ATTRS
)) {
664 return obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
665 UndefinedValue(), NULL
, NULL
,
666 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_SHARED
);
670 str_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
673 if (!JSID_IS_INT(id
))
676 JSString
*str
= obj
->getPrimitiveThis().toString();
678 jsint slot
= JSID_TO_INT(id
);
679 if ((size_t)slot
< str
->length()) {
680 JSString
*str1
= JSString::getUnitString(cx
, str
, size_t(slot
));
683 if (!obj
->defineProperty(cx
, id
, StringValue(str1
), NULL
, NULL
,
684 STRING_ELEMENT_ATTRS
)) {
692 Class js_StringClass
= {
694 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE
|
695 JSCLASS_HAS_CACHED_PROTO(JSProto_String
),
696 PropertyStub
, /* addProperty */
697 PropertyStub
, /* delProperty */
699 PropertyStub
, /* setProperty */
701 (JSResolveOp
)str_resolve
,
705 #define NORMALIZE_THIS(cx,vp,str) \
707 if (vp[1].isString()) { \
708 str = vp[1].toString(); \
710 str = NormalizeThis(cx, vp); \
717 NormalizeThis(JSContext
*cx
, Value
*vp
)
719 if (vp
[1].isNullOrUndefined() && !ComputeThisFromVp(cx
, vp
))
723 * String.prototype.{toString,toSource,valueOf} throw a TypeError if the
724 * this-argument is not a string or a String object. So those methods use
725 * js::GetPrimitiveThis which provides that behavior.
727 * By standard, the rest of the String methods must ToString the
728 * this-argument rather than throw a TypeError. So those methods use
729 * NORMALIZE_THIS (and thus NormalizeThis) instead.
731 if (vp
[1].isObject()) {
732 JSObject
*obj
= &vp
[1].toObject();
733 if (obj
->getClass() == &js_StringClass
) {
734 vp
[1] = obj
->getPrimitiveThis();
735 return vp
[1].toString();
739 JSString
*str
= js_ValueToString(cx
, vp
[1]);
742 vp
[1].setString(str
);
749 * String.prototype.quote is generic (as are most string methods), unlike
750 * toSource, toString, and valueOf.
753 str_quote(JSContext
*cx
, uintN argc
, Value
*vp
)
757 NORMALIZE_THIS(cx
, vp
, str
);
758 str
= js_QuoteString(cx
, str
, '"');
766 str_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
769 if (!GetPrimitiveThis(cx
, vp
, &str
))
772 str
= js_QuoteString(cx
, str
, '"');
777 size_t j
= JS_snprintf(buf
, sizeof buf
, "(new String(");
779 size_t k
= str
->length();
780 const jschar
*s
= str
->getChars(cx
);
784 size_t n
= j
+ k
+ 2;
785 jschar
*t
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
790 for (i
= 0; i
< j
; i
++)
792 for (j
= 0; j
< k
; i
++, j
++)
798 str
= js_NewString(cx
, t
, n
);
807 #endif /* JS_HAS_TOSOURCE */
810 js_str_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
813 if (!GetPrimitiveThis(cx
, vp
, &str
))
820 * Java-like string native methods.
823 JS_ALWAYS_INLINE
bool
824 ValueToIntegerRange(JSContext
*cx
, const Value
&v
, int32
*out
)
831 if (!ValueToNumber(cx
, v
, &d
))
834 d
= js_DoubleToInteger(d
);
837 else if (d
< INT32_MIN
)
847 str_substring(JSContext
*cx
, uintN argc
, Value
*vp
)
850 int32 length
, begin
, end
;
852 NORMALIZE_THIS(cx
, vp
, str
);
855 end
= length
= int32(str
->length());
857 if (!ValueToIntegerRange(cx
, vp
[2], &begin
))
862 else if (begin
> length
)
865 if (argc
> 1 && !vp
[3].isUndefined()) {
866 if (!ValueToIntegerRange(cx
, vp
[3], &end
))
882 str
= js_NewDependentString(cx
, str
, size_t(begin
), size_t(end
- begin
));
891 JSString
* JS_FASTCALL
892 js_toLowerCase(JSContext
*cx
, JSString
*str
)
894 size_t n
= str
->length();
895 const jschar
*s
= str
->getChars(cx
);
899 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
902 for (size_t i
= 0; i
< n
; i
++)
903 news
[i
] = JS_TOLOWER(s
[i
]);
905 str
= js_NewString(cx
, news
, n
);
914 str_toLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
918 NORMALIZE_THIS(cx
, vp
, str
);
919 str
= js_toLowerCase(cx
, str
);
927 str_toLocaleLowerCase(JSContext
*cx
, uintN argc
, Value
*vp
)
932 * Forcefully ignore the first (or any) argument and return toLowerCase(),
933 * ECMA has reserved that argument, presumably for defining the locale.
935 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToLowerCase
) {
936 NORMALIZE_THIS(cx
, vp
, str
);
937 return cx
->localeCallbacks
->localeToLowerCase(cx
, str
, Jsvalify(vp
));
939 return str_toLowerCase(cx
, 0, vp
);
942 JSString
* JS_FASTCALL
943 js_toUpperCase(JSContext
*cx
, JSString
*str
)
945 size_t n
= str
->length();
946 const jschar
*s
= str
->getChars(cx
);
949 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
952 for (size_t i
= 0; i
< n
; i
++)
953 news
[i
] = JS_TOUPPER(s
[i
]);
955 str
= js_NewString(cx
, news
, n
);
964 str_toUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
968 NORMALIZE_THIS(cx
, vp
, str
);
969 str
= js_toUpperCase(cx
, str
);
977 str_toLocaleUpperCase(JSContext
*cx
, uintN argc
, Value
*vp
)
982 * Forcefully ignore the first (or any) argument and return toUpperCase(),
983 * ECMA has reserved that argument, presumably for defining the locale.
985 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUpperCase
) {
986 NORMALIZE_THIS(cx
, vp
, str
);
987 return cx
->localeCallbacks
->localeToUpperCase(cx
, str
, Jsvalify(vp
));
989 return str_toUpperCase(cx
, 0, vp
);
993 str_localeCompare(JSContext
*cx
, uintN argc
, Value
*vp
)
995 JSString
*str
, *thatStr
;
997 NORMALIZE_THIS(cx
, vp
, str
);
1001 thatStr
= js_ValueToString(cx
, vp
[2]);
1004 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeCompare
) {
1005 vp
[2].setString(thatStr
);
1006 return cx
->localeCallbacks
->localeCompare(cx
, str
, thatStr
, Jsvalify(vp
));
1009 if (!CompareStrings(cx
, str
, thatStr
, &result
))
1011 vp
->setInt32(result
);
1017 js_str_charAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1023 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1024 str
= vp
[1].toString();
1025 i
= vp
[2].toInt32();
1026 if ((size_t)i
>= str
->length())
1029 NORMALIZE_THIS(cx
, vp
, str
);
1034 if (!ValueToNumber(cx
, vp
[2], &d
))
1036 d
= js_DoubleToInteger(d
);
1039 if (d
< 0 || str
->length() <= d
)
1044 str
= JSString::getUnitString(cx
, str
, size_t(i
));
1051 vp
->setString(cx
->runtime
->emptyString
);
1056 js_str_charCodeAt(JSContext
*cx
, uintN argc
, Value
*vp
)
1060 if (vp
[1].isString() && argc
!= 0 && vp
[2].isInt32()) {
1061 str
= vp
[1].toString();
1062 i
= vp
[2].toInt32();
1063 if ((size_t)i
>= str
->length())
1066 NORMALIZE_THIS(cx
, vp
, str
);
1072 if (!ValueToNumber(cx
, vp
[2], &d
))
1074 d
= js_DoubleToInteger(d
);
1077 if (d
< 0 || str
->length() <= d
)
1082 const jschar
*chars
;
1083 chars
= str
->getChars(cx
);
1087 vp
->setInt32(chars
[i
]);
1091 vp
->setDouble(js_NaN
);
1096 js_BoyerMooreHorspool(const jschar
*text
, jsuint textlen
,
1097 const jschar
*pat
, jsuint patlen
)
1099 uint8 skip
[sBMHCharSetSize
];
1101 JS_ASSERT(0 < patlen
&& patlen
<= sBMHPatLenMax
);
1102 for (jsuint i
= 0; i
< sBMHCharSetSize
; i
++)
1103 skip
[i
] = (uint8
)patlen
;
1104 jsuint m
= patlen
- 1;
1105 for (jsuint i
= 0; i
< m
; i
++) {
1107 if (c
>= sBMHCharSetSize
)
1108 return sBMHBadPattern
;
1109 skip
[c
] = (uint8
)(m
- i
);
1114 k
+= ((c
= text
[k
]) >= sBMHCharSetSize
) ? patlen
: skip
[c
]) {
1115 for (jsuint i
= k
, j
= m
; ; i
--, j
--) {
1116 if (text
[i
] != pat
[j
])
1119 return static_cast<jsint
>(i
); /* safe: max string size */
1126 typedef jsuint Extent
;
1127 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*, jsuint patlen
) {
1128 return (patlen
- 1) * sizeof(jschar
);
1130 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1131 return memcmp(p
, t
, extent
) == 0;
1136 typedef const jschar
*Extent
;
1137 static JS_ALWAYS_INLINE Extent
computeExtent(const jschar
*pat
, jsuint patlen
) {
1138 return pat
+ patlen
;
1140 static JS_ALWAYS_INLINE
bool match(const jschar
*p
, const jschar
*t
, Extent extent
) {
1141 for (; p
!= extent
; ++p
, ++t
) {
1149 template <class InnerMatch
>
1151 UnrolledMatch(const jschar
*text
, jsuint textlen
, const jschar
*pat
, jsuint patlen
)
1153 JS_ASSERT(patlen
> 0 && textlen
> 0);
1154 const jschar
*textend
= text
+ textlen
- (patlen
- 1);
1155 const jschar p0
= *pat
;
1156 const jschar
*const patNext
= pat
+ 1;
1157 const typename
InnerMatch::Extent extent
= InnerMatch::computeExtent(pat
, patlen
);
1160 const jschar
*t
= text
;
1161 switch ((textend
- t
) & 7) {
1162 case 0: if (*t
++ == p0
) { fixup
= 8; goto match
; }
1163 case 7: if (*t
++ == p0
) { fixup
= 7; goto match
; }
1164 case 6: if (*t
++ == p0
) { fixup
= 6; goto match
; }
1165 case 5: if (*t
++ == p0
) { fixup
= 5; goto match
; }
1166 case 4: if (*t
++ == p0
) { fixup
= 4; goto match
; }
1167 case 3: if (*t
++ == p0
) { fixup
= 3; goto match
; }
1168 case 2: if (*t
++ == p0
) { fixup
= 2; goto match
; }
1169 case 1: if (*t
++ == p0
) { fixup
= 1; goto match
; }
1171 while (t
!= textend
) {
1172 if (t
[0] == p0
) { t
+= 1; fixup
= 8; goto match
; }
1173 if (t
[1] == p0
) { t
+= 2; fixup
= 7; goto match
; }
1174 if (t
[2] == p0
) { t
+= 3; fixup
= 6; goto match
; }
1175 if (t
[3] == p0
) { t
+= 4; fixup
= 5; goto match
; }
1176 if (t
[4] == p0
) { t
+= 5; fixup
= 4; goto match
; }
1177 if (t
[5] == p0
) { t
+= 6; fixup
= 3; goto match
; }
1178 if (t
[6] == p0
) { t
+= 7; fixup
= 2; goto match
; }
1179 if (t
[7] == p0
) { t
+= 8; fixup
= 1; goto match
; }
1185 if (!InnerMatch::match(patNext
, t
, extent
))
1187 return t
- text
- 1;
1190 } while (--fixup
> 0);
1195 static JS_ALWAYS_INLINE jsint
1196 StringMatch(const jschar
*text
, jsuint textlen
,
1197 const jschar
*pat
, jsuint patlen
)
1201 if (textlen
< patlen
)
1204 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1206 * Given enough registers, the unrolled loop below is faster than the
1207 * following loop. 32-bit x86 does not have enough registers.
1210 const jschar p0
= *pat
;
1211 for (const jschar
*c
= text
, *end
= text
+ textlen
; c
!= end
; ++c
) {
1220 * If the text or pattern string is short, BMH will be more expensive than
1221 * the basic linear scan due to initialization cost and a more complex loop
1222 * body. While the correct threshold is input-dependent, we can make a few
1223 * conservative observations:
1224 * - When |textlen| is "big enough", the initialization time will be
1225 * proportionally small, so the worst-case slowdown is minimized.
1226 * - When |patlen| is "too small", even the best case for BMH will be
1227 * slower than a simple scan for large |textlen| due to the more complex
1229 * From this, the values for "big enough" and "too small" are determined
1230 * empirically. See bug 526348.
1232 if (textlen
>= 512 && patlen
>= 11 && patlen
<= sBMHPatLenMax
) {
1233 jsint index
= js_BoyerMooreHorspool(text
, textlen
, pat
, patlen
);
1234 if (index
!= sBMHBadPattern
)
1239 * For big patterns with large potential overlap we want the SIMD-optimized
1240 * speed of memcmp. For small patterns, a simple loop is faster.
1242 * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1245 #if !defined(__linux__)
1246 patlen
> 128 ? UnrolledMatch
<MemCmp
>(text
, textlen
, pat
, patlen
)
1249 UnrolledMatch
<ManualCmp
>(text
, textlen
, pat
, patlen
);
1252 static const size_t sRopeMatchThresholdRatioLog2
= 5;
1255 * RopeMatch takes the text to search, the patern to search for in the text.
1256 * RopeMatch returns false on OOM and otherwise returns the match index through
1257 * the 'match' outparam (-1 for not found).
1260 RopeMatch(JSContext
*cx
, JSString
*textstr
, const jschar
*pat
, jsuint patlen
, jsint
*match
)
1262 JS_ASSERT(textstr
->isRope());
1268 if (textstr
->length() < patlen
) {
1274 * List of leaf nodes in the rope. If we run out of memory when trying to
1275 * append to this list, we can still fall back to StringMatch, so use the
1276 * system allocator so we don't report OOM in that case.
1278 Vector
<JSString
*, 16, SystemAllocPolicy
> strs
;
1281 * We don't want to do rope matching if there is a poor node-to-char ratio,
1282 * since this means spending a lot of time in the match loop below. We also
1283 * need to build the list of leaf nodes. Do both here: iterate over the
1284 * nodes so long as there are not too many.
1287 size_t textstrlen
= textstr
->length();
1288 size_t threshold
= textstrlen
>> sRopeMatchThresholdRatioLog2
;
1289 StringSegmentRange
r(cx
);
1290 if (!r
.init(textstr
))
1292 while (!r
.empty()) {
1293 if (threshold
-- == 0 || !strs
.append(r
.front())) {
1294 const jschar
*chars
= textstr
->getChars(cx
);
1297 *match
= StringMatch(chars
, textstrlen
, pat
, patlen
);
1305 /* Absolute offset from the beginning of the logical string textstr. */
1308 // TODO: consider branching to a simple loop if patlen == 1
1310 for (JSString
**outerp
= strs
.begin(); outerp
!= strs
.end(); ++outerp
) {
1311 /* First try to match without spanning two nodes. */
1312 JSString
*outer
= *outerp
;
1313 const jschar
*chars
= outer
->nonRopeChars();
1314 size_t len
= outer
->length();
1315 jsint matchResult
= StringMatch(chars
, len
, pat
, patlen
);
1316 if (matchResult
!= -1) {
1317 *match
= pos
+ matchResult
;
1321 /* Test the overlap. */
1322 JSString
**innerp
= outerp
;
1325 * Start searching at the first place where StringMatch wouldn't have
1328 const jschar
*const text
= chars
+ (patlen
> len
? 0 : len
- patlen
+ 1);
1329 const jschar
*const textend
= chars
+ len
;
1330 const jschar p0
= *pat
;
1331 const jschar
*const p1
= pat
+ 1;
1332 const jschar
*const patend
= pat
+ patlen
;
1333 for (const jschar
*t
= text
; t
!= textend
; ) {
1336 const jschar
*ttend
= textend
;
1337 for (const jschar
*pp
= p1
, *tt
= t
; pp
!= patend
; ++pp
, ++tt
) {
1338 while (tt
== ttend
) {
1339 if (++innerp
== strs
.end()) {
1343 JSString
*inner
= *innerp
;
1344 tt
= inner
->nonRopeChars();
1345 ttend
= tt
+ inner
->length();
1348 goto break_continue
;
1352 *match
= pos
+ (t
- chars
) - 1; /* -1 because of *t++ above */
1366 str_indexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1370 NORMALIZE_THIS(cx
, vp
, str
);
1372 JSLinearString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1376 jsuint textlen
= str
->length();
1377 const jschar
*text
= str
->getChars(cx
);
1381 jsuint patlen
= patstr
->length();
1382 const jschar
*pat
= patstr
->chars();
1386 if (vp
[3].isInt32()) {
1387 jsint i
= vp
[3].toInt32();
1390 } else if (jsuint(i
) > textlen
) {
1400 if (!ValueToNumber(cx
, vp
[3], &d
))
1402 d
= js_DoubleToInteger(d
);
1405 } else if (d
> textlen
) {
1418 jsint match
= StringMatch(text
, textlen
, pat
, patlen
);
1419 vp
->setInt32((match
== -1) ? -1 : start
+ match
);
1424 str_lastIndexOf(JSContext
*cx
, uintN argc
, Value
*vp
)
1427 NORMALIZE_THIS(cx
, vp
, textstr
);
1428 size_t textlen
= textstr
->length();
1429 const jschar
*text
= textstr
->getChars(cx
);
1433 JSLinearString
*patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1437 size_t patlen
= patstr
->length();
1438 const jschar
*pat
= patstr
->chars();
1440 jsint i
= textlen
- patlen
; // Start searching here
1447 if (vp
[3].isInt32()) {
1448 jsint j
= vp
[3].toInt32();
1455 if (!ValueToNumber(cx
, vp
[3], &d
))
1457 if (!JSDOUBLE_IS_NaN(d
)) {
1458 d
= js_DoubleToInteger(d
);
1472 const jschar
*t
= text
+ i
;
1473 const jschar
*textend
= text
- 1;
1474 const jschar p0
= *pat
;
1475 const jschar
*patNext
= pat
+ 1;
1476 const jschar
*patEnd
= pat
+ patlen
;
1478 for (; t
!= textend
; --t
) {
1480 const jschar
*t1
= t
+ 1;
1481 for (const jschar
*p1
= patNext
; p1
!= patEnd
; ++p1
, ++t1
) {
1483 goto break_continue
;
1485 vp
->setInt32(t
- text
);
1496 js_TrimString(JSContext
*cx
, Value
*vp
, JSBool trimLeft
, JSBool trimRight
)
1499 NORMALIZE_THIS(cx
, vp
, str
);
1500 size_t length
= str
->length();
1501 const jschar
*chars
= str
->getChars(cx
);
1506 size_t end
= length
;
1509 while (begin
< length
&& JS_ISSPACE(chars
[begin
]))
1514 while (end
> begin
&& JS_ISSPACE(chars
[end
-1]))
1518 str
= js_NewDependentString(cx
, str
, begin
, end
- begin
);
1527 str_trim(JSContext
*cx
, uintN argc
, Value
*vp
)
1529 return js_TrimString(cx
, vp
, JS_TRUE
, JS_TRUE
);
1533 str_trimLeft(JSContext
*cx
, uintN argc
, Value
*vp
)
1535 return js_TrimString(cx
, vp
, JS_TRUE
, JS_FALSE
);
1539 str_trimRight(JSContext
*cx
, uintN argc
, Value
*vp
)
1541 return js_TrimString(cx
, vp
, JS_FALSE
, JS_TRUE
);
1545 * Perl-inspired string functions.
1548 /* Result of a successfully performed flat match. */
1551 JSLinearString
*patstr
;
1556 friend class RegExpGuard
;
1559 FlatMatch() : patstr(NULL
) {} /* Old GCC wants this initialization. */
1560 JSString
*pattern() const { return patstr
; }
1561 size_t patternLength() const { return patlen
; }
1564 * @note The match is -1 when the match is performed successfully,
1565 * but no match is found.
1567 int32
match() const { return match_
; }
1570 /* A regexp and optional associated object. */
1576 explicit RegExpPair(RegExp
*re
): re_(re
) {}
1577 friend class RegExpGuard
;
1580 /* @note May be null. */
1581 JSObject
*reobj() const { return reobj_
; }
1582 RegExp
&re() const { JS_ASSERT(re_
); return *re_
; }
1586 * RegExpGuard factors logic out of String regexp operations.
1588 * @param optarg Indicates in which argument position RegExp
1589 * flags will be found, if present. This is a Mozilla
1590 * extension and not part of any ECMA spec.
1594 RegExpGuard(const RegExpGuard
&);
1595 void operator=(const RegExpGuard
&);
1602 * Upper bound on the number of characters we are willing to potentially
1603 * waste on searching for RegExp meta-characters.
1605 static const size_t MAX_FLAT_PAT_LEN
= 256;
1607 static JSString
*flattenPattern(JSContext
*cx
, JSLinearString
*patstr
) {
1608 JSCharBuffer
cb(cx
);
1609 if (!cb
.reserve(patstr
->length()))
1612 static const jschar ESCAPE_CHAR
= '\\';
1613 const jschar
*chars
= patstr
->chars();
1614 size_t len
= patstr
->length();
1615 for (const jschar
*it
= chars
; it
!= chars
+ len
; ++it
) {
1616 if (RegExp::isMetaChar(*it
)) {
1617 if (!cb
.append(ESCAPE_CHAR
) || !cb
.append(*it
))
1620 if (!cb
.append(*it
))
1624 return js_NewStringFromCharBuffer(cx
, cb
);
1628 explicit RegExpGuard(JSContext
*cx
) : cx(cx
), rep(NULL
) {}
1632 rep
.re_
->decref(cx
);
1635 /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1637 init(uintN argc
, Value
*vp
)
1639 if (argc
!= 0 && VALUE_IS_REGEXP(cx
, vp
[2])) {
1640 rep
.reobj_
= &vp
[2].toObject();
1641 rep
.re_
= RegExp::extractFrom(rep
.reobj_
);
1642 rep
.re_
->incref(cx
);
1644 fm
.patstr
= ArgToRootedString(cx
, argc
, vp
, 0);
1652 * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1653 * pattern string, or a lengthy pattern string can thwart this process.
1655 * @param checkMetaChars Look for regexp metachars in the pattern string.
1656 * @return Whether flat matching could be used.
1658 * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->throwing.
1661 tryFlatMatch(JSContext
*cx
, JSString
*textstr
, uintN optarg
, uintN argc
,
1662 bool checkMetaChars
= true)
1667 fm
.pat
= fm
.patstr
->chars();
1668 fm
.patlen
= fm
.patstr
->length();
1673 if (checkMetaChars
&&
1674 (fm
.patlen
> MAX_FLAT_PAT_LEN
|| RegExp::hasMetaChars(fm
.pat
, fm
.patlen
))) {
1679 * textstr could be a rope, so we want to avoid flattening it for as
1682 if (textstr
->isRope()) {
1683 if (!RopeMatch(cx
, textstr
, fm
.pat
, fm
.patlen
, &fm
.match_
))
1686 const jschar
*text
= textstr
->nonRopeChars();
1687 size_t textlen
= textstr
->length();
1688 fm
.match_
= StringMatch(text
, textlen
, fm
.pat
, fm
.patlen
);
1693 /* If the pattern is not already a regular expression, make it so. */
1695 normalizeRegExp(bool flat
, uintN optarg
, uintN argc
, Value
*vp
)
1697 /* If we don't have a RegExp, build RegExp from pattern string. */
1702 if (optarg
< argc
) {
1703 opt
= js_ValueToString(cx
, vp
[2 + optarg
]);
1712 patstr
= flattenPattern(cx
, fm
.patstr
);
1720 rep
.re_
= RegExp::createFlagged(cx
, patstr
, opt
);
1728 bool hasRegExpPair() const { return rep
.re_
; }
1732 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1733 static JS_ALWAYS_INLINE
bool
1734 Matched(bool test
, const Value
&v
)
1736 return test
? v
.isTrue() : !v
.isNull();
1739 typedef bool (*DoMatchCallback
)(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *data
);
1742 * BitOR-ing these flags allows the DoMatch caller to control when how the
1743 * RegExp engine is called and when callbacks are fired.
1745 enum MatchControlFlags
{
1746 TEST_GLOBAL_BIT
= 0x1, /* use RegExp.test for global regexps */
1747 TEST_SINGLE_BIT
= 0x2, /* use RegExp.test for non-global regexps */
1748 CALLBACK_ON_SINGLE_BIT
= 0x4, /* fire callback on non-global match */
1750 MATCH_ARGS
= TEST_GLOBAL_BIT
,
1751 MATCHALL_ARGS
= CALLBACK_ON_SINGLE_BIT
,
1752 REPLACE_ARGS
= TEST_GLOBAL_BIT
| TEST_SINGLE_BIT
| CALLBACK_ON_SINGLE_BIT
1755 /* Factor out looping and matching logic. */
1757 DoMatch(JSContext
*cx
, RegExpStatics
*res
, Value
*vp
, JSString
*str
, const RegExpPair
&rep
,
1758 DoMatchCallback callback
, void *data
, MatchControlFlags flags
)
1760 RegExp
&re
= rep
.re();
1762 /* global matching ('g') */
1763 bool testGlobal
= flags
& TEST_GLOBAL_BIT
;
1765 rep
.reobj()->zeroRegExpLastIndex();
1766 for (size_t count
= 0, i
= 0, length
= str
->length(); i
<= length
; ++count
) {
1767 if (!re
.execute(cx
, res
, str
, &i
, testGlobal
, vp
))
1769 if (!Matched(testGlobal
, *vp
))
1771 if (!callback(cx
, res
, count
, data
))
1773 if (!res
->matched())
1778 bool testSingle
= !!(flags
& TEST_SINGLE_BIT
),
1779 callbackOnSingle
= !!(flags
& CALLBACK_ON_SINGLE_BIT
);
1781 if (!re
.execute(cx
, res
, str
, &i
, testSingle
, vp
))
1783 if (callbackOnSingle
&& Matched(testSingle
, *vp
) && !callback(cx
, res
, 0, data
))
1790 BuildFlatMatchArray(JSContext
*cx
, JSString
*textstr
, const FlatMatch
&fm
, Value
*vp
)
1792 if (fm
.match() < 0) {
1797 /* For this non-global match, produce a RegExp.exec-style array. */
1798 JSObject
*obj
= NewSlowEmptyArray(cx
);
1801 vp
->setObject(*obj
);
1803 return obj
->defineProperty(cx
, INT_TO_JSID(0), StringValue(fm
.pattern())) &&
1804 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.indexAtom
),
1805 Int32Value(fm
.match())) &&
1806 obj
->defineProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.inputAtom
),
1807 StringValue(textstr
));
1810 typedef JSObject
**MatchArgType
;
1813 * DoMatch will only callback on global matches, hence this function builds
1814 * only the "array of matches" returned by match on global regexps.
1817 MatchCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
1819 JS_ASSERT(count
<= JSID_INT_MAX
); /* by max string length */
1821 JSObject
*&arrayobj
= *static_cast<MatchArgType
>(p
);
1823 arrayobj
= NewDenseEmptyArray(cx
);
1829 if (!res
->createLastMatch(cx
, &v
))
1832 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
1833 return !!arrayobj
->setProperty(cx
, INT_TO_JSID(count
), &v
, false);
1837 str_match(JSContext
*cx
, uintN argc
, Value
*vp
)
1840 NORMALIZE_THIS(cx
, vp
, str
);
1843 if (!g
.init(argc
, vp
))
1845 if (const FlatMatch
*fm
= g
.tryFlatMatch(cx
, str
, 1, argc
))
1846 return BuildFlatMatchArray(cx
, str
, *fm
, vp
);
1847 if (cx
->throwing
) /* from tryFlatMatch */
1850 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1854 AutoObjectRooter
array(cx
);
1855 MatchArgType arg
= array
.addr();
1856 RegExpStatics
*res
= cx
->regExpStatics();
1857 if (!DoMatch(cx
, res
, vp
, str
, *rep
, MatchCallback
, arg
, MATCH_ARGS
))
1860 /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1861 if (rep
->re().global())
1862 vp
->setObjectOrNull(array
.object());
1867 str_search(JSContext
*cx
, uintN argc
, Value
*vp
)
1870 NORMALIZE_THIS(cx
, vp
, str
);
1873 if (!g
.init(argc
, vp
))
1875 if (const FlatMatch
*fm
= g
.tryFlatMatch(cx
, str
, 1, argc
)) {
1876 vp
->setInt32(fm
->match());
1879 if (cx
->throwing
) /* from tryFlatMatch */
1881 const RegExpPair
*rep
= g
.normalizeRegExp(false, 1, argc
, vp
);
1885 RegExpStatics
*res
= cx
->regExpStatics();
1887 if (!rep
->re().execute(cx
, res
, str
, &i
, true, vp
))
1891 vp
->setInt32(res
->matchStart());
1899 ReplaceData(JSContext
*cx
)
1903 JSString
*str
; /* 'this' parameter object as a string */
1904 RegExpGuard g
; /* regexp parameter object and private data */
1905 JSObject
*lambda
; /* replacement function object or null */
1906 JSObject
*elembase
; /* object for function(a){return b[a]} replace */
1907 JSLinearString
*repstr
; /* replacement string */
1908 const jschar
*dollar
; /* null or pointer to first $ in repstr */
1909 const jschar
*dollarEnd
; /* limit pointer for js_strchr_limit */
1910 jsint index
; /* index in result of next replacement */
1911 jsint leftIndex
; /* left context index in str->chars */
1912 JSSubString dollarStr
; /* for "$$" InterpretDollar result */
1913 bool calledBack
; /* record whether callback has been called */
1914 InvokeSessionGuard session
; /* arguments for repeated lambda Invoke call */
1915 InvokeArgsGuard singleShot
; /* arguments for single lambda Invoke call */
1916 JSCharBuffer cb
; /* buffer built during DoMatch */
1920 InterpretDollar(JSContext
*cx
, RegExpStatics
*res
, const jschar
*dp
, const jschar
*ep
,
1921 ReplaceData
&rdata
, JSSubString
*out
, size_t *skip
)
1923 JS_ASSERT(*dp
== '$');
1925 /* If there is only a dollar, bail now */
1929 /* Interpret all Perl match-induced dollar variables. */
1931 if (JS7_ISDEC(dc
)) {
1932 /* ECMA-262 Edition 3: 1-9 or 01-99 */
1933 uintN num
= JS7_UNDEC(dc
);
1934 if (num
> res
->parenCount())
1937 const jschar
*cp
= dp
+ 2;
1938 if (cp
< ep
&& (dc
= *cp
, JS7_ISDEC(dc
))) {
1939 uintN tmp
= 10 * num
+ JS7_UNDEC(dc
);
1940 if (tmp
<= res
->parenCount()) {
1950 JS_ASSERT(num
<= res
->parenCount());
1953 * Note: we index to get the paren with the (1-indexed) pair
1954 * number, as opposed to a (0-indexed) paren number.
1956 res
->getParen(num
, out
);
1963 rdata
.dollarStr
.chars
= dp
;
1964 rdata
.dollarStr
.length
= 1;
1965 *out
= rdata
.dollarStr
;
1968 res
->getLastMatch(out
);
1971 res
->getLastParen(out
);
1974 res
->getLeftContext(out
);
1977 res
->getRightContext(out
);
1984 FindReplaceLength(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, size_t *sizep
)
1986 JSObject
*base
= rdata
.elembase
;
1989 * The base object is used when replace was passed a lambda which looks like
1990 * 'function(a) { return b[a]; }' for the base object b. b will not change
1991 * in the course of the replace unless we end up making a scripted call due
1992 * to accessing a scripted getter or a value with a scripted toString.
1994 JS_ASSERT(rdata
.lambda
);
1995 JS_ASSERT(!base
->getOps()->lookupProperty
);
1996 JS_ASSERT(!base
->getOps()->getProperty
);
1999 if (!res
->createLastMatch(cx
, &match
))
2001 JSString
*str
= match
.toString();
2004 if (str
->isAtomized()) {
2005 atom
= STRING_TO_ATOM(str
);
2007 atom
= js_AtomizeString(cx
, str
, 0);
2011 jsid id
= ATOM_TO_JSID(atom
);
2014 JSProperty
*prop
= NULL
;
2015 if (js_LookupPropertyWithFlags(cx
, base
, id
, JSRESOLVE_QUALIFIED
, &holder
, &prop
) < 0)
2018 /* Only handle the case where the property exists and is on this object. */
2019 if (prop
&& holder
== base
) {
2020 Shape
*shape
= (Shape
*) prop
;
2021 if (shape
->slot
!= SHAPE_INVALID_SLOT
&& shape
->hasDefaultGetter()) {
2022 Value value
= base
->getSlot(shape
->slot
);
2023 if (value
.isString()) {
2024 rdata
.repstr
= value
.toString()->ensureLinear(cx
);
2027 *sizep
= rdata
.repstr
->length();
2034 * Couldn't handle this property, fall through and despecialize to the
2035 * general lambda case.
2037 rdata
.elembase
= NULL
;
2040 JSObject
*lambda
= rdata
.lambda
;
2043 * In the lambda case, not only do we find the replacement string's
2044 * length, we compute repstr and return it via rdata for use within
2045 * DoReplace. The lambda is called with arguments ($&, $1, $2, ...,
2046 * index, input), i.e., all the properties of a regexp match array.
2047 * For $&, etc., we must create string jsvals from cx->regExpStatics.
2048 * We grab up stack space to keep the newborn strings GC-rooted.
2050 uintN p
= res
->parenCount();
2051 uintN argc
= 1 + p
+ 2;
2053 InvokeSessionGuard
&session
= rdata
.session
;
2054 if (!session
.started()) {
2055 Value lambdav
= ObjectValue(*lambda
);
2056 if (!session
.start(cx
, lambdav
, UndefinedValue(), argc
))
2060 PreserveRegExpStatics
staticsGuard(res
);
2061 if (!staticsGuard
.init(cx
))
2064 /* Push $&, $1, $2, ... */
2066 if (!res
->createLastMatch(cx
, &session
[argi
++]))
2069 for (size_t i
= 0; i
< res
->parenCount(); ++i
) {
2070 if (!res
->createParen(cx
, i
+ 1, &session
[argi
++]))
2074 /* Push match index and input string. */
2075 session
[argi
++].setInt32(res
->matchStart());
2076 session
[argi
].setString(rdata
.str
);
2078 if (!session
.invoke(cx
))
2081 /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2082 JSString
*repstr
= ValueToString_TestForStringInline(cx
, session
.rval());
2085 rdata
.repstr
= repstr
->ensureLinear(cx
);
2088 *sizep
= rdata
.repstr
->length();
2092 JSString
*repstr
= rdata
.repstr
;
2093 size_t replen
= repstr
->length();
2094 for (const jschar
*dp
= rdata
.dollar
, *ep
= rdata
.dollarEnd
; dp
;
2095 dp
= js_strchr_limit(dp
, '$', ep
)) {
2098 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2099 replen
+= sub
.length
- skip
;
2110 DoReplace(JSContext
*cx
, RegExpStatics
*res
, ReplaceData
&rdata
, jschar
*chars
)
2112 JSLinearString
*repstr
= rdata
.repstr
;
2114 const jschar
*bp
= cp
= repstr
->chars();
2116 const jschar
*dp
= rdata
.dollar
;
2117 const jschar
*ep
= rdata
.dollarEnd
;
2118 for (; dp
; dp
= js_strchr_limit(dp
, '$', ep
)) {
2119 size_t len
= dp
- cp
;
2120 js_strncpy(chars
, cp
, len
);
2126 if (InterpretDollar(cx
, res
, dp
, ep
, rdata
, &sub
, &skip
)) {
2128 js_strncpy(chars
, sub
.chars
, len
);
2136 js_strncpy(chars
, cp
, repstr
->length() - (cp
- bp
));
2140 ReplaceRegExpCallback(JSContext
*cx
, RegExpStatics
*res
, size_t count
, void *p
)
2142 ReplaceData
&rdata
= *static_cast<ReplaceData
*>(p
);
2144 rdata
.calledBack
= true;
2145 JSLinearString
*str
= rdata
.str
->assertIsLinear(); /* flattened for regexp */
2146 size_t leftoff
= rdata
.leftIndex
;
2147 const jschar
*left
= str
->chars() + leftoff
;
2148 size_t leftlen
= res
->matchStart() - leftoff
;
2149 rdata
.leftIndex
= res
->matchLimit();
2151 size_t replen
= 0; /* silence 'unused' warning */
2152 if (!FindReplaceLength(cx
, res
, rdata
, &replen
))
2155 size_t growth
= leftlen
+ replen
;
2156 if (!rdata
.cb
.growByUninitialized(growth
))
2159 jschar
*chars
= rdata
.cb
.begin() + rdata
.index
;
2160 rdata
.index
+= growth
;
2161 js_strncpy(chars
, left
, leftlen
);
2163 DoReplace(cx
, res
, rdata
, chars
);
2168 BuildFlatReplacement(JSContext
*cx
, JSString
*textstr
, JSString
*repstr
,
2169 const FlatMatch
&fm
, Value
*vp
)
2171 RopeBuilder
builder(cx
);
2172 size_t match
= fm
.match();
2173 size_t matchEnd
= match
+ fm
.patternLength();
2175 if (textstr
->isRope()) {
2177 * If we are replacing over a rope, avoid flattening it by iterating
2178 * through it, building a new rope.
2180 StringSegmentRange
r(cx
);
2181 if (!r
.init(textstr
))
2184 while (!r
.empty()) {
2185 JSString
*str
= r
.front();
2186 size_t len
= str
->length();
2187 size_t strEnd
= pos
+ len
;
2188 if (pos
< matchEnd
&& strEnd
> match
) {
2190 * We need to special-case any part of the rope that overlaps
2191 * with the replacement string.
2195 * If this part of the rope overlaps with the left side of
2196 * the pattern, then it must be the only one to overlap with
2197 * the first character in the pattern, so we include the
2198 * replacement string here.
2200 JSString
*leftSide
= js_NewDependentString(cx
, str
, 0, match
- pos
);
2202 !builder
.append(leftSide
) ||
2203 !builder
.append(repstr
)) {
2209 * If str runs off the end of the matched string, append the
2212 if (strEnd
> matchEnd
) {
2213 JSString
*rightSide
= js_NewDependentString(cx
, str
, matchEnd
- pos
,
2215 if (!rightSide
|| !builder
.append(rightSide
))
2219 if (!builder
.append(str
))
2222 pos
+= str
->length();
2227 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, match
);
2230 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, match
+ fm
.patternLength(),
2231 textstr
->length() - match
- fm
.patternLength());
2233 !builder
.append(leftSide
) ||
2234 !builder
.append(repstr
) ||
2235 !builder
.append(rightSide
)) {
2240 vp
->setString(builder
.result());
2245 * Perform a linear-scan dollar substitution on the replacement text,
2246 * constructing a result string that looks like:
2248 * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2251 BuildDollarReplacement(JSContext
*cx
, JSString
*textstrArg
, JSLinearString
*repstr
,
2252 const jschar
*firstDollar
, const FlatMatch
&fm
, Value
*vp
)
2254 JSLinearString
*textstr
= textstrArg
->ensureLinear(cx
);
2258 JS_ASSERT(repstr
->chars() <= firstDollar
&& firstDollar
< repstr
->chars() + repstr
->length());
2259 size_t matchStart
= fm
.match();
2260 size_t matchLimit
= matchStart
+ fm
.patternLength();
2265 * len(newstr) >= len(orig) - len(match) + len(replacement)
2267 * Note that dollar vars _could_ make the resulting text smaller than this.
2269 JSCharBuffer
newReplaceChars(cx
);
2270 if (!newReplaceChars
.reserve(textstr
->length() - fm
.patternLength() + repstr
->length()))
2273 /* Move the pre-dollar chunk in bulk. */
2274 JS_ALWAYS_TRUE(newReplaceChars
.append(repstr
->chars(), firstDollar
));
2276 /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2277 #define ENSURE(__cond) if (!(__cond)) return false;
2278 const jschar
*repstrLimit
= repstr
->chars() + repstr
->length();
2279 for (const jschar
*it
= firstDollar
; it
< repstrLimit
; ++it
) {
2280 if (*it
!= '$' || it
== repstrLimit
- 1) {
2281 ENSURE(newReplaceChars
.append(*it
));
2285 switch (*(it
+ 1)) {
2286 case '$': /* Eat one of the dollars. */
2287 ENSURE(newReplaceChars
.append(*it
));
2290 ENSURE(newReplaceChars
.append(textstr
->chars() + matchStart
,
2291 textstr
->chars() + matchLimit
));
2294 ENSURE(newReplaceChars
.append(textstr
->chars(), textstr
->chars() + matchStart
));
2297 ENSURE(newReplaceChars
.append(textstr
->chars() + matchLimit
,
2298 textstr
->chars() + textstr
->length()));
2300 default: /* The dollar we saw was not special (no matter what its mother told it). */
2301 ENSURE(newReplaceChars
.append(*it
));
2304 ++it
; /* We always eat an extra char in the above switch. */
2307 JSString
*leftSide
= js_NewDependentString(cx
, textstr
, 0, matchStart
);
2310 JSString
*newReplace
= js_NewStringFromCharBuffer(cx
, newReplaceChars
);
2313 JS_ASSERT(textstr
->length() >= matchLimit
);
2314 JSString
*rightSide
= js_NewDependentString(cx
, textstr
, matchLimit
,
2315 textstr
->length() - matchLimit
);
2318 RopeBuilder
builder(cx
);
2319 ENSURE(builder
.append(leftSide
) &&
2320 builder
.append(newReplace
) &&
2321 builder
.append(rightSide
));
2324 vp
->setString(builder
.result());
2329 str_replace_regexp(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
)
2331 const RegExpPair
*rep
= rdata
.g
.normalizeRegExp(true, 2, argc
, vp
);
2336 rdata
.leftIndex
= 0;
2337 rdata
.calledBack
= false;
2339 RegExpStatics
*res
= cx
->regExpStatics();
2340 if (!DoMatch(cx
, res
, vp
, rdata
.str
, *rep
, ReplaceRegExpCallback
, &rdata
, REPLACE_ARGS
))
2343 if (!rdata
.calledBack
) {
2344 /* Didn't match, so the string is unmodified. */
2345 vp
->setString(rdata
.str
);
2350 res
->getRightContext(&sub
);
2351 if (!rdata
.cb
.append(sub
.chars
, sub
.length
))
2354 JSString
*retstr
= js_NewStringFromCharBuffer(cx
, rdata
.cb
);
2358 vp
->setString(retstr
);
2363 str_replace_flat_lambda(JSContext
*cx
, uintN argc
, Value
*vp
, ReplaceData
&rdata
,
2364 const FlatMatch
&fm
)
2366 JS_ASSERT(fm
.match() >= 0);
2369 JSString
*matchStr
= js_NewDependentString(cx
, rdata
.str
, fm
.match(), fm
.patternLength());
2373 /* lambda(matchStr, matchStart, textstr) */
2374 static const uint32 lambdaArgc
= 3;
2375 if (!cx
->stack().pushInvokeArgs(cx
, lambdaArgc
, &rdata
.singleShot
))
2378 CallArgs
&args
= rdata
.singleShot
;
2379 args
.callee().setObject(*rdata
.lambda
);
2380 args
.thisv().setUndefined();
2382 Value
*sp
= args
.argv();
2383 sp
[0].setString(matchStr
);
2384 sp
[1].setInt32(fm
.match());
2385 sp
[2].setString(rdata
.str
);
2387 if (!Invoke(cx
, rdata
.singleShot
, 0))
2390 JSString
*repstr
= js_ValueToString(cx
, args
.rval());
2394 JSString
*leftSide
= js_NewDependentString(cx
, rdata
.str
, 0, fm
.match());
2398 size_t matchLimit
= fm
.match() + fm
.patternLength();
2399 JSString
*rightSide
= js_NewDependentString(cx
, rdata
.str
, matchLimit
,
2400 rdata
.str
->length() - matchLimit
);
2404 RopeBuilder
builder(cx
);
2405 if (!(builder
.append(leftSide
) &&
2406 builder
.append(repstr
) &&
2407 builder
.append(rightSide
))) {
2411 vp
->setString(builder
.result());
2416 js::str_replace(JSContext
*cx
, uintN argc
, Value
*vp
)
2418 ReplaceData
rdata(cx
);
2419 NORMALIZE_THIS(cx
, vp
, rdata
.str
);
2420 static const uint32 optarg
= 2;
2422 /* Extract replacement string/function. */
2423 if (argc
>= optarg
&& js_IsCallable(vp
[3])) {
2424 rdata
.lambda
= &vp
[3].toObject();
2425 rdata
.elembase
= NULL
;
2426 rdata
.repstr
= NULL
;
2427 rdata
.dollar
= rdata
.dollarEnd
= NULL
;
2429 if (rdata
.lambda
->isFunction()) {
2430 JSFunction
*fun
= rdata
.lambda
->getFunctionPrivate();
2431 if (fun
->isInterpreted()) {
2433 * Pattern match the script to check if it is is indexing into a
2434 * particular object, e.g. 'function(a) { return b[a]; }'. Avoid
2435 * calling the script in such cases, which are used by javascript
2436 * packers (particularly the popular Dean Edwards packer) to efficiently
2437 * encode large scripts. We only handle the code patterns generated
2438 * by such packers here.
2440 JSScript
*script
= fun
->u
.i
.script
;
2441 jsbytecode
*pc
= script
->code
;
2443 Value table
= UndefinedValue();
2444 if (JSOp(*pc
) == JSOP_GETFCSLOT
) {
2445 table
= rdata
.lambda
->getFlatClosureUpvar(GET_UINT16(pc
));
2446 pc
+= JSOP_GETFCSLOT_LENGTH
;
2449 if (table
.isObject() &&
2450 JSOp(*pc
) == JSOP_GETARG
&& GET_SLOTNO(pc
) == 0 &&
2451 JSOp(*(pc
+ JSOP_GETARG_LENGTH
)) == JSOP_GETELEM
&&
2452 JSOp(*(pc
+ JSOP_GETARG_LENGTH
+ JSOP_GETELEM_LENGTH
)) == JSOP_RETURN
) {
2453 Class
*clasp
= table
.toObject().getClass();
2454 if (clasp
->isNative() &&
2455 !clasp
->ops
.lookupProperty
&&
2456 !clasp
->ops
.getProperty
) {
2457 rdata
.elembase
= &table
.toObject();
2463 rdata
.lambda
= NULL
;
2464 rdata
.elembase
= NULL
;
2465 rdata
.repstr
= ArgToRootedString(cx
, argc
, vp
, 1);
2469 /* We're about to store pointers into the middle of our string. */
2470 if (!js_MakeStringImmutable(cx
, rdata
.repstr
))
2472 rdata
.dollarEnd
= rdata
.repstr
->chars() + rdata
.repstr
->length();
2473 rdata
.dollar
= js_strchr_limit(rdata
.repstr
->chars(), '$',
2477 if (!rdata
.g
.init(argc
, vp
))
2481 * Unlike its |String.prototype| brethren, |replace| doesn't convert
2482 * its input to a regular expression. (Even if it contains metachars.)
2484 * However, if the user invokes our (non-standard) |flags| argument
2485 * extension then we revert to creating a regular expression. Note that
2486 * this is observable behavior through the side-effect mutation of the
2490 const FlatMatch
*fm
= rdata
.g
.tryFlatMatch(cx
, rdata
.str
, optarg
, argc
, false);
2492 if (cx
->throwing
) /* oom in RopeMatch in tryFlatMatch */
2494 JS_ASSERT_IF(!rdata
.g
.hasRegExpPair(), argc
> optarg
);
2495 return str_replace_regexp(cx
, argc
, vp
, rdata
);
2498 if (fm
->match() < 0) {
2499 vp
->setString(rdata
.str
);
2504 return str_replace_flat_lambda(cx
, argc
, vp
, rdata
, *fm
);
2507 * Note: we could optimize the text.length == pattern.length case if we wanted,
2508 * even in the presence of dollar metachars.
2511 return BuildDollarReplacement(cx
, rdata
.str
, rdata
.repstr
, rdata
.dollar
, *fm
, vp
);
2513 return BuildFlatReplacement(cx
, rdata
.str
, rdata
.repstr
, *fm
, vp
);
2517 * Subroutine used by str_split to find the next split point in str, starting
2518 * at offset *ip and looking either for the separator substring given by sep, or
2519 * for the next re match. In the re case, return the matched separator in *sep,
2520 * and the possibly updated offset in *ip.
2522 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2523 * separator occurrence if found, or str->length if no separator is found.
2526 find_split(JSContext
*cx
, RegExpStatics
*res
, JSString
*str
, js::RegExp
*re
, jsint
*ip
,
2530 * Stop if past end of string. If at end of string, we will compare the
2531 * null char stored there (by js_NewString*) to sep->chars[j] in the while
2532 * loop at the end of this function, so that
2534 * "ab,".split(',') => ["ab", ""]
2536 * and the resulting array converts back to the string "ab," for symmetry.
2537 * However, we ape Perl and do this only if there is a sufficiently large
2538 * limit argument (see str_split).
2541 size_t length
= str
->length();
2542 if ((size_t)i
> length
)
2545 const jschar
*chars
= str
->getChars(cx
);
2550 * Match a regular expression against the separator at or above index i.
2551 * Call js_ExecuteRegExp with true for the test argument. On successful
2552 * match, get the separator from cx->regExpStatics.lastMatch.
2559 /* JS1.2 deviated from Perl by never matching at end of string. */
2561 if (!re
->execute(cx
, res
, str
, &index
, true, &rval
))
2563 if (!rval
.isTrue()) {
2564 /* Mismatch: ensure our caller advances i past end of string. */
2570 res
->getLastMatch(sep
);
2571 if (sep
->length
== 0) {
2573 * Empty string match: never split on an empty match at the start
2574 * of a find_split cycle. Same rule as for an empty global match
2579 * "Bump-along" to avoid sticking at an empty match, but don't
2580 * bump past end of string -- our caller must do that by adding
2581 * sep->length to our return value.
2583 if ((size_t)i
== length
)
2588 if ((size_t)i
== length
) {
2590 * If there was a trivial zero-length match at the end of the
2591 * split, then we shouldn't output the matched string at the end
2592 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2597 JS_ASSERT((size_t)i
>= sep
->length
);
2598 return i
- sep
->length
;
2602 * Special case: if sep is the empty string, split str into one character
2603 * substrings. Let our caller worry about whether to split once at end of
2604 * string into an empty substring.
2606 if (sep
->length
== 0)
2607 return ((size_t)i
== length
) ? -1 : i
+ 1;
2610 * Now that we know sep is non-empty, search starting at i in str for an
2611 * occurrence of all of sep's chars. If we find them, return the index of
2612 * the first separator char. Otherwise, return length.
2614 jsint match
= StringMatch(chars
+ i
, length
- i
, sep
->chars
, sep
->length
);
2615 return match
== -1 ? length
: match
+ i
;
2619 str_split(JSContext
*cx
, uintN argc
, Value
*vp
)
2622 NORMALIZE_THIS(cx
, vp
, str
);
2625 Value v
= StringValue(str
);
2626 JSObject
*aobj
= NewDenseCopiedArray(cx
, 1, &v
);
2629 vp
->setObject(*aobj
);
2634 JSSubString
*sep
, tmp
;
2635 if (VALUE_IS_REGEXP(cx
, vp
[2])) {
2636 re
= static_cast<RegExp
*>(vp
[2].toObject().getPrivate());
2639 /* Set a magic value so we can detect a successful re match. */
2643 JSString
*sepstr
= js_ValueToString(cx
, vp
[2]);
2646 vp
[2].setString(sepstr
);
2649 * Point sep at a local copy of sepstr's header because find_split
2650 * will modify sep->length.
2652 tmp
.length
= sepstr
->length();
2653 tmp
.chars
= sepstr
->getChars(cx
);
2660 /* Use the second argument as the split limit, if given. */
2661 uint32 limit
= 0; /* Avoid warning. */
2662 bool limited
= (argc
> 1) && !vp
[3].isUndefined();
2665 if (!ValueToNumber(cx
, vp
[3], &d
))
2668 /* Clamp limit between 0 and 1 + string length. */
2669 limit
= js_DoubleToECMAUint32(d
);
2670 if (limit
> str
->length())
2671 limit
= 1 + str
->length();
2674 AutoValueVector
splits(cx
);
2676 RegExpStatics
*res
= cx
->regExpStatics();
2679 while ((j
= find_split(cx
, res
, str
, re
, &i
, sep
)) >= 0) {
2680 if (limited
&& len
>= limit
)
2683 JSString
*sub
= js_NewDependentString(cx
, str
, i
, size_t(j
- i
));
2684 if (!sub
|| !splits
.append(StringValue(sub
)))
2689 * Imitate perl's feature of including parenthesized substrings that
2690 * matched part of the delimiter in the new array, after the split
2691 * substring that was delimited.
2693 if (re
&& sep
->chars
) {
2694 for (uintN num
= 0; num
< res
->parenCount(); num
++) {
2695 if (limited
&& len
>= limit
)
2698 res
->getParen(num
+ 1, &parsub
);
2699 sub
= js_NewStringCopyN(cx
, parsub
.chars
, parsub
.length
);
2700 if (!sub
|| !splits
.append(StringValue(sub
)))
2706 i
= j
+ sep
->length
;
2712 JSObject
*aobj
= NewDenseCopiedArray(cx
, splits
.length(), splits
.begin());
2715 vp
->setObject(*aobj
);
2719 #if JS_HAS_PERL_SUBSTR
2721 str_substr(JSContext
*cx
, uintN argc
, Value
*vp
)
2724 int32 length
, len
, begin
;
2726 NORMALIZE_THIS(cx
, vp
, str
);
2729 length
= int32(str
->length());
2730 if (!ValueToIntegerRange(cx
, vp
[2], &begin
))
2733 if (begin
>= length
) {
2734 str
= cx
->runtime
->emptyString
;
2738 begin
+= length
; /* length + INT_MIN will always be less then 0 */
2743 if (argc
== 1 || vp
[3].isUndefined()) {
2744 len
= length
- begin
;
2746 if (!ValueToIntegerRange(cx
, vp
[3], &len
))
2750 str
= cx
->runtime
->emptyString
;
2754 if (uint32(length
) < uint32(begin
+ len
))
2755 len
= length
- begin
;
2758 str
= js_NewDependentString(cx
, str
, size_t(begin
), size_t(len
));
2767 #endif /* JS_HAS_PERL_SUBSTR */
2770 * Python-esque sequence operations.
2773 str_concat(JSContext
*cx
, uintN argc
, Value
*vp
)
2775 JSString
*str
, *str2
;
2779 NORMALIZE_THIS(cx
, vp
, str
);
2781 /* Set vp (aka rval) early to handle the argc == 0 case. */
2784 for (i
= 0, argv
= vp
+ 2; i
< argc
; i
++) {
2785 str2
= js_ValueToString(cx
, argv
[i
]);
2788 argv
[i
].setString(str2
);
2790 str
= js_ConcatStrings(cx
, str
, str2
);
2800 str_slice(JSContext
*cx
, uintN argc
, Value
*vp
)
2802 if (argc
== 1 && vp
[1].isString() && vp
[2].isInt32()) {
2803 size_t begin
, end
, length
;
2805 JSString
*str
= vp
[1].toString();
2806 begin
= vp
[2].toInt32();
2807 end
= str
->length();
2809 length
= end
- begin
;
2811 str
= cx
->runtime
->emptyString
;
2814 ? JSString::getUnitString(cx
, str
, begin
)
2815 : js_NewDependentString(cx
, str
, begin
, length
);
2825 NORMALIZE_THIS(cx
, vp
, str
);
2828 double begin
, end
, length
;
2830 if (!ValueToNumber(cx
, vp
[2], &begin
))
2832 begin
= js_DoubleToInteger(begin
);
2833 length
= str
->length();
2838 } else if (begin
> length
) {
2842 if (argc
== 1 || vp
[3].isUndefined()) {
2845 if (!ValueToNumber(cx
, vp
[3], &end
))
2847 end
= js_DoubleToInteger(end
);
2852 } else if (end
> length
) {
2859 str
= js_NewDependentString(cx
, str
,
2861 (size_t)(end
- begin
));
2869 #if JS_HAS_STR_HTML_HELPERS
2871 * HTML composition aids.
2874 tagify(JSContext
*cx
, const char *begin
, JSLinearString
*param
, const char *end
,
2878 NORMALIZE_THIS(cx
, vp
, thisstr
);
2879 JSLinearString
*str
= thisstr
->ensureLinear(cx
);
2886 size_t beglen
= strlen(begin
);
2887 size_t taglen
= 1 + beglen
+ 1; /* '<begin' + '>' */
2888 size_t parlen
= 0; /* Avoid warning. */
2890 parlen
= param
->length();
2891 taglen
+= 2 + parlen
+ 1; /* '="param"' */
2893 size_t endlen
= strlen(end
);
2894 taglen
+= str
->length() + 2 + endlen
+ 1; /* 'str</end>' */
2896 if (taglen
>= ~(size_t)0 / sizeof(jschar
)) {
2897 js_ReportAllocationOverflow(cx
);
2901 jschar
*tagbuf
= (jschar
*) cx
->malloc((taglen
+ 1) * sizeof(jschar
));
2907 for (size_t i
= 0; i
< beglen
; i
++)
2908 tagbuf
[j
++] = (jschar
)begin
[i
];
2912 js_strncpy(&tagbuf
[j
], param
->chars(), parlen
);
2918 js_strncpy(&tagbuf
[j
], str
->chars(), str
->length());
2922 for (size_t i
= 0; i
< endlen
; i
++)
2923 tagbuf
[j
++] = (jschar
)end
[i
];
2925 JS_ASSERT(j
== taglen
);
2928 JSString
*retstr
= js_NewString(cx
, tagbuf
, taglen
);
2930 js_free((char *)tagbuf
);
2933 vp
->setString(retstr
);
2938 tagify_value(JSContext
*cx
, uintN argc
, Value
*vp
,
2939 const char *begin
, const char *end
)
2941 JSLinearString
*param
= ArgToRootedString(cx
, argc
, vp
, 0);
2944 return tagify(cx
, begin
, param
, end
, vp
);
2948 str_bold(JSContext
*cx
, uintN argc
, Value
*vp
)
2950 return tagify(cx
, "b", NULL
, NULL
, vp
);
2954 str_italics(JSContext
*cx
, uintN argc
, Value
*vp
)
2956 return tagify(cx
, "i", NULL
, NULL
, vp
);
2960 str_fixed(JSContext
*cx
, uintN argc
, Value
*vp
)
2962 return tagify(cx
, "tt", NULL
, NULL
, vp
);
2966 str_fontsize(JSContext
*cx
, uintN argc
, Value
*vp
)
2968 return tagify_value(cx
, argc
, vp
, "font size", "font");
2972 str_fontcolor(JSContext
*cx
, uintN argc
, Value
*vp
)
2974 return tagify_value(cx
, argc
, vp
, "font color", "font");
2978 str_link(JSContext
*cx
, uintN argc
, Value
*vp
)
2980 return tagify_value(cx
, argc
, vp
, "a href", "a");
2984 str_anchor(JSContext
*cx
, uintN argc
, Value
*vp
)
2986 return tagify_value(cx
, argc
, vp
, "a name", "a");
2990 str_strike(JSContext
*cx
, uintN argc
, Value
*vp
)
2992 return tagify(cx
, "strike", NULL
, NULL
, vp
);
2996 str_small(JSContext
*cx
, uintN argc
, Value
*vp
)
2998 return tagify(cx
, "small", NULL
, NULL
, vp
);
3002 str_big(JSContext
*cx
, uintN argc
, Value
*vp
)
3004 return tagify(cx
, "big", NULL
, NULL
, vp
);
3008 str_blink(JSContext
*cx
, uintN argc
, Value
*vp
)
3010 return tagify(cx
, "blink", NULL
, NULL
, vp
);
3014 str_sup(JSContext
*cx
, uintN argc
, Value
*vp
)
3016 return tagify(cx
, "sup", NULL
, NULL
, vp
);
3020 str_sub(JSContext
*cx
, uintN argc
, Value
*vp
)
3022 return tagify(cx
, "sub", NULL
, NULL
, vp
);
3024 #endif /* JS_HAS_STR_HTML_HELPERS */
3028 js_String_getelem(JSContext
* cx
, JSString
* str
, int32 i
)
3030 if ((size_t)i
>= str
->length())
3032 return JSString::getUnitString(cx
, str
, size_t(i
));
3036 JS_DEFINE_TRCINFO_1(str_concat
,
3037 (3, (extern, STRING_RETRY
, js_ConcatStrings
, CONTEXT
, THIS_STRING
, STRING
,
3038 1, nanojit::ACCSET_NONE
)))
3040 static JSFunctionSpec string_methods
[] = {
3042 JS_FN("quote", str_quote
, 0,JSFUN_GENERIC_NATIVE
),
3043 JS_FN(js_toSource_str
, str_toSource
, 0,0),
3046 /* Java-like methods. */
3047 JS_FN(js_toString_str
, js_str_toString
, 0,0),
3048 JS_FN(js_valueOf_str
, js_str_toString
, 0,0),
3049 JS_FN(js_toJSON_str
, js_str_toString
, 0,0),
3050 JS_FN("substring", str_substring
, 2,JSFUN_GENERIC_NATIVE
),
3051 JS_FN("toLowerCase", str_toLowerCase
, 0,JSFUN_GENERIC_NATIVE
),
3052 JS_FN("toUpperCase", str_toUpperCase
, 0,JSFUN_GENERIC_NATIVE
),
3053 JS_FN("charAt", js_str_charAt
, 1,JSFUN_GENERIC_NATIVE
),
3054 JS_FN("charCodeAt", js_str_charCodeAt
, 1,JSFUN_GENERIC_NATIVE
),
3055 JS_FN("indexOf", str_indexOf
, 1,JSFUN_GENERIC_NATIVE
),
3056 JS_FN("lastIndexOf", str_lastIndexOf
, 1,JSFUN_GENERIC_NATIVE
),
3057 JS_FN("trim", str_trim
, 0,JSFUN_GENERIC_NATIVE
),
3058 JS_FN("trimLeft", str_trimLeft
, 0,JSFUN_GENERIC_NATIVE
),
3059 JS_FN("trimRight", str_trimRight
, 0,JSFUN_GENERIC_NATIVE
),
3060 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase
, 0,JSFUN_GENERIC_NATIVE
),
3061 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase
, 0,JSFUN_GENERIC_NATIVE
),
3062 JS_FN("localeCompare", str_localeCompare
, 1,JSFUN_GENERIC_NATIVE
),
3064 /* Perl-ish methods (search is actually Python-esque). */
3065 JS_FN("match", str_match
, 1,JSFUN_GENERIC_NATIVE
),
3066 JS_FN("search", str_search
, 1,JSFUN_GENERIC_NATIVE
),
3067 JS_FN("replace", str_replace
, 2,JSFUN_GENERIC_NATIVE
),
3068 JS_FN("split", str_split
, 2,JSFUN_GENERIC_NATIVE
),
3069 #if JS_HAS_PERL_SUBSTR
3070 JS_FN("substr", str_substr
, 2,JSFUN_GENERIC_NATIVE
),
3073 /* Python-esque sequence methods. */
3074 JS_TN("concat", str_concat
, 1,JSFUN_GENERIC_NATIVE
, &str_concat_trcinfo
),
3075 JS_FN("slice", str_slice
, 2,JSFUN_GENERIC_NATIVE
),
3077 /* HTML string methods. */
3078 #if JS_HAS_STR_HTML_HELPERS
3079 JS_FN("bold", str_bold
, 0,0),
3080 JS_FN("italics", str_italics
, 0,0),
3081 JS_FN("fixed", str_fixed
, 0,0),
3082 JS_FN("fontsize", str_fontsize
, 1,0),
3083 JS_FN("fontcolor", str_fontcolor
, 1,0),
3084 JS_FN("link", str_link
, 1,0),
3085 JS_FN("anchor", str_anchor
, 1,0),
3086 JS_FN("strike", str_strike
, 0,0),
3087 JS_FN("small", str_small
, 0,0),
3088 JS_FN("big", str_big
, 0,0),
3089 JS_FN("blink", str_blink
, 0,0),
3090 JS_FN("sup", str_sup
, 0,0),
3091 JS_FN("sub", str_sub
, 0,0),
3098 * Set up some tools to make it easier to generate large tables. After constant
3099 * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3100 * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3101 * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3104 #define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
3105 #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
3106 #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
3107 #define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
3108 #define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
3109 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3111 #define R3(n) R2(n), R2((n) + (1 << 2))
3112 #define R7(n) R6(n), R6((n) + (1 << 6))
3114 #define BUILD_LENGTH_AND_FLAGS(length, flags) \
3115 (((length) << JSString::LENGTH_SHIFT) | (flags))
3118 * Declare unit strings. Pack the string data itself into the mInlineChars
3119 * place in the header.
3122 BUILD_LENGTH_AND_FLAGS(1, JSString::FLAT | JSString::ATOMIZED), \
3123 { (jschar *)(((char *)(unitStringTable + (c))) + \
3124 offsetof(JSString, inlineStorage)) }, \
3130 #pragma pack(push, 8)
3133 const JSString
JSString::unitStringTable
[]
3135 __attribute__ ((aligned (8)))
3148 * Declare length-2 strings. We only store strings where both characters are
3149 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3150 * the lowercase letters, and the next 26 are the uppercase letters.
3152 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
3153 (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
3154 (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
3155 JSString::INVALID_SMALL_CHAR)
3157 #define R TO_SMALL_CHAR
3159 const JSString::SmallChar
JSString::toSmallChar
[] = { R7(0) };
3164 * This is used when we generate our table of short strings, so the compiler is
3165 * happier if we use |c| as few times as possible.
3167 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
3168 (c) < 36 ? 'a' - 10 : \
3170 #define R FROM_SMALL_CHAR
3172 const jschar
JSString::fromSmallChar
[] = { R6(0) };
3177 * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3178 * where the upper 6 bits is the first character and the lower 6 bits is the
3182 BUILD_LENGTH_AND_FLAGS(2, JSString::FLAT | JSString::ATOMIZED), \
3183 { (jschar *)(((char *)(length2StringTable + (c))) + \
3184 offsetof(JSString, inlineStorage)) }, \
3185 { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3190 #pragma pack(push, 8)
3193 const JSString
JSString::length2StringTable
[]
3195 __attribute__ ((aligned (8)))
3208 * Declare int strings. Only int strings from 100 to 255 actually have to be
3209 * generated, since the rest are either unit strings or length-2 strings. To
3210 * avoid the runtime cost of figuring out where to look for the string for a
3211 * particular integer, we precompute a table of JSString*s which refer to the
3212 * correct location of the int string.
3215 BUILD_LENGTH_AND_FLAGS(3, JSString::FLAT | JSString::ATOMIZED), \
3216 { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \
3217 offsetof(JSString, inlineStorage)) }, \
3218 { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3221 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3226 #pragma pack(push, 8)
3229 const JSString
JSString::hundredStringTable
[]
3231 __attribute__ ((aligned (8)))
3233 = { R7(100), /* 100 through 227 */
3234 R4(100 + (1 << 7)), /* 228 through 243 */
3235 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3236 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3241 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \
3242 (c) < 100 ? JSString::length2StringTable + \
3243 ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
3244 TO_SMALL_CHAR(((c) % 10) + '0') : \
3245 JSString::hundredStringTable + ((c) - 100))
3247 const JSString
*const JSString::intStringTable
[] = { R8(0) };
3268 js_String(JSContext
*cx
, uintN argc
, Value
*vp
)
3270 Value
*argv
= vp
+ 2;
3274 str
= js_ValueToString(cx
, argv
[0]);
3278 str
= cx
->runtime
->emptyString
;
3281 if (IsConstructing(vp
)) {
3282 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_StringClass
);
3285 obj
->setPrimitiveThis(StringValue(str
));
3286 vp
->setObject(*obj
);
3294 str_fromCharCode(JSContext
*cx
, uintN argc
, Value
*vp
)
3302 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
3305 if (!ValueToUint16(cx
, argv
[0], &code
))
3307 if (code
< UNIT_STRING_LIMIT
) {
3308 str
= JSString::unitString(code
);
3314 argv
[0].setInt32(code
);
3316 chars
= (jschar
*) cx
->malloc((argc
+ 1) * sizeof(jschar
));
3319 for (i
= 0; i
< argc
; i
++) {
3321 if (!ValueToUint16(cx
, argv
[i
], &code
)) {
3325 chars
[i
] = (jschar
)code
;
3328 str
= js_NewString(cx
, chars
, argc
);
3338 static JSString
* FASTCALL
3339 String_fromCharCode(JSContext
* cx
, int32 i
)
3341 JS_ASSERT(JS_ON_TRACE(cx
));
3342 jschar c
= (jschar
)i
;
3343 if (c
< UNIT_STRING_LIMIT
)
3344 return JSString::unitString(c
);
3345 return js_NewStringCopyN(cx
, &c
, 1);
3349 JS_DEFINE_TRCINFO_1(str_fromCharCode
,
3350 (2, (static, STRING_RETRY
, String_fromCharCode
, CONTEXT
, INT32
, 1, nanojit::ACCSET_NONE
)))
3352 static JSFunctionSpec string_static_methods
[] = {
3353 JS_TN("fromCharCode", str_fromCharCode
, 1, 0, &str_fromCharCode_trcinfo
),
3358 js_InitStringClass(JSContext
*cx
, JSObject
*obj
)
3362 /* Define the escape, unescape functions in the global object. */
3363 if (!JS_DefineFunctions(cx
, obj
, string_functions
))
3366 proto
= js_InitClass(cx
, obj
, NULL
, &js_StringClass
, js_String
, 1,
3367 NULL
, string_methods
,
3368 NULL
, string_static_methods
);
3371 proto
->setPrimitiveThis(StringValue(cx
->runtime
->emptyString
));
3372 if (!js_DefineNativeProperty(cx
, proto
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
3373 UndefinedValue(), NULL
, NULL
,
3374 JSPROP_READONLY
| JSPROP_PERMANENT
| JSPROP_SHARED
, 0, 0,
3383 js_NewString(JSContext
*cx
, jschar
*chars
, size_t length
)
3387 if (length
> JSString::MAX_LENGTH
) {
3388 if (JS_ON_TRACE(cx
)) {
3390 * If we can't leave the trace, signal OOM condition, otherwise
3391 * exit from trace before throwing.
3393 if (!CanLeaveTrace(cx
))
3398 js_ReportAllocationOverflow(cx
);
3402 str
= js_NewGCString(cx
);
3405 str
->initFlat(chars
, length
);
3408 JSRuntime
*rt
= cx
->runtime
;
3409 JS_RUNTIME_METER(rt
, liveStrings
);
3410 JS_RUNTIME_METER(rt
, totalStrings
);
3411 JS_LOCK_RUNTIME_VOID(rt
,
3412 (rt
->lengthSum
+= (double)length
,
3413 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3416 return str
->assertIsFlat();
3419 static JS_ALWAYS_INLINE JSFlatString
*
3420 NewShortString(JSContext
*cx
, const jschar
*chars
, size_t length
)
3422 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3423 JSShortString
*str
= js_NewGCShortString(cx
);
3426 jschar
*storage
= str
->init(length
);
3427 js_short_strncpy(storage
, chars
, length
);
3428 storage
[length
] = 0;
3429 return str
->header()->assertIsFlat();
3432 static JSFlatString
*
3433 NewShortString(JSContext
*cx
, const char *chars
, size_t length
)
3435 JS_ASSERT(JSShortString::fitsIntoShortString(length
));
3436 JSShortString
*str
= js_NewGCShortString(cx
);
3439 jschar
*storage
= str
->init(length
);
3441 if (js_CStringsAreUTF8
) {
3443 size_t oldLength
= length
;
3445 if (!js_InflateStringToBuffer(cx
, chars
, length
, storage
, &length
))
3447 JS_ASSERT(length
<= oldLength
);
3448 storage
[length
] = 0;
3449 str
->resetLength(length
);
3452 jschar
*p
= storage
;
3454 *p
++ = (unsigned char)*chars
++;
3457 return str
->header()->assertIsFlat();
3460 static const size_t sMinWasteSize
= 16;
3463 js_NewStringFromCharBuffer(JSContext
*cx
, JSCharBuffer
&cb
)
3466 return ATOM_TO_STRING(cx
->runtime
->atomState
.emptyAtom
);
3468 size_t length
= cb
.length();
3470 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH
< JSCharBuffer::InlineLength
);
3471 if (JSShortString::fitsIntoShortString(length
))
3472 return NewShortString(cx
, cb
.begin(), length
);
3474 if (!cb
.append('\0'))
3477 size_t capacity
= cb
.capacity();
3479 jschar
*buf
= cb
.extractRawBuffer();
3483 /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3484 JS_ASSERT(capacity
>= length
);
3485 if (capacity
> sMinWasteSize
&& capacity
- length
> (length
>> 2)) {
3486 size_t bytes
= sizeof(jschar
) * (length
+ 1);
3487 jschar
*tmp
= (jschar
*)cx
->realloc(buf
, bytes
);
3495 JSFlatString
*str
= js_NewString(cx
, buf
, length
);
3502 js_NewDependentString(JSContext
*cx
, JSString
*baseArg
, size_t start
,
3508 return cx
->runtime
->emptyString
;
3510 JSLinearString
*base
= baseArg
->ensureLinear(cx
);
3514 if (start
== 0 && length
== base
->length())
3517 const jschar
*chars
= base
->chars() + start
;
3519 JSLinearString
*staticStr
= JSString::lookupStaticString(chars
, length
);
3523 /* Try to avoid long chains of dependent strings. */
3524 while (base
->isDependent())
3525 base
= base
->dependentBase();
3527 JS_ASSERT(base
->isFlat());
3529 ds
= js_NewGCString(cx
);
3532 ds
->initDependent(base
, chars
, length
);
3535 JSRuntime
*rt
= cx
->runtime
;
3536 JS_RUNTIME_METER(rt
, liveDependentStrings
);
3537 JS_RUNTIME_METER(rt
, totalDependentStrings
);
3538 JS_RUNTIME_METER(rt
, liveStrings
);
3539 JS_RUNTIME_METER(rt
, totalStrings
);
3540 JS_LOCK_RUNTIME_VOID(rt
,
3541 (rt
->strdepLengthSum
+= (double)length
,
3542 rt
->strdepLengthSquaredSum
+= (double)length
* (double)length
));
3543 JS_LOCK_RUNTIME_VOID(rt
,
3544 (rt
->lengthSum
+= (double)length
,
3545 rt
->lengthSquaredSum
+= (double)length
* (double)length
));
3548 return ds
->assertIsLinear();
3554 void printJSStringStats(JSRuntime
*rt
)
3558 mean
= JS_MeanAndStdDev(rt
->totalStrings
, rt
->lengthSum
,
3559 rt
->lengthSquaredSum
, &sigma
);
3561 fprintf(stderr
, "%lu total strings, mean length %g (sigma %g)\n",
3562 (unsigned long)rt
->totalStrings
, mean
, sigma
);
3564 mean
= JS_MeanAndStdDev(rt
->totalDependentStrings
, rt
->strdepLengthSum
,
3565 rt
->strdepLengthSquaredSum
, &sigma
);
3567 fprintf(stderr
, "%lu total dependent strings, mean length %g (sigma %g)\n",
3568 (unsigned long)rt
->totalDependentStrings
, mean
, sigma
);
3573 js_NewStringCopyN(JSContext
*cx
, const jschar
*s
, size_t n
)
3575 if (JSShortString::fitsIntoShortString(n
))
3576 return NewShortString(cx
, s
, n
);
3578 jschar
*news
= (jschar
*) cx
->malloc((n
+ 1) * sizeof(jschar
));
3581 js_strncpy(news
, s
, n
);
3583 JSFlatString
*str
= js_NewString(cx
, news
, n
);
3590 js_NewStringCopyN(JSContext
*cx
, const char *s
, size_t n
)
3592 if (JSShortString::fitsIntoShortString(n
))
3593 return NewShortString(cx
, s
, n
);
3595 jschar
*chars
= js_InflateString(cx
, s
, &n
);
3598 JSFlatString
*str
= js_NewString(cx
, chars
, n
);
3605 js_NewStringCopyZ(JSContext
*cx
, const jschar
*s
)
3607 size_t n
= js_strlen(s
);
3608 if (JSShortString::fitsIntoShortString(n
))
3609 return NewShortString(cx
, s
, n
);
3611 size_t m
= (n
+ 1) * sizeof(jschar
);
3612 jschar
*news
= (jschar
*) cx
->malloc(m
);
3616 JSFlatString
*str
= js_NewString(cx
, news
, n
);
3623 js_NewStringCopyZ(JSContext
*cx
, const char *s
)
3625 return js_NewStringCopyN(cx
, s
, strlen(s
));
3629 js_ValueToPrintable(JSContext
*cx
, const Value
&v
, JSAutoByteString
*bytes
, bool asSource
)
3633 str
= (asSource
? js_ValueToSource
: js_ValueToString
)(cx
, v
);
3636 str
= js_QuoteString(cx
, str
, 0);
3639 return bytes
->encode(cx
, str
);
3643 js_ValueToString(JSContext
*cx
, const Value
&arg
)
3646 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3652 } else if (v
.isInt32()) {
3653 str
= js_IntToString(cx
, v
.toInt32());
3654 } else if (v
.isDouble()) {
3655 str
= js_NumberToString(cx
, v
.toDouble());
3656 } else if (v
.isBoolean()) {
3657 str
= js_BooleanToString(cx
, v
.toBoolean());
3658 } else if (v
.isNull()) {
3659 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.nullAtom
);
3661 str
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
]);
3666 static inline JSBool
3667 AppendAtom(JSAtom
*atom
, JSCharBuffer
&cb
)
3669 return cb
.append(atom
->chars(), atom
->length());
3672 /* This function implements E-262-3 section 9.8, toString. */
3674 js_ValueToCharBuffer(JSContext
*cx
, const Value
&arg
, JSCharBuffer
&cb
)
3677 if (v
.isObject() && !DefaultValue(cx
, &v
.toObject(), JSTYPE_STRING
, &v
))
3681 JSString
*str
= v
.toString();
3682 size_t length
= str
->length();
3683 const jschar
*chars
= str
->getChars(cx
);
3686 return cb
.append(chars
, length
);
3689 return js_NumberValueToCharBuffer(cx
, v
, cb
);
3691 return js_BooleanToCharBuffer(cx
, v
.toBoolean(), cb
);
3693 return AppendAtom(cx
->runtime
->atomState
.nullAtom
, cb
);
3694 JS_ASSERT(v
.isUndefined());
3695 return AppendAtom(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
], cb
);
3698 JS_FRIEND_API(JSString
*)
3699 js_ValueToSource(JSContext
*cx
, const Value
&v
)
3701 if (v
.isUndefined())
3702 return ATOM_TO_STRING(cx
->runtime
->atomState
.void0Atom
);
3704 return js_QuoteString(cx
, v
.toString(), '"');
3705 if (v
.isPrimitive()) {
3706 /* Special case to preserve negative zero, _contra_ toString. */
3707 if (v
.isDouble() && JSDOUBLE_IS_NEGZERO(v
.toDouble())) {
3708 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3709 static const jschar js_negzero_ucNstr
[] = {'-', '0'};
3711 return js_NewStringCopyN(cx
, js_negzero_ucNstr
, 2);
3713 return js_ValueToString(cx
, v
);
3716 JSAtom
*atom
= cx
->runtime
->atomState
.toSourceAtom
;
3717 AutoValueRooter
tvr(cx
);
3718 if (!js_TryMethod(cx
, &v
.toObject(), atom
, 0, NULL
, tvr
.addr()))
3720 return js_ValueToString(cx
, tvr
.value());
3726 * str is not necessarily a GC thing here.
3728 static JS_ALWAYS_INLINE
bool
3729 EqualStringsTail(JSLinearString
*str1
, size_t length1
, JSLinearString
*str2
)
3731 const jschar
*s1
= str1
->chars();
3732 const jschar
*s1end
= s1
+ length1
;
3733 const jschar
*s2
= str2
->chars();
3739 } while (s1
!= s1end
);
3745 EqualStrings(JSContext
*cx
, JSString
*str1
, JSString
*str2
, JSBool
*result
)
3752 size_t length1
= str1
->length();
3753 if (length1
!= str2
->length()) {
3763 JSLinearString
*linear1
= str1
->ensureLinear(cx
);
3766 JSLinearString
*linear2
= str2
->ensureLinear(cx
);
3770 *result
= EqualStringsTail(linear1
, length1
, linear2
);
3775 EqualStrings(JSLinearString
*str1
, JSLinearString
*str2
)
3780 size_t length1
= str1
->length();
3781 if (length1
!= str2
->length())
3787 return EqualStringsTail(str1
, length1
, str2
);
3790 } /* namespace js */
3793 js_EqualStringsOnTrace(JSContext
*cx
, JSString
*str1
, JSString
*str2
)
3796 return EqualStrings(cx
, str1
, str2
, &result
) ? result
: JS_NEITHER
;
3798 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_EqualStringsOnTrace
,
3799 CONTEXT
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3804 CompareStringsImpl(JSContext
*cx
, JSString
*str1
, JSString
*str2
, int32
*result
)
3814 size_t l1
= str1
->length();
3815 const jschar
*s1
= str1
->getChars(cx
);
3819 size_t l2
= str2
->length();
3820 const jschar
*s2
= str2
->getChars(cx
);
3824 size_t n
= JS_MIN(l1
, l2
);
3825 for (size_t i
= 0; i
< n
; i
++) {
3826 if (int32 cmp
= s1
[i
] - s2
[i
]) {
3831 *result
= (int32
)(l1
- l2
);
3836 CompareStrings(JSContext
*cx
, JSString
*str1
, JSString
*str2
, int32
*result
)
3838 return CompareStringsImpl(cx
, str1
, str2
, result
);
3841 } /* namespace js */
3844 js_CompareStringsOnTrace(JSContext
*cx
, JSString
*str1
, JSString
*str2
)
3847 if (!CompareStringsImpl(cx
, str1
, str2
, &result
))
3849 JS_ASSERT(result
!= INT32_MIN
);
3852 JS_DEFINE_CALLINFO_3(extern, INT32
, js_CompareStringsOnTrace
,
3853 CONTEXT
, STRING
, STRING
, 1, nanojit::ACCSET_NONE
)
3858 StringEqualsAscii(JSLinearString
*str
, const char *asciiBytes
)
3860 size_t length
= strlen(asciiBytes
);
3862 for (size_t i
= 0; i
!= length
; ++i
)
3863 JS_ASSERT(unsigned(asciiBytes
[i
]) <= 127);
3865 if (length
!= str
->length())
3867 const jschar
*chars
= str
->chars();
3868 for (size_t i
= 0; i
!= length
; ++i
) {
3869 if (unsigned(asciiBytes
[i
]) != unsigned(chars
[i
]))
3878 js_strlen(const jschar
*s
)
3882 for (t
= s
; *t
!= 0; t
++)
3884 return (size_t)(t
- s
);
3888 js_strchr(const jschar
*s
, jschar c
)
3899 js_strchr_limit(const jschar
*s
, jschar c
, const jschar
*limit
)
3910 js_InflateString(JSContext
*cx
, const char *bytes
, size_t *lengthp
)
3912 size_t nbytes
, nchars
, i
;
3919 if (js_CStringsAreUTF8
) {
3920 if (!js_InflateStringToBuffer(cx
, bytes
, nbytes
, NULL
, &nchars
))
3922 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof (jschar
));
3928 js_InflateStringToBuffer(cx
, bytes
, nbytes
, chars
, &nchars
);
3932 chars
= (jschar
*) cx
->malloc((nchars
+ 1) * sizeof(jschar
));
3935 for (i
= 0; i
< nchars
; i
++)
3936 chars
[i
] = (unsigned char) bytes
[i
];
3944 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3952 * May be called with null cx.
3955 js_DeflateString(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3963 if (js_CStringsAreUTF8
) {
3964 nbytes
= js_GetDeflatedStringLength(cx
, chars
, nchars
);
3965 if (nbytes
== (size_t) -1)
3967 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3973 js_DeflateStringToBuffer(cx
, chars
, nchars
, bytes
, &nbytes
);
3977 bytes
= (char *) (cx
? cx
->malloc(nbytes
+ 1) : js_malloc(nbytes
+ 1));
3980 for (i
= 0; i
< nbytes
; i
++)
3981 bytes
[i
] = (char) chars
[i
];
3988 js_GetDeflatedStringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
3990 if (!js_CStringsAreUTF8
)
3993 return js_GetDeflatedUTF8StringLength(cx
, chars
, nchars
);
3997 * May be called with null cx through public API, see below.
4000 js_GetDeflatedUTF8StringLength(JSContext
*cx
, const jschar
*chars
, size_t nchars
)
4008 for (end
= chars
+ nchars
; chars
!= end
; chars
++) {
4012 if (0xD800 <= c
&& c
<= 0xDFFF) {
4013 /* Surrogate pair. */
4016 /* nbytes sets 1 length since this is surrogate pair. */
4018 if (c
>= 0xDC00 || chars
== end
)
4021 if (c2
< 0xDC00 || c2
> 0xDFFF)
4023 c
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4036 JS_snprintf(buffer
, 10, "0x%x", c
);
4037 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
4038 NULL
, JSMSG_BAD_SURROGATE_CHAR
, buffer
);
4044 js_DeflateStringToBuffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4045 char *dst
, size_t *dstlenp
)
4050 if (!js_CStringsAreUTF8
) {
4051 if (srclen
> dstlen
) {
4052 for (i
= 0; i
< dstlen
; i
++)
4053 dst
[i
] = (char) src
[i
];
4055 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4056 JSMSG_BUFFER_TOO_SMALL
);
4060 for (i
= 0; i
< srclen
; i
++)
4061 dst
[i
] = (char) src
[i
];
4066 return js_DeflateStringToUTF8Buffer(cx
, src
, srclen
, dst
, dstlenp
);
4070 js_DeflateStringToUTF8Buffer(JSContext
*cx
, const jschar
*src
, size_t srclen
,
4071 char *dst
, size_t *dstlenp
)
4073 size_t dstlen
, i
, origDstlen
, utf8Len
;
4079 origDstlen
= dstlen
;
4083 if ((c
>= 0xDC00) && (c
<= 0xDFFF))
4085 if (c
< 0xD800 || c
> 0xDBFF) {
4091 if ((c2
< 0xDC00) || (c2
> 0xDFFF))
4095 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
4098 /* no encoding necessary - performance hack */
4100 goto bufferTooSmall
;
4104 utf8Len
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
4105 if (utf8Len
> dstlen
)
4106 goto bufferTooSmall
;
4107 for (i
= 0; i
< utf8Len
; i
++)
4108 *dst
++ = (char) utf8buf
[i
];
4112 *dstlenp
= (origDstlen
- dstlen
);
4116 *dstlenp
= (origDstlen
- dstlen
);
4117 /* Delegate error reporting to the measurement function. */
4119 js_GetDeflatedStringLength(cx
, src
- 1, srclen
+ 1);
4123 *dstlenp
= (origDstlen
- dstlen
);
4125 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4126 JSMSG_BUFFER_TOO_SMALL
);
4132 js_InflateStringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4133 jschar
*dst
, size_t *dstlenp
)
4137 if (!js_CStringsAreUTF8
) {
4140 if (srclen
> dstlen
) {
4141 for (i
= 0; i
< dstlen
; i
++)
4142 dst
[i
] = (unsigned char) src
[i
];
4144 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4145 JSMSG_BUFFER_TOO_SMALL
);
4149 for (i
= 0; i
< srclen
; i
++)
4150 dst
[i
] = (unsigned char) src
[i
];
4156 return js_InflateUTF8StringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
4160 js_InflateUTF8StringToBuffer(JSContext
*cx
, const char *src
, size_t srclen
,
4161 jschar
*dst
, size_t *dstlenp
)
4163 size_t dstlen
, origDstlen
, offset
, j
, n
;
4166 dstlen
= dst
? *dstlenp
: (size_t) -1;
4167 origDstlen
= dstlen
;
4174 while (v
& (0x80 >> n
))
4177 goto bufferTooSmall
;
4178 if (n
== 1 || n
> 4)
4180 for (j
= 1; j
< n
; j
++) {
4181 if ((src
[j
] & 0xC0) != 0x80)
4184 v
= Utf8ToOneUcs4Char((uint8
*)src
, n
);
4187 if (v
> 0xFFFFF || dstlen
< 2) {
4188 *dstlenp
= (origDstlen
- dstlen
);
4191 JS_snprintf(buffer
, 10, "0x%x", v
+ 0x10000);
4192 JS_ReportErrorFlagsAndNumber(cx
,
4194 js_GetErrorMessage
, NULL
,
4195 JSMSG_UTF8_CHAR_TOO_LARGE
,
4201 *dst
++ = (jschar
)((v
>> 10) + 0xD800);
4202 v
= (jschar
)((v
& 0x3FF) + 0xDC00);
4208 goto bufferTooSmall
;
4210 *dst
++ = (jschar
) v
;
4216 *dstlenp
= (origDstlen
- dstlen
);
4220 *dstlenp
= (origDstlen
- dstlen
);
4223 JS_snprintf(buffer
, 10, "%d", offset
);
4224 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
4225 js_GetErrorMessage
, NULL
,
4226 JSMSG_MALFORMED_UTF8_CHAR
,
4232 *dstlenp
= (origDstlen
- dstlen
);
4234 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4235 JSMSG_BUFFER_TOO_SMALL
);
4241 * From java.lang.Character.java:
4243 * The character properties are currently encoded into 32 bits in the
4246 * 10 bits signed offset used for converting case
4247 * 1 bit if 1, adding the signed offset converts the character to
4249 * 1 bit if 1, subtracting the signed offset converts the character to
4251 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
4252 * 3 bits 0 may not be part of an identifier
4253 * 1 ignorable control; may continue a Unicode identifier or JS
4255 * 2 may continue a JS identifier but not a Unicode identifier
4257 * 3 may continue a Unicode identifier or JS identifier
4258 * 4 is a JS whitespace character
4259 * 5 may start or continue a JS identifier;
4260 * may continue but not start a Unicode identifier (_)
4261 * 6 may start or continue a JS identifier but not a Unicode
4263 * 7 may start or continue a Unicode identifier or JS identifier
4265 * 5, 6, 7 may start a JS identifier
4266 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
4267 * 7 may start a Unicode identifier
4268 * 1, 3, 5, 7 may continue a Unicode identifier
4269 * 1 is ignorable within an identifier
4270 * 4 is JS whitespace
4271 * 2 bits 0 this character has no numeric property
4272 * 1 adding the digit offset to the character code and then
4273 * masking with 0x1F will produce the desired numeric value
4274 * 2 this character has a "strange" numeric value
4275 * 3 a JS supradecimal digit: adding the digit offset to the
4276 * character code, then masking with 0x1F, then adding 10
4277 * will produce the desired numeric value
4278 * 5 bits digit offset
4279 * 1 bit XML 1.0 name start character
4280 * 1 bit XML 1.0 name character
4281 * 2 bits reserved for future use
4282 * 5 bits character type
4285 /* The X table has 1024 entries for a total of 1024 bytes. */
4287 const uint8 js_X
[] = {
4288 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
4289 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
4290 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
4291 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
4292 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
4293 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
4294 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
4295 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
4296 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
4297 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
4298 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
4299 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
4300 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
4301 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
4302 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
4303 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
4304 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
4305 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
4306 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
4307 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
4308 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
4309 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
4310 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
4311 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
4312 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
4313 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
4314 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
4315 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
4316 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
4317 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
4318 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
4319 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
4320 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
4321 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
4322 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
4323 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
4324 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
4325 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
4326 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
4327 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
4328 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
4329 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
4330 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
4331 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
4332 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
4333 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
4334 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
4335 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
4336 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
4337 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
4338 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
4339 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
4340 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
4341 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
4342 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
4343 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
4344 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
4345 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
4346 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
4347 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
4348 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
4349 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
4350 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
4351 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
4352 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
4353 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
4354 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
4355 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
4356 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
4357 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
4358 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
4359 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
4360 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
4361 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
4362 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
4363 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
4364 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
4365 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
4366 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
4367 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
4368 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
4369 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
4370 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
4371 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
4372 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
4373 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
4374 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
4375 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
4376 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
4377 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
4378 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
4379 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
4380 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
4381 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
4382 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
4383 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
4384 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
4385 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
4386 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
4387 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
4388 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
4389 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
4390 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
4391 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
4392 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
4393 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
4394 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
4395 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
4396 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
4397 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
4398 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
4399 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
4400 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
4401 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
4402 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
4403 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
4404 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
4405 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
4406 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
4407 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
4408 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
4409 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
4410 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
4411 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
4412 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
4413 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
4414 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
4415 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
4418 /* The Y table has 7808 entries for a total of 7808 bytes. */
4420 const uint8 js_Y
[] = {
4421 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4422 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
4423 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4424 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4425 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
4426 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
4427 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
4428 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
4429 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4430 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4431 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4432 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
4433 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4434 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4435 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4436 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
4437 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4438 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4439 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4440 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4441 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
4442 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
4443 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
4444 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
4445 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4446 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4447 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
4448 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
4449 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4450 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4451 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
4452 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
4453 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4454 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4455 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4456 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4457 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4458 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4459 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
4460 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
4461 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
4462 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
4463 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4464 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4465 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4466 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4467 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4468 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
4469 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
4470 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
4471 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
4472 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
4473 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
4474 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
4475 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
4476 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
4477 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
4478 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
4479 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
4480 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
4481 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4482 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4483 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
4484 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
4485 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4486 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4487 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4488 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4489 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4490 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4491 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4492 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4493 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4494 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4495 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
4496 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
4497 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
4498 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
4499 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
4500 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
4501 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
4502 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
4503 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
4504 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4505 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4506 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
4507 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
4508 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
4509 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4510 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
4511 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4512 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
4513 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
4514 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
4515 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4516 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4517 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4518 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4519 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4520 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4521 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4522 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4523 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4524 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4525 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
4526 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4527 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4528 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4529 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
4530 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4531 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
4532 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
4533 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
4534 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
4535 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4536 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4537 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
4538 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
4539 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4540 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4541 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
4542 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
4543 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
4544 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
4545 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
4546 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
4547 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
4548 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
4549 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
4550 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
4551 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4552 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4553 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4554 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4555 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4556 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4557 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4558 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4559 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
4560 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
4561 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4562 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4563 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4564 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4565 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
4566 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
4567 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4568 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4569 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4570 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4571 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4572 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4573 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
4574 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
4575 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4576 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4577 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4578 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
4579 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
4580 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
4581 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4582 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4583 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4584 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4585 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4586 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4587 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4588 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4589 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4590 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4591 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
4592 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
4593 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4594 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4595 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4596 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4597 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
4598 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
4599 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4600 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4601 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
4602 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4603 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4604 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
4605 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
4606 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4607 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4608 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4609 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4610 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
4611 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
4612 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4613 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4614 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
4615 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4616 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
4617 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4618 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4619 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4620 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
4621 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4622 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
4623 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
4624 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
4625 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
4626 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
4627 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4628 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4629 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4630 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4631 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4632 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4633 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4634 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4635 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4636 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4637 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4638 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4639 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4640 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4641 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4642 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4643 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4644 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4645 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4646 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4647 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4648 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4649 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4650 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4651 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4652 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4653 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4654 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4655 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4656 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4657 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4658 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4659 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4660 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
4661 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4662 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4663 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4664 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4665 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4666 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4667 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4668 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4669 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4670 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4671 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4672 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4673 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4674 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4675 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4676 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4677 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4678 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4679 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4680 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4681 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4682 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4683 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4684 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4685 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4686 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4687 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4688 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4689 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4690 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4691 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4692 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4693 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4694 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4695 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4696 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4697 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4698 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4699 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4700 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4701 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4702 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4703 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4704 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4705 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4706 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4707 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4708 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4709 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4710 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4711 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4712 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4713 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4714 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4715 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4716 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4717 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4718 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4719 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4720 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4721 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4722 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4723 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4724 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4725 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4726 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4727 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4728 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4729 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4730 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4731 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4732 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4733 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4734 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4735 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4736 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4737 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4738 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4739 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4740 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4741 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4742 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4743 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4744 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4745 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4746 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4747 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4748 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4749 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4750 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4751 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4752 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4753 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4754 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4755 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4756 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4757 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4758 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4759 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4760 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4761 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4762 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4763 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4764 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4765 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4766 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4767 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4768 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4769 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4770 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4771 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4772 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4773 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4774 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4775 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4776 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4777 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4778 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4779 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4780 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4781 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4782 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4783 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4784 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4785 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4786 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4787 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4788 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
4789 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4790 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4791 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4792 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4793 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4794 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4795 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4796 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4797 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4798 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4799 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4800 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4801 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4802 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
4803 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4804 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4805 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4806 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4807 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4808 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4809 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4810 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4811 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4812 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4813 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4814 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4815 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
4816 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
4817 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
4818 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
4819 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
4820 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
4821 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
4822 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
4823 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
4824 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
4825 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4826 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4827 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4828 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4829 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
4830 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
4831 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
4832 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
4833 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
4834 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
4835 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
4836 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
4837 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4838 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4839 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4840 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4841 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4842 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
4843 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
4844 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
4845 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
4846 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
4847 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
4848 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4849 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4850 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
4851 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4852 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
4853 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4854 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4855 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4856 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4857 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4858 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4859 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4860 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4861 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
4862 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
4863 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4864 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4865 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4866 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4867 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
4868 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
4869 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4870 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4871 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4872 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4873 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4874 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4875 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4876 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4877 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4878 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4879 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4880 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
4881 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4882 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4883 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4884 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4885 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4886 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4887 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4888 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4889 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
4890 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4891 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4892 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4893 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4894 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4895 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4896 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4897 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4898 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4899 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4900 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
4901 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4902 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4903 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4904 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4905 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4906 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4907 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4908 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4909 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4910 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4911 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
4912 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
4913 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4914 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4915 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4916 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4917 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4918 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4919 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4920 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4921 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4922 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4923 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4924 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
4925 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4926 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4927 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
4928 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
4929 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4930 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4931 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4932 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4933 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
4934 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
4935 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
4936 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
4937 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
4938 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
4939 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
4940 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
4941 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4942 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4943 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4944 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4945 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4946 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4947 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
4948 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
4949 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
4950 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
4951 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
4952 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
4953 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
4954 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
4955 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
4956 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
4957 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
4958 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
4959 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
4960 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
4961 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4962 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
4963 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4964 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
4965 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
4966 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4967 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4968 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4969 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4970 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
4971 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
4972 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
4973 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
4974 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
4975 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4976 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4977 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
4978 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
4979 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4980 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4981 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4982 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4983 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
4984 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
4985 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
4986 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4987 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4988 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4989 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
4990 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
4991 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
4992 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
4993 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
4994 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
4995 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
4996 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
4997 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
4998 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
4999 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
5000 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
5001 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
5002 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
5003 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
5004 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
5005 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
5006 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
5007 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
5008 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5009 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5010 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5011 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5012 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5013 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5014 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5015 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
5016 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5017 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5018 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
5019 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5020 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5021 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5022 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5023 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5024 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5025 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5026 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5027 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5028 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5029 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5030 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5031 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5032 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5033 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5034 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5035 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
5036 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
5037 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
5038 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
5039 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5040 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5041 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
5042 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
5043 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5044 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5045 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5046 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5047 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5048 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5049 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5050 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5051 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5052 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
5053 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5054 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5055 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5056 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5057 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
5058 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5059 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5060 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5061 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
5062 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
5063 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5064 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5065 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5066 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5067 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
5068 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
5069 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
5070 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5071 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5072 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
5073 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5074 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5075 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
5076 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
5077 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5078 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5079 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5080 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5081 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5082 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
5083 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5084 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5085 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5086 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5087 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5088 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5089 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5090 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5091 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5092 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5093 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5094 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5095 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
5096 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
5097 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5098 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5099 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5100 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5101 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5102 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5103 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5104 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5105 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5106 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5107 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5108 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5109 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5110 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5111 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
5112 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
5113 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5114 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5115 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5116 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5117 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
5118 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
5119 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5120 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5121 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5122 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5123 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5124 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5125 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5126 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
5127 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
5128 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
5129 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5130 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
5131 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
5132 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
5133 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
5134 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
5135 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
5136 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5137 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5138 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5139 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5140 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
5141 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
5142 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
5143 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
5144 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
5145 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
5146 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
5147 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
5148 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
5149 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5150 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5151 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5152 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5153 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5154 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5155 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5156 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5157 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5158 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5159 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
5160 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
5161 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5162 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5163 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5164 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5165 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5166 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5167 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5168 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5169 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5170 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5171 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5172 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
5173 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
5174 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5175 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5176 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5177 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5178 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
5179 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5180 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5181 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
5182 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
5183 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
5184 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
5185 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5186 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5187 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5188 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5189 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5190 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5191 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5192 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
5193 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
5194 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
5195 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5196 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5197 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
5198 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5199 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5200 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5201 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5202 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5203 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5204 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
5205 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
5206 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
5207 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5208 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5209 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5210 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5211 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5212 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5213 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5214 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
5215 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5216 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5217 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5218 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5219 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5220 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
5221 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5222 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5223 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5224 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5225 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5226 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5227 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
5228 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
5229 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5230 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5231 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5232 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
5233 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5234 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5235 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5236 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
5237 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5238 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5239 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5240 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5241 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
5242 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5243 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5244 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5245 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5246 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5247 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5248 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5249 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
5250 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5251 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5252 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5253 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5254 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5255 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5256 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5257 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5258 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5259 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5260 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5261 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5262 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5263 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5264 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5265 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5266 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5267 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5268 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5269 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5270 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5271 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5272 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5273 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5274 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
5275 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5276 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5277 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
5278 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
5279 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
5280 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
5281 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
5282 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
5283 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
5284 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
5285 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
5286 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5287 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5288 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5289 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5290 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5291 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5292 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5293 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5294 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5295 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5296 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5297 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5298 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5299 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
5300 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
5301 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5302 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5303 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
5304 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5305 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5306 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5307 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5308 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5309 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5310 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5311 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5312 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5313 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5314 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5315 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5316 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
5317 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5318 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5319 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5320 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5321 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5322 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5323 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5324 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5325 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5326 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5327 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
5328 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5329 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5330 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5331 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5332 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5333 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5334 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5335 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5336 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5337 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5338 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5339 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5340 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
5341 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5342 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5343 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5344 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5345 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
5346 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5347 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
5348 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
5349 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
5350 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
5351 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
5352 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
5353 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
5354 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
5355 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
5356 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
5357 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5358 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5359 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5360 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5361 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5362 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5363 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5364 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
5365 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
5366 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
5367 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
5368 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
5369 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5370 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5371 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5372 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
5373 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5374 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5375 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5376 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
5377 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
5378 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5379 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5380 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5381 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5382 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5383 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5384 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
5385 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5386 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5387 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5388 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
5389 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5390 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5391 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5392 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
5393 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
5394 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
5395 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
5396 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
5399 /* The A table has 124 entries for a total of 496 bytes. */
5401 const uint32 js_A
[] = {
5402 0x0001000F, /* 0 Cc, ignorable */
5403 0x0004000F, /* 1 Cc, whitespace */
5404 0x0004000C, /* 2 Zs, whitespace */
5405 0x00000018, /* 3 Po */
5406 0x0006001A, /* 4 Sc, currency */
5407 0x00000015, /* 5 Ps */
5408 0x00000016, /* 6 Pe */
5409 0x00000019, /* 7 Sm */
5410 0x00000014, /* 8 Pd */
5411 0x00036089, /* 9 Nd, identifier part, decimal 16 */
5412 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
5413 0x0000001B, /* 11 Sk */
5414 0x00050017, /* 12 Pc, underscore */
5415 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5416 0x0000000C, /* 14 Zs */
5417 0x0000001C, /* 15 So */
5418 0x00070182, /* 16 Ll, identifier start */
5419 0x0000600B, /* 17 No, decimal 16 */
5420 0x0000500B, /* 18 No, decimal 8 */
5421 0x0000800B, /* 19 No, strange */
5422 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
5423 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
5424 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
5425 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
5426 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
5427 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
5428 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
5429 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
5430 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
5431 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
5432 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
5433 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
5434 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
5435 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
5436 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
5437 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
5438 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
5439 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
5440 0x00070181, /* 38 Lu, identifier start */
5441 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
5442 0x00070185, /* 40 Lo, identifier start */
5443 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
5444 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
5445 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
5446 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5447 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
5448 0x00000000, /* 46 unassigned */
5449 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
5450 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
5451 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
5452 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
5453 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
5454 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
5455 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
5456 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
5457 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
5458 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
5459 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
5460 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
5461 0x00070084, /* 59 Lm, identifier start */
5462 0x00030086, /* 60 Mn, identifier part */
5463 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
5464 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
5465 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
5466 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
5467 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
5468 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
5469 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
5470 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
5471 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
5472 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
5473 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
5474 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
5475 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
5476 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
5477 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
5478 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
5479 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
5480 0x00034089, /* 78 Nd, identifier part, decimal 0 */
5481 0x00000087, /* 79 Me */
5482 0x00030088, /* 80 Mc, identifier part */
5483 0x00037489, /* 81 Nd, identifier part, decimal 26 */
5484 0x00005A0B, /* 82 No, decimal 13 */
5485 0x00006E0B, /* 83 No, decimal 23 */
5486 0x0000740B, /* 84 No, decimal 26 */
5487 0x0000000B, /* 85 No */
5488 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
5489 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
5490 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
5491 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
5492 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
5493 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
5494 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
5495 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
5496 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
5497 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
5498 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
5499 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
5500 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
5501 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
5502 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
5503 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
5504 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
5505 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
5506 0x00010010, /* 104 Cf, ignorable */
5507 0x0004000D, /* 105 Zl, whitespace */
5508 0x0004000E, /* 106 Zp, whitespace */
5509 0x0000400B, /* 107 No, decimal 0 */
5510 0x0000440B, /* 108 No, decimal 2 */
5511 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
5512 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
5513 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5514 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
5515 0x0007818A, /* 113 Nl, identifier start, strange */
5516 0x0000420B, /* 114 No, decimal 1 */
5517 0x0000720B, /* 115 No, decimal 25 */
5518 0x06A0001C, /* 116 So, hasLower (add 26) */
5519 0x0690001C, /* 117 So, hasUpper (subtract 26) */
5520 0x00006C0B, /* 118 No, decimal 22 */
5521 0x0000560B, /* 119 No, decimal 11 */
5522 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
5523 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
5524 0x00000013, /* 122 Cs */
5525 0x00000012 /* 123 Co */
5528 const jschar js_uriReservedPlusPound_ucstr
[] =
5529 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5530 const jschar js_uriUnescaped_ucstr
[] =
5531 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5532 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5533 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5534 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5535 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5536 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5539 * This table allows efficient testing for the regular expression \w which is
5540 * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5542 const bool js_alnum
[] = {
5543 /* 0 1 2 3 4 5 5 7 8 9 */
5544 /* 0 */ false, false, false, false, false, false, false, false, false, false,
5545 /* 1 */ false, false, false, false, false, false, false, false, false, false,
5546 /* 2 */ false, false, false, false, false, false, false, false, false, false,
5547 /* 3 */ false, false, false, false, false, false, false, false, false, false,
5548 /* 4 */ false, false, false, false, false, false, false, false, true, true,
5549 /* 5 */ true, true, true, true, true, true, true, true, false, false,
5550 /* 6 */ false, false, false, false, false, true, true, true, true, true,
5551 /* 7 */ true, true, true, true, true, true, true, true, true, true,
5552 /* 8 */ true, true, true, true, true, true, true, true, true, true,
5553 /* 9 */ true, false, false, false, false, true, false, true, true, true,
5554 /* 10 */ true, true, true, true, true, true, true, true, true, true,
5555 /* 11 */ true, true, true, true, true, true, true, true, true, true,
5556 /* 12 */ true, true, true, false, false, false, false, false
5559 #define URI_CHUNK 64U
5562 TransferBufferToString(JSContext
*cx
, JSCharBuffer
&cb
, Value
*rval
)
5564 JSString
*str
= js_NewStringFromCharBuffer(cx
, cb
);
5567 rval
->setString(str
);
5572 * ECMA 3, 15.1.3 URI Handling Function Properties
5574 * The following are implementations of the algorithms
5575 * given in the ECMA specification for the hidden functions
5576 * 'Encode' and 'Decode'.
5579 Encode(JSContext
*cx
, JSString
*str
, const jschar
*unescapedSet
,
5580 const jschar
*unescapedSet2
, Value
*rval
)
5582 static const char HexDigits
[] = "0123456789ABCDEF"; /* NB: uppercase */
5584 size_t length
= str
->length();
5585 const jschar
*chars
= str
->getChars(cx
);
5590 rval
->setString(cx
->runtime
->emptyString
);
5594 JSCharBuffer
cb(cx
);
5598 for (size_t k
= 0; k
< length
; k
++) {
5599 jschar c
= chars
[k
];
5600 if (js_strchr(unescapedSet
, c
) ||
5601 (unescapedSet2
&& js_strchr(unescapedSet2
, c
))) {
5605 if ((c
>= 0xDC00) && (c
<= 0xDFFF)) {
5606 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5607 JSMSG_BAD_URI
, NULL
);
5611 if (c
< 0xD800 || c
> 0xDBFF) {
5616 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5617 JSMSG_BAD_URI
, NULL
);
5620 jschar c2
= chars
[k
];
5621 if ((c2
< 0xDC00) || (c2
> 0xDFFF)) {
5622 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
5623 JSMSG_BAD_URI
, NULL
);
5626 v
= ((c
- 0xD800) << 10) + (c2
- 0xDC00) + 0x10000;
5629 size_t L
= js_OneUcs4ToUtf8Char(utf8buf
, v
);
5630 for (size_t j
= 0; j
< L
; j
++) {
5631 hexBuf
[1] = HexDigits
[utf8buf
[j
] >> 4];
5632 hexBuf
[2] = HexDigits
[utf8buf
[j
] & 0xf];
5633 if (!cb
.append(hexBuf
, 3))
5639 return TransferBufferToString(cx
, cb
, rval
);
5643 Decode(JSContext
*cx
, JSString
*str
, const jschar
*reservedSet
, Value
*rval
)
5645 size_t length
= str
->length();
5646 const jschar
*chars
= str
->getChars(cx
);
5651 rval
->setString(cx
->runtime
->emptyString
);
5655 JSCharBuffer
cb(cx
);
5656 for (size_t k
= 0; k
< length
; k
++) {
5657 jschar c
= chars
[k
];
5660 if ((k
+ 2) >= length
)
5661 goto report_bad_uri
;
5662 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5663 goto report_bad_uri
;
5664 jsuint B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5670 while (B
& (0x80 >> n
))
5672 if (n
== 1 || n
> 4)
5673 goto report_bad_uri
;
5675 octets
[0] = (uint8
)B
;
5676 if (k
+ 3 * (n
- 1) >= length
)
5677 goto report_bad_uri
;
5678 for (intN j
= 1; j
< n
; j
++) {
5680 if (chars
[k
] != '%')
5681 goto report_bad_uri
;
5682 if (!JS7_ISHEX(chars
[k
+1]) || !JS7_ISHEX(chars
[k
+2]))
5683 goto report_bad_uri
;
5684 B
= JS7_UNHEX(chars
[k
+1]) * 16 + JS7_UNHEX(chars
[k
+2]);
5685 if ((B
& 0xC0) != 0x80)
5686 goto report_bad_uri
;
5688 octets
[j
] = (char)B
;
5690 uint32 v
= Utf8ToOneUcs4Char(octets
, n
);
5694 goto report_bad_uri
;
5695 c
= (jschar
)((v
& 0x3FF) + 0xDC00);
5696 jschar H
= (jschar
)((v
>> 10) + 0xD800);
5703 if (js_strchr(reservedSet
, c
)) {
5704 if (!cb
.append(chars
+ start
, k
- start
+ 1))
5716 return TransferBufferToString(cx
, cb
, rval
);
5719 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_URI
);
5726 str_decodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5728 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5731 return Decode(cx
, str
, js_uriReservedPlusPound_ucstr
, vp
);
5735 str_decodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5737 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5740 return Decode(cx
, str
, js_empty_ucstr
, vp
);
5744 str_encodeURI(JSContext
*cx
, uintN argc
, Value
*vp
)
5746 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5749 return Encode(cx
, str
, js_uriReservedPlusPound_ucstr
, js_uriUnescaped_ucstr
,
5754 str_encodeURI_Component(JSContext
*cx
, uintN argc
, Value
*vp
)
5756 JSLinearString
*str
= ArgToRootedString(cx
, argc
, vp
, 0);
5759 return Encode(cx
, str
, js_uriUnescaped_ucstr
, NULL
, vp
);
5763 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5764 * least 4 bytes long. Return the number of UTF-8 bytes of data written.
5767 js_OneUcs4ToUtf8Char(uint8
*utf8Buffer
, uint32 ucs4Char
)
5771 JS_ASSERT(ucs4Char
<= 0x10FFFF);
5772 if (ucs4Char
< 0x80) {
5773 *utf8Buffer
= (uint8
)ucs4Char
;
5776 uint32 a
= ucs4Char
>> 11;
5784 utf8Buffer
[i
] = (uint8
)((ucs4Char
& 0x3F) | 0x80);
5787 *utf8Buffer
= (uint8
)(0x100 - (1 << (8-utf8Length
)) + ucs4Char
);
5793 * Convert a utf8 character sequence into a UCS-4 character and return that
5794 * character. It is assumed that the caller already checked that the sequence
5798 Utf8ToOneUcs4Char(const uint8
*utf8Buffer
, int utf8Length
)
5802 /* from Unicode 3.1, non-shortest form is illegal */
5803 static const uint32 minucs4Table
[] = {
5804 0x00000080, 0x00000800, 0x00010000
5807 JS_ASSERT(utf8Length
>= 1 && utf8Length
<= 4);
5808 if (utf8Length
== 1) {
5809 ucs4Char
= *utf8Buffer
;
5810 JS_ASSERT(!(ucs4Char
& 0x80));
5812 JS_ASSERT((*utf8Buffer
& (0x100 - (1 << (7-utf8Length
)))) ==
5813 (0x100 - (1 << (8-utf8Length
))));
5814 ucs4Char
= *utf8Buffer
++ & ((1<<(7-utf8Length
))-1);
5815 minucs4Char
= minucs4Table
[utf8Length
-2];
5816 while (--utf8Length
) {
5817 JS_ASSERT((*utf8Buffer
& 0xC0) == 0x80);
5818 ucs4Char
= ucs4Char
<<6 | (*utf8Buffer
++ & 0x3F);
5820 if (JS_UNLIKELY(ucs4Char
< minucs4Char
)) {
5821 ucs4Char
= OVERLONG_UTF8
;
5822 } else if (ucs4Char
== 0xFFFE || ucs4Char
== 0xFFFF) {
5832 PutEscapedStringImpl(char *buffer
, size_t bufferSize
, FILE *fp
, JSLinearString
*str
, uint32 quote
)
5835 STOP
, FIRST_QUOTE
, LAST_QUOTE
, CHARS
, ESCAPE_START
, ESCAPE_MORE
5838 JS_ASSERT(quote
== 0 || quote
== '\'' || quote
== '"');
5839 JS_ASSERT_IF(!buffer
, bufferSize
== 0);
5840 JS_ASSERT_IF(fp
, !buffer
);
5842 if (bufferSize
== 0)
5847 const jschar
*chars
= str
->chars();
5848 const jschar
*charsEnd
= chars
+ str
->length();
5850 state
= FIRST_QUOTE
;
5854 char c
= 0; /* to quell GCC warnings */
5871 if (chars
== charsEnd
) {
5878 const char *escape
= strchr(js_EscapeMap
, (int)u
);
5887 if (u
== quote
|| u
== '\\')
5890 } else if (u
< 0x100) {
5905 state
= ESCAPE_START
;
5908 JS_ASSERT(' ' <= u
&& u
< 127);
5910 state
= ESCAPE_MORE
;
5918 u
= 0xF & (hex
>> shift
);
5919 c
= (char)(u
+ (u
< 10 ? '0' : 'A' - 10));
5923 JS_ASSERT(n
<= bufferSize
);
5924 if (n
!= bufferSize
) {
5931 if (fputc(c
, fp
) < 0)
5942 } /* namespace js */