1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JS string type implementation.
44 * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
45 * native methods store strings (possibly newborn) converted from their 'this'
46 * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
47 * conversions at their index (argv[0], argv[1]). This is a legitimate method
48 * of rooting things that might lose their newborn root due to subsequent GC
49 * allocations in the same native method.
62 #include "jsbuiltins.h"
64 #include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */
73 #include "jsstaticcheck.h"
77 #include "jsversion.h"
79 #include "jscntxtinlines.h"
80 #include "jsinterpinlines.h"
81 #include "jsobjinlines.h"
82 #include "jsregexpinlines.h"
83 #include "jsstrinlines.h"
84 #include "jsautooplen.h" // generated headers last
87 using namespace js::gc;
89 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH) <= size_t(JSVAL_INT_MAX));
90 JS_STATIC_ASSERT(JSString::MAX_LENGTH <= JSVAL_INT_MAX);
93 js_GetStringChars(JSContext *cx, JSString *str)
95 if (!js_MakeStringImmutable(cx, str))
97 return str->flatChars();
100 static JS_ALWAYS_INLINE size_t
101 RopeCapacityFor(size_t length)
103 static const size_t ROPE_DOUBLING_MAX = 1024 * 1024;
106 * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
107 * next power of 2. This is similar to what we do with arrays; see
108 * JSObject::ensureDenseArrayElements.
110 if (length > ROPE_DOUBLING_MAX)
111 return length + (length / 8);
112 return RoundUpPow2(length);
115 static JS_ALWAYS_INLINE jschar *
116 AllocChars(JSContext *maybecx, size_t wholeCapacity)
118 /* +1 for the null char at the end. */
119 JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
120 size_t bytes = (wholeCapacity + 1) * sizeof(jschar);
122 return (jschar *)maybecx->malloc(bytes);
123 return (jschar *)js_malloc(bytes);
127 JSString::flatten(JSContext *maybecx)
132 * Perform a depth-first dag traversal, splatting each node's characters
133 * into a contiguous buffer. Visit each rope node three times:
134 * 1. record position in the buffer and recurse into left child;
135 * 2. recurse into the right child;
136 * 3. transform the node into a dependent string.
137 * To avoid maintaining a stack, tree nodes are mutated to indicate how
138 * many times they have been visited. Since ropes can be dags, a node may
139 * be encountered multiple times during traversal. However, step 3 above
140 * leaves a valid dependent string, so everythings works out. This
141 * algorithm is homomorphic to TypedMarker(JSTracer *, JSString *).
143 * While ropes avoid all sorts of quadratic cases with string
144 * concatenation, they can't help when ropes are immediately flattened.
145 * One idiomatic case that we'd like to keep linear (and has traditionally
146 * been linear in SM and other JS engines) is:
153 * To do this, when the buffer for a to-be-flattened rope is allocated, the
154 * allocation size is rounded up. Then, if the resulting flat string is the
155 * left-hand side of a new rope that gets flattened and there is enough
156 * capacity, the rope is flattened into the same buffer, thereby avoiding
157 * copying the left-hand side. Clearing the 'extensible' bit turns off this
158 * optimization. This is necessary, e.g., when the JSAPI hands out the raw
159 * null-terminated char array of a flat string.
161 * N.B. This optimization can create chains of dependent strings.
163 const size_t wholeLength = length();
164 size_t wholeCapacity;
166 JSString *str = this;
169 if (u.left->isExtensible() && u.left->s.capacity >= wholeLength) {
170 wholeCapacity = u.left->s.capacity;
171 wholeChars = const_cast<jschar *>(u.left->u.chars);
172 pos = wholeChars + u.left->length();
173 u.left->finishTraversalConversion(this, wholeChars, pos);
174 goto visit_right_child;
177 wholeCapacity = RopeCapacityFor(wholeLength);
178 wholeChars = AllocChars(maybecx, wholeCapacity);
183 maybecx->runtime->stringMemoryUsed += wholeLength * 2;
186 JSString *left = str->u.left; /* Read before clobbered. */
188 if (left->isRope()) {
189 left->s.parent = str; /* Return to this when 'left' done, */
190 left->lengthAndFlags = 0x200; /* but goto visit_right_child. */
192 goto first_visit_node;
194 size_t len = left->length();
195 PodCopy(pos, left->u.chars, len);
199 JSString *right = str->s.right;
200 if (right->isRope()) {
201 right->s.parent = str; /* Return to this node when 'right' done, */
202 right->lengthAndFlags = 0x300; /* but goto finish_node. */
204 goto first_visit_node;
206 size_t len = right->length();
207 PodCopy(pos, right->u.chars, len);
212 JS_ASSERT(pos == wholeChars + wholeLength);
214 initFlatExtensible(wholeChars, wholeLength, wholeCapacity);
217 size_t progress = str->lengthAndFlags; /* Read before clobbered. */
218 JSString *parent = str->s.parent;
219 str->finishTraversalConversion(this, wholeChars, pos);
221 if (progress == 0x200)
222 goto visit_right_child;
227 JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8);
228 JSStringFinalizeOp JSExternalString::str_finalizers[JSExternalString::TYPE_LIMIT] = {
229 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
235 js_Flatten(JSContext *cx, JSString* str)
237 return !!str->flatten(cx);
239 JS_DEFINE_CALLINFO_2(extern, BOOL, js_Flatten, CONTEXT, STRING, 0, nanojit::ACCSET_STORE_ANY)
241 #endif /* !JS_TRACER */
243 JSString * JS_FASTCALL
244 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
246 JS_ASSERT_IF(!JSString::isStatic(left) && !left->isAtomized(),
247 left->asCell()->compartment() == cx->compartment);
248 JS_ASSERT_IF(!JSString::isStatic(right) && !right->isAtomized(),
249 right->asCell()->compartment() == cx->compartment);
251 size_t leftLen = left->length();
255 size_t rightLen = right->length();
259 size_t wholeLength = leftLen + rightLen;
261 if (JSShortString::fitsIntoShortString(wholeLength)) {
262 JSShortString *shortStr = js_NewGCShortString(cx);
265 const jschar *leftChars = left->getChars(cx);
268 const jschar *rightChars = right->getChars(cx);
272 jschar *buf = shortStr->init(wholeLength);
273 js_short_strncpy(buf, leftChars, leftLen);
274 js_short_strncpy(buf + leftLen, rightChars, rightLen);
275 buf[wholeLength] = 0;
276 return shortStr->header();
279 if (wholeLength > JSString::MAX_LENGTH) {
280 if (JS_ON_TRACE(cx)) {
281 if (!CanLeaveTrace(cx))
285 js_ReportAllocationOverflow(cx);
289 JSString *newRoot = js_NewGCString(cx);
293 newRoot->initRopeNode(left, right, wholeLength);
298 JSString::undepend(JSContext *cx)
303 if (!ensureLinear(cx))
307 n = dependentLength();
308 size = (n + 1) * sizeof(jschar);
309 s = (jschar *) cx->malloc(size);
313 cx->runtime->stringMemoryUsed += size;
314 js_strncpy(s, dependentChars(), n);
320 JSRuntime *rt = cx->runtime;
321 JS_RUNTIME_UNMETER(rt, liveDependentStrings);
322 JS_RUNTIME_UNMETER(rt, totalDependentStrings);
323 JS_LOCK_RUNTIME_VOID(rt,
324 (rt->strdepLengthSum -= (double)n,
325 rt->strdepLengthSquaredSum -= (double)n * (double)n));
334 js_MakeStringImmutable(JSContext *cx, JSString *str)
337 * Flattening a rope may result in a dependent string, so we need to flatten
338 * before undepending the string.
340 if (!str->isFlat() && !str->undepend(cx)) {
341 JS_RUNTIME_METER(cx->runtime, badUndependStrings);
344 str->flatClearExtensible();
348 static JSLinearString *
349 ArgToRootedString(JSContext *cx, uintN argc, Value *vp, uintN arg)
352 return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
355 if (vp->isObject() && !DefaultValue(cx, &vp->toObject(), JSTYPE_STRING, vp))
359 if (vp->isString()) {
360 str = vp->toString()->ensureLinear(cx);
361 } else if (vp->isBoolean()) {
362 str = ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[
363 (int)vp->toBoolean()]);
364 } else if (vp->isNull()) {
365 str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
366 } else if (vp->isUndefined()) {
367 str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
370 str = NumberToString(cx, vp->toNumber());
379 * Forward declarations for URI encode/decode and helper routines
382 str_decodeURI(JSContext *cx, uintN argc, Value *vp);
385 str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp);
388 str_encodeURI(JSContext *cx, uintN argc, Value *vp);
391 str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp);
393 static const uint32 OVERLONG_UTF8 = UINT32_MAX;
396 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
399 * Contributions from the String class to the set of methods defined for the
400 * global object. escape and unescape used to be defined in the Mocha library,
401 * but as ECMA decided to spec them, they've been moved to the core engine
402 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
403 * characters by unescape.)
407 * Stuff to emulate the old libmocha escape, which took a second argument
408 * giving the type of escape to perform. Retained for compatibility, and
409 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
412 #define URL_XALPHAS ((uint8) 1)
413 #define URL_XPALPHAS ((uint8) 2)
414 #define URL_PATH ((uint8) 4)
416 static const uint8 urlCharType[256] =
417 /* Bit 0 xalpha -- the alphas
418 * Bit 1 xpalpha -- as xalpha but
419 * converts spaces to plus and plus to %20
420 * Bit 2 ... path -- as xalphas but doesn't escape '/'
422 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
423 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
424 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
425 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
426 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
427 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
428 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
429 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
430 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
433 /* This matches the ECMA escape set when mask is 7 (default.) */
435 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
437 /* See ECMA-262 Edition 3 B.2.1 */
439 js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
441 const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
442 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
444 jsint mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
447 if (!ValueToNumber(cx, vp[3], &d))
449 if (!JSDOUBLE_IS_FINITE(d) ||
450 (mask = (jsint)d) != d ||
451 mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
454 JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
455 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
456 JSMSG_BAD_STRING_MASK, numBuf);
461 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
465 size_t length = str->length();
466 const jschar *chars = str->chars();
468 /* Take a first pass and see how big the result string will need to be. */
469 size_t newlength = length;
470 for (size_t i = 0; i < length; i++) {
472 if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
475 if (mask == URL_XPALPHAS && ch == ' ')
476 continue; /* The character will be encoded as '+' */
477 newlength += 2; /* The character will be encoded as %XX */
479 newlength += 5; /* The character will be encoded as %uXXXX */
483 * This overflow test works because newlength is incremented by at
484 * most 5 on each iteration.
486 if (newlength < length) {
487 js_ReportAllocationOverflow(cx);
492 if (newlength >= ~(size_t)0 / sizeof(jschar)) {
493 js_ReportAllocationOverflow(cx);
497 jschar *newchars = (jschar *) cx->malloc((newlength + 1) * sizeof(jschar));
501 for (i = 0, ni = 0; i < length; i++) {
503 if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
505 } else if (ch < 256) {
506 if (mask == URL_XPALPHAS && ch == ' ') {
507 newchars[ni++] = '+'; /* convert spaces to pluses */
509 newchars[ni++] = '%';
510 newchars[ni++] = digits[ch >> 4];
511 newchars[ni++] = digits[ch & 0xF];
514 newchars[ni++] = '%';
515 newchars[ni++] = 'u';
516 newchars[ni++] = digits[ch >> 12];
517 newchars[ni++] = digits[(ch & 0xF00) >> 8];
518 newchars[ni++] = digits[(ch & 0xF0) >> 4];
519 newchars[ni++] = digits[ch & 0xF];
522 JS_ASSERT(ni == newlength);
523 newchars[newlength] = 0;
525 JSString *retstr = js_NewString(cx, newchars, newlength);
530 rval->setString(retstr);
536 str_escape(JSContext *cx, uintN argc, Value *vp)
538 return js_str_escape(cx, argc, vp, vp);
541 /* See ECMA-262 Edition 3 B.2.2 */
543 str_unescape(JSContext *cx, uintN argc, Value *vp)
545 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
549 size_t length = str->length();
550 const jschar *chars = str->chars();
552 /* Don't bother allocating less space for the new string. */
553 jschar *newchars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
556 size_t ni = 0, i = 0;
558 jschar ch = chars[i++];
560 if (i + 1 < length &&
561 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
563 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
565 } else if (i + 4 < length && chars[i] == 'u' &&
566 JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
567 JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
569 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
570 + JS7_UNHEX(chars[i + 2])) << 4)
571 + JS7_UNHEX(chars[i + 3])) << 4)
572 + JS7_UNHEX(chars[i + 4]);
580 JSString *retstr = js_NewString(cx, newchars, ni);
585 vp->setString(retstr);
591 str_uneval(JSContext *cx, uintN argc, Value *vp)
595 str = js_ValueToSource(cx, argc != 0 ? vp[2] : UndefinedValue());
603 const char js_escape_str[] = "escape";
604 const char js_unescape_str[] = "unescape";
606 const char js_uneval_str[] = "uneval";
608 const char js_decodeURI_str[] = "decodeURI";
609 const char js_encodeURI_str[] = "encodeURI";
610 const char js_decodeURIComponent_str[] = "decodeURIComponent";
611 const char js_encodeURIComponent_str[] = "encodeURIComponent";
613 static JSFunctionSpec string_functions[] = {
614 JS_FN(js_escape_str, str_escape, 1,0),
615 JS_FN(js_unescape_str, str_unescape, 1,0),
617 JS_FN(js_uneval_str, str_uneval, 1,0),
619 JS_FN(js_decodeURI_str, str_decodeURI, 1,0),
620 JS_FN(js_encodeURI_str, str_encodeURI, 1,0),
621 JS_FN(js_decodeURIComponent_str, str_decodeURI_Component, 1,0),
622 JS_FN(js_encodeURIComponent_str, str_encodeURI_Component, 1,0),
627 jschar js_empty_ucstr[] = {0};
628 JSSubString js_EmptySubString = {0, js_empty_ucstr};
631 str_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
635 if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
636 if (obj->getClass() == &js_StringClass) {
637 /* Follow ECMA-262 by fetching intrinsic length of our string. */
638 str = obj->getPrimitiveThis().toString();
640 /* Preserve compatibility: convert obj to a string primitive. */
641 str = js_ValueToString(cx, ObjectValue(*obj));
646 vp->setInt32(str->length());
652 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
655 str_enumerate(JSContext *cx, JSObject *obj)
657 JSString *str, *str1;
660 str = obj->getPrimitiveThis().toString();
662 length = str->length();
663 for (i = 0; i < length; i++) {
664 str1 = js_NewDependentString(cx, str, i, 1);
667 if (!obj->defineProperty(cx, INT_TO_JSID(i), StringValue(str1),
668 PropertyStub, StrictPropertyStub,
669 STRING_ELEMENT_ATTRS)) {
674 return obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
675 UndefinedValue(), NULL, NULL,
676 JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED);
680 str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
683 if (!JSID_IS_INT(id))
686 JSString *str = obj->getPrimitiveThis().toString();
688 jsint slot = JSID_TO_INT(id);
689 if ((size_t)slot < str->length()) {
690 JSString *str1 = JSString::getUnitString(cx, str, size_t(slot));
693 if (!obj->defineProperty(cx, id, StringValue(str1), NULL, NULL,
694 STRING_ELEMENT_ATTRS)) {
702 Class js_StringClass = {
704 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE |
705 JSCLASS_HAS_CACHED_PROTO(JSProto_String),
706 PropertyStub, /* addProperty */
707 PropertyStub, /* delProperty */
709 StrictPropertyStub, /* setProperty */
711 (JSResolveOp)str_resolve,
716 * Returns a JSString * for the |this| value associated with vp, or throws a
717 * TypeError if |this| is null or undefined. This algorithm is the same as
718 * calling CheckObjectCoercible(this), then returning ToString(this), as all
719 * String.prototype.* methods do.
721 static JS_ALWAYS_INLINE JSString *
722 ThisToStringForStringProto(JSContext *cx, Value *vp)
724 if (vp[1].isString())
725 return vp[1].toString();
727 if (vp[1].isObject()) {
728 JSObject *obj = &vp[1].toObject();
729 if (obj->getClass() == &js_StringClass &&
730 ClassMethodIsNative(cx, obj,
732 ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
735 vp[1] = obj->getPrimitiveThis();
736 return vp[1].toString();
738 } else if (vp[1].isNullOrUndefined()) {
739 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
740 vp[1].isNull() ? "null" : "undefined", "object");
744 JSString *str = js_ValueToString(cx, vp[1]);
747 vp[1].setString(str);
754 * String.prototype.quote is generic (as are most string methods), unlike
755 * toSource, toString, and valueOf.
758 str_quote(JSContext *cx, uintN argc, Value *vp)
760 JSString *str = ThisToStringForStringProto(cx, vp);
763 str = js_QuoteString(cx, str, '"');
771 str_toSource(JSContext *cx, uintN argc, Value *vp)
774 if (!GetPrimitiveThis(cx, vp, &str))
777 str = js_QuoteString(cx, str, '"');
782 size_t j = JS_snprintf(buf, sizeof buf, "(new String(");
784 JS::Anchor<JSString *> anchor(str);
785 size_t k = str->length();
786 const jschar *s = str->getChars(cx);
790 size_t n = j + k + 2;
791 jschar *t = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
796 for (i = 0; i < j; i++)
798 for (j = 0; j < k; i++, j++)
804 str = js_NewString(cx, t, n);
813 #endif /* JS_HAS_TOSOURCE */
816 js_str_toString(JSContext *cx, uintN argc, Value *vp)
819 if (!GetPrimitiveThis(cx, vp, &str))
826 * Java-like string native methods.
829 JS_ALWAYS_INLINE bool
830 ValueToIntegerRange(JSContext *cx, const Value &v, int32 *out)
837 if (!ValueToNumber(cx, v, &d))
840 d = js_DoubleToInteger(d);
843 else if (d < INT32_MIN)
853 str_substring(JSContext *cx, uintN argc, Value *vp)
855 JSString *str = ThisToStringForStringProto(cx, vp);
859 int32 length, begin, end;
861 end = length = int32(str->length());
863 if (!ValueToIntegerRange(cx, vp[2], &begin))
868 else if (begin > length)
871 if (argc > 1 && !vp[3].isUndefined()) {
872 if (!ValueToIntegerRange(cx, vp[3], &end))
888 str = js_NewDependentString(cx, str, size_t(begin), size_t(end - begin));
897 JSString* JS_FASTCALL
898 js_toLowerCase(JSContext *cx, JSString *str)
900 size_t n = str->length();
901 const jschar *s = str->getChars(cx);
905 jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
908 for (size_t i = 0; i < n; i++)
909 news[i] = JS_TOLOWER(s[i]);
911 str = js_NewString(cx, news, n);
920 str_toLowerCase(JSContext *cx, uintN argc, Value *vp)
922 JSString *str = ThisToStringForStringProto(cx, vp);
925 str = js_toLowerCase(cx, str);
933 str_toLocaleLowerCase(JSContext *cx, uintN argc, Value *vp)
936 * Forcefully ignore the first (or any) argument and return toLowerCase(),
937 * ECMA has reserved that argument, presumably for defining the locale.
939 if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
940 JSString *str = ThisToStringForStringProto(cx, vp);
943 return cx->localeCallbacks->localeToLowerCase(cx, str, Jsvalify(vp));
946 return str_toLowerCase(cx, 0, vp);
949 JSString* JS_FASTCALL
950 js_toUpperCase(JSContext *cx, JSString *str)
952 size_t n = str->length();
953 const jschar *s = str->getChars(cx);
956 jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
959 for (size_t i = 0; i < n; i++)
960 news[i] = JS_TOUPPER(s[i]);
962 str = js_NewString(cx, news, n);
971 str_toUpperCase(JSContext *cx, uintN argc, Value *vp)
973 JSString *str = ThisToStringForStringProto(cx, vp);
976 str = js_toUpperCase(cx, str);
984 str_toLocaleUpperCase(JSContext *cx, uintN argc, Value *vp)
987 * Forcefully ignore the first (or any) argument and return toUpperCase(),
988 * ECMA has reserved that argument, presumably for defining the locale.
990 if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
991 JSString *str = ThisToStringForStringProto(cx, vp);
994 return cx->localeCallbacks->localeToUpperCase(cx, str, Jsvalify(vp));
997 return str_toUpperCase(cx, 0, vp);
1001 str_localeCompare(JSContext *cx, uintN argc, Value *vp)
1003 JSString *str = ThisToStringForStringProto(cx, vp);
1010 JSString *thatStr = js_ValueToString(cx, vp[2]);
1013 if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
1014 vp[2].setString(thatStr);
1015 return cx->localeCallbacks->localeCompare(cx, str, thatStr, Jsvalify(vp));
1018 if (!CompareStrings(cx, str, thatStr, &result))
1020 vp->setInt32(result);
1026 js_str_charAt(JSContext *cx, uintN argc, Value *vp)
1032 if (vp[1].isString() && argc != 0 && vp[2].isInt32()) {
1033 str = vp[1].toString();
1034 i = vp[2].toInt32();
1035 if ((size_t)i >= str->length())
1038 str = ThisToStringForStringProto(cx, vp);
1045 if (!ValueToNumber(cx, vp[2], &d))
1047 d = js_DoubleToInteger(d);
1050 if (d < 0 || str->length() <= d)
1055 str = JSString::getUnitString(cx, str, size_t(i));
1062 vp->setString(cx->runtime->emptyString);
1067 js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
1071 if (vp[1].isString() && argc != 0 && vp[2].isInt32()) {
1072 str = vp[1].toString();
1073 i = vp[2].toInt32();
1074 if ((size_t)i >= str->length())
1077 str = ThisToStringForStringProto(cx, vp);
1085 if (!ValueToNumber(cx, vp[2], &d))
1087 d = js_DoubleToInteger(d);
1090 if (d < 0 || str->length() <= d)
1095 const jschar *chars;
1096 chars = str->getChars(cx);
1100 vp->setInt32(chars[i]);
1104 vp->setDouble(js_NaN);
1109 js_BoyerMooreHorspool(const jschar *text, jsuint textlen,
1110 const jschar *pat, jsuint patlen)
1112 uint8 skip[sBMHCharSetSize];
1114 JS_ASSERT(0 < patlen && patlen <= sBMHPatLenMax);
1115 for (jsuint i = 0; i < sBMHCharSetSize; i++)
1116 skip[i] = (uint8)patlen;
1117 jsuint m = patlen - 1;
1118 for (jsuint i = 0; i < m; i++) {
1120 if (c >= sBMHCharSetSize)
1121 return sBMHBadPattern;
1122 skip[c] = (uint8)(m - i);
1127 k += ((c = text[k]) >= sBMHCharSetSize) ? patlen : skip[c]) {
1128 for (jsuint i = k, j = m; ; i--, j--) {
1129 if (text[i] != pat[j])
1132 return static_cast<jsint>(i); /* safe: max string size */
1139 typedef jsuint Extent;
1140 static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) {
1141 return (patlen - 1) * sizeof(jschar);
1143 static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) {
1144 return memcmp(p, t, extent) == 0;
1149 typedef const jschar *Extent;
1150 static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) {
1151 return pat + patlen;
1153 static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) {
1154 for (; p != extent; ++p, ++t) {
1162 template <class InnerMatch>
1164 UnrolledMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen)
1166 JS_ASSERT(patlen > 0 && textlen > 0);
1167 const jschar *textend = text + textlen - (patlen - 1);
1168 const jschar p0 = *pat;
1169 const jschar *const patNext = pat + 1;
1170 const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen);
1173 const jschar *t = text;
1174 switch ((textend - t) & 7) {
1175 case 0: if (*t++ == p0) { fixup = 8; goto match; }
1176 case 7: if (*t++ == p0) { fixup = 7; goto match; }
1177 case 6: if (*t++ == p0) { fixup = 6; goto match; }
1178 case 5: if (*t++ == p0) { fixup = 5; goto match; }
1179 case 4: if (*t++ == p0) { fixup = 4; goto match; }
1180 case 3: if (*t++ == p0) { fixup = 3; goto match; }
1181 case 2: if (*t++ == p0) { fixup = 2; goto match; }
1182 case 1: if (*t++ == p0) { fixup = 1; goto match; }
1184 while (t != textend) {
1185 if (t[0] == p0) { t += 1; fixup = 8; goto match; }
1186 if (t[1] == p0) { t += 2; fixup = 7; goto match; }
1187 if (t[2] == p0) { t += 3; fixup = 6; goto match; }
1188 if (t[3] == p0) { t += 4; fixup = 5; goto match; }
1189 if (t[4] == p0) { t += 5; fixup = 4; goto match; }
1190 if (t[5] == p0) { t += 6; fixup = 3; goto match; }
1191 if (t[6] == p0) { t += 7; fixup = 2; goto match; }
1192 if (t[7] == p0) { t += 8; fixup = 1; goto match; }
1198 if (!InnerMatch::match(patNext, t, extent))
1200 return t - text - 1;
1203 } while (--fixup > 0);
1208 static JS_ALWAYS_INLINE jsint
1209 StringMatch(const jschar *text, jsuint textlen,
1210 const jschar *pat, jsuint patlen)
1214 if (textlen < patlen)
1217 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1219 * Given enough registers, the unrolled loop below is faster than the
1220 * following loop. 32-bit x86 does not have enough registers.
1223 const jschar p0 = *pat;
1224 for (const jschar *c = text, *end = text + textlen; c != end; ++c) {
1233 * If the text or pattern string is short, BMH will be more expensive than
1234 * the basic linear scan due to initialization cost and a more complex loop
1235 * body. While the correct threshold is input-dependent, we can make a few
1236 * conservative observations:
1237 * - When |textlen| is "big enough", the initialization time will be
1238 * proportionally small, so the worst-case slowdown is minimized.
1239 * - When |patlen| is "too small", even the best case for BMH will be
1240 * slower than a simple scan for large |textlen| due to the more complex
1242 * From this, the values for "big enough" and "too small" are determined
1243 * empirically. See bug 526348.
1245 if (textlen >= 512 && patlen >= 11 && patlen <= sBMHPatLenMax) {
1246 jsint index = js_BoyerMooreHorspool(text, textlen, pat, patlen);
1247 if (index != sBMHBadPattern)
1252 * For big patterns with large potential overlap we want the SIMD-optimized
1253 * speed of memcmp. For small patterns, a simple loop is faster.
1255 * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1258 #if !defined(__linux__)
1259 patlen > 128 ? UnrolledMatch<MemCmp>(text, textlen, pat, patlen)
1262 UnrolledMatch<ManualCmp>(text, textlen, pat, patlen);
1265 static const size_t sRopeMatchThresholdRatioLog2 = 5;
1268 * RopeMatch takes the text to search, the patern to search for in the text.
1269 * RopeMatch returns false on OOM and otherwise returns the match index through
1270 * the 'match' outparam (-1 for not found).
1273 RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, jsint *match)
1275 JS_ASSERT(textstr->isRope());
1281 if (textstr->length() < patlen) {
1287 * List of leaf nodes in the rope. If we run out of memory when trying to
1288 * append to this list, we can still fall back to StringMatch, so use the
1289 * system allocator so we don't report OOM in that case.
1291 Vector<JSString *, 16, SystemAllocPolicy> strs;
1294 * We don't want to do rope matching if there is a poor node-to-char ratio,
1295 * since this means spending a lot of time in the match loop below. We also
1296 * need to build the list of leaf nodes. Do both here: iterate over the
1297 * nodes so long as there are not too many.
1300 size_t textstrlen = textstr->length();
1301 size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
1302 StringSegmentRange r(cx);
1303 if (!r.init(textstr))
1305 while (!r.empty()) {
1306 if (threshold-- == 0 || !strs.append(r.front())) {
1307 const jschar *chars = textstr->getChars(cx);
1310 *match = StringMatch(chars, textstrlen, pat, patlen);
1318 /* Absolute offset from the beginning of the logical string textstr. */
1321 // TODO: consider branching to a simple loop if patlen == 1
1323 for (JSString **outerp = strs.begin(); outerp != strs.end(); ++outerp) {
1324 /* First try to match without spanning two nodes. */
1325 JSString *outer = *outerp;
1326 const jschar *chars = outer->nonRopeChars();
1327 size_t len = outer->length();
1328 jsint matchResult = StringMatch(chars, len, pat, patlen);
1329 if (matchResult != -1) {
1330 *match = pos + matchResult;
1334 /* Test the overlap. */
1335 JSString **innerp = outerp;
1338 * Start searching at the first place where StringMatch wouldn't have
1341 const jschar *const text = chars + (patlen > len ? 0 : len - patlen + 1);
1342 const jschar *const textend = chars + len;
1343 const jschar p0 = *pat;
1344 const jschar *const p1 = pat + 1;
1345 const jschar *const patend = pat + patlen;
1346 for (const jschar *t = text; t != textend; ) {
1349 const jschar *ttend = textend;
1350 for (const jschar *pp = p1, *tt = t; pp != patend; ++pp, ++tt) {
1351 while (tt == ttend) {
1352 if (++innerp == strs.end()) {
1356 JSString *inner = *innerp;
1357 tt = inner->nonRopeChars();
1358 ttend = tt + inner->length();
1361 goto break_continue;
1365 *match = pos + (t - chars) - 1; /* -1 because of *t++ above */
1379 str_indexOf(JSContext *cx, uintN argc, Value *vp)
1381 JSString *str = ThisToStringForStringProto(cx, vp);
1385 JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0);
1389 jsuint textlen = str->length();
1390 const jschar *text = str->getChars(cx);
1394 jsuint patlen = patstr->length();
1395 const jschar *pat = patstr->chars();
1399 if (vp[3].isInt32()) {
1400 jsint i = vp[3].toInt32();
1403 } else if (jsuint(i) > textlen) {
1413 if (!ValueToNumber(cx, vp[3], &d))
1415 d = js_DoubleToInteger(d);
1418 } else if (d > textlen) {
1431 jsint match = StringMatch(text, textlen, pat, patlen);
1432 vp->setInt32((match == -1) ? -1 : start + match);
1437 str_lastIndexOf(JSContext *cx, uintN argc, Value *vp)
1439 JSString *textstr = ThisToStringForStringProto(cx, vp);
1442 size_t textlen = textstr->length();
1443 const jschar *text = textstr->getChars(cx);
1447 JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0);
1451 size_t patlen = patstr->length();
1452 const jschar *pat = patstr->chars();
1454 jsint i = textlen - patlen; // Start searching here
1461 if (vp[3].isInt32()) {
1462 jsint j = vp[3].toInt32();
1469 if (!ValueToNumber(cx, vp[3], &d))
1471 if (!JSDOUBLE_IS_NaN(d)) {
1472 d = js_DoubleToInteger(d);
1486 const jschar *t = text + i;
1487 const jschar *textend = text - 1;
1488 const jschar p0 = *pat;
1489 const jschar *patNext = pat + 1;
1490 const jschar *patEnd = pat + patlen;
1492 for (; t != textend; --t) {
1494 const jschar *t1 = t + 1;
1495 for (const jschar *p1 = patNext; p1 != patEnd; ++p1, ++t1) {
1497 goto break_continue;
1499 vp->setInt32(t - text);
1510 js_TrimString(JSContext *cx, Value *vp, JSBool trimLeft, JSBool trimRight)
1512 JSString *str = ThisToStringForStringProto(cx, vp);
1515 size_t length = str->length();
1516 const jschar *chars = str->getChars(cx);
1521 size_t end = length;
1524 while (begin < length && JS_ISSPACE(chars[begin]))
1529 while (end > begin && JS_ISSPACE(chars[end-1]))
1533 str = js_NewDependentString(cx, str, begin, end - begin);
1542 str_trim(JSContext *cx, uintN argc, Value *vp)
1544 return js_TrimString(cx, vp, JS_TRUE, JS_TRUE);
1548 str_trimLeft(JSContext *cx, uintN argc, Value *vp)
1550 return js_TrimString(cx, vp, JS_TRUE, JS_FALSE);
1554 str_trimRight(JSContext *cx, uintN argc, Value *vp)
1556 return js_TrimString(cx, vp, JS_FALSE, JS_TRUE);
1560 * Perl-inspired string functions.
1563 /* Result of a successfully performed flat match. */
1566 JSLinearString *patstr;
1571 friend class RegExpGuard;
1574 FlatMatch() : patstr(NULL) {} /* Old GCC wants this initialization. */
1575 JSString *pattern() const { return patstr; }
1576 size_t patternLength() const { return patlen; }
1579 * Note: The match is -1 when the match is performed successfully,
1580 * but no match is found.
1582 int32 match() const { return match_; }
1585 /* A regexp and optional associated object. */
1588 AutoRefCount<RegExp> re_;
1591 explicit RegExpPair(RegExpPair &);
1594 explicit RegExpPair(JSContext *cx) : re_(cx) {}
1596 void reset(JSObject &obj) {
1598 RegExp *re = RegExp::extractFrom(reobj_);
1600 re_.reset(NeedsIncRef<RegExp>(re));
1603 void reset(AlreadyIncRefed<RegExp> re) {
1608 /* Note: May be null. */
1609 JSObject *reobj() const { return reobj_; }
1610 bool hasRegExp() const { return !re_.null(); }
1611 RegExp &re() const { JS_ASSERT(hasRegExp()); return *re_; }
1615 * RegExpGuard factors logic out of String regexp operations.
1617 * @param optarg Indicates in which argument position RegExp
1618 * flags will be found, if present. This is a Mozilla
1619 * extension and not part of any ECMA spec.
1623 RegExpGuard(const RegExpGuard &);
1624 void operator=(const RegExpGuard &);
1631 * Upper bound on the number of characters we are willing to potentially
1632 * waste on searching for RegExp meta-characters.
1634 static const size_t MAX_FLAT_PAT_LEN = 256;
1636 static JSString *flattenPattern(JSContext *cx, JSLinearString *patstr) {
1637 StringBuffer sb(cx);
1638 if (!sb.reserve(patstr->length()))
1641 static const jschar ESCAPE_CHAR = '\\';
1642 const jschar *chars = patstr->chars();
1643 size_t len = patstr->length();
1644 for (const jschar *it = chars; it != chars + len; ++it) {
1645 if (RegExp::isMetaChar(*it)) {
1646 if (!sb.append(ESCAPE_CHAR) || !sb.append(*it))
1649 if (!sb.append(*it))
1653 return sb.finishString();
1657 explicit RegExpGuard(JSContext *cx) : cx(cx), rep(cx) {}
1660 /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1662 init(uintN argc, Value *vp)
1664 if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) {
1665 rep.reset(vp[2].toObject());
1667 fm.patstr = ArgToRootedString(cx, argc, vp, 0);
1675 * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1676 * pattern string, or a lengthy pattern string can thwart this process.
1678 * @param checkMetaChars Look for regexp metachars in the pattern string.
1679 * @return Whether flat matching could be used.
1681 * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->isExceptionPending().
1684 tryFlatMatch(JSContext *cx, JSString *textstr, uintN optarg, uintN argc,
1685 bool checkMetaChars = true)
1687 if (rep.hasRegExp())
1690 fm.pat = fm.patstr->chars();
1691 fm.patlen = fm.patstr->length();
1696 if (checkMetaChars &&
1697 (fm.patlen > MAX_FLAT_PAT_LEN || RegExp::hasMetaChars(fm.pat, fm.patlen))) {
1702 * textstr could be a rope, so we want to avoid flattening it for as
1705 if (textstr->isRope()) {
1706 if (!RopeMatch(cx, textstr, fm.pat, fm.patlen, &fm.match_))
1709 const jschar *text = textstr->nonRopeChars();
1710 size_t textlen = textstr->length();
1711 fm.match_ = StringMatch(text, textlen, fm.pat, fm.patlen);
1716 /* If the pattern is not already a regular expression, make it so. */
1718 normalizeRegExp(bool flat, uintN optarg, uintN argc, Value *vp)
1720 if (rep.hasRegExp())
1723 /* Build RegExp from pattern string. */
1725 if (optarg < argc) {
1726 opt = js_ValueToString(cx, vp[2 + optarg]);
1735 patstr = flattenPattern(cx, fm.patstr);
1743 AlreadyIncRefed<RegExp> re = RegExp::createFlagged(cx, patstr, opt);
1751 bool hasRegExpPair() const { return rep.hasRegExp(); }
1755 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1756 static JS_ALWAYS_INLINE bool
1757 Matched(bool test, const Value &v)
1759 return test ? v.isTrue() : !v.isNull();
1762 typedef bool (*DoMatchCallback)(JSContext *cx, RegExpStatics *res, size_t count, void *data);
1765 * BitOR-ing these flags allows the DoMatch caller to control when how the
1766 * RegExp engine is called and when callbacks are fired.
1768 enum MatchControlFlags {
1769 TEST_GLOBAL_BIT = 0x1, /* use RegExp.test for global regexps */
1770 TEST_SINGLE_BIT = 0x2, /* use RegExp.test for non-global regexps */
1771 CALLBACK_ON_SINGLE_BIT = 0x4, /* fire callback on non-global match */
1773 MATCH_ARGS = TEST_GLOBAL_BIT,
1774 MATCHALL_ARGS = CALLBACK_ON_SINGLE_BIT,
1775 REPLACE_ARGS = TEST_GLOBAL_BIT | TEST_SINGLE_BIT | CALLBACK_ON_SINGLE_BIT
1778 /* Factor out looping and matching logic. */
1780 DoMatch(JSContext *cx, RegExpStatics *res, Value *vp, JSString *str, const RegExpPair &rep,
1781 DoMatchCallback callback, void *data, MatchControlFlags flags)
1783 RegExp &re = rep.re();
1785 /* global matching ('g') */
1786 bool testGlobal = flags & TEST_GLOBAL_BIT;
1788 rep.reobj()->zeroRegExpLastIndex();
1789 for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
1790 if (!re.execute(cx, res, str, &i, testGlobal, vp))
1792 if (!Matched(testGlobal, *vp))
1794 if (!callback(cx, res, count, data))
1796 if (!res->matched())
1801 bool testSingle = !!(flags & TEST_SINGLE_BIT),
1802 callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
1804 if (!re.execute(cx, res, str, &i, testSingle, vp))
1806 if (callbackOnSingle && Matched(testSingle, *vp) && !callback(cx, res, 0, data))
1813 BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value *vp)
1815 if (fm.match() < 0) {
1820 /* For this non-global match, produce a RegExp.exec-style array. */
1821 JSObject *obj = NewSlowEmptyArray(cx);
1824 vp->setObject(*obj);
1826 return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(fm.pattern())) &&
1827 obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom),
1828 Int32Value(fm.match())) &&
1829 obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom),
1830 StringValue(textstr));
1833 typedef JSObject **MatchArgType;
1836 * DoMatch will only callback on global matches, hence this function builds
1837 * only the "array of matches" returned by match on global regexps.
1840 MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
1842 JS_ASSERT(count <= JSID_INT_MAX); /* by max string length */
1844 JSObject *&arrayobj = *static_cast<MatchArgType>(p);
1846 arrayobj = NewDenseEmptyArray(cx);
1852 if (!res->createLastMatch(cx, &v))
1855 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
1856 return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false);
1860 str_match(JSContext *cx, uintN argc, Value *vp)
1862 JSString *str = ThisToStringForStringProto(cx, vp);
1867 if (!g.init(argc, vp))
1869 if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc))
1870 return BuildFlatMatchArray(cx, str, *fm, vp);
1871 if (cx->isExceptionPending()) /* from tryFlatMatch */
1874 const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
1878 AutoObjectRooter array(cx);
1879 MatchArgType arg = array.addr();
1880 RegExpStatics *res = cx->regExpStatics();
1881 if (!DoMatch(cx, res, vp, str, *rep, MatchCallback, arg, MATCH_ARGS))
1884 /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1885 if (rep->re().global())
1886 vp->setObjectOrNull(array.object());
1891 str_search(JSContext *cx, uintN argc, Value *vp)
1893 JSString *str = ThisToStringForStringProto(cx, vp);
1898 if (!g.init(argc, vp))
1900 if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc)) {
1901 vp->setInt32(fm->match());
1904 if (cx->isExceptionPending()) /* from tryFlatMatch */
1906 const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
1910 RegExpStatics *res = cx->regExpStatics();
1912 if (!rep->re().execute(cx, res, str, &i, true, vp))
1916 vp->setInt32(res->matchStart());
1924 ReplaceData(JSContext *cx)
1928 JSString *str; /* 'this' parameter object as a string */
1929 RegExpGuard g; /* regexp parameter object and private data */
1930 JSObject *lambda; /* replacement function object or null */
1931 JSObject *elembase; /* object for function(a){return b[a]} replace */
1932 JSLinearString *repstr; /* replacement string */
1933 const jschar *dollar; /* null or pointer to first $ in repstr */
1934 const jschar *dollarEnd; /* limit pointer for js_strchr_limit */
1935 jsint leftIndex; /* left context index in str->chars */
1936 JSSubString dollarStr; /* for "$$" InterpretDollar result */
1937 bool calledBack; /* record whether callback has been called */
1938 InvokeSessionGuard session; /* arguments for repeated lambda Invoke call */
1939 InvokeArgsGuard singleShot; /* arguments for single lambda Invoke call */
1940 StringBuffer sb; /* buffer built during DoMatch */
1944 InterpretDollar(JSContext *cx, RegExpStatics *res, const jschar *dp, const jschar *ep,
1945 ReplaceData &rdata, JSSubString *out, size_t *skip)
1947 JS_ASSERT(*dp == '$');
1949 /* If there is only a dollar, bail now */
1953 /* Interpret all Perl match-induced dollar variables. */
1955 if (JS7_ISDEC(dc)) {
1956 /* ECMA-262 Edition 3: 1-9 or 01-99 */
1957 uintN num = JS7_UNDEC(dc);
1958 if (num > res->parenCount())
1961 const jschar *cp = dp + 2;
1962 if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
1963 uintN tmp = 10 * num + JS7_UNDEC(dc);
1964 if (tmp <= res->parenCount()) {
1974 JS_ASSERT(num <= res->parenCount());
1977 * Note: we index to get the paren with the (1-indexed) pair
1978 * number, as opposed to a (0-indexed) paren number.
1980 res->getParen(num, out);
1987 rdata.dollarStr.chars = dp;
1988 rdata.dollarStr.length = 1;
1989 *out = rdata.dollarStr;
1992 res->getLastMatch(out);
1995 res->getLastParen(out);
1998 res->getLeftContext(out);
2001 res->getRightContext(out);
2008 FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
2010 JSObject *base = rdata.elembase;
2013 * The base object is used when replace was passed a lambda which looks like
2014 * 'function(a) { return b[a]; }' for the base object b. b will not change
2015 * in the course of the replace unless we end up making a scripted call due
2016 * to accessing a scripted getter or a value with a scripted toString.
2018 JS_ASSERT(rdata.lambda);
2019 JS_ASSERT(!base->getOps()->lookupProperty);
2020 JS_ASSERT(!base->getOps()->getProperty);
2023 if (!res->createLastMatch(cx, &match))
2025 JSString *str = match.toString();
2028 if (str->isAtomized()) {
2029 atom = STRING_TO_ATOM(str);
2031 atom = js_AtomizeString(cx, str, 0);
2035 jsid id = ATOM_TO_JSID(atom);
2038 JSProperty *prop = NULL;
2039 if (js_LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop) < 0)
2042 /* Only handle the case where the property exists and is on this object. */
2043 if (prop && holder == base) {
2044 Shape *shape = (Shape *) prop;
2045 if (shape->slot != SHAPE_INVALID_SLOT && shape->hasDefaultGetter()) {
2046 Value value = base->getSlot(shape->slot);
2047 if (value.isString()) {
2048 rdata.repstr = value.toString()->ensureLinear(cx);
2051 *sizep = rdata.repstr->length();
2058 * Couldn't handle this property, fall through and despecialize to the
2059 * general lambda case.
2061 rdata.elembase = NULL;
2064 JSObject *lambda = rdata.lambda;
2067 * In the lambda case, not only do we find the replacement string's
2068 * length, we compute repstr and return it via rdata for use within
2069 * DoReplace. The lambda is called with arguments ($&, $1, $2, ...,
2070 * index, input), i.e., all the properties of a regexp match array.
2071 * For $&, etc., we must create string jsvals from cx->regExpStatics.
2072 * We grab up stack space to keep the newborn strings GC-rooted.
2074 uintN p = res->parenCount();
2075 uintN argc = 1 + p + 2;
2077 InvokeSessionGuard &session = rdata.session;
2078 if (!session.started()) {
2079 Value lambdav = ObjectValue(*lambda);
2080 if (!session.start(cx, lambdav, UndefinedValue(), argc))
2084 PreserveRegExpStatics staticsGuard(res);
2085 if (!staticsGuard.init(cx))
2088 /* Push $&, $1, $2, ... */
2090 if (!res->createLastMatch(cx, &session[argi++]))
2093 for (size_t i = 0; i < res->parenCount(); ++i) {
2094 if (!res->createParen(cx, i + 1, &session[argi++]))
2098 /* Push match index and input string. */
2099 session[argi++].setInt32(res->matchStart());
2100 session[argi].setString(rdata.str);
2102 if (!session.invoke(cx))
2105 /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2106 JSString *repstr = ValueToString_TestForStringInline(cx, session.rval());
2109 rdata.repstr = repstr->ensureLinear(cx);
2112 *sizep = rdata.repstr->length();
2116 JSString *repstr = rdata.repstr;
2117 size_t replen = repstr->length();
2118 for (const jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp;
2119 dp = js_strchr_limit(dp, '$', ep)) {
2122 if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) {
2123 replen += sub.length - skip;
2134 * Precondition: |rdata.sb| already has necessary growth space reserved (as
2135 * derived from FindReplaceLength).
2138 DoReplace(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
2140 JSLinearString *repstr = rdata.repstr;
2142 const jschar *bp = cp = repstr->chars();
2144 const jschar *dp = rdata.dollar;
2145 const jschar *ep = rdata.dollarEnd;
2146 for (; dp; dp = js_strchr_limit(dp, '$', ep)) {
2147 /* Move one of the constant portions of the replacement value. */
2148 size_t len = dp - cp;
2149 JS_ALWAYS_TRUE(rdata.sb.append(cp, len));
2154 if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) {
2156 JS_ALWAYS_TRUE(rdata.sb.append(sub.chars, len));
2163 JS_ALWAYS_TRUE(rdata.sb.append(cp, repstr->length() - (cp - bp)));
2167 ReplaceRegExpCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
2169 ReplaceData &rdata = *static_cast<ReplaceData *>(p);
2171 rdata.calledBack = true;
2172 JSLinearString *str = rdata.str->assertIsLinear(); /* flattened for regexp */
2173 size_t leftoff = rdata.leftIndex;
2174 const jschar *left = str->chars() + leftoff;
2175 size_t leftlen = res->matchStart() - leftoff;
2176 rdata.leftIndex = res->matchLimit();
2178 size_t replen = 0; /* silence 'unused' warning */
2179 if (!FindReplaceLength(cx, res, rdata, &replen))
2182 size_t growth = leftlen + replen;
2183 if (!rdata.sb.reserve(rdata.sb.length() + growth))
2185 JS_ALWAYS_TRUE(rdata.sb.append(left, leftlen)); /* skipped-over portion of the search value */
2186 DoReplace(cx, res, rdata);
2191 BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr,
2192 const FlatMatch &fm, Value *vp)
2194 RopeBuilder builder(cx);
2195 size_t match = fm.match();
2196 size_t matchEnd = match + fm.patternLength();
2198 if (textstr->isRope()) {
2200 * If we are replacing over a rope, avoid flattening it by iterating
2201 * through it, building a new rope.
2203 StringSegmentRange r(cx);
2204 if (!r.init(textstr))
2207 while (!r.empty()) {
2208 JSString *str = r.front();
2209 size_t len = str->length();
2210 size_t strEnd = pos + len;
2211 if (pos < matchEnd && strEnd > match) {
2213 * We need to special-case any part of the rope that overlaps
2214 * with the replacement string.
2218 * If this part of the rope overlaps with the left side of
2219 * the pattern, then it must be the only one to overlap with
2220 * the first character in the pattern, so we include the
2221 * replacement string here.
2223 JSString *leftSide = js_NewDependentString(cx, str, 0, match - pos);
2225 !builder.append(leftSide) ||
2226 !builder.append(repstr)) {
2232 * If str runs off the end of the matched string, append the
2235 if (strEnd > matchEnd) {
2236 JSString *rightSide = js_NewDependentString(cx, str, matchEnd - pos,
2238 if (!rightSide || !builder.append(rightSide))
2242 if (!builder.append(str))
2245 pos += str->length();
2250 JSString *leftSide = js_NewDependentString(cx, textstr, 0, match);
2253 JSString *rightSide = js_NewDependentString(cx, textstr, match + fm.patternLength(),
2254 textstr->length() - match - fm.patternLength());
2256 !builder.append(leftSide) ||
2257 !builder.append(repstr) ||
2258 !builder.append(rightSide)) {
2263 vp->setString(builder.result());
2268 * Perform a linear-scan dollar substitution on the replacement text,
2269 * constructing a result string that looks like:
2271 * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2274 BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *repstr,
2275 const jschar *firstDollar, const FlatMatch &fm, Value *vp)
2277 JSLinearString *textstr = textstrArg->ensureLinear(cx);
2281 JS_ASSERT(repstr->chars() <= firstDollar && firstDollar < repstr->chars() + repstr->length());
2282 size_t matchStart = fm.match();
2283 size_t matchLimit = matchStart + fm.patternLength();
2288 * len(newstr) >= len(orig) - len(match) + len(replacement)
2290 * Note that dollar vars _could_ make the resulting text smaller than this.
2292 StringBuffer newReplaceChars(cx);
2293 if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))
2296 /* Move the pre-dollar chunk in bulk. */
2297 JS_ALWAYS_TRUE(newReplaceChars.append(repstr->chars(), firstDollar));
2299 /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2300 #define ENSURE(__cond) if (!(__cond)) return false;
2301 const jschar *repstrLimit = repstr->chars() + repstr->length();
2302 for (const jschar *it = firstDollar; it < repstrLimit; ++it) {
2303 if (*it != '$' || it == repstrLimit - 1) {
2304 ENSURE(newReplaceChars.append(*it));
2308 switch (*(it + 1)) {
2309 case '$': /* Eat one of the dollars. */
2310 ENSURE(newReplaceChars.append(*it));
2313 ENSURE(newReplaceChars.append(textstr->chars() + matchStart,
2314 textstr->chars() + matchLimit));
2317 ENSURE(newReplaceChars.append(textstr->chars(), textstr->chars() + matchStart));
2320 ENSURE(newReplaceChars.append(textstr->chars() + matchLimit,
2321 textstr->chars() + textstr->length()));
2323 default: /* The dollar we saw was not special (no matter what its mother told it). */
2324 ENSURE(newReplaceChars.append(*it));
2327 ++it; /* We always eat an extra char in the above switch. */
2330 JSString *leftSide = js_NewDependentString(cx, textstr, 0, matchStart);
2333 JSString *newReplace = newReplaceChars.finishString();
2336 JS_ASSERT(textstr->length() >= matchLimit);
2337 JSString *rightSide = js_NewDependentString(cx, textstr, matchLimit,
2338 textstr->length() - matchLimit);
2341 RopeBuilder builder(cx);
2342 ENSURE(builder.append(leftSide) &&
2343 builder.append(newReplace) &&
2344 builder.append(rightSide));
2347 vp->setString(builder.result());
2352 str_replace_regexp(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata)
2354 const RegExpPair *rep = rdata.g.normalizeRegExp(true, 2, argc, vp);
2358 rdata.leftIndex = 0;
2359 rdata.calledBack = false;
2361 RegExpStatics *res = cx->regExpStatics();
2362 if (!DoMatch(cx, res, vp, rdata.str, *rep, ReplaceRegExpCallback, &rdata, REPLACE_ARGS))
2365 if (!rdata.calledBack) {
2366 /* Didn't match, so the string is unmodified. */
2367 vp->setString(rdata.str);
2372 res->getRightContext(&sub);
2373 if (!rdata.sb.append(sub.chars, sub.length))
2376 JSString *retstr = rdata.sb.finishString();
2380 vp->setString(retstr);
2385 str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata,
2386 const FlatMatch &fm)
2388 JS_ASSERT(fm.match() >= 0);
2391 JSString *matchStr = js_NewDependentString(cx, rdata.str, fm.match(), fm.patternLength());
2395 /* lambda(matchStr, matchStart, textstr) */
2396 static const uint32 lambdaArgc = 3;
2397 if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.singleShot))
2400 CallArgs &args = rdata.singleShot;
2401 args.callee().setObject(*rdata.lambda);
2402 args.thisv().setUndefined();
2404 Value *sp = args.argv();
2405 sp[0].setString(matchStr);
2406 sp[1].setInt32(fm.match());
2407 sp[2].setString(rdata.str);
2409 if (!Invoke(cx, rdata.singleShot, 0))
2412 JSString *repstr = js_ValueToString(cx, args.rval());
2416 JSString *leftSide = js_NewDependentString(cx, rdata.str, 0, fm.match());
2420 size_t matchLimit = fm.match() + fm.patternLength();
2421 JSString *rightSide = js_NewDependentString(cx, rdata.str, matchLimit,
2422 rdata.str->length() - matchLimit);
2426 RopeBuilder builder(cx);
2427 if (!(builder.append(leftSide) &&
2428 builder.append(repstr) &&
2429 builder.append(rightSide))) {
2433 vp->setString(builder.result());
2438 js::str_replace(JSContext *cx, uintN argc, Value *vp)
2440 ReplaceData rdata(cx);
2441 rdata.str = ThisToStringForStringProto(cx, vp);
2444 static const uint32 optarg = 2;
2446 /* Extract replacement string/function. */
2447 if (argc >= optarg && js_IsCallable(vp[3])) {
2448 rdata.lambda = &vp[3].toObject();
2449 rdata.elembase = NULL;
2450 rdata.repstr = NULL;
2451 rdata.dollar = rdata.dollarEnd = NULL;
2453 if (rdata.lambda->isFunction()) {
2454 JSFunction *fun = rdata.lambda->getFunctionPrivate();
2455 if (fun->isInterpreted()) {
2457 * Pattern match the script to check if it is is indexing into a
2458 * particular object, e.g. 'function(a) { return b[a]; }'. Avoid
2459 * calling the script in such cases, which are used by javascript
2460 * packers (particularly the popular Dean Edwards packer) to efficiently
2461 * encode large scripts. We only handle the code patterns generated
2462 * by such packers here.
2464 JSScript *script = fun->u.i.script;
2465 jsbytecode *pc = script->code;
2467 Value table = UndefinedValue();
2468 if (JSOp(*pc) == JSOP_GETFCSLOT) {
2469 table = rdata.lambda->getFlatClosureUpvar(GET_UINT16(pc));
2470 pc += JSOP_GETFCSLOT_LENGTH;
2473 if (table.isObject() &&
2474 JSOp(*pc) == JSOP_GETARG && GET_SLOTNO(pc) == 0 &&
2475 JSOp(*(pc + JSOP_GETARG_LENGTH)) == JSOP_GETELEM &&
2476 JSOp(*(pc + JSOP_GETARG_LENGTH + JSOP_GETELEM_LENGTH)) == JSOP_RETURN) {
2477 Class *clasp = table.toObject().getClass();
2478 if (clasp->isNative() &&
2479 !clasp->ops.lookupProperty &&
2480 !clasp->ops.getProperty) {
2481 rdata.elembase = &table.toObject();
2487 rdata.lambda = NULL;
2488 rdata.elembase = NULL;
2489 rdata.repstr = ArgToRootedString(cx, argc, vp, 1);
2493 /* We're about to store pointers into the middle of our string. */
2494 if (!js_MakeStringImmutable(cx, rdata.repstr))
2496 rdata.dollarEnd = rdata.repstr->chars() + rdata.repstr->length();
2497 rdata.dollar = js_strchr_limit(rdata.repstr->chars(), '$',
2501 if (!rdata.g.init(argc, vp))
2505 * Unlike its |String.prototype| brethren, |replace| doesn't convert
2506 * its input to a regular expression. (Even if it contains metachars.)
2508 * However, if the user invokes our (non-standard) |flags| argument
2509 * extension then we revert to creating a regular expression. Note that
2510 * this is observable behavior through the side-effect mutation of the
2514 const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, optarg, argc, false);
2516 if (cx->isExceptionPending()) /* oom in RopeMatch in tryFlatMatch */
2518 JS_ASSERT_IF(!rdata.g.hasRegExpPair(), argc > optarg);
2519 return str_replace_regexp(cx, argc, vp, rdata);
2522 if (fm->match() < 0) {
2523 vp->setString(rdata.str);
2528 return str_replace_flat_lambda(cx, argc, vp, rdata, *fm);
2531 * Note: we could optimize the text.length == pattern.length case if we wanted,
2532 * even in the presence of dollar metachars.
2535 return BuildDollarReplacement(cx, rdata.str, rdata.repstr, rdata.dollar, *fm, vp);
2537 return BuildFlatReplacement(cx, rdata.str, rdata.repstr, *fm, vp);
2541 * Subroutine used by str_split to find the next split point in str, starting
2542 * at offset *ip and looking either for the separator substring given by sep, or
2543 * for the next re match. In the re case, return the matched separator in *sep,
2544 * and the possibly updated offset in *ip.
2546 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2547 * separator occurrence if found, or str->length if no separator is found.
2550 find_split(JSContext *cx, RegExpStatics *res, JSString *str, js::RegExp *re, jsint *ip,
2554 * Stop if past end of string. If at end of string, we will compare the
2555 * null char stored there (by js_NewString*) to sep->chars[j] in the while
2556 * loop at the end of this function, so that
2558 * "ab,".split(',') => ["ab", ""]
2560 * and the resulting array converts back to the string "ab," for symmetry.
2561 * However, we ape Perl and do this only if there is a sufficiently large
2562 * limit argument (see str_split).
2565 size_t length = str->length();
2566 if ((size_t)i > length)
2569 const jschar *chars = str->getChars(cx);
2574 * Match a regular expression against the separator at or above index i.
2575 * Call js_ExecuteRegExp with true for the test argument. On successful
2576 * match, get the separator from cx->regExpStatics.lastMatch.
2583 /* JS1.2 deviated from Perl by never matching at end of string. */
2585 if (!re->execute(cx, res, str, &index, true, &rval))
2587 if (!rval.isTrue()) {
2588 /* Mismatch: ensure our caller advances i past end of string. */
2594 res->getLastMatch(sep);
2595 if (sep->length == 0) {
2597 * Empty string match: never split on an empty match at the start
2598 * of a find_split cycle. Same rule as for an empty global match
2603 * "Bump-along" to avoid sticking at an empty match, but don't
2604 * bump past end of string -- our caller must do that by adding
2605 * sep->length to our return value.
2607 if ((size_t)i == length)
2612 if ((size_t)i == length) {
2614 * If there was a trivial zero-length match at the end of the
2615 * split, then we shouldn't output the matched string at the end
2616 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2621 JS_ASSERT((size_t)i >= sep->length);
2622 return i - sep->length;
2626 * Special case: if sep is the empty string, split str into one character
2627 * substrings. Let our caller worry about whether to split once at end of
2628 * string into an empty substring.
2630 if (sep->length == 0)
2631 return ((size_t)i == length) ? -1 : i + 1;
2634 * Now that we know sep is non-empty, search starting at i in str for an
2635 * occurrence of all of sep's chars. If we find them, return the index of
2636 * the first separator char. Otherwise, return length.
2638 jsint match = StringMatch(chars + i, length - i, sep->chars, sep->length);
2639 return match == -1 ? length : match + i;
2643 str_split(JSContext *cx, uintN argc, Value *vp)
2645 JSString *str = ThisToStringForStringProto(cx, vp);
2650 Value v = StringValue(str);
2651 JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
2654 vp->setObject(*aobj);
2659 JSSubString *sep, tmp;
2660 if (VALUE_IS_REGEXP(cx, vp[2])) {
2661 re = static_cast<RegExp *>(vp[2].toObject().getPrivate());
2664 /* Set a magic value so we can detect a successful re match. */
2668 JSString *sepstr = js_ValueToString(cx, vp[2]);
2671 vp[2].setString(sepstr);
2674 * Point sep at a local copy of sepstr's header because find_split
2675 * will modify sep->length.
2677 tmp.length = sepstr->length();
2678 tmp.chars = sepstr->getChars(cx);
2685 /* Use the second argument as the split limit, if given. */
2686 uint32 limit = 0; /* Avoid warning. */
2687 bool limited = (argc > 1) && !vp[3].isUndefined();
2690 if (!ValueToNumber(cx, vp[3], &d))
2693 /* Clamp limit between 0 and 1 + string length. */
2694 limit = js_DoubleToECMAUint32(d);
2695 if (limit > str->length())
2696 limit = 1 + str->length();
2699 AutoValueVector splits(cx);
2701 RegExpStatics *res = cx->regExpStatics();
2704 while ((j = find_split(cx, res, str, re, &i, sep)) >= 0) {
2705 if (limited && len >= limit)
2708 JSString *sub = js_NewDependentString(cx, str, i, size_t(j - i));
2709 if (!sub || !splits.append(StringValue(sub)))
2714 * Imitate perl's feature of including parenthesized substrings that
2715 * matched part of the delimiter in the new array, after the split
2716 * substring that was delimited.
2718 if (re && sep->chars) {
2719 for (uintN num = 0; num < res->parenCount(); num++) {
2720 if (limited && len >= limit)
2723 res->getParen(num + 1, &parsub);
2724 sub = js_NewStringCopyN(cx, parsub.chars, parsub.length);
2725 if (!sub || !splits.append(StringValue(sub)))
2731 i = j + sep->length;
2737 JSObject *aobj = NewDenseCopiedArray(cx, splits.length(), splits.begin());
2740 vp->setObject(*aobj);
2744 #if JS_HAS_PERL_SUBSTR
2746 str_substr(JSContext *cx, uintN argc, Value *vp)
2748 JSString *str = ThisToStringForStringProto(cx, vp);
2752 int32 length, len, begin;
2754 length = int32(str->length());
2755 if (!ValueToIntegerRange(cx, vp[2], &begin))
2758 if (begin >= length) {
2759 str = cx->runtime->emptyString;
2763 begin += length; /* length + INT_MIN will always be less then 0 */
2768 if (argc == 1 || vp[3].isUndefined()) {
2769 len = length - begin;
2771 if (!ValueToIntegerRange(cx, vp[3], &len))
2775 str = cx->runtime->emptyString;
2779 if (uint32(length) < uint32(begin + len))
2780 len = length - begin;
2783 str = js_NewDependentString(cx, str, size_t(begin), size_t(len));
2792 #endif /* JS_HAS_PERL_SUBSTR */
2795 * Python-esque sequence operations.
2798 str_concat(JSContext *cx, uintN argc, Value *vp)
2800 JSString *str = ThisToStringForStringProto(cx, vp);
2804 /* Set vp (aka rval) early to handle the argc == 0 case. */
2809 for (i = 0, argv = vp + 2; i < argc; i++) {
2810 JSString *str2 = js_ValueToString(cx, argv[i]);
2813 argv[i].setString(str2);
2815 str = js_ConcatStrings(cx, str, str2);
2825 str_slice(JSContext *cx, uintN argc, Value *vp)
2827 if (argc == 1 && vp[1].isString() && vp[2].isInt32()) {
2828 size_t begin, end, length;
2830 JSString *str = vp[1].toString();
2831 begin = vp[2].toInt32();
2832 end = str->length();
2834 length = end - begin;
2836 str = cx->runtime->emptyString;
2839 ? JSString::getUnitString(cx, str, begin)
2840 : js_NewDependentString(cx, str, begin, length);
2849 JSString *str = ThisToStringForStringProto(cx, vp);
2854 double begin, end, length;
2856 if (!ValueToNumber(cx, vp[2], &begin))
2858 begin = js_DoubleToInteger(begin);
2859 length = str->length();
2864 } else if (begin > length) {
2868 if (argc == 1 || vp[3].isUndefined()) {
2871 if (!ValueToNumber(cx, vp[3], &end))
2873 end = js_DoubleToInteger(end);
2878 } else if (end > length) {
2885 str = js_NewDependentString(cx, str,
2887 (size_t)(end - begin));
2895 #if JS_HAS_STR_HTML_HELPERS
2897 * HTML composition aids.
2900 tagify(JSContext *cx, const char *begin, JSLinearString *param, const char *end,
2903 JSString *thisstr = ThisToStringForStringProto(cx, vp);
2906 JSLinearString *str = thisstr->ensureLinear(cx);
2913 size_t beglen = strlen(begin);
2914 size_t taglen = 1 + beglen + 1; /* '<begin' + '>' */
2915 size_t parlen = 0; /* Avoid warning. */
2917 parlen = param->length();
2918 taglen += 2 + parlen + 1; /* '="param"' */
2920 size_t endlen = strlen(end);
2921 taglen += str->length() + 2 + endlen + 1; /* 'str</end>' */
2923 if (taglen >= ~(size_t)0 / sizeof(jschar)) {
2924 js_ReportAllocationOverflow(cx);
2928 jschar *tagbuf = (jschar *) cx->malloc((taglen + 1) * sizeof(jschar));
2934 for (size_t i = 0; i < beglen; i++)
2935 tagbuf[j++] = (jschar)begin[i];
2939 js_strncpy(&tagbuf[j], param->chars(), parlen);
2945 js_strncpy(&tagbuf[j], str->chars(), str->length());
2949 for (size_t i = 0; i < endlen; i++)
2950 tagbuf[j++] = (jschar)end[i];
2952 JS_ASSERT(j == taglen);
2955 JSString *retstr = js_NewString(cx, tagbuf, taglen);
2957 js_free((char *)tagbuf);
2960 vp->setString(retstr);
2965 tagify_value(JSContext *cx, uintN argc, Value *vp,
2966 const char *begin, const char *end)
2968 JSLinearString *param = ArgToRootedString(cx, argc, vp, 0);
2971 return tagify(cx, begin, param, end, vp);
2975 str_bold(JSContext *cx, uintN argc, Value *vp)
2977 return tagify(cx, "b", NULL, NULL, vp);
2981 str_italics(JSContext *cx, uintN argc, Value *vp)
2983 return tagify(cx, "i", NULL, NULL, vp);
2987 str_fixed(JSContext *cx, uintN argc, Value *vp)
2989 return tagify(cx, "tt", NULL, NULL, vp);
2993 str_fontsize(JSContext *cx, uintN argc, Value *vp)
2995 return tagify_value(cx, argc, vp, "font size", "font");
2999 str_fontcolor(JSContext *cx, uintN argc, Value *vp)
3001 return tagify_value(cx, argc, vp, "font color", "font");
3005 str_link(JSContext *cx, uintN argc, Value *vp)
3007 return tagify_value(cx, argc, vp, "a href", "a");
3011 str_anchor(JSContext *cx, uintN argc, Value *vp)
3013 return tagify_value(cx, argc, vp, "a name", "a");
3017 str_strike(JSContext *cx, uintN argc, Value *vp)
3019 return tagify(cx, "strike", NULL, NULL, vp);
3023 str_small(JSContext *cx, uintN argc, Value *vp)
3025 return tagify(cx, "small", NULL, NULL, vp);
3029 str_big(JSContext *cx, uintN argc, Value *vp)
3031 return tagify(cx, "big", NULL, NULL, vp);
3035 str_blink(JSContext *cx, uintN argc, Value *vp)
3037 return tagify(cx, "blink", NULL, NULL, vp);
3041 str_sup(JSContext *cx, uintN argc, Value *vp)
3043 return tagify(cx, "sup", NULL, NULL, vp);
3047 str_sub(JSContext *cx, uintN argc, Value *vp)
3049 return tagify(cx, "sub", NULL, NULL, vp);
3051 #endif /* JS_HAS_STR_HTML_HELPERS */
3055 js_String_getelem(JSContext* cx, JSString* str, int32 i)
3057 if ((size_t)i >= str->length())
3059 return JSString::getUnitString(cx, str, size_t(i));
3063 JS_DEFINE_TRCINFO_1(str_concat,
3064 (3, (extern, STRING_RETRY, js_ConcatStrings, CONTEXT, THIS_STRING, STRING,
3065 1, nanojit::ACCSET_NONE)))
3067 static JSFunctionSpec string_methods[] = {
3069 JS_FN("quote", str_quote, 0,JSFUN_GENERIC_NATIVE),
3070 JS_FN(js_toSource_str, str_toSource, 0,0),
3073 /* Java-like methods. */
3074 JS_FN(js_toString_str, js_str_toString, 0,0),
3075 JS_FN(js_valueOf_str, js_str_toString, 0,0),
3076 JS_FN(js_toJSON_str, js_str_toString, 0,0),
3077 JS_FN("substring", str_substring, 2,JSFUN_GENERIC_NATIVE),
3078 JS_FN("toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE),
3079 JS_FN("toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE),
3080 JS_FN("charAt", js_str_charAt, 1,JSFUN_GENERIC_NATIVE),
3081 JS_FN("charCodeAt", js_str_charCodeAt, 1,JSFUN_GENERIC_NATIVE),
3082 JS_FN("indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE),
3083 JS_FN("lastIndexOf", str_lastIndexOf, 1,JSFUN_GENERIC_NATIVE),
3084 JS_FN("trim", str_trim, 0,JSFUN_GENERIC_NATIVE),
3085 JS_FN("trimLeft", str_trimLeft, 0,JSFUN_GENERIC_NATIVE),
3086 JS_FN("trimRight", str_trimRight, 0,JSFUN_GENERIC_NATIVE),
3087 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE),
3088 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE),
3089 JS_FN("localeCompare", str_localeCompare, 1,JSFUN_GENERIC_NATIVE),
3091 /* Perl-ish methods (search is actually Python-esque). */
3092 JS_FN("match", str_match, 1,JSFUN_GENERIC_NATIVE),
3093 JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE),
3094 JS_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE),
3095 JS_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE),
3096 #if JS_HAS_PERL_SUBSTR
3097 JS_FN("substr", str_substr, 2,JSFUN_GENERIC_NATIVE),
3100 /* Python-esque sequence methods. */
3101 JS_TN("concat", str_concat, 1,JSFUN_GENERIC_NATIVE, &str_concat_trcinfo),
3102 JS_FN("slice", str_slice, 2,JSFUN_GENERIC_NATIVE),
3104 /* HTML string methods. */
3105 #if JS_HAS_STR_HTML_HELPERS
3106 JS_FN("bold", str_bold, 0,0),
3107 JS_FN("italics", str_italics, 0,0),
3108 JS_FN("fixed", str_fixed, 0,0),
3109 JS_FN("fontsize", str_fontsize, 1,0),
3110 JS_FN("fontcolor", str_fontcolor, 1,0),
3111 JS_FN("link", str_link, 1,0),
3112 JS_FN("anchor", str_anchor, 1,0),
3113 JS_FN("strike", str_strike, 0,0),
3114 JS_FN("small", str_small, 0,0),
3115 JS_FN("big", str_big, 0,0),
3116 JS_FN("blink", str_blink, 0,0),
3117 JS_FN("sup", str_sup, 0,0),
3118 JS_FN("sub", str_sub, 0,0),
3125 * Set up some tools to make it easier to generate large tables. After constant
3126 * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3127 * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3128 * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3131 #define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
3132 #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
3133 #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
3134 #define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
3135 #define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
3136 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3138 #define R3(n) R2(n), R2((n) + (1 << 2))
3139 #define R7(n) R6(n), R6((n) + (1 << 6))
3141 #define BUILD_LENGTH_AND_FLAGS(length, flags) \
3142 (((length) << JSString::LENGTH_SHIFT) | (flags))
3145 * Declare unit strings. Pack the string data itself into the mInlineChars
3146 * place in the header.
3149 BUILD_LENGTH_AND_FLAGS(1, JSString::FLAT | JSString::ATOMIZED), \
3150 { (jschar *)(((char *)(unitStringTable + (c))) + \
3151 offsetof(JSString, inlineStorage)) }, \
3157 #pragma pack(push, 8)
3160 const JSString JSString::unitStringTable[]
3162 __attribute__ ((aligned (8)))
3175 * Declare length-2 strings. We only store strings where both characters are
3176 * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3177 * the lowercase letters, and the next 26 are the uppercase letters.
3179 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
3180 (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
3181 (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
3182 JSString::INVALID_SMALL_CHAR)
3184 #define R TO_SMALL_CHAR
3186 const JSString::SmallChar JSString::toSmallChar[] = { R7(0) };
3191 * This is used when we generate our table of short strings, so the compiler is
3192 * happier if we use |c| as few times as possible.
3194 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
3195 (c) < 36 ? 'a' - 10 : \
3197 #define R FROM_SMALL_CHAR
3199 const jschar JSString::fromSmallChar[] = { R6(0) };
3204 * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3205 * where the upper 6 bits is the first character and the lower 6 bits is the
3209 BUILD_LENGTH_AND_FLAGS(2, JSString::FLAT | JSString::ATOMIZED), \
3210 { (jschar *)(((char *)(length2StringTable + (c))) + \
3211 offsetof(JSString, inlineStorage)) }, \
3212 { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3217 #pragma pack(push, 8)
3220 const JSString JSString::length2StringTable[]
3222 __attribute__ ((aligned (8)))
3235 * Declare int strings. Only int strings from 100 to 255 actually have to be
3236 * generated, since the rest are either unit strings or length-2 strings. To
3237 * avoid the runtime cost of figuring out where to look for the string for a
3238 * particular integer, we precompute a table of JSString*s which refer to the
3239 * correct location of the int string.
3242 BUILD_LENGTH_AND_FLAGS(3, JSString::FLAT | JSString::ATOMIZED), \
3243 { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \
3244 offsetof(JSString, inlineStorage)) }, \
3245 { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3248 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3253 #pragma pack(push, 8)
3256 const JSString JSString::hundredStringTable[]
3258 __attribute__ ((aligned (8)))
3260 = { R7(100), /* 100 through 227 */
3261 R4(100 + (1 << 7)), /* 228 through 243 */
3262 R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3263 R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3268 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \
3269 (c) < 100 ? JSString::length2StringTable + \
3270 ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
3271 TO_SMALL_CHAR(((c) % 10) + '0') : \
3272 JSString::hundredStringTable + ((c) - 100))
3274 const JSString *const JSString::intStringTable[] = { R8(0) };
3295 js_String(JSContext *cx, uintN argc, Value *vp)
3297 Value *argv = vp + 2;
3301 str = js_ValueToString(cx, argv[0]);
3305 str = cx->runtime->emptyString;
3308 if (IsConstructing(vp)) {
3309 JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
3312 obj->setPrimitiveThis(StringValue(str));
3313 vp->setObject(*obj);
3321 str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
3329 JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
3332 if (!ValueToUint16(cx, argv[0], &code))
3334 if (code < UNIT_STRING_LIMIT) {
3335 str = JSString::unitString(code);
3341 argv[0].setInt32(code);
3343 chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar));
3346 for (i = 0; i < argc; i++) {
3348 if (!ValueToUint16(cx, argv[i], &code)) {
3352 chars[i] = (jschar)code;
3355 str = js_NewString(cx, chars, argc);
3365 static JSString* FASTCALL
3366 String_fromCharCode(JSContext* cx, int32 i)
3368 JS_ASSERT(JS_ON_TRACE(cx));
3369 jschar c = (jschar)i;
3370 if (c < UNIT_STRING_LIMIT)
3371 return JSString::unitString(c);
3372 return js_NewStringCopyN(cx, &c, 1);
3376 JS_DEFINE_TRCINFO_1(str_fromCharCode,
3377 (2, (static, STRING_RETRY, String_fromCharCode, CONTEXT, INT32, 1, nanojit::ACCSET_NONE)))
3379 static JSFunctionSpec string_static_methods[] = {
3380 JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo),
3385 js_InitStringClass(JSContext *cx, JSObject *obj)
3389 /* Define the escape, unescape functions in the global object. */
3390 if (!JS_DefineFunctions(cx, obj, string_functions))
3393 proto = js_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1,
3394 NULL, string_methods,
3395 NULL, string_static_methods);
3398 proto->setPrimitiveThis(StringValue(cx->runtime->emptyString));
3399 if (!js_DefineNativeProperty(cx, proto, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
3400 UndefinedValue(), NULL, NULL,
3401 JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0,
3410 js_NewString(JSContext *cx, jschar *chars, size_t length)
3414 if (length > JSString::MAX_LENGTH) {
3415 if (JS_ON_TRACE(cx)) {
3417 * If we can't leave the trace, signal OOM condition, otherwise
3418 * exit from trace before throwing.
3420 if (!CanLeaveTrace(cx))
3425 js_ReportAllocationOverflow(cx);
3429 str = js_NewGCString(cx);
3432 str->initFlat(chars, length);
3433 cx->runtime->stringMemoryUsed += length * 2;
3436 JSRuntime *rt = cx->runtime;
3437 JS_RUNTIME_METER(rt, liveStrings);
3438 JS_RUNTIME_METER(rt, totalStrings);
3439 JS_LOCK_RUNTIME_VOID(rt,
3440 (rt->lengthSum += (double)length,
3441 rt->lengthSquaredSum += (double)length * (double)length));
3444 return str->assertIsFlat();
3447 static JS_ALWAYS_INLINE JSFlatString *
3448 NewShortString(JSContext *cx, const jschar *chars, size_t length)
3450 JS_ASSERT(JSShortString::fitsIntoShortString(length));
3451 JSShortString *str = js_NewGCShortString(cx);
3454 jschar *storage = str->init(length);
3455 js_short_strncpy(storage, chars, length);
3456 storage[length] = 0;
3457 return str->header()->assertIsFlat();
3460 static JSFlatString *
3461 NewShortString(JSContext *cx, const char *chars, size_t length)
3463 JS_ASSERT(JSShortString::fitsIntoShortString(length));
3464 JSShortString *str = js_NewGCShortString(cx);
3467 jschar *storage = str->init(length);
3469 if (js_CStringsAreUTF8) {
3471 size_t oldLength = length;
3473 if (!js_InflateStringToBuffer(cx, chars, length, storage, &length))
3475 JS_ASSERT(length <= oldLength);
3476 storage[length] = 0;
3477 str->resetLength(length);
3480 jschar *p = storage;
3482 *p++ = (unsigned char)*chars++;
3485 return str->header()->assertIsFlat();
3488 static const size_t sMinWasteSize = 16;
3491 StringBuffer::finishString()
3493 JSContext *cx = context();
3495 return ATOM_TO_STRING(cx->runtime->atomState.emptyAtom);
3497 size_t length = cb.length();
3498 if (!checkLength(length))
3501 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH < CharBuffer::InlineLength);
3502 if (JSShortString::fitsIntoShortString(length))
3503 return NewShortString(cx, cb.begin(), length);
3505 if (!cb.append('\0'))
3508 size_t capacity = cb.capacity();
3510 jschar *buf = cb.extractRawBuffer();
3514 /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3515 JS_ASSERT(capacity >= length);
3516 if (capacity > sMinWasteSize && capacity - length > (length >> 2)) {
3517 size_t bytes = sizeof(jschar) * (length + 1);
3518 jschar *tmp = (jschar *)cx->realloc(buf, bytes);
3526 JSFlatString *str = js_NewString(cx, buf, length);
3533 js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start,
3539 return cx->runtime->emptyString;
3541 JSLinearString *base = baseArg->ensureLinear(cx);
3545 if (start == 0 && length == base->length())
3548 const jschar *chars = base->chars() + start;
3550 JSLinearString *staticStr = JSString::lookupStaticString(chars, length);
3554 /* Try to avoid long chains of dependent strings. */
3555 while (base->isDependent())
3556 base = base->dependentBase();
3558 JS_ASSERT(base->isFlat());
3560 ds = js_NewGCString(cx);
3563 ds->initDependent(base, chars, length);
3566 JSRuntime *rt = cx->runtime;
3567 JS_RUNTIME_METER(rt, liveDependentStrings);
3568 JS_RUNTIME_METER(rt, totalDependentStrings);
3569 JS_RUNTIME_METER(rt, liveStrings);
3570 JS_RUNTIME_METER(rt, totalStrings);
3571 JS_LOCK_RUNTIME_VOID(rt,
3572 (rt->strdepLengthSum += (double)length,
3573 rt->strdepLengthSquaredSum += (double)length * (double)length));
3574 JS_LOCK_RUNTIME_VOID(rt,
3575 (rt->lengthSum += (double)length,
3576 rt->lengthSquaredSum += (double)length * (double)length));
3579 return ds->assertIsLinear();
3585 void printJSStringStats(JSRuntime *rt)
3589 mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum,
3590 rt->lengthSquaredSum, &sigma);
3592 fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
3593 (unsigned long)rt->totalStrings, mean, sigma);
3595 mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum,
3596 rt->strdepLengthSquaredSum, &sigma);
3598 fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
3599 (unsigned long)rt->totalDependentStrings, mean, sigma);
3604 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
3606 if (JSShortString::fitsIntoShortString(n))
3607 return NewShortString(cx, s, n);
3609 jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
3612 js_strncpy(news, s, n);
3614 JSFlatString *str = js_NewString(cx, news, n);
3621 js_NewStringCopyN(JSContext *cx, const char *s, size_t n)
3623 if (JSShortString::fitsIntoShortString(n))
3624 return NewShortString(cx, s, n);
3626 jschar *chars = js_InflateString(cx, s, &n);
3629 JSFlatString *str = js_NewString(cx, chars, n);
3636 js_NewStringCopyZ(JSContext *cx, const jschar *s)
3638 size_t n = js_strlen(s);
3639 if (JSShortString::fitsIntoShortString(n))
3640 return NewShortString(cx, s, n);
3642 size_t m = (n + 1) * sizeof(jschar);
3643 jschar *news = (jschar *) cx->malloc(m);
3647 JSFlatString *str = js_NewString(cx, news, n);
3654 js_NewStringCopyZ(JSContext *cx, const char *s)
3656 return js_NewStringCopyN(cx, s, strlen(s));
3660 js_ValueToPrintable(JSContext *cx, const Value &v, JSAutoByteString *bytes, bool asSource)
3664 str = (asSource ? js_ValueToSource : js_ValueToString)(cx, v);
3667 str = js_QuoteString(cx, str, 0);
3670 return bytes->encode(cx, str);
3674 js_ValueToString(JSContext *cx, const Value &arg)
3677 if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v))
3683 } else if (v.isInt32()) {
3684 str = js_IntToString(cx, v.toInt32());
3685 } else if (v.isDouble()) {
3686 str = js_NumberToString(cx, v.toDouble());
3687 } else if (v.isBoolean()) {
3688 str = js_BooleanToString(cx, v.toBoolean());
3689 } else if (v.isNull()) {
3690 str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
3692 str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
3697 /* This function implements E-262-3 section 9.8, toString. */
3699 js::ValueToStringBuffer(JSContext *cx, const Value &arg, StringBuffer &sb)
3702 if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v))
3706 JSString *str = v.toString();
3707 size_t length = str->length();
3708 const jschar *chars = str->getChars(cx);
3711 return sb.append(chars, length);
3714 return NumberValueToStringBuffer(cx, v, sb);
3716 return BooleanToStringBuffer(cx, v.toBoolean(), sb);
3718 return sb.append(cx->runtime->atomState.nullAtom);
3719 JS_ASSERT(v.isUndefined());
3720 return sb.append(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
3723 JS_FRIEND_API(JSString *)
3724 js_ValueToSource(JSContext *cx, const Value &v)
3726 if (v.isUndefined())
3727 return ATOM_TO_STRING(cx->runtime->atomState.void0Atom);
3729 return js_QuoteString(cx, v.toString(), '"');
3730 if (v.isPrimitive()) {
3731 /* Special case to preserve negative zero, _contra_ toString. */
3732 if (v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble())) {
3733 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3734 static const jschar js_negzero_ucNstr[] = {'-', '0'};
3736 return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
3738 return js_ValueToString(cx, v);
3741 JSAtom *atom = cx->runtime->atomState.toSourceAtom;
3742 AutoValueRooter tvr(cx);
3743 if (!js_TryMethod(cx, &v.toObject(), atom, 0, NULL, tvr.addr()))
3745 return js_ValueToString(cx, tvr.value());
3751 * str is not necessarily a GC thing here.
3753 static JS_ALWAYS_INLINE bool
3754 EqualStringsTail(JSLinearString *str1, size_t length1, JSLinearString *str2)
3756 const jschar *s1 = str1->chars();
3757 const jschar *s1end = s1 + length1;
3758 const jschar *s2 = str2->chars();
3764 } while (s1 != s1end);
3770 EqualStrings(JSContext *cx, JSString *str1, JSString *str2, JSBool *result)
3777 size_t length1 = str1->length();
3778 if (length1 != str2->length()) {
3788 JSLinearString *linear1 = str1->ensureLinear(cx);
3791 JSLinearString *linear2 = str2->ensureLinear(cx);
3795 *result = EqualStringsTail(linear1, length1, linear2);
3800 EqualStrings(JSLinearString *str1, JSLinearString *str2)
3805 size_t length1 = str1->length();
3806 if (length1 != str2->length())
3812 return EqualStringsTail(str1, length1, str2);
3815 } /* namespace js */
3818 js_EqualStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2)
3821 return EqualStrings(cx, str1, str2, &result) ? result : JS_NEITHER;
3823 JS_DEFINE_CALLINFO_3(extern, BOOL, js_EqualStringsOnTrace,
3824 CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE)
3829 CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
3839 size_t l1 = str1->length();
3840 const jschar *s1 = str1->getChars(cx);
3844 size_t l2 = str2->length();
3845 const jschar *s2 = str2->getChars(cx);
3849 size_t n = JS_MIN(l1, l2);
3850 for (size_t i = 0; i < n; i++) {
3851 if (int32 cmp = s1[i] - s2[i]) {
3856 *result = (int32)(l1 - l2);
3861 CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
3863 return CompareStringsImpl(cx, str1, str2, result);
3866 } /* namespace js */
3869 js_CompareStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2)
3872 if (!CompareStringsImpl(cx, str1, str2, &result))
3874 JS_ASSERT(result != INT32_MIN);
3877 JS_DEFINE_CALLINFO_3(extern, INT32, js_CompareStringsOnTrace,
3878 CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE)
3883 StringEqualsAscii(JSLinearString *str, const char *asciiBytes)
3885 size_t length = strlen(asciiBytes);
3887 for (size_t i = 0; i != length; ++i)
3888 JS_ASSERT(unsigned(asciiBytes[i]) <= 127);
3890 if (length != str->length())
3892 const jschar *chars = str->chars();
3893 for (size_t i = 0; i != length; ++i) {
3894 if (unsigned(asciiBytes[i]) != unsigned(chars[i]))
3903 js_strlen(const jschar *s)
3907 for (t = s; *t != 0; t++)
3909 return (size_t)(t - s);
3913 js_strchr(const jschar *s, jschar c)
3924 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
3935 js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp)
3937 size_t nbytes, nchars, i;
3944 if (js_CStringsAreUTF8) {
3945 if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars))
3947 chars = (jschar *) cx->malloc((nchars + 1) * sizeof (jschar));
3953 js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars);
3957 chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
3960 for (i = 0; i < nchars; i++)
3961 chars[i] = (unsigned char) bytes[i];
3969 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3977 * May be called with null cx.
3980 js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
3988 if (js_CStringsAreUTF8) {
3989 nbytes = js_GetDeflatedStringLength(cx, chars, nchars);
3990 if (nbytes == (size_t) -1)
3992 bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
3998 js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes);
4002 bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
4005 for (i = 0; i < nbytes; i++)
4006 bytes[i] = (char) chars[i];
4013 js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
4015 if (!js_CStringsAreUTF8)
4018 return js_GetDeflatedUTF8StringLength(cx, chars, nchars);
4022 * May be called with null cx through public API, see below.
4025 js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars)
4033 for (end = chars + nchars; chars != end; chars++) {
4037 if (0xD800 <= c && c <= 0xDFFF) {
4038 /* Surrogate pair. */
4041 /* nbytes sets 1 length since this is surrogate pair. */
4043 if (c >= 0xDC00 || chars == end)
4046 if (c2 < 0xDC00 || c2 > 0xDFFF)
4048 c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
4061 JS_snprintf(buffer, 10, "0x%x", c);
4062 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
4063 NULL, JSMSG_BAD_SURROGATE_CHAR, buffer);
4069 js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen,
4070 char *dst, size_t *dstlenp)
4075 if (!js_CStringsAreUTF8) {
4076 if (srclen > dstlen) {
4077 for (i = 0; i < dstlen; i++)
4078 dst[i] = (char) src[i];
4080 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4081 JSMSG_BUFFER_TOO_SMALL);
4085 for (i = 0; i < srclen; i++)
4086 dst[i] = (char) src[i];
4091 return js_DeflateStringToUTF8Buffer(cx, src, srclen, dst, dstlenp);
4095 js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *src, size_t srclen,
4096 char *dst, size_t *dstlenp)
4098 size_t dstlen, i, origDstlen, utf8Len;
4104 origDstlen = dstlen;
4108 if ((c >= 0xDC00) && (c <= 0xDFFF))
4110 if (c < 0xD800 || c > 0xDBFF) {
4116 if ((c2 < 0xDC00) || (c2 > 0xDFFF))
4120 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
4123 /* no encoding necessary - performance hack */
4125 goto bufferTooSmall;
4129 utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
4130 if (utf8Len > dstlen)
4131 goto bufferTooSmall;
4132 for (i = 0; i < utf8Len; i++)
4133 *dst++ = (char) utf8buf[i];
4137 *dstlenp = (origDstlen - dstlen);
4141 *dstlenp = (origDstlen - dstlen);
4142 /* Delegate error reporting to the measurement function. */
4144 js_GetDeflatedStringLength(cx, src - 1, srclen + 1);
4148 *dstlenp = (origDstlen - dstlen);
4150 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4151 JSMSG_BUFFER_TOO_SMALL);
4157 js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen,
4158 jschar *dst, size_t *dstlenp)
4162 if (!js_CStringsAreUTF8) {
4165 if (srclen > dstlen) {
4166 for (i = 0; i < dstlen; i++)
4167 dst[i] = (unsigned char) src[i];
4169 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4170 JSMSG_BUFFER_TOO_SMALL);
4174 for (i = 0; i < srclen; i++)
4175 dst[i] = (unsigned char) src[i];
4181 return js_InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp);
4185 js_InflateUTF8StringToBuffer(JSContext *cx, const char *src, size_t srclen,
4186 jschar *dst, size_t *dstlenp)
4188 size_t dstlen, origDstlen, offset, j, n;
4191 dstlen = dst ? *dstlenp : (size_t) -1;
4192 origDstlen = dstlen;
4199 while (v & (0x80 >> n))
4202 goto bufferTooSmall;
4203 if (n == 1 || n > 4)
4205 for (j = 1; j < n; j++) {
4206 if ((src[j] & 0xC0) != 0x80)
4209 v = Utf8ToOneUcs4Char((uint8 *)src, n);
4212 if (v > 0xFFFFF || dstlen < 2) {
4213 *dstlenp = (origDstlen - dstlen);
4216 JS_snprintf(buffer, 10, "0x%x", v + 0x10000);
4217 JS_ReportErrorFlagsAndNumber(cx,
4219 js_GetErrorMessage, NULL,
4220 JSMSG_UTF8_CHAR_TOO_LARGE,
4226 *dst++ = (jschar)((v >> 10) + 0xD800);
4227 v = (jschar)((v & 0x3FF) + 0xDC00);
4233 goto bufferTooSmall;
4235 *dst++ = (jschar) v;
4241 *dstlenp = (origDstlen - dstlen);
4245 *dstlenp = (origDstlen - dstlen);
4248 JS_snprintf(buffer, 10, "%d", offset);
4249 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
4250 js_GetErrorMessage, NULL,
4251 JSMSG_MALFORMED_UTF8_CHAR,
4257 *dstlenp = (origDstlen - dstlen);
4259 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4260 JSMSG_BUFFER_TOO_SMALL);
4266 * From java.lang.Character.java:
4268 * The character properties are currently encoded into 32 bits in the
4271 * 10 bits signed offset used for converting case
4272 * 1 bit if 1, adding the signed offset converts the character to
4274 * 1 bit if 1, subtracting the signed offset converts the character to
4276 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
4277 * 3 bits 0 may not be part of an identifier
4278 * 1 ignorable control; may continue a Unicode identifier or JS
4280 * 2 may continue a JS identifier but not a Unicode identifier
4282 * 3 may continue a Unicode identifier or JS identifier
4283 * 4 is a JS whitespace character
4284 * 5 may start or continue a JS identifier;
4285 * may continue but not start a Unicode identifier (_)
4286 * 6 may start or continue a JS identifier but not a Unicode
4288 * 7 may start or continue a Unicode identifier or JS identifier
4290 * 5, 6, 7 may start a JS identifier
4291 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
4292 * 7 may start a Unicode identifier
4293 * 1, 3, 5, 7 may continue a Unicode identifier
4294 * 1 is ignorable within an identifier
4295 * 4 is JS whitespace
4296 * 2 bits 0 this character has no numeric property
4297 * 1 adding the digit offset to the character code and then
4298 * masking with 0x1F will produce the desired numeric value
4299 * 2 this character has a "strange" numeric value
4300 * 3 a JS supradecimal digit: adding the digit offset to the
4301 * character code, then masking with 0x1F, then adding 10
4302 * will produce the desired numeric value
4303 * 5 bits digit offset
4304 * 1 bit XML 1.0 name start character
4305 * 1 bit XML 1.0 name character
4306 * 2 bits reserved for future use
4307 * 5 bits character type
4310 /* The X table has 1024 entries for a total of 1024 bytes. */
4312 const uint8 js_X[] = {
4313 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
4314 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
4315 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
4316 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
4317 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
4318 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
4319 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
4320 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
4321 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
4322 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
4323 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
4324 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
4325 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
4326 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
4327 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
4328 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
4329 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
4330 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
4331 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
4332 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
4333 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
4334 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
4335 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
4336 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
4337 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
4338 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
4339 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
4340 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
4341 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
4342 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
4343 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
4344 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
4345 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
4346 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
4347 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
4348 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
4349 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
4350 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
4351 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
4352 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
4353 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
4354 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
4355 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
4356 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
4357 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
4358 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
4359 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
4360 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
4361 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
4362 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
4363 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
4364 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
4365 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
4366 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
4367 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
4368 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
4369 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
4370 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
4371 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
4372 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
4373 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
4374 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
4375 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
4376 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
4377 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
4378 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
4379 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
4380 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
4381 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
4382 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
4383 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
4384 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
4385 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
4386 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
4387 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
4388 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
4389 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
4390 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
4391 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
4392 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
4393 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
4394 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
4395 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
4396 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
4397 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
4398 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
4399 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
4400 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
4401 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
4402 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
4403 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
4404 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
4405 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
4406 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
4407 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
4408 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
4409 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
4410 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
4411 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
4412 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
4413 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
4414 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
4415 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
4416 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
4417 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
4418 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
4419 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
4420 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
4421 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
4422 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
4423 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
4424 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
4425 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
4426 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
4427 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
4428 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
4429 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
4430 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
4431 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
4432 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
4433 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
4434 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
4435 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
4436 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
4437 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
4438 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
4439 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
4440 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
4443 /* The Y table has 7808 entries for a total of 7808 bytes. */
4445 const uint8 js_Y[] = {
4446 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4447 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
4448 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4449 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
4450 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
4451 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
4452 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
4453 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
4454 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4455 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4456 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
4457 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
4458 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4459 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4460 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
4461 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
4462 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4463 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4464 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4465 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
4466 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
4467 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
4468 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
4469 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
4470 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4471 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
4472 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
4473 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
4474 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4475 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
4476 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
4477 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
4478 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4479 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4480 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4481 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4482 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4483 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
4484 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
4485 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
4486 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
4487 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
4488 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4489 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4490 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4491 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4492 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
4493 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
4494 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
4495 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
4496 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
4497 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
4498 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
4499 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
4500 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
4501 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
4502 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
4503 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
4504 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
4505 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
4506 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4507 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
4508 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
4509 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
4510 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4511 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4512 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
4513 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4514 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4515 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4516 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4517 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
4518 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4519 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
4520 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
4521 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
4522 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
4523 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
4524 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
4525 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
4526 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
4527 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
4528 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
4529 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4530 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
4531 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
4532 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
4533 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
4534 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4535 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
4536 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
4537 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
4538 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
4539 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
4540 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4541 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
4542 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4543 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4544 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4545 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4546 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4547 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4548 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4549 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
4550 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
4551 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4552 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4553 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4554 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
4555 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
4556 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
4557 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
4558 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
4559 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
4560 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4561 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
4562 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
4563 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
4564 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4565 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
4566 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
4567 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
4568 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
4569 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
4570 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
4571 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
4572 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
4573 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
4574 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
4575 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
4576 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4577 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4578 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4579 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
4580 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4581 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
4582 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4583 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
4584 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
4585 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
4586 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4587 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4588 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4589 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
4590 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
4591 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
4592 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4593 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4594 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4595 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4596 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4597 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
4598 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
4599 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
4600 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4601 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4602 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
4603 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
4604 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
4605 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
4606 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4607 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4608 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4609 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4610 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4611 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
4612 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4613 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
4614 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4615 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
4616 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
4617 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
4618 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4619 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4620 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4621 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
4622 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
4623 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
4624 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4625 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4626 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
4627 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4628 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
4629 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
4630 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
4631 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4632 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4633 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4634 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
4635 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
4636 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
4637 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
4638 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4639 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
4640 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
4641 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
4642 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4643 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4644 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
4645 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
4646 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4647 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
4648 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
4649 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
4650 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
4651 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
4652 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4653 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4654 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4655 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4656 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4657 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4658 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4659 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4660 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4661 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4662 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4663 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4664 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4665 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4666 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4667 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4668 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4669 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4670 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4671 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4672 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4673 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4674 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4675 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4676 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4677 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4678 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4679 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4680 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4681 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4682 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4683 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4684 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4685 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
4686 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4687 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4688 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4689 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4690 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4691 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4692 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4693 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4694 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4695 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4696 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4697 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4698 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4699 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4700 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4701 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4702 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4703 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4704 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4705 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4706 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4707 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4708 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4709 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4710 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4711 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4712 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4713 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4714 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4715 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4716 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4717 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4718 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4719 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4720 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4721 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4722 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4723 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4724 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4725 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4726 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4727 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4728 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4729 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4730 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4731 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4732 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4733 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4734 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4735 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4736 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4737 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4738 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4739 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4740 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4741 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4742 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4743 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4744 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4745 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4746 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4747 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4748 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4749 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4750 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4751 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4752 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4753 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4754 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4755 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4756 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4757 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4758 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4759 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4760 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4761 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4762 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4763 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4764 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4765 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4766 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4767 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4768 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4769 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4770 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4771 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4772 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4773 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4774 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4775 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4776 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4777 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4778 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4779 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4780 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4781 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4782 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4783 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4784 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4785 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4786 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4787 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4788 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4789 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4790 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4791 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4792 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4793 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4794 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4795 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4796 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4797 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4798 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4799 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4800 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4801 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4802 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4803 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4804 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4805 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4806 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4807 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4808 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4809 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4810 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4811 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4812 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4813 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
4814 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4815 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4816 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4817 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4818 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4819 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4820 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4821 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4822 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4823 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4824 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4825 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4826 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4827 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
4828 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4829 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4830 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4831 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4832 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4833 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4834 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4835 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4836 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4837 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4838 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4839 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4840 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
4841 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
4842 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
4843 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
4844 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
4845 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
4846 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
4847 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
4848 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
4849 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
4850 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4851 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4852 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4853 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4854 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
4855 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
4856 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
4857 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
4858 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
4859 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
4860 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
4861 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
4862 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4863 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4864 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4865 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4866 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4867 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
4868 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
4869 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
4870 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
4871 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
4872 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
4873 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4874 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4875 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
4876 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4877 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
4878 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4879 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4880 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4881 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4882 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4883 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4884 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4885 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4886 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
4887 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
4888 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4889 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4890 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4891 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4892 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
4893 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
4894 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4895 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4896 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4897 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4898 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4899 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4900 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4901 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4902 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4903 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4904 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4905 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
4906 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4907 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4908 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4909 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4910 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4911 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4912 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4913 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4914 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
4915 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4916 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4917 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4918 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4919 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4920 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4921 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4922 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4923 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4924 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4925 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
4926 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4927 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4928 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4929 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4930 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4931 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4932 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4933 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4934 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4935 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4936 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
4937 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
4938 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4939 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4940 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4941 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4942 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4943 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4944 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4945 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4946 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4947 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4948 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4949 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
4950 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4951 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4952 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
4953 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
4954 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4955 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4956 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4957 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4958 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
4959 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
4960 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
4961 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
4962 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
4963 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
4964 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
4965 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
4966 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4967 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4968 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4969 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4970 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4971 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4972 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
4973 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
4974 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
4975 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
4976 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
4977 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
4978 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
4979 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
4980 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
4981 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
4982 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
4983 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
4984 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
4985 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
4986 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4987 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
4988 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4989 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
4990 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
4991 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4992 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4993 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4994 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4995 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
4996 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
4997 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
4998 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
4999 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
5000 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5001 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5002 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
5003 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
5004 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5005 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
5006 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5007 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5008 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
5009 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
5010 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
5011 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5012 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5013 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
5014 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
5015 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
5016 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
5017 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
5018 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
5019 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
5020 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
5021 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
5022 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5023 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
5024 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
5025 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
5026 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
5027 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
5028 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
5029 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
5030 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
5031 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
5032 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
5033 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5034 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5035 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5036 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5037 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
5038 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5039 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5040 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
5041 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5042 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
5043 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
5044 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5045 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
5046 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5047 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5048 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5049 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5050 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5051 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5052 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5053 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
5054 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5055 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5056 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5057 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5058 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5059 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
5060 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
5061 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
5062 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
5063 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
5064 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5065 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5066 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
5067 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
5068 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5069 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
5070 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5071 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5072 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5073 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5074 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5075 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5076 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
5077 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
5078 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5079 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5080 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5081 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
5082 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
5083 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5084 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5085 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
5086 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
5087 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
5088 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5089 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
5090 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5091 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
5092 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
5093 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
5094 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
5095 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5096 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
5097 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
5098 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5099 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
5100 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
5101 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
5102 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5103 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
5104 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5105 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5106 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
5107 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
5108 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5109 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
5110 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5111 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5112 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5113 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5114 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5115 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5116 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5117 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
5118 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5119 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5120 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
5121 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
5122 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5123 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5124 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5125 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
5126 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5127 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5128 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5129 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5130 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5131 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
5132 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5133 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
5134 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5135 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5136 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
5137 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
5138 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5139 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5140 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5141 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
5142 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
5143 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
5144 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5145 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5146 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5147 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5148 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5149 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
5150 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5151 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
5152 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
5153 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
5154 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
5155 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
5156 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
5157 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
5158 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
5159 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
5160 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
5161 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5162 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5163 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5164 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
5165 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
5166 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
5167 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
5168 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
5169 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
5170 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
5171 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
5172 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
5173 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
5174 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5175 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5176 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5177 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5178 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5179 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5180 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5181 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
5182 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5183 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5184 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
5185 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
5186 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5187 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5188 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5189 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
5190 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5191 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5192 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5193 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5194 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5195 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5196 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
5197 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
5198 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
5199 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5200 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5201 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5202 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5203 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
5204 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5205 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
5206 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
5207 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
5208 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
5209 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
5210 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5211 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5212 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5213 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
5214 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5215 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5216 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5217 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
5218 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
5219 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
5220 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5221 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
5222 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
5223 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5224 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5225 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
5226 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5227 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5228 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
5229 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
5230 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
5231 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
5232 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5233 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5234 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5235 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
5236 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5237 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
5238 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5239 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
5240 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5241 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5242 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5243 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5244 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
5245 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
5246 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5247 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5248 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5249 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5250 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5251 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
5252 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
5253 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
5254 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5255 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5256 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5257 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
5258 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5259 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5260 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
5261 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
5262 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5263 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5264 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5265 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
5266 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
5267 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5268 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5269 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
5270 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5271 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5272 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5273 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
5274 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
5275 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5276 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5277 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
5278 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5279 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5280 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5281 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5282 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5283 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5284 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5285 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
5286 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5287 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5288 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5289 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5290 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5291 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5292 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5293 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
5294 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5295 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5296 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5297 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5298 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
5299 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
5300 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5301 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
5302 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
5303 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
5304 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
5305 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
5306 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
5307 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
5308 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
5309 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
5310 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
5311 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5312 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5313 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5314 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5315 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5316 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5317 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
5318 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5319 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5320 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5321 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5322 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5323 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
5324 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
5325 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
5326 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5327 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
5328 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
5329 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5330 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5331 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5332 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5333 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
5334 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5335 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5336 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5337 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5338 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5339 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5340 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
5341 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
5342 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5343 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
5344 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5345 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5346 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5347 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5348 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5349 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
5350 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5351 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5352 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
5353 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5354 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5355 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5356 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5357 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
5358 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5359 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5360 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5361 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5362 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5363 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
5364 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
5365 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
5366 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5367 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5368 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5369 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5370 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
5371 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
5372 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
5373 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
5374 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
5375 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
5376 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
5377 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
5378 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
5379 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
5380 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
5381 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
5382 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5383 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5384 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5385 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5386 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5387 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5388 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
5389 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
5390 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
5391 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
5392 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
5393 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
5394 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5395 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5396 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
5397 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
5398 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5399 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5400 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
5401 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
5402 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
5403 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5404 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5405 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
5406 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5407 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5408 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5409 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
5410 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5411 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5412 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
5413 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
5414 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5415 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5416 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
5417 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
5418 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
5419 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
5420 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
5421 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
5424 /* The A table has 124 entries for a total of 496 bytes. */
5426 const uint32 js_A[] = {
5427 0x0001000F, /* 0 Cc, ignorable */
5428 0x0004000F, /* 1 Cc, whitespace */
5429 0x0004000C, /* 2 Zs, whitespace */
5430 0x00000018, /* 3 Po */
5431 0x0006001A, /* 4 Sc, currency */
5432 0x00000015, /* 5 Ps */
5433 0x00000016, /* 6 Pe */
5434 0x00000019, /* 7 Sm */
5435 0x00000014, /* 8 Pd */
5436 0x00036089, /* 9 Nd, identifier part, decimal 16 */
5437 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
5438 0x0000001B, /* 11 Sk */
5439 0x00050017, /* 12 Pc, underscore */
5440 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5441 0x0000000C, /* 14 Zs */
5442 0x0000001C, /* 15 So */
5443 0x00070182, /* 16 Ll, identifier start */
5444 0x0000600B, /* 17 No, decimal 16 */
5445 0x0000500B, /* 18 No, decimal 8 */
5446 0x0000800B, /* 19 No, strange */
5447 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
5448 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
5449 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
5450 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
5451 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
5452 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
5453 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
5454 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
5455 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
5456 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
5457 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
5458 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
5459 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
5460 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
5461 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
5462 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
5463 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
5464 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
5465 0x00070181, /* 38 Lu, identifier start */
5466 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
5467 0x00070185, /* 40 Lo, identifier start */
5468 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
5469 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
5470 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
5471 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5472 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
5473 0x00000000, /* 46 unassigned */
5474 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
5475 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
5476 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
5477 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
5478 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
5479 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
5480 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
5481 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
5482 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
5483 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
5484 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
5485 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
5486 0x00070084, /* 59 Lm, identifier start */
5487 0x00030086, /* 60 Mn, identifier part */
5488 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
5489 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
5490 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
5491 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
5492 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
5493 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
5494 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
5495 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
5496 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
5497 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
5498 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
5499 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
5500 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
5501 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
5502 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
5503 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
5504 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
5505 0x00034089, /* 78 Nd, identifier part, decimal 0 */
5506 0x00000087, /* 79 Me */
5507 0x00030088, /* 80 Mc, identifier part */
5508 0x00037489, /* 81 Nd, identifier part, decimal 26 */
5509 0x00005A0B, /* 82 No, decimal 13 */
5510 0x00006E0B, /* 83 No, decimal 23 */
5511 0x0000740B, /* 84 No, decimal 26 */
5512 0x0000000B, /* 85 No */
5513 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
5514 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
5515 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
5516 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
5517 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
5518 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
5519 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
5520 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
5521 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
5522 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
5523 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
5524 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
5525 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
5526 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
5527 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
5528 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
5529 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
5530 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
5531 0x00010010, /* 104 Cf, ignorable */
5532 0x0004000D, /* 105 Zl, whitespace */
5533 0x0004000E, /* 106 Zp, whitespace */
5534 0x0000400B, /* 107 No, decimal 0 */
5535 0x0000440B, /* 108 No, decimal 2 */
5536 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
5537 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
5538 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5539 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
5540 0x0007818A, /* 113 Nl, identifier start, strange */
5541 0x0000420B, /* 114 No, decimal 1 */
5542 0x0000720B, /* 115 No, decimal 25 */
5543 0x06A0001C, /* 116 So, hasLower (add 26) */
5544 0x0690001C, /* 117 So, hasUpper (subtract 26) */
5545 0x00006C0B, /* 118 No, decimal 22 */
5546 0x0000560B, /* 119 No, decimal 11 */
5547 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
5548 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
5549 0x00000013, /* 122 Cs */
5550 0x00000012 /* 123 Co */
5553 const jschar js_uriReservedPlusPound_ucstr[] =
5554 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5555 const jschar js_uriUnescaped_ucstr[] =
5556 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5557 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5558 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5559 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5560 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5561 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5564 * This table allows efficient testing for the regular expression \w which is
5565 * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5567 const bool js_alnum[] = {
5568 /* 0 1 2 3 4 5 5 7 8 9 */
5569 /* 0 */ false, false, false, false, false, false, false, false, false, false,
5570 /* 1 */ false, false, false, false, false, false, false, false, false, false,
5571 /* 2 */ false, false, false, false, false, false, false, false, false, false,
5572 /* 3 */ false, false, false, false, false, false, false, false, false, false,
5573 /* 4 */ false, false, false, false, false, false, false, false, true, true,
5574 /* 5 */ true, true, true, true, true, true, true, true, false, false,
5575 /* 6 */ false, false, false, false, false, true, true, true, true, true,
5576 /* 7 */ true, true, true, true, true, true, true, true, true, true,
5577 /* 8 */ true, true, true, true, true, true, true, true, true, true,
5578 /* 9 */ true, false, false, false, false, true, false, true, true, true,
5579 /* 10 */ true, true, true, true, true, true, true, true, true, true,
5580 /* 11 */ true, true, true, true, true, true, true, true, true, true,
5581 /* 12 */ true, true, true, false, false, false, false, false
5584 #define URI_CHUNK 64U
5587 TransferBufferToString(JSContext *cx, StringBuffer &sb, Value *rval)
5589 JSString *str = sb.finishString();
5592 rval->setString(str);
5597 * ECMA 3, 15.1.3 URI Handling Function Properties
5599 * The following are implementations of the algorithms
5600 * given in the ECMA specification for the hidden functions
5601 * 'Encode' and 'Decode'.
5604 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
5605 const jschar *unescapedSet2, Value *rval)
5607 static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
5609 size_t length = str->length();
5610 const jschar *chars = str->getChars(cx);
5615 rval->setString(cx->runtime->emptyString);
5619 StringBuffer sb(cx);
5623 for (size_t k = 0; k < length; k++) {
5624 jschar c = chars[k];
5625 if (js_strchr(unescapedSet, c) ||
5626 (unescapedSet2 && js_strchr(unescapedSet2, c))) {
5630 if ((c >= 0xDC00) && (c <= 0xDFFF)) {
5631 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5632 JSMSG_BAD_URI, NULL);
5636 if (c < 0xD800 || c > 0xDBFF) {
5641 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5642 JSMSG_BAD_URI, NULL);
5645 jschar c2 = chars[k];
5646 if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
5647 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5648 JSMSG_BAD_URI, NULL);
5651 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
5654 size_t L = js_OneUcs4ToUtf8Char(utf8buf, v);
5655 for (size_t j = 0; j < L; j++) {
5656 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
5657 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
5658 if (!sb.append(hexBuf, 3))
5664 return TransferBufferToString(cx, sb, rval);
5668 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, Value *rval)
5670 size_t length = str->length();
5671 const jschar *chars = str->getChars(cx);
5676 rval->setString(cx->runtime->emptyString);
5680 StringBuffer sb(cx);
5681 for (size_t k = 0; k < length; k++) {
5682 jschar c = chars[k];
5685 if ((k + 2) >= length)
5686 goto report_bad_uri;
5687 if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5688 goto report_bad_uri;
5689 jsuint B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5695 while (B & (0x80 >> n))
5697 if (n == 1 || n > 4)
5698 goto report_bad_uri;
5700 octets[0] = (uint8)B;
5701 if (k + 3 * (n - 1) >= length)
5702 goto report_bad_uri;
5703 for (intN j = 1; j < n; j++) {
5705 if (chars[k] != '%')
5706 goto report_bad_uri;
5707 if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5708 goto report_bad_uri;
5709 B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5710 if ((B & 0xC0) != 0x80)
5711 goto report_bad_uri;
5713 octets[j] = (char)B;
5715 uint32 v = Utf8ToOneUcs4Char(octets, n);
5719 goto report_bad_uri;
5720 c = (jschar)((v & 0x3FF) + 0xDC00);
5721 jschar H = (jschar)((v >> 10) + 0xD800);
5728 if (js_strchr(reservedSet, c)) {
5729 if (!sb.append(chars + start, k - start + 1))
5741 return TransferBufferToString(cx, sb, rval);
5744 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
5751 str_decodeURI(JSContext *cx, uintN argc, Value *vp)
5753 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5756 return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp);
5760 str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp)
5762 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5765 return Decode(cx, str, js_empty_ucstr, vp);
5769 str_encodeURI(JSContext *cx, uintN argc, Value *vp)
5771 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5774 return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
5779 str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp)
5781 JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5784 return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp);
5788 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5789 * least 4 bytes long. Return the number of UTF-8 bytes of data written.
5792 js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
5796 JS_ASSERT(ucs4Char <= 0x10FFFF);
5797 if (ucs4Char < 0x80) {
5798 *utf8Buffer = (uint8)ucs4Char;
5801 uint32 a = ucs4Char >> 11;
5809 utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
5812 *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
5818 * Convert a utf8 character sequence into a UCS-4 character and return that
5819 * character. It is assumed that the caller already checked that the sequence
5823 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
5827 /* from Unicode 3.1, non-shortest form is illegal */
5828 static const uint32 minucs4Table[] = {
5829 0x00000080, 0x00000800, 0x00010000
5832 JS_ASSERT(utf8Length >= 1 && utf8Length <= 4);
5833 if (utf8Length == 1) {
5834 ucs4Char = *utf8Buffer;
5835 JS_ASSERT(!(ucs4Char & 0x80));
5837 JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
5838 (0x100 - (1 << (8-utf8Length))));
5839 ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
5840 minucs4Char = minucs4Table[utf8Length-2];
5841 while (--utf8Length) {
5842 JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
5843 ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
5845 if (JS_UNLIKELY(ucs4Char < minucs4Char)) {
5846 ucs4Char = OVERLONG_UTF8;
5847 } else if (ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
5857 PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, JSLinearString *str, uint32 quote)
5860 STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
5863 JS_ASSERT(quote == 0 || quote == '\'' || quote == '"');
5864 JS_ASSERT_IF(!buffer, bufferSize == 0);
5865 JS_ASSERT_IF(fp, !buffer);
5867 if (bufferSize == 0)
5872 const jschar *chars = str->chars();
5873 const jschar *charsEnd = chars + str->length();
5875 state = FIRST_QUOTE;
5879 char c = 0; /* to quell GCC warnings */
5896 if (chars == charsEnd) {
5903 const char *escape = strchr(js_EscapeMap, (int)u);
5912 if (u == quote || u == '\\')
5915 } else if (u < 0x100) {
5930 state = ESCAPE_START;
5933 JS_ASSERT(' ' <= u && u < 127);
5935 state = ESCAPE_MORE;
5943 u = 0xF & (hex >> shift);
5944 c = (char)(u + (u < 10 ? '0' : 'A' - 10));
5948 JS_ASSERT(n <= bufferSize);
5949 if (n != bufferSize) {
5956 if (fputc(c, fp) < 0)
5967 } /* namespace js */