Bug 469739 - Add support for displaying Vista UAC shield icon; r=joe sr=vladimir
[wine-gecko.git] / js / src / jsstr.cpp
blob3b676880d2fc9a786cecc7b863f2c0c3ce580901
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
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
25 * Contributor(s):
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.
51 #include "jsstddef.h"
52 #include <stdlib.h>
53 #include <string.h>
54 #include "jstypes.h"
55 #include "jsutil.h" /* Added by JSIFY */
56 #include "jshash.h" /* Added by JSIFY */
57 #include "jsprf.h"
58 #include "jsapi.h"
59 #include "jsarray.h"
60 #include "jsatom.h"
61 #include "jsbool.h"
62 #include "jsbuiltins.h"
63 #include "jscntxt.h"
64 #include "jsversion.h"
65 #include "jsgc.h"
66 #include "jsinterp.h"
67 #include "jslock.h"
68 #include "jsnum.h"
69 #include "jsobj.h"
70 #include "jsopcode.h"
71 #include "jsregexp.h"
72 #include "jsscope.h"
73 #include "jsstr.h"
74 #include "jsbit.h"
76 #define JSSTRDEP_RECURSION_LIMIT 100
78 size_t
79 js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
81 JSString *base;
82 size_t start, length;
84 JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
85 base = JSSTRDEP_BASE(str);
86 start = JSSTRDEP_START(str);
87 if (JSSTRING_IS_DEPENDENT(base)) {
88 if (level < JSSTRDEP_RECURSION_LIMIT) {
89 start += js_MinimizeDependentStrings(base, level + 1, &base);
90 } else {
91 do {
92 start += JSSTRDEP_START(base);
93 base = JSSTRDEP_BASE(base);
94 } while (JSSTRING_IS_DEPENDENT(base));
96 if (start == 0) {
97 JS_ASSERT(JSSTRDEP_IS_PREFIX(str));
98 JSPREFIX_SET_BASE(str, base);
99 } else if (start <= JSSTRDEP_START_MASK) {
100 length = JSSTRDEP_LENGTH(str);
101 JSSTRDEP_INIT(str, base, start, length);
104 *basep = base;
105 return start;
108 jschar *
109 js_GetDependentStringChars(JSString *str)
111 size_t start;
112 JSString *base;
114 start = js_MinimizeDependentStrings(str, 0, &base);
115 JS_ASSERT(start < JSFLATSTR_LENGTH(base));
116 return JSFLATSTR_CHARS(base) + start;
119 const jschar *
120 js_GetStringChars(JSContext *cx, JSString *str)
122 if (!js_MakeStringImmutable(cx, str))
123 return NULL;
124 return JSFLATSTR_CHARS(str);
127 JSString * JS_FASTCALL
128 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
130 size_t rn, ln, lrdist, n;
131 jschar *rs, *ls, *s;
132 JSString *ldep; /* non-null if left should become dependent */
133 JSString *str;
135 JSSTRING_CHARS_AND_LENGTH(right, rs, rn);
136 if (rn == 0)
137 return left;
139 JSSTRING_CHARS_AND_LENGTH(left, ls, ln);
140 if (ln == 0)
141 return right;
143 if (!JSSTRING_IS_MUTABLE(left)) {
144 /* We must copy if left does not own a buffer to realloc. */
145 s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
146 if (!s)
147 return NULL;
148 js_strncpy(s, ls, ln);
149 ldep = NULL;
150 } else {
151 /* We can realloc left's space and make it depend on our result. */
152 JS_ASSERT(JSSTRING_IS_FLAT(left));
153 s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
154 if (!s)
155 return NULL;
157 /* Take care: right could depend on left! */
158 lrdist = (size_t)(rs - ls);
159 if (lrdist < ln)
160 rs = s + lrdist;
161 left->u.chars = ls = s;
162 ldep = left;
165 js_strncpy(s + ln, rs, rn);
166 n = ln + rn;
167 s[n] = 0;
168 str = js_NewString(cx, s, n);
169 if (!str) {
170 /* Out of memory: clean up any space we (re-)allocated. */
171 if (!ldep) {
172 JS_free(cx, s);
173 } else {
174 s = (jschar *) JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
175 if (s)
176 left->u.chars = s;
178 } else {
179 JSFLATSTR_SET_MUTABLE(str);
181 /* Morph left into a dependent prefix if we realloc'd its buffer. */
182 if (ldep) {
183 JSPREFIX_INIT(ldep, str, ln);
184 #ifdef DEBUG
186 JSRuntime *rt = cx->runtime;
187 JS_RUNTIME_METER(rt, liveDependentStrings);
188 JS_RUNTIME_METER(rt, totalDependentStrings);
189 JS_LOCK_RUNTIME_VOID(rt,
190 (rt->strdepLengthSum += (double)ln,
191 rt->strdepLengthSquaredSum += (double)ln * (double)ln));
193 #endif
197 return str;
200 const jschar *
201 js_UndependString(JSContext *cx, JSString *str)
203 size_t n, size;
204 jschar *s;
206 if (JSSTRING_IS_DEPENDENT(str)) {
207 n = JSSTRDEP_LENGTH(str);
208 size = (n + 1) * sizeof(jschar);
209 s = (jschar *) JS_malloc(cx, size);
210 if (!s)
211 return NULL;
213 js_strncpy(s, JSSTRDEP_CHARS(str), n);
214 s[n] = 0;
215 JSFLATSTR_INIT(str, s, n);
217 #ifdef DEBUG
219 JSRuntime *rt = cx->runtime;
220 JS_RUNTIME_UNMETER(rt, liveDependentStrings);
221 JS_RUNTIME_UNMETER(rt, totalDependentStrings);
222 JS_LOCK_RUNTIME_VOID(rt,
223 (rt->strdepLengthSum -= (double)n,
224 rt->strdepLengthSquaredSum -= (double)n * (double)n));
226 #endif
229 return JSFLATSTR_CHARS(str);
232 JSBool
233 js_MakeStringImmutable(JSContext *cx, JSString *str)
235 if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(cx, str)) {
236 JS_RUNTIME_METER(cx->runtime, badUndependStrings);
237 return JS_FALSE;
239 JSFLATSTR_CLEAR_MUTABLE(str);
240 return JS_TRUE;
243 static JSString *
244 ArgToRootedString(JSContext *cx, uintN argc, jsval *vp, uintN arg)
246 JSObject *obj;
247 JSString *str;
249 if (arg >= argc)
250 return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
251 vp += 2 + arg;
253 if (JSVAL_IS_OBJECT(*vp)) {
254 obj = JSVAL_TO_OBJECT(*vp);
255 if (!obj)
256 return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
257 if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, vp))
258 return NULL;
260 if (JSVAL_IS_STRING(*vp))
261 return JSVAL_TO_STRING(*vp);
262 if (JSVAL_IS_INT(*vp)) {
263 str = js_NumberToString(cx, JSVAL_TO_INT(*vp));
264 } else if (JSVAL_IS_DOUBLE(*vp)) {
265 str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(*vp));
266 } else if (JSVAL_IS_BOOLEAN(*vp)) {
267 return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[
268 JSVAL_TO_BOOLEAN(*vp)? 1 : 0]);
269 } else {
270 JS_ASSERT(JSVAL_IS_VOID(*vp));
271 return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
273 if (str)
274 *vp = STRING_TO_JSVAL(str);
275 return str;
279 * Forward declarations for URI encode/decode and helper routines
281 static JSBool
282 str_decodeURI(JSContext *cx, uintN argc, jsval *vp);
284 static JSBool
285 str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp);
287 static JSBool
288 str_encodeURI(JSContext *cx, uintN argc, jsval *vp);
290 static JSBool
291 str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp);
293 static uint32
294 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
297 * Contributions from the String class to the set of methods defined for the
298 * global object. escape and unescape used to be defined in the Mocha library,
299 * but as ECMA decided to spec them, they've been moved to the core engine
300 * and made ECMA-compliant. (Incomplete escapes are interpreted as literal
301 * characters by unescape.)
305 * Stuff to emulate the old libmocha escape, which took a second argument
306 * giving the type of escape to perform. Retained for compatibility, and
307 * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
310 #define URL_XALPHAS ((uint8) 1)
311 #define URL_XPALPHAS ((uint8) 2)
312 #define URL_PATH ((uint8) 4)
314 static const uint8 urlCharType[256] =
315 /* Bit 0 xalpha -- the alphas
316 * Bit 1 xpalpha -- as xalpha but
317 * converts spaces to plus and plus to %20
318 * Bit 2 ... path -- as xalphas but doesn't escape '/'
320 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
321 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
322 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
323 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
324 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
325 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
326 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
327 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
328 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
329 0, };
331 /* This matches the ECMA escape set when mask is 7 (default.) */
333 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
335 /* See ECMA-262 Edition 3 B.2.1 */
336 JSBool
337 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
339 JSString *str;
340 size_t i, ni, length, newlength;
341 const jschar *chars;
342 jschar *newchars;
343 jschar ch;
344 jsint mask;
345 jsdouble d;
346 const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
347 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
349 mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
350 if (argc > 1) {
351 d = js_ValueToNumber(cx, &argv[1]);
352 if (JSVAL_IS_NULL(argv[1]))
353 return JS_FALSE;
354 if (!JSDOUBLE_IS_FINITE(d) ||
355 (mask = (jsint)d) != d ||
356 mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
358 char numBuf[12];
359 JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
360 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
361 JSMSG_BAD_STRING_MASK, numBuf);
362 return JS_FALSE;
366 str = ArgToRootedString(cx, argc, argv - 2, 0);
367 if (!str)
368 return JS_FALSE;
370 JSSTRING_CHARS_AND_LENGTH(str, chars, length);
371 newlength = length;
373 /* Take a first pass and see how big the result string will need to be. */
374 for (i = 0; i < length; i++) {
375 if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
376 continue;
377 if (ch < 256) {
378 if (mask == URL_XPALPHAS && ch == ' ')
379 continue; /* The character will be encoded as '+' */
380 newlength += 2; /* The character will be encoded as %XX */
381 } else {
382 newlength += 5; /* The character will be encoded as %uXXXX */
386 * This overflow test works because newlength is incremented by at
387 * most 5 on each iteration.
389 if (newlength < length) {
390 js_ReportAllocationOverflow(cx);
391 return JS_FALSE;
395 if (newlength >= ~(size_t)0 / sizeof(jschar)) {
396 js_ReportAllocationOverflow(cx);
397 return JS_FALSE;
400 newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
401 if (!newchars)
402 return JS_FALSE;
403 for (i = 0, ni = 0; i < length; i++) {
404 if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
405 newchars[ni++] = ch;
406 } else if (ch < 256) {
407 if (mask == URL_XPALPHAS && ch == ' ') {
408 newchars[ni++] = '+'; /* convert spaces to pluses */
409 } else {
410 newchars[ni++] = '%';
411 newchars[ni++] = digits[ch >> 4];
412 newchars[ni++] = digits[ch & 0xF];
414 } else {
415 newchars[ni++] = '%';
416 newchars[ni++] = 'u';
417 newchars[ni++] = digits[ch >> 12];
418 newchars[ni++] = digits[(ch & 0xF00) >> 8];
419 newchars[ni++] = digits[(ch & 0xF0) >> 4];
420 newchars[ni++] = digits[ch & 0xF];
423 JS_ASSERT(ni == newlength);
424 newchars[newlength] = 0;
426 str = js_NewString(cx, newchars, newlength);
427 if (!str) {
428 JS_free(cx, newchars);
429 return JS_FALSE;
431 *rval = STRING_TO_JSVAL(str);
432 return JS_TRUE;
434 #undef IS_OK
436 static JSBool
437 str_escape(JSContext *cx, uintN argc, jsval *vp)
439 JSObject *obj;
441 obj = JS_THIS_OBJECT(cx, vp);
442 return obj && js_str_escape(cx, obj, argc, vp + 2, vp);
445 /* See ECMA-262 Edition 3 B.2.2 */
446 static JSBool
447 str_unescape(JSContext *cx, uintN argc, jsval *vp)
449 JSString *str;
450 size_t i, ni, length;
451 const jschar *chars;
452 jschar *newchars;
453 jschar ch;
455 str = ArgToRootedString(cx, argc, vp, 0);
456 if (!str)
457 return JS_FALSE;
459 JSSTRING_CHARS_AND_LENGTH(str, chars, length);
461 /* Don't bother allocating less space for the new string. */
462 newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
463 if (!newchars)
464 return JS_FALSE;
465 ni = i = 0;
466 while (i < length) {
467 ch = chars[i++];
468 if (ch == '%') {
469 if (i + 1 < length &&
470 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
472 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
473 i += 2;
474 } else if (i + 4 < length && chars[i] == 'u' &&
475 JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
476 JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
478 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
479 + JS7_UNHEX(chars[i + 2])) << 4)
480 + JS7_UNHEX(chars[i + 3])) << 4)
481 + JS7_UNHEX(chars[i + 4]);
482 i += 5;
485 newchars[ni++] = ch;
487 newchars[ni] = 0;
489 str = js_NewString(cx, newchars, ni);
490 if (!str) {
491 JS_free(cx, newchars);
492 return JS_FALSE;
494 *vp = STRING_TO_JSVAL(str);
495 return JS_TRUE;
498 #if JS_HAS_UNEVAL
499 static JSBool
500 str_uneval(JSContext *cx, uintN argc, jsval *vp)
502 JSString *str;
504 str = js_ValueToSource(cx, argc != 0 ? vp[2] : JSVAL_VOID);
505 if (!str)
506 return JS_FALSE;
507 *vp = STRING_TO_JSVAL(str);
508 return JS_TRUE;
510 #endif
512 const char js_escape_str[] = "escape";
513 const char js_unescape_str[] = "unescape";
514 #if JS_HAS_UNEVAL
515 const char js_uneval_str[] = "uneval";
516 #endif
517 const char js_decodeURI_str[] = "decodeURI";
518 const char js_encodeURI_str[] = "encodeURI";
519 const char js_decodeURIComponent_str[] = "decodeURIComponent";
520 const char js_encodeURIComponent_str[] = "encodeURIComponent";
522 static JSFunctionSpec string_functions[] = {
523 JS_FN(js_escape_str, str_escape, 1,0),
524 JS_FN(js_unescape_str, str_unescape, 1,0),
525 #if JS_HAS_UNEVAL
526 JS_FN(js_uneval_str, str_uneval, 1,0),
527 #endif
528 JS_FN(js_decodeURI_str, str_decodeURI, 1,0),
529 JS_FN(js_encodeURI_str, str_encodeURI, 1,0),
530 JS_FN(js_decodeURIComponent_str, str_decodeURI_Component, 1,0),
531 JS_FN(js_encodeURIComponent_str, str_encodeURI_Component, 1,0),
533 JS_FS_END
536 jschar js_empty_ucstr[] = {0};
537 JSSubString js_EmptySubString = {0, js_empty_ucstr};
539 enum string_tinyid {
540 STRING_LENGTH = -1
543 static JSPropertySpec string_props[] = {
544 {js_length_str, STRING_LENGTH,
545 JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0},
546 {0,0,0,0,0}
549 static JSBool
550 str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
552 jsval v;
553 JSString *str;
554 jsint slot;
556 if (!JSVAL_IS_INT(id))
557 return JS_TRUE;
559 slot = JSVAL_TO_INT(id);
560 if (slot == STRING_LENGTH) {
561 if (OBJ_GET_CLASS(cx, obj) == &js_StringClass) {
562 /* Follow ECMA-262 by fetching intrinsic length of our string. */
563 v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
564 JS_ASSERT(JSVAL_IS_STRING(v));
565 str = JSVAL_TO_STRING(v);
566 } else {
567 /* Preserve compatibility: convert obj to a string primitive. */
568 str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
569 if (!str)
570 return JS_FALSE;
573 *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
575 return JS_TRUE;
578 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
580 static JSBool
581 str_enumerate(JSContext *cx, JSObject *obj)
583 jsval v;
584 JSString *str, *str1;
585 size_t i, length;
587 v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
588 JS_ASSERT(JSVAL_IS_STRING(v));
589 str = JSVAL_TO_STRING(v);
591 length = JSSTRING_LENGTH(str);
592 for (i = 0; i < length; i++) {
593 str1 = js_NewDependentString(cx, str, i, 1);
594 if (!str1)
595 return JS_FALSE;
596 if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(i),
597 STRING_TO_JSVAL(str1), NULL, NULL,
598 STRING_ELEMENT_ATTRS, NULL)) {
599 return JS_FALSE;
602 return JS_TRUE;
605 static JSBool
606 str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
607 JSObject **objp)
609 jsval v;
610 JSString *str, *str1;
611 jsint slot;
613 if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING))
614 return JS_TRUE;
616 v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
617 JS_ASSERT(JSVAL_IS_STRING(v));
618 str = JSVAL_TO_STRING(v);
620 slot = JSVAL_TO_INT(id);
621 if ((size_t)slot < JSSTRING_LENGTH(str)) {
622 str1 = js_GetUnitString(cx, str, (size_t)slot);
623 if (!str1)
624 return JS_FALSE;
625 if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(slot),
626 STRING_TO_JSVAL(str1), NULL, NULL,
627 STRING_ELEMENT_ATTRS, NULL)) {
628 return JS_FALSE;
630 *objp = obj;
632 return JS_TRUE;
635 JSClass js_StringClass = {
636 js_String_str,
637 JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
638 JSCLASS_HAS_CACHED_PROTO(JSProto_String),
639 JS_PropertyStub, JS_PropertyStub, str_getProperty, JS_PropertyStub,
640 str_enumerate, (JSResolveOp)str_resolve, JS_ConvertStub, JS_FinalizeStub,
641 JSCLASS_NO_OPTIONAL_MEMBERS
644 #define NORMALIZE_THIS(cx,vp,str) \
645 JS_BEGIN_MACRO \
646 if (JSVAL_IS_STRING(vp[1])) { \
647 str = JSVAL_TO_STRING(vp[1]); \
648 } else { \
649 str = NormalizeThis(cx, vp); \
650 if (!str) \
651 return JS_FALSE; \
653 JS_END_MACRO
655 static JSString *
656 NormalizeThis(JSContext *cx, jsval *vp)
658 JSString *str;
660 if (JSVAL_IS_NULL(vp[1]) && JSVAL_IS_NULL(JS_THIS(cx, vp)))
661 return NULL;
662 str = js_ValueToString(cx, vp[1]);
663 if (!str)
664 return NULL;
665 vp[1] = STRING_TO_JSVAL(str);
666 return str;
669 #if JS_HAS_TOSOURCE
672 * String.prototype.quote is generic (as are most string methods), unlike
673 * toSource, toString, and valueOf.
675 static JSBool
676 str_quote(JSContext *cx, uintN argc, jsval *vp)
678 JSString *str;
680 NORMALIZE_THIS(cx, vp, str);
681 str = js_QuoteString(cx, str, '"');
682 if (!str)
683 return JS_FALSE;
684 *vp = STRING_TO_JSVAL(str);
685 return JS_TRUE;
688 static JSBool
689 str_toSource(JSContext *cx, uintN argc, jsval *vp)
691 jsval v;
692 JSString *str;
693 size_t i, j, k, n;
694 char buf[16];
695 jschar *s, *t;
697 if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &v))
698 return JS_FALSE;
699 JS_ASSERT(JSVAL_IS_STRING(v));
700 str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
701 if (!str)
702 return JS_FALSE;
703 j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name);
704 JSSTRING_CHARS_AND_LENGTH(str, s, k);
705 n = j + k + 2;
706 t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
707 if (!t)
708 return JS_FALSE;
709 for (i = 0; i < j; i++)
710 t[i] = buf[i];
711 for (j = 0; j < k; i++, j++)
712 t[i] = s[j];
713 t[i++] = ')';
714 t[i++] = ')';
715 t[i] = 0;
716 str = js_NewString(cx, t, n);
717 if (!str) {
718 JS_free(cx, t);
719 return JS_FALSE;
721 *vp = STRING_TO_JSVAL(str);
722 return JS_TRUE;
725 #endif /* JS_HAS_TOSOURCE */
727 static JSBool
728 str_toString(JSContext *cx, uintN argc, jsval *vp)
730 return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp);
734 * Java-like string native methods.
737 static JSString *
738 SubstringTail(JSContext *cx, JSString *str, jsdouble length, jsdouble begin, jsdouble end)
740 if (begin < 0)
741 begin = 0;
742 else if (begin > length)
743 begin = length;
745 if (end < 0)
746 end = 0;
747 else if (end > length)
748 end = length;
749 if (end < begin) {
750 /* ECMA emulates old JDK1.0 java.lang.String.substring. */
751 jsdouble tmp = begin;
752 begin = end;
753 end = tmp;
756 return js_NewDependentString(cx, str, (size_t)begin, (size_t)(end - begin));
759 static JSBool
760 str_substring(JSContext *cx, uintN argc, jsval *vp)
762 JSString *str;
763 jsdouble d;
764 jsdouble length, begin, end;
766 NORMALIZE_THIS(cx, vp, str);
767 if (argc != 0) {
768 d = js_ValueToNumber(cx, &vp[2]);
769 if (JSVAL_IS_NULL(vp[2]))
770 return JS_FALSE;
771 length = JSSTRING_LENGTH(str);
772 begin = js_DoubleToInteger(d);
773 if (argc == 1) {
774 end = length;
775 } else {
776 d = js_ValueToNumber(cx, &vp[3]);
777 if (JSVAL_IS_NULL(vp[3]))
778 return JS_FALSE;
779 end = js_DoubleToInteger(d);
782 str = SubstringTail(cx, str, length, begin, end);
783 if (!str)
784 return JS_FALSE;
786 *vp = STRING_TO_JSVAL(str);
787 return JS_TRUE;
790 #ifdef JS_TRACER
791 static JSString* FASTCALL
792 String_p_toString(JSContext* cx, JSObject* obj)
794 if (!JS_InstanceOf(cx, obj, &js_StringClass, NULL))
795 return NULL;
796 jsval v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
797 JS_ASSERT(JSVAL_IS_STRING(v));
798 return JSVAL_TO_STRING(v);
801 static JSString* FASTCALL
802 String_p_substring(JSContext* cx, JSString* str, int32 begin, int32 end)
804 JS_ASSERT(JS_ON_TRACE(cx));
806 size_t length = JSSTRING_LENGTH(str);
807 return SubstringTail(cx, str, length, begin, end);
810 static JSString* FASTCALL
811 String_p_substring_1(JSContext* cx, JSString* str, int32 begin)
813 JS_ASSERT(JS_ON_TRACE(cx));
815 size_t length = JSSTRING_LENGTH(str);
816 return SubstringTail(cx, str, length, begin, length);
818 #endif
820 JSString* JS_FASTCALL
821 js_toLowerCase(JSContext *cx, JSString *str)
823 size_t i, n;
824 jschar *s, *news;
826 JSSTRING_CHARS_AND_LENGTH(str, s, n);
827 news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
828 if (!news)
829 return NULL;
830 for (i = 0; i < n; i++)
831 news[i] = JS_TOLOWER(s[i]);
832 news[n] = 0;
833 str = js_NewString(cx, news, n);
834 if (!str) {
835 JS_free(cx, news);
836 return NULL;
838 return str;
841 static JSBool
842 str_toLowerCase(JSContext *cx, uintN argc, jsval *vp)
844 JSString *str;
846 NORMALIZE_THIS(cx, vp, str);
847 str = js_toLowerCase(cx, str);
848 if (!str)
849 return JS_FALSE;
850 *vp = STRING_TO_JSVAL(str);
851 return JS_TRUE;
854 static JSBool
855 str_toLocaleLowerCase(JSContext *cx, uintN argc, jsval *vp)
857 JSString *str;
860 * Forcefully ignore the first (or any) argument and return toLowerCase(),
861 * ECMA has reserved that argument, presumably for defining the locale.
863 if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
864 NORMALIZE_THIS(cx, vp, str);
865 return cx->localeCallbacks->localeToLowerCase(cx, str, vp);
867 return str_toLowerCase(cx, 0, vp);
870 JSString* JS_FASTCALL
871 js_toUpperCase(JSContext *cx, JSString *str)
873 size_t i, n;
874 jschar *s, *news;
876 JSSTRING_CHARS_AND_LENGTH(str, s, n);
877 news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
878 if (!news)
879 return NULL;
880 for (i = 0; i < n; i++)
881 news[i] = JS_TOUPPER(s[i]);
882 news[n] = 0;
883 str = js_NewString(cx, news, n);
884 if (!str) {
885 JS_free(cx, news);
886 return NULL;
888 return str;
891 static JSBool
892 str_toUpperCase(JSContext *cx, uintN argc, jsval *vp)
894 JSString *str;
896 NORMALIZE_THIS(cx, vp, str);
897 str = js_toUpperCase(cx, str);
898 if (!str)
899 return JS_FALSE;
900 *vp = STRING_TO_JSVAL(str);
901 return JS_TRUE;
904 static JSBool
905 str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp)
907 JSString *str;
910 * Forcefully ignore the first (or any) argument and return toUpperCase(),
911 * ECMA has reserved that argument, presumably for defining the locale.
913 if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
914 NORMALIZE_THIS(cx, vp, str);
915 return cx->localeCallbacks->localeToUpperCase(cx, str, vp);
917 return str_toUpperCase(cx, 0, vp);
920 static JSBool
921 str_localeCompare(JSContext *cx, uintN argc, jsval *vp)
923 JSString *str, *thatStr;
925 NORMALIZE_THIS(cx, vp, str);
926 if (argc == 0) {
927 *vp = JSVAL_ZERO;
928 } else {
929 thatStr = js_ValueToString(cx, vp[2]);
930 if (!thatStr)
931 return JS_FALSE;
932 if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
933 vp[2] = STRING_TO_JSVAL(thatStr);
934 return cx->localeCallbacks->localeCompare(cx, str, thatStr, vp);
936 *vp = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
938 return JS_TRUE;
941 static JSBool
942 str_charAt(JSContext *cx, uintN argc, jsval *vp)
944 jsval t;
945 JSString *str;
946 jsint i;
947 jsdouble d;
949 t = vp[1];
950 if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) {
951 str = JSVAL_TO_STRING(t);
952 i = JSVAL_TO_INT(vp[2]);
953 if ((size_t)i >= JSSTRING_LENGTH(str))
954 goto out_of_range;
955 } else {
956 str = NormalizeThis(cx, vp);
957 if (!str)
958 return JS_FALSE;
960 if (argc == 0) {
961 d = 0.0;
962 } else {
963 d = js_ValueToNumber(cx, &vp[2]);
964 if (JSVAL_IS_NULL(vp[2]))
965 return JS_FALSE;
966 d = js_DoubleToInteger(d);
969 if (d < 0 || JSSTRING_LENGTH(str) <= d)
970 goto out_of_range;
971 i = (jsint) d;
974 str = js_GetUnitString(cx, str, (size_t)i);
975 if (!str)
976 return JS_FALSE;
977 *vp = STRING_TO_JSVAL(str);
978 return JS_TRUE;
980 out_of_range:
981 *vp = JS_GetEmptyStringValue(cx);
982 return JS_TRUE;
985 static JSBool
986 str_charCodeAt(JSContext *cx, uintN argc, jsval *vp)
988 jsval t;
989 JSString *str;
990 jsint i;
991 jsdouble d;
993 t = vp[1];
994 if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) {
995 str = JSVAL_TO_STRING(t);
996 i = JSVAL_TO_INT(vp[2]);
997 if ((size_t)i >= JSSTRING_LENGTH(str))
998 goto out_of_range;
999 } else {
1000 str = NormalizeThis(cx, vp);
1001 if (!str)
1002 return JS_FALSE;
1004 if (argc == 0) {
1005 d = 0.0;
1006 } else {
1007 d = js_ValueToNumber(cx, &vp[2]);
1008 if (JSVAL_IS_NULL(vp[2]))
1009 return JS_FALSE;
1010 d = js_DoubleToInteger(d);
1013 if (d < 0 || JSSTRING_LENGTH(str) <= d)
1014 goto out_of_range;
1015 i = (jsint) d;
1018 *vp = INT_TO_JSVAL(JSSTRING_CHARS(str)[i]);
1019 return JS_TRUE;
1021 out_of_range:
1022 *vp = JS_GetNaNValue(cx);
1023 return JS_TRUE;
1026 #ifdef JS_TRACER
1027 int32 FASTCALL
1028 js_String_p_charCodeAt(JSString* str, int32 i)
1030 if (i < 0 || (int32)JSSTRING_LENGTH(str) <= i)
1031 return -1;
1032 return JSSTRING_CHARS(str)[i];
1034 #endif
1036 jsint
1037 js_BoyerMooreHorspool(const jschar *text, jsint textlen,
1038 const jschar *pat, jsint patlen,
1039 jsint start)
1041 jsint i, j, k, m;
1042 uint8 skip[BMH_CHARSET_SIZE];
1043 jschar c;
1045 JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
1046 for (i = 0; i < BMH_CHARSET_SIZE; i++)
1047 skip[i] = (uint8)patlen;
1048 m = patlen - 1;
1049 for (i = 0; i < m; i++) {
1050 c = pat[i];
1051 if (c >= BMH_CHARSET_SIZE)
1052 return BMH_BAD_PATTERN;
1053 skip[c] = (uint8)(m - i);
1055 for (k = start + m;
1056 k < textlen;
1057 k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
1058 for (i = k, j = m; ; i--, j--) {
1059 if (j < 0)
1060 return i + 1;
1061 if (text[i] != pat[j])
1062 break;
1065 return -1;
1068 static JSBool
1069 str_indexOf(JSContext *cx, uintN argc, jsval *vp)
1071 jsval t;
1072 JSString *str, *str2;
1073 const jschar *text, *pat;
1074 jsint i, j, index, textlen, patlen;
1075 jsdouble d;
1077 t = vp[1];
1078 if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_STRING(vp[2])) {
1079 str = JSVAL_TO_STRING(t);
1080 str2 = JSVAL_TO_STRING(vp[2]);
1081 } else {
1082 str = NormalizeThis(cx, vp);
1083 if (!str)
1084 return JS_FALSE;
1086 str2 = ArgToRootedString(cx, argc, vp, 0);
1087 if (!str2)
1088 return JS_FALSE;
1091 text = JSSTRING_CHARS(str);
1092 textlen = (jsint) JSSTRING_LENGTH(str);
1093 pat = JSSTRING_CHARS(str2);
1094 patlen = (jsint) JSSTRING_LENGTH(str2);
1096 if (argc > 1) {
1097 d = js_ValueToNumber(cx, &vp[3]);
1098 if (JSVAL_IS_NULL(vp[3]))
1099 return JS_FALSE;
1100 d = js_DoubleToInteger(d);
1101 if (d < 0)
1102 i = 0;
1103 else if (d > textlen)
1104 i = textlen;
1105 else
1106 i = (jsint)d;
1107 } else {
1108 i = 0;
1110 if (patlen == 0) {
1111 *vp = INT_TO_JSVAL(i);
1112 return JS_TRUE;
1115 /* XXX tune the BMH threshold (512) */
1116 if (textlen - i >= 512 && (jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2) {
1117 index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
1118 if (index != BMH_BAD_PATTERN)
1119 goto out;
1122 index = -1;
1123 j = 0;
1124 while (i + j < textlen) {
1125 if (text[i + j] == pat[j]) {
1126 if (++j == patlen) {
1127 index = i;
1128 break;
1130 } else {
1131 i++;
1132 j = 0;
1136 out:
1137 *vp = INT_TO_JSVAL(index);
1138 return JS_TRUE;
1141 static JSBool
1142 str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp)
1144 JSString *str, *str2;
1145 const jschar *text, *pat;
1146 jsint i, j, textlen, patlen;
1147 jsdouble d;
1149 NORMALIZE_THIS(cx, vp, str);
1150 text = JSSTRING_CHARS(str);
1151 textlen = (jsint) JSSTRING_LENGTH(str);
1153 str2 = ArgToRootedString(cx, argc, vp, 0);
1154 if (!str2)
1155 return JS_FALSE;
1156 pat = JSSTRING_CHARS(str2);
1157 patlen = (jsint) JSSTRING_LENGTH(str2);
1159 if (argc > 1) {
1160 d = js_ValueToNumber(cx, &vp[3]);
1161 if (JSVAL_IS_NULL(vp[3]))
1162 return JS_FALSE;
1163 if (JSDOUBLE_IS_NaN(d)) {
1164 i = textlen;
1165 } else {
1166 d = js_DoubleToInteger(d);
1167 if (d < 0)
1168 i = 0;
1169 else if (d > textlen)
1170 i = textlen;
1171 else
1172 i = (jsint)d;
1174 } else {
1175 i = textlen;
1178 if (patlen == 0) {
1179 *vp = INT_TO_JSVAL(i);
1180 return JS_TRUE;
1183 j = 0;
1184 while (i >= 0) {
1185 /* Don't assume that text is NUL-terminated: it could be dependent. */
1186 if (i + j < textlen && text[i + j] == pat[j]) {
1187 if (++j == patlen)
1188 break;
1189 } else {
1190 i--;
1191 j = 0;
1194 *vp = INT_TO_JSVAL(i);
1195 return JS_TRUE;
1198 static JSBool
1199 js_TrimString(JSContext *cx, jsval *vp, JSBool trimLeft, JSBool trimRight)
1201 JSString *str;
1202 const jschar *chars;
1203 size_t length, begin, end;
1205 NORMALIZE_THIS(cx, vp, str);
1206 JSSTRING_CHARS_AND_LENGTH(str, chars, length);
1207 begin = 0;
1208 end = length;
1210 if (trimLeft) {
1211 while (begin < length && JS_ISSPACE(chars[begin]))
1212 ++begin;
1215 if (trimRight) {
1216 while (end > begin && JS_ISSPACE(chars[end-1]))
1217 --end;
1220 str = js_NewDependentString(cx, str, begin, end - begin);
1221 if (!str)
1222 return JS_FALSE;
1224 *vp = STRING_TO_JSVAL(str);
1225 return JS_TRUE;
1228 static JSBool
1229 str_trim(JSContext *cx, uintN argc, jsval *vp)
1231 return js_TrimString(cx, vp, JS_TRUE, JS_TRUE);
1234 static JSBool
1235 str_trimLeft(JSContext *cx, uintN argc, jsval *vp)
1237 return js_TrimString(cx, vp, JS_TRUE, JS_FALSE);
1240 static JSBool
1241 str_trimRight(JSContext *cx, uintN argc, jsval *vp)
1243 return js_TrimString(cx, vp, JS_FALSE, JS_TRUE);
1247 * Perl-inspired string functions.
1249 typedef struct GlobData {
1250 jsbytecode *pc; /* in: program counter resulting in us matching */
1251 uintN flags; /* inout: mode and flag bits, see below */
1252 uintN optarg; /* in: index of optional flags argument */
1253 JSString *str; /* out: 'this' parameter object as string */
1254 JSRegExp *regexp; /* out: regexp parameter object private data */
1255 } GlobData;
1258 * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
1260 #define MODE_MATCH 0x00 /* in: return match array on success */
1261 #define MODE_REPLACE 0x01 /* in: match and replace */
1262 #define MODE_SEARCH 0x02 /* in: search only, return match index or -1 */
1263 #define GET_MODE(f) ((f) & 0x03)
1264 #define FORCE_FLAT 0x04 /* in: force flat (non-regexp) string match */
1265 #define KEEP_REGEXP 0x08 /* inout: keep GlobData.regexp alive for caller
1266 of match_or_replace; if set on input
1267 but clear on output, regexp ownership
1268 does not pass to caller */
1269 #define GLOBAL_REGEXP 0x10 /* out: regexp had the 'g' flag */
1271 static JSBool
1272 match_or_replace(JSContext *cx,
1273 JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
1274 void (*destroy)(JSContext *cx, GlobData *data),
1275 GlobData *data, uintN argc, jsval *vp)
1277 JSString *str, *src, *opt;
1278 JSObject *reobj;
1279 JSRegExp *re;
1280 size_t index, length;
1281 JSBool ok, test;
1282 jsint count;
1284 NORMALIZE_THIS(cx, vp, str);
1285 data->str = str;
1287 if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) {
1288 reobj = JSVAL_TO_OBJECT(vp[2]);
1289 re = (JSRegExp *) JS_GetPrivate(cx, reobj);
1290 } else {
1291 src = ArgToRootedString(cx, argc, vp, 0);
1292 if (!src)
1293 return JS_FALSE;
1294 if (data->optarg < argc) {
1295 opt = js_ValueToString(cx, vp[2 + data->optarg]);
1296 if (!opt)
1297 return JS_FALSE;
1298 } else {
1299 opt = NULL;
1301 re = js_NewRegExpOpt(cx, src, opt, (data->flags & FORCE_FLAT) != 0);
1302 if (!re)
1303 return JS_FALSE;
1304 reobj = NULL;
1306 /* From here on, all control flow must reach the matching DROP. */
1307 data->regexp = re;
1308 HOLD_REGEXP(cx, re);
1310 if (re->flags & JSREG_GLOB)
1311 data->flags |= GLOBAL_REGEXP;
1312 index = 0;
1313 if (GET_MODE(data->flags) == MODE_SEARCH) {
1314 ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp);
1315 if (ok) {
1316 *vp = (*vp == JSVAL_TRUE)
1317 ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
1318 : INT_TO_JSVAL(-1);
1320 } else if (data->flags & GLOBAL_REGEXP) {
1321 if (reobj) {
1322 /* Set the lastIndex property's reserved slot to 0. */
1323 ok = js_SetLastIndex(cx, reobj, 0);
1324 } else {
1325 ok = JS_TRUE;
1327 if (ok) {
1328 length = JSSTRING_LENGTH(str);
1329 for (count = 0; index <= length; count++) {
1330 ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp);
1331 if (!ok || *vp != JSVAL_TRUE)
1332 break;
1333 ok = glob(cx, count, data);
1334 if (!ok)
1335 break;
1336 if (cx->regExpStatics.lastMatch.length == 0) {
1337 if (index == length)
1338 break;
1339 index++;
1342 if (!ok && destroy)
1343 destroy(cx, data);
1345 } else {
1346 jsval savedObject = JSVAL_NULL;
1348 if (GET_MODE(data->flags) == MODE_REPLACE) {
1349 test = JS_TRUE;
1350 } else {
1352 * MODE_MATCH implies str_match is being called from a script or a
1353 * scripted function. If the caller cares only about testing null
1354 * vs. non-null return value, optimize away the array object that
1355 * would normally be returned in *vp. Instead return an arbitrary
1356 * object (not JSVAL_TRUE, for type map integrity; see bug 453564).
1357 * The caller provides the object in *vp and is responsible for
1358 * rooting it elsewhere.
1360 * Assume a full array result is required, then prove otherwise.
1362 test = JS_FALSE;
1363 if (data->pc && (*data->pc == JSOP_CALL || *data->pc == JSOP_NEW)) {
1364 JS_ASSERT(js_CodeSpec[*data->pc].length == 3);
1365 switch (data->pc[3]) {
1366 case JSOP_POP:
1367 case JSOP_IFEQ:
1368 case JSOP_IFNE:
1369 case JSOP_IFEQX:
1370 case JSOP_IFNEX:
1371 test = JS_TRUE;
1372 savedObject = *vp;
1373 JS_ASSERT(!JSVAL_IS_PRIMITIVE(savedObject));
1374 break;
1375 default:;
1379 ok = js_ExecuteRegExp(cx, re, str, &index, test, vp);
1380 if (ok && !JSVAL_IS_NULL(savedObject) && *vp == JSVAL_TRUE)
1381 *vp = savedObject;
1384 DROP_REGEXP(cx, re);
1385 if (reobj) {
1386 /* Tell our caller that it doesn't need to destroy data->regexp. */
1387 data->flags &= ~KEEP_REGEXP;
1388 } else if (!ok || !(data->flags & KEEP_REGEXP)) {
1389 /* Caller didn't want to keep data->regexp, so null and destroy it. */
1390 data->regexp = NULL;
1391 js_DestroyRegExp(cx, re);
1394 return ok;
1397 typedef struct MatchData {
1398 GlobData base;
1399 jsval *arrayval; /* NB: local root pointer */
1400 } MatchData;
1402 static JSBool
1403 match_glob(JSContext *cx, jsint count, GlobData *data)
1405 MatchData *mdata;
1406 JSObject *arrayobj;
1407 JSSubString *matchsub;
1408 JSString *matchstr;
1409 jsval v;
1411 mdata = (MatchData *)data;
1412 arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
1413 if (!arrayobj) {
1414 arrayobj = js_NewArrayObject(cx, 0, NULL);
1415 if (!arrayobj)
1416 return JS_FALSE;
1417 *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
1419 matchsub = &cx->regExpStatics.lastMatch;
1420 matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length);
1421 if (!matchstr)
1422 return JS_FALSE;
1423 v = STRING_TO_JSVAL(matchstr);
1424 JS_ASSERT(count <= JSVAL_INT_MAX);
1426 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
1427 return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v);
1430 static JSBool
1431 StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc)
1433 JSTempValueRooter tvr;
1434 MatchData mdata;
1435 JSBool ok;
1437 JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
1438 mdata.base.pc = pc;
1439 mdata.base.flags = MODE_MATCH;
1440 mdata.base.optarg = 1;
1441 mdata.arrayval = &tvr.u.value;
1442 ok = match_or_replace(cx, match_glob, NULL, &mdata.base, argc, vp);
1443 if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
1444 *vp = *mdata.arrayval;
1445 JS_POP_TEMP_ROOT(cx, &tvr);
1446 return ok;
1449 static JSBool
1450 str_match(JSContext *cx, uintN argc, jsval *vp)
1452 JSStackFrame *fp;
1454 for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
1455 JS_ASSERT(!fp->script);
1457 /* Root the object in vp[0]. See comment in match_or_replace. */
1458 JSAutoTempValueRooter tvr(cx, vp[0]);
1459 return StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL);
1462 #ifdef JS_TRACER
1463 static JSObject* FASTCALL
1464 String_p_match(JSContext* cx, JSString* str, jsbytecode *pc, JSObject* regexp)
1466 /* arbitrary object in vp[0] */
1467 jsval vp[3] = { OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) };
1468 if (!StringMatchHelper(cx, 1, vp, pc))
1469 return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID);
1470 JS_ASSERT(JSVAL_IS_OBJECT(vp[0]));
1471 return JSVAL_TO_OBJECT(vp[0]);
1474 static JSObject* FASTCALL
1475 String_p_match_obj(JSContext* cx, JSObject* str, jsbytecode *pc, JSObject* regexp)
1477 /* arbitrary object in vp[0] */
1478 jsval vp[3] = { OBJECT_TO_JSVAL(regexp), OBJECT_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) };
1479 if (!StringMatchHelper(cx, 1, vp, pc))
1480 return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID);
1481 JS_ASSERT(JSVAL_IS_OBJECT(vp[0]));
1482 return JSVAL_TO_OBJECT(vp[0]);
1484 #endif
1486 static JSBool
1487 str_search(JSContext *cx, uintN argc, jsval *vp)
1489 GlobData data;
1491 data.flags = MODE_SEARCH;
1492 data.optarg = 1;
1493 return match_or_replace(cx, NULL, NULL, &data, argc, vp);
1496 typedef struct ReplaceData {
1497 GlobData base; /* base struct state */
1498 JSObject *lambda; /* replacement function object or null */
1499 JSString *repstr; /* replacement string */
1500 jschar *dollar; /* null or pointer to first $ in repstr */
1501 jschar *dollarEnd; /* limit pointer for js_strchr_limit */
1502 jschar *chars; /* result chars, null initially */
1503 size_t length; /* result length, 0 initially */
1504 jsint index; /* index in result of next replacement */
1505 jsint leftIndex; /* left context index in base.str->chars */
1506 JSSubString dollarStr; /* for "$$" interpret_dollar result */
1507 } ReplaceData;
1509 static JSSubString *
1510 interpret_dollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData *rdata,
1511 size_t *skip)
1513 JSRegExpStatics *res;
1514 jschar dc, *cp;
1515 uintN num, tmp;
1517 JS_ASSERT(*dp == '$');
1519 /* If there is only a dollar, bail now */
1520 if (dp + 1 >= ep)
1521 return NULL;
1523 /* Interpret all Perl match-induced dollar variables. */
1524 res = &cx->regExpStatics;
1525 dc = dp[1];
1526 if (JS7_ISDEC(dc)) {
1527 /* ECMA-262 Edition 3: 1-9 or 01-99 */
1528 num = JS7_UNDEC(dc);
1529 if (num > res->parenCount)
1530 return NULL;
1532 cp = dp + 2;
1533 if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
1534 tmp = 10 * num + JS7_UNDEC(dc);
1535 if (tmp <= res->parenCount) {
1536 cp++;
1537 num = tmp;
1540 if (num == 0)
1541 return NULL;
1543 /* Adjust num from 1 $n-origin to 0 array-index-origin. */
1544 num--;
1545 *skip = cp - dp;
1546 return REGEXP_PAREN_SUBSTRING(res, num);
1549 *skip = 2;
1550 switch (dc) {
1551 case '$':
1552 rdata->dollarStr.chars = dp;
1553 rdata->dollarStr.length = 1;
1554 return &rdata->dollarStr;
1555 case '&':
1556 return &res->lastMatch;
1557 case '+':
1558 return &res->lastParen;
1559 case '`':
1560 return &res->leftContext;
1561 case '\'':
1562 return &res->rightContext;
1564 return NULL;
1567 static JSBool
1568 find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
1570 JSString *repstr;
1571 size_t replen, skip;
1572 jschar *dp, *ep;
1573 JSSubString *sub;
1574 JSObject *lambda;
1576 lambda = rdata->lambda;
1577 if (lambda) {
1578 uintN argc, i, j, m, n, p;
1579 jsval *invokevp, *sp;
1580 void *mark;
1581 JSBool ok;
1584 * Save the regExpStatics from the current regexp, since they may be
1585 * clobbered by a RegExp usage in the lambda function. Note that all
1586 * members of JSRegExpStatics are JSSubStrings, so not GC roots, save
1587 * input, which is rooted otherwise via vp[1] in str_replace.
1589 JSRegExpStatics save = cx->regExpStatics;
1590 JSBool freeMoreParens = JS_FALSE;
1593 * In the lambda case, not only do we find the replacement string's
1594 * length, we compute repstr and return it via rdata for use within
1595 * do_replace. The lambda is called with arguments ($&, $1, $2, ...,
1596 * index, input), i.e., all the properties of a regexp match array.
1597 * For $&, etc., we must create string jsvals from cx->regExpStatics.
1598 * We grab up stack space to keep the newborn strings GC-rooted.
1600 p = rdata->base.regexp->parenCount;
1601 argc = 1 + p + 2;
1602 invokevp = js_AllocStack(cx, 2 + argc, &mark);
1603 if (!invokevp)
1604 return JS_FALSE;
1606 /* Push lambda and its 'this' parameter. */
1607 sp = invokevp;
1608 *sp++ = OBJECT_TO_JSVAL(lambda);
1609 *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
1611 #define PUSH_REGEXP_STATIC(sub) \
1612 JS_BEGIN_MACRO \
1613 JSString *str = js_NewStringCopyN(cx, \
1614 cx->regExpStatics.sub.chars, \
1615 cx->regExpStatics.sub.length); \
1616 if (!str) { \
1617 ok = JS_FALSE; \
1618 goto lambda_out; \
1620 *sp++ = STRING_TO_JSVAL(str); \
1621 JS_END_MACRO
1623 /* Push $&, $1, $2, ... */
1624 PUSH_REGEXP_STATIC(lastMatch);
1625 i = 0;
1626 m = cx->regExpStatics.parenCount;
1627 n = JS_MIN(m, 9);
1628 for (j = 0; i < n; i++, j++)
1629 PUSH_REGEXP_STATIC(parens[j]);
1630 for (j = 0; i < m; i++, j++)
1631 PUSH_REGEXP_STATIC(moreParens[j]);
1634 * We need to clear moreParens in the top-of-stack cx->regExpStatics
1635 * to it won't be possibly realloc'ed, leaving the bottom-of-stack
1636 * moreParens pointing to freed memory.
1638 cx->regExpStatics.moreParens = NULL;
1639 freeMoreParens = JS_TRUE;
1641 #undef PUSH_REGEXP_STATIC
1643 /* Make sure to push undefined for any unmatched parens. */
1644 for (; i < p; i++)
1645 *sp++ = JSVAL_VOID;
1647 /* Push match index and input string. */
1648 *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
1649 *sp++ = STRING_TO_JSVAL(rdata->base.str);
1651 ok = js_Invoke(cx, argc, invokevp, 0);
1652 if (ok) {
1654 * NB: we count on the newborn string root to hold any string
1655 * created by this js_ValueToString that would otherwise be GC-
1656 * able, until we use rdata->repstr in do_replace.
1658 repstr = js_ValueToString(cx, *invokevp);
1659 if (!repstr) {
1660 ok = JS_FALSE;
1661 } else {
1662 rdata->repstr = repstr;
1663 *sizep = JSSTRING_LENGTH(repstr);
1667 lambda_out:
1668 js_FreeStack(cx, mark);
1669 if (freeMoreParens)
1670 JS_free(cx, cx->regExpStatics.moreParens);
1671 cx->regExpStatics = save;
1672 return ok;
1675 repstr = rdata->repstr;
1676 replen = JSSTRING_LENGTH(repstr);
1677 for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1678 dp = js_strchr_limit(dp, '$', ep)) {
1679 sub = interpret_dollar(cx, dp, ep, rdata, &skip);
1680 if (sub) {
1681 replen += sub->length - skip;
1682 dp += skip;
1684 else
1685 dp++;
1687 *sizep = replen;
1688 return JS_TRUE;
1691 static void
1692 do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
1694 JSString *repstr;
1695 jschar *bp, *cp, *dp, *ep;
1696 size_t len, skip;
1697 JSSubString *sub;
1699 repstr = rdata->repstr;
1700 bp = cp = JSSTRING_CHARS(repstr);
1701 for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1702 dp = js_strchr_limit(dp, '$', ep)) {
1703 len = dp - cp;
1704 js_strncpy(chars, cp, len);
1705 chars += len;
1706 cp = dp;
1707 sub = interpret_dollar(cx, dp, ep, rdata, &skip);
1708 if (sub) {
1709 len = sub->length;
1710 js_strncpy(chars, sub->chars, len);
1711 chars += len;
1712 cp += skip;
1713 dp += skip;
1714 } else {
1715 dp++;
1718 js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
1721 static void
1722 replace_destroy(JSContext *cx, GlobData *data)
1724 ReplaceData *rdata;
1726 rdata = (ReplaceData *)data;
1727 JS_free(cx, rdata->chars);
1728 rdata->chars = NULL;
1731 static JSBool
1732 replace_glob(JSContext *cx, jsint count, GlobData *data)
1734 ReplaceData *rdata;
1735 JSString *str;
1736 size_t leftoff, leftlen, replen, growth;
1737 const jschar *left;
1738 jschar *chars;
1740 rdata = (ReplaceData *)data;
1741 str = data->str;
1742 leftoff = rdata->leftIndex;
1743 left = JSSTRING_CHARS(str) + leftoff;
1744 leftlen = cx->regExpStatics.lastMatch.chars - left;
1745 rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
1746 rdata->leftIndex += cx->regExpStatics.lastMatch.length;
1747 if (!find_replen(cx, rdata, &replen))
1748 return JS_FALSE;
1749 growth = leftlen + replen;
1750 chars = (jschar *)
1751 (rdata->chars
1752 ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1)
1753 * sizeof(jschar))
1754 : JS_malloc(cx, (growth + 1) * sizeof(jschar)));
1755 if (!chars)
1756 return JS_FALSE;
1757 rdata->chars = chars;
1758 rdata->length += growth;
1759 chars += rdata->index;
1760 rdata->index += growth;
1761 js_strncpy(chars, left, leftlen);
1762 chars += leftlen;
1763 do_replace(cx, rdata, chars);
1764 return JS_TRUE;
1767 static JSBool
1768 str_replace(JSContext *cx, uintN argc, jsval *vp)
1770 JSObject *lambda;
1771 JSString *repstr;
1773 if (argc >= 2 && JS_TypeOfValue(cx, vp[3]) == JSTYPE_FUNCTION) {
1774 lambda = JSVAL_TO_OBJECT(vp[3]);
1775 repstr = NULL;
1776 } else {
1777 lambda = NULL;
1778 repstr = ArgToRootedString(cx, argc, vp, 1);
1779 if (!repstr)
1780 return JS_FALSE;
1783 return js_StringReplaceHelper(cx, argc, lambda, repstr, vp);
1786 #ifdef JS_TRACER
1787 static JSString* FASTCALL
1788 String_p_replace_str(JSContext* cx, JSString* str, JSObject* regexp, JSString* repstr)
1790 jsval vp[4] = {
1791 JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(repstr)
1793 if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp))
1794 return NULL;
1795 JS_ASSERT(JSVAL_IS_STRING(vp[0]));
1796 return JSVAL_TO_STRING(vp[0]);
1799 static JSString* FASTCALL
1800 String_p_replace_str2(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr)
1802 jsval vp[4] = {
1803 JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr)
1805 if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp))
1806 return NULL;
1807 JS_ASSERT(JSVAL_IS_STRING(vp[0]));
1808 return JSVAL_TO_STRING(vp[0]);
1811 static JSString* FASTCALL
1812 String_p_replace_str3(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr,
1813 JSString* flagstr)
1815 jsval vp[5] = {
1816 JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr),
1817 STRING_TO_JSVAL(flagstr)
1819 if (!js_StringReplaceHelper(cx, 3, NULL, repstr, vp))
1820 return NULL;
1821 JS_ASSERT(JSVAL_IS_STRING(vp[0]));
1822 return JSVAL_TO_STRING(vp[0]);
1824 #endif
1826 JSBool
1827 js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
1828 JSString *repstr, jsval *vp)
1830 ReplaceData rdata;
1831 JSBool ok;
1832 size_t leftlen, rightlen, length;
1833 jschar *chars;
1834 JSString *str;
1837 * For ECMA Edition 3, the first argument is to be converted to a string
1838 * to match in a "flat" sense (without regular expression metachars having
1839 * special meanings) UNLESS the first arg is a RegExp object.
1841 rdata.base.flags = MODE_REPLACE | KEEP_REGEXP | FORCE_FLAT;
1842 rdata.base.optarg = 2;
1844 rdata.lambda = lambda;
1845 rdata.repstr = repstr;
1846 if (repstr) {
1847 rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
1848 rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
1849 rdata.dollarEnd);
1850 } else {
1851 rdata.dollar = rdata.dollarEnd = NULL;
1853 rdata.chars = NULL;
1854 rdata.length = 0;
1855 rdata.index = 0;
1856 rdata.leftIndex = 0;
1858 ok = match_or_replace(cx, replace_glob, replace_destroy, &rdata.base,
1859 argc, vp);
1860 if (!ok)
1861 return JS_FALSE;
1863 if (!rdata.chars) {
1864 if ((rdata.base.flags & GLOBAL_REGEXP) || *vp != JSVAL_TRUE) {
1865 /* Didn't match even once. */
1866 *vp = STRING_TO_JSVAL(rdata.base.str);
1867 goto out;
1869 leftlen = cx->regExpStatics.leftContext.length;
1870 ok = find_replen(cx, &rdata, &length);
1871 if (!ok)
1872 goto out;
1873 length += leftlen;
1874 chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
1875 if (!chars) {
1876 ok = JS_FALSE;
1877 goto out;
1879 js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
1880 do_replace(cx, &rdata, chars + leftlen);
1881 rdata.chars = chars;
1882 rdata.length = length;
1885 rightlen = cx->regExpStatics.rightContext.length;
1886 length = rdata.length + rightlen;
1887 chars = (jschar *)
1888 JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
1889 if (!chars) {
1890 JS_free(cx, rdata.chars);
1891 ok = JS_FALSE;
1892 goto out;
1894 js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
1895 rightlen);
1896 chars[length] = 0;
1898 str = js_NewString(cx, chars, length);
1899 if (!str) {
1900 JS_free(cx, chars);
1901 ok = JS_FALSE;
1902 goto out;
1904 *vp = STRING_TO_JSVAL(str);
1906 out:
1907 /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
1908 if (rdata.base.flags & KEEP_REGEXP)
1909 js_DestroyRegExp(cx, rdata.base.regexp);
1910 return ok;
1914 * Subroutine used by str_split to find the next split point in str, starting
1915 * at offset *ip and looking either for the separator substring given by sep, or
1916 * for the next re match. In the re case, return the matched separator in *sep,
1917 * and the possibly updated offset in *ip.
1919 * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
1920 * separator occurrence if found, or str->length if no separator is found.
1922 static jsint
1923 find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
1924 JSSubString *sep)
1926 jsint i, j, k;
1927 size_t length;
1928 jschar *chars;
1931 * Stop if past end of string. If at end of string, we will compare the
1932 * null char stored there (by js_NewString*) to sep->chars[j] in the while
1933 * loop at the end of this function, so that
1935 * "ab,".split(',') => ["ab", ""]
1937 * and the resulting array converts back to the string "ab," for symmetry.
1938 * However, we ape Perl and do this only if there is a sufficiently large
1939 * limit argument (see str_split).
1941 i = *ip;
1942 length = JSSTRING_LENGTH(str);
1943 if ((size_t)i > length)
1944 return -1;
1946 chars = JSSTRING_CHARS(str);
1949 * Match a regular expression against the separator at or above index i.
1950 * Call js_ExecuteRegExp with true for the test argument. On successful
1951 * match, get the separator from cx->regExpStatics.lastMatch.
1953 if (re) {
1954 size_t index;
1955 jsval rval;
1957 again:
1958 /* JS1.2 deviated from Perl by never matching at end of string. */
1959 index = (size_t)i;
1960 if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
1961 return -2;
1962 if (rval != JSVAL_TRUE) {
1963 /* Mismatch: ensure our caller advances i past end of string. */
1964 sep->length = 1;
1965 return length;
1967 i = (jsint)index;
1968 *sep = cx->regExpStatics.lastMatch;
1969 if (sep->length == 0) {
1971 * Empty string match: never split on an empty match at the start
1972 * of a find_split cycle. Same rule as for an empty global match
1973 * in match_or_replace.
1975 if (i == *ip) {
1977 * "Bump-along" to avoid sticking at an empty match, but don't
1978 * bump past end of string -- our caller must do that by adding
1979 * sep->length to our return value.
1981 if ((size_t)i == length)
1982 return -1;
1983 i++;
1984 goto again;
1986 if ((size_t)i == length) {
1988 * If there was a trivial zero-length match at the end of the
1989 * split, then we shouldn't output the matched string at the end
1990 * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
1992 sep->chars = NULL;
1995 JS_ASSERT((size_t)i >= sep->length);
1996 return i - sep->length;
2000 * Special case: if sep is the empty string, split str into one character
2001 * substrings. Let our caller worry about whether to split once at end of
2002 * string into an empty substring.
2004 if (sep->length == 0)
2005 return ((size_t)i == length) ? -1 : i + 1;
2008 * Now that we know sep is non-empty, search starting at i in str for an
2009 * occurrence of all of sep's chars. If we find them, return the index of
2010 * the first separator char. Otherwise, return length.
2012 j = 0;
2013 while ((size_t)(k = i + j) < length) {
2014 if (chars[k] == sep->chars[j]) {
2015 if ((size_t)++j == sep->length)
2016 return i;
2017 } else {
2018 i++;
2019 j = 0;
2022 return k;
2025 static JSBool
2026 str_split(JSContext *cx, uintN argc, jsval *vp)
2028 JSString *str, *sub;
2029 JSObject *arrayobj;
2030 jsval v;
2031 JSBool ok, limited;
2032 JSRegExp *re;
2033 JSSubString *sep, tmp;
2034 jsdouble d;
2035 jsint i, j;
2036 uint32 len, limit;
2038 NORMALIZE_THIS(cx, vp, str);
2040 arrayobj = js_NewArrayObject(cx, 0, NULL);
2041 if (!arrayobj)
2042 return JS_FALSE;
2043 *vp = OBJECT_TO_JSVAL(arrayobj);
2045 if (argc == 0) {
2046 v = STRING_TO_JSVAL(str);
2047 ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v);
2048 } else {
2049 if (VALUE_IS_REGEXP(cx, vp[2])) {
2050 re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));
2051 sep = &tmp;
2053 /* Set a magic value so we can detect a successful re match. */
2054 sep->chars = NULL;
2055 sep->length = 0;
2056 } else {
2057 JSString *str2 = js_ValueToString(cx, vp[2]);
2058 if (!str2)
2059 return JS_FALSE;
2060 vp[2] = STRING_TO_JSVAL(str2);
2063 * Point sep at a local copy of str2's header because find_split
2064 * will modify sep->length.
2066 JSSTRING_CHARS_AND_LENGTH(str2, tmp.chars, tmp.length);
2067 sep = &tmp;
2068 re = NULL;
2071 /* Use the second argument as the split limit, if given. */
2072 limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]);
2073 limit = 0; /* Avoid warning. */
2074 if (limited) {
2075 d = js_ValueToNumber(cx, &vp[3]);
2076 if (JSVAL_IS_NULL(vp[3]))
2077 return JS_FALSE;
2079 /* Clamp limit between 0 and 1 + string length. */
2080 limit = js_DoubleToECMAUint32(d);
2081 if (limit > JSSTRING_LENGTH(str))
2082 limit = 1 + JSSTRING_LENGTH(str);
2085 len = i = 0;
2086 while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
2087 if (limited && len >= limit)
2088 break;
2089 sub = js_NewDependentString(cx, str, i, (size_t)(j - i));
2090 if (!sub)
2091 return JS_FALSE;
2092 v = STRING_TO_JSVAL(sub);
2093 if (!JS_SetElement(cx, arrayobj, len, &v))
2094 return JS_FALSE;
2095 len++;
2098 * Imitate perl's feature of including parenthesized substrings
2099 * that matched part of the delimiter in the new array, after the
2100 * split substring that was delimited.
2102 if (re && sep->chars) {
2103 uintN num;
2104 JSSubString *parsub;
2106 for (num = 0; num < cx->regExpStatics.parenCount; num++) {
2107 if (limited && len >= limit)
2108 break;
2109 parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
2110 sub = js_NewStringCopyN(cx, parsub->chars, parsub->length);
2111 if (!sub)
2112 return JS_FALSE;
2113 v = STRING_TO_JSVAL(sub);
2114 if (!JS_SetElement(cx, arrayobj, len, &v))
2115 return JS_FALSE;
2116 len++;
2118 sep->chars = NULL;
2120 i = j + sep->length;
2122 ok = (j != -2);
2124 return ok;
2127 #ifdef JS_TRACER
2128 static JSObject* FASTCALL
2129 String_p_split(JSContext* cx, JSString* str, JSString* sepstr)
2131 // FIXME: Avoid building and then parsing this array.
2132 jsval vp[4] = { JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(sepstr), JSVAL_VOID };
2133 if (!str_split(cx, 2, vp))
2134 return NULL;
2135 JS_ASSERT(JSVAL_IS_OBJECT(vp[0]));
2136 return JSVAL_TO_OBJECT(vp[0]);
2138 #endif
2140 #if JS_HAS_PERL_SUBSTR
2141 static JSBool
2142 str_substr(JSContext *cx, uintN argc, jsval *vp)
2144 JSString *str;
2145 jsdouble d;
2146 jsdouble length, begin, end;
2148 NORMALIZE_THIS(cx, vp, str);
2149 if (argc != 0) {
2150 d = js_ValueToNumber(cx, &vp[2]);
2151 if (JSVAL_IS_NULL(vp[2]))
2152 return JS_FALSE;
2153 length = JSSTRING_LENGTH(str);
2154 begin = js_DoubleToInteger(d);
2155 if (begin < 0) {
2156 begin += length;
2157 if (begin < 0)
2158 begin = 0;
2159 } else if (begin > length) {
2160 begin = length;
2163 if (argc == 1) {
2164 end = length;
2165 } else {
2166 d = js_ValueToNumber(cx, &vp[3]);
2167 if (JSVAL_IS_NULL(vp[3]))
2168 return JS_FALSE;
2169 end = js_DoubleToInteger(d);
2170 if (end < 0)
2171 end = 0;
2172 end += begin;
2173 if (end > length)
2174 end = length;
2177 str = js_NewDependentString(cx, str,
2178 (size_t)begin,
2179 (size_t)(end - begin));
2180 if (!str)
2181 return JS_FALSE;
2183 *vp = STRING_TO_JSVAL(str);
2184 return JS_TRUE;
2186 #endif /* JS_HAS_PERL_SUBSTR */
2189 * Python-esque sequence operations.
2191 static JSBool
2192 str_concat(JSContext *cx, uintN argc, jsval *vp)
2194 JSString *str, *str2;
2195 jsval *argv;
2196 uintN i;
2198 NORMALIZE_THIS(cx, vp, str);
2200 for (i = 0, argv = vp + 2; i < argc; i++) {
2201 str2 = js_ValueToString(cx, argv[i]);
2202 if (!str2)
2203 return JS_FALSE;
2204 argv[i] = STRING_TO_JSVAL(str2);
2206 str = js_ConcatStrings(cx, str, str2);
2207 if (!str)
2208 return JS_FALSE;
2211 *vp = STRING_TO_JSVAL(str);
2212 return JS_TRUE;
2215 #ifdef JS_TRACER
2216 static JSString* FASTCALL
2217 String_p_concat_1int(JSContext* cx, JSString* str, int32 i)
2219 // FIXME: should be able to use stack buffer and avoid istr...
2220 JSString* istr = js_NumberToString(cx, i);
2221 if (!istr)
2222 return NULL;
2223 return js_ConcatStrings(cx, str, istr);
2226 static JSString* FASTCALL
2227 String_p_concat_2str(JSContext* cx, JSString* str, JSString* a, JSString* b)
2229 str = js_ConcatStrings(cx, str, a);
2230 if (str)
2231 return js_ConcatStrings(cx, str, b);
2232 return NULL;
2235 static JSString* FASTCALL
2236 String_p_concat_3str(JSContext* cx, JSString* str, JSString* a, JSString* b, JSString* c)
2238 str = js_ConcatStrings(cx, str, a);
2239 if (str) {
2240 str = js_ConcatStrings(cx, str, b);
2241 if (str)
2242 return js_ConcatStrings(cx, str, c);
2244 return NULL;
2246 #endif
2248 static JSBool
2249 str_slice(JSContext *cx, uintN argc, jsval *vp)
2251 jsval t, v;
2252 JSString *str;
2254 t = vp[1];
2255 v = vp[2];
2256 if (argc == 1 && JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) {
2257 size_t begin, end, length;
2259 str = JSVAL_TO_STRING(t);
2260 begin = JSVAL_TO_INT(v);
2261 end = JSSTRING_LENGTH(str);
2262 if (begin <= end) {
2263 length = end - begin;
2264 if (length == 0) {
2265 str = cx->runtime->emptyString;
2266 } else {
2267 str = (length == 1)
2268 ? js_GetUnitString(cx, str, begin)
2269 : js_NewDependentString(cx, str, begin, length);
2270 if (!str)
2271 return JS_FALSE;
2273 *vp = STRING_TO_JSVAL(str);
2274 return JS_TRUE;
2278 NORMALIZE_THIS(cx, vp, str);
2280 if (argc != 0) {
2281 double begin, end, length;
2283 begin = js_ValueToNumber(cx, &vp[2]);
2284 if (JSVAL_IS_NULL(vp[2]))
2285 return JS_FALSE;
2286 begin = js_DoubleToInteger(begin);
2287 length = JSSTRING_LENGTH(str);
2288 if (begin < 0) {
2289 begin += length;
2290 if (begin < 0)
2291 begin = 0;
2292 } else if (begin > length) {
2293 begin = length;
2296 if (argc == 1) {
2297 end = length;
2298 } else {
2299 end = js_ValueToNumber(cx, &vp[3]);
2300 if (JSVAL_IS_NULL(vp[3]))
2301 return JS_FALSE;
2302 end = js_DoubleToInteger(end);
2303 if (end < 0) {
2304 end += length;
2305 if (end < 0)
2306 end = 0;
2307 } else if (end > length) {
2308 end = length;
2310 if (end < begin)
2311 end = begin;
2314 str = js_NewDependentString(cx, str,
2315 (size_t)begin,
2316 (size_t)(end - begin));
2317 if (!str)
2318 return JS_FALSE;
2320 *vp = STRING_TO_JSVAL(str);
2321 return JS_TRUE;
2324 #if JS_HAS_STR_HTML_HELPERS
2326 * HTML composition aids.
2328 static JSBool
2329 tagify(JSContext *cx, const char *begin, JSString *param, const char *end,
2330 jsval *vp)
2332 JSString *str;
2333 jschar *tagbuf;
2334 size_t beglen, endlen, parlen, taglen;
2335 size_t i, j;
2337 NORMALIZE_THIS(cx, vp, str);
2339 if (!end)
2340 end = begin;
2342 beglen = strlen(begin);
2343 taglen = 1 + beglen + 1; /* '<begin' + '>' */
2344 parlen = 0; /* Avoid warning. */
2345 if (param) {
2346 parlen = JSSTRING_LENGTH(param);
2347 taglen += 2 + parlen + 1; /* '="param"' */
2349 endlen = strlen(end);
2350 taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1; /* 'str</end>' */
2352 if (taglen >= ~(size_t)0 / sizeof(jschar)) {
2353 js_ReportAllocationOverflow(cx);
2354 return JS_FALSE;
2357 tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
2358 if (!tagbuf)
2359 return JS_FALSE;
2361 j = 0;
2362 tagbuf[j++] = '<';
2363 for (i = 0; i < beglen; i++)
2364 tagbuf[j++] = (jschar)begin[i];
2365 if (param) {
2366 tagbuf[j++] = '=';
2367 tagbuf[j++] = '"';
2368 js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen);
2369 j += parlen;
2370 tagbuf[j++] = '"';
2372 tagbuf[j++] = '>';
2373 js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
2374 j += JSSTRING_LENGTH(str);
2375 tagbuf[j++] = '<';
2376 tagbuf[j++] = '/';
2377 for (i = 0; i < endlen; i++)
2378 tagbuf[j++] = (jschar)end[i];
2379 tagbuf[j++] = '>';
2380 JS_ASSERT(j == taglen);
2381 tagbuf[j] = 0;
2383 str = js_NewString(cx, tagbuf, taglen);
2384 if (!str) {
2385 free((char *)tagbuf);
2386 return JS_FALSE;
2388 *vp = STRING_TO_JSVAL(str);
2389 return JS_TRUE;
2392 static JSBool
2393 tagify_value(JSContext *cx, uintN argc, jsval *vp,
2394 const char *begin, const char *end)
2396 JSString *param;
2398 param = ArgToRootedString(cx, argc, vp, 0);
2399 if (!param)
2400 return JS_FALSE;
2401 return tagify(cx, begin, param, end, vp);
2404 static JSBool
2405 str_bold(JSContext *cx, uintN argc, jsval *vp)
2407 return tagify(cx, "b", NULL, NULL, vp);
2410 static JSBool
2411 str_italics(JSContext *cx, uintN argc, jsval *vp)
2413 return tagify(cx, "i", NULL, NULL, vp);
2416 static JSBool
2417 str_fixed(JSContext *cx, uintN argc, jsval *vp)
2419 return tagify(cx, "tt", NULL, NULL, vp);
2422 static JSBool
2423 str_fontsize(JSContext *cx, uintN argc, jsval *vp)
2425 return tagify_value(cx, argc, vp, "font size", "font");
2428 static JSBool
2429 str_fontcolor(JSContext *cx, uintN argc, jsval *vp)
2431 return tagify_value(cx, argc, vp, "font color", "font");
2434 static JSBool
2435 str_link(JSContext *cx, uintN argc, jsval *vp)
2437 return tagify_value(cx, argc, vp, "a href", "a");
2440 static JSBool
2441 str_anchor(JSContext *cx, uintN argc, jsval *vp)
2443 return tagify_value(cx, argc, vp, "a name", "a");
2446 static JSBool
2447 str_strike(JSContext *cx, uintN argc, jsval *vp)
2449 return tagify(cx, "strike", NULL, NULL, vp);
2452 static JSBool
2453 str_small(JSContext *cx, uintN argc, jsval *vp)
2455 return tagify(cx, "small", NULL, NULL, vp);
2458 static JSBool
2459 str_big(JSContext *cx, uintN argc, jsval *vp)
2461 return tagify(cx, "big", NULL, NULL, vp);
2464 static JSBool
2465 str_blink(JSContext *cx, uintN argc, jsval *vp)
2467 return tagify(cx, "blink", NULL, NULL, vp);
2470 static JSBool
2471 str_sup(JSContext *cx, uintN argc, jsval *vp)
2473 return tagify(cx, "sup", NULL, NULL, vp);
2476 static JSBool
2477 str_sub(JSContext *cx, uintN argc, jsval *vp)
2479 return tagify(cx, "sub", NULL, NULL, vp);
2481 #endif /* JS_HAS_STR_HTML_HELPERS */
2483 #ifdef JS_TRACER
2484 JSString* FASTCALL
2485 js_String_getelem(JSContext* cx, JSString* str, int32 i)
2487 if ((size_t)i >= JSSTRING_LENGTH(str))
2488 return NULL;
2489 return js_GetUnitString(cx, str, (size_t)i);
2491 #endif
2493 JS_DEFINE_CALLINFO_2(extern, BOOL, js_EqualStrings, STRING, STRING, 1, 1)
2494 JS_DEFINE_CALLINFO_2(extern, INT32, js_CompareStrings, STRING, STRING, 1, 1)
2496 JS_DEFINE_TRCINFO_1(str_toString,
2497 (2, (extern, STRING_FAIL, String_p_toString, CONTEXT, THIS, 1, 1)))
2498 JS_DEFINE_TRCINFO_2(str_substring,
2499 (4, (static, STRING_FAIL, String_p_substring, CONTEXT, THIS_STRING, INT32, INT32, 1, 1)),
2500 (3, (static, STRING_FAIL, String_p_substring_1, CONTEXT, THIS_STRING, INT32, 1, 1)))
2501 JS_DEFINE_TRCINFO_1(str_charAt,
2502 (3, (extern, STRING_FAIL, js_String_getelem, CONTEXT, THIS_STRING, INT32, 1, 1)))
2503 JS_DEFINE_TRCINFO_1(str_charCodeAt,
2504 (2, (extern, INT32_FAIL, js_String_p_charCodeAt, THIS_STRING, INT32, 1, 1)))
2505 JS_DEFINE_TRCINFO_4(str_concat,
2506 (3, (static, STRING_FAIL, String_p_concat_1int, CONTEXT, THIS_STRING, INT32, 1, 1)),
2507 (3, (extern, STRING_FAIL, js_ConcatStrings, CONTEXT, THIS_STRING, STRING, 1, 1)),
2508 (4, (static, STRING_FAIL, String_p_concat_2str, CONTEXT, THIS_STRING, STRING, STRING, 1, 1)),
2509 (5, (static, STRING_FAIL, String_p_concat_3str, CONTEXT, THIS_STRING, STRING, STRING, STRING, 1, 1)))
2510 JS_DEFINE_TRCINFO_2(str_match,
2511 (4, (static, OBJECT_FAIL_VOID, String_p_match, CONTEXT, THIS_STRING, PC, REGEXP, 1, 1)),
2512 (4, (static, OBJECT_FAIL_VOID, String_p_match_obj, CONTEXT, THIS, PC, REGEXP, 1, 1)))
2513 JS_DEFINE_TRCINFO_3(str_replace,
2514 (4, (static, STRING_FAIL, String_p_replace_str, CONTEXT, THIS_STRING, REGEXP, STRING, 1, 1)),
2515 (4, (static, STRING_FAIL, String_p_replace_str2, CONTEXT, THIS_STRING, STRING, STRING, 1, 1)),
2516 (5, (static, STRING_FAIL, String_p_replace_str3, CONTEXT, THIS_STRING, STRING, STRING, STRING, 1, 1)))
2517 JS_DEFINE_TRCINFO_1(str_split,
2518 (3, (static, OBJECT_FAIL_NULL, String_p_split, CONTEXT, THIS_STRING, STRING, 0, 0)))
2519 JS_DEFINE_TRCINFO_1(str_toLowerCase,
2520 (2, (extern, STRING_FAIL, js_toLowerCase, CONTEXT, THIS_STRING, 1, 1)))
2521 JS_DEFINE_TRCINFO_1(str_toUpperCase,
2522 (2, (extern, STRING_FAIL, js_toUpperCase, CONTEXT, THIS_STRING, 1, 1)))
2524 #define GENERIC JSFUN_GENERIC_NATIVE
2525 #define PRIMITIVE JSFUN_THISP_PRIMITIVE
2526 #define GENERIC_PRIMITIVE (GENERIC | PRIMITIVE)
2528 static JSFunctionSpec string_methods[] = {
2529 #if JS_HAS_TOSOURCE
2530 JS_FN("quote", str_quote, 0,GENERIC_PRIMITIVE),
2531 JS_FN(js_toSource_str, str_toSource, 0,JSFUN_THISP_STRING),
2532 #endif
2534 /* Java-like methods. */
2535 JS_TN(js_toString_str, str_toString, 0,JSFUN_THISP_STRING, str_toString_trcinfo),
2536 JS_FN(js_valueOf_str, str_toString, 0,JSFUN_THISP_STRING),
2537 JS_FN(js_toJSON_str, str_toString, 0,JSFUN_THISP_STRING),
2538 JS_TN("substring", str_substring, 2,GENERIC_PRIMITIVE, str_substring_trcinfo),
2539 JS_TN("toLowerCase", str_toLowerCase, 0,GENERIC_PRIMITIVE, str_toLowerCase_trcinfo),
2540 JS_TN("toUpperCase", str_toUpperCase, 0,GENERIC_PRIMITIVE, str_toUpperCase_trcinfo),
2541 JS_TN("charAt", str_charAt, 1,GENERIC_PRIMITIVE, str_charAt_trcinfo),
2542 JS_TN("charCodeAt", str_charCodeAt, 1,GENERIC_PRIMITIVE, str_charCodeAt_trcinfo),
2543 JS_FN("indexOf", str_indexOf, 1,GENERIC_PRIMITIVE),
2544 JS_FN("lastIndexOf", str_lastIndexOf, 1,GENERIC_PRIMITIVE),
2545 JS_FN("trim", str_trim, 0,GENERIC_PRIMITIVE),
2546 JS_FN("trimLeft", str_trimLeft, 0,GENERIC_PRIMITIVE),
2547 JS_FN("trimRight", str_trimRight, 0,GENERIC_PRIMITIVE),
2548 JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,GENERIC_PRIMITIVE),
2549 JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,GENERIC_PRIMITIVE),
2550 JS_FN("localeCompare", str_localeCompare, 1,GENERIC_PRIMITIVE),
2552 /* Perl-ish methods (search is actually Python-esque). */
2553 JS_TN("match", str_match, 1,GENERIC_PRIMITIVE, str_match_trcinfo),
2554 JS_FN("search", str_search, 1,GENERIC_PRIMITIVE),
2555 JS_TN("replace", str_replace, 2,GENERIC_PRIMITIVE, str_replace_trcinfo),
2556 JS_TN("split", str_split, 2,GENERIC_PRIMITIVE, str_split_trcinfo),
2557 #if JS_HAS_PERL_SUBSTR
2558 JS_FN("substr", str_substr, 2,GENERIC_PRIMITIVE),
2559 #endif
2561 /* Python-esque sequence methods. */
2562 JS_TN("concat", str_concat, 1,GENERIC_PRIMITIVE, str_concat_trcinfo),
2563 JS_FN("slice", str_slice, 2,GENERIC_PRIMITIVE),
2565 /* HTML string methods. */
2566 #if JS_HAS_STR_HTML_HELPERS
2567 JS_FN("bold", str_bold, 0,PRIMITIVE),
2568 JS_FN("italics", str_italics, 0,PRIMITIVE),
2569 JS_FN("fixed", str_fixed, 0,PRIMITIVE),
2570 JS_FN("fontsize", str_fontsize, 1,PRIMITIVE),
2571 JS_FN("fontcolor", str_fontcolor, 1,PRIMITIVE),
2572 JS_FN("link", str_link, 1,PRIMITIVE),
2573 JS_FN("anchor", str_anchor, 1,PRIMITIVE),
2574 JS_FN("strike", str_strike, 0,PRIMITIVE),
2575 JS_FN("small", str_small, 0,PRIMITIVE),
2576 JS_FN("big", str_big, 0,PRIMITIVE),
2577 JS_FN("blink", str_blink, 0,PRIMITIVE),
2578 JS_FN("sup", str_sup, 0,PRIMITIVE),
2579 JS_FN("sub", str_sub, 0,PRIMITIVE),
2580 #endif
2582 JS_FS_END
2585 static JSBool
2586 String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2588 JSString *str;
2590 if (argc > 0) {
2591 str = js_ValueToString(cx, argv[0]);
2592 if (!str)
2593 return JS_FALSE;
2594 argv[0] = STRING_TO_JSVAL(str);
2595 } else {
2596 str = cx->runtime->emptyString;
2598 if (!JS_IsConstructing(cx)) {
2599 *rval = STRING_TO_JSVAL(str);
2600 return JS_TRUE;
2602 STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
2603 return JS_TRUE;
2606 static JSBool
2607 str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
2609 jsval *argv;
2610 uintN i;
2611 uint16 code;
2612 jschar *chars;
2613 JSString *str;
2615 argv = vp + 2;
2616 JS_ASSERT(argc < ARRAY_INIT_LIMIT);
2617 if (argc == 1 &&
2618 (code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
2619 str = js_GetUnitStringForChar(cx, code);
2620 if (!str)
2621 return JS_FALSE;
2622 *vp = STRING_TO_JSVAL(str);
2623 return JS_TRUE;
2625 chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
2626 if (!chars)
2627 return JS_FALSE;
2628 for (i = 0; i < argc; i++) {
2629 code = js_ValueToUint16(cx, &argv[i]);
2630 if (JSVAL_IS_NULL(argv[i])) {
2631 JS_free(cx, chars);
2632 return JS_FALSE;
2634 chars[i] = (jschar)code;
2636 chars[i] = 0;
2637 str = js_NewString(cx, chars, argc);
2638 if (!str) {
2639 JS_free(cx, chars);
2640 return JS_FALSE;
2642 *vp = STRING_TO_JSVAL(str);
2643 return JS_TRUE;
2646 #ifdef JS_TRACER
2647 static JSString* FASTCALL
2648 String_fromCharCode(JSContext* cx, int32 i)
2650 JS_ASSERT(JS_ON_TRACE(cx));
2651 jschar c = (jschar)i;
2652 if (c < UNIT_STRING_LIMIT)
2653 return js_GetUnitStringForChar(cx, c);
2654 return js_NewStringCopyN(cx, &c, 1);
2656 #endif
2658 JS_DEFINE_TRCINFO_1(str_fromCharCode,
2659 (2, (static, STRING_FAIL, String_fromCharCode, CONTEXT, INT32, 1, 1)))
2661 static JSFunctionSpec string_static_methods[] = {
2662 JS_TN("fromCharCode", str_fromCharCode, 1, 0, str_fromCharCode_trcinfo),
2663 JS_FS_END
2666 static JSHashNumber
2667 js_hash_string_pointer(const void *key)
2669 return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
2672 JSBool
2673 js_InitRuntimeStringState(JSContext *cx)
2675 JSRuntime *rt;
2677 rt = cx->runtime;
2678 rt->emptyString = ATOM_TO_STRING(rt->atomState.emptyAtom);
2679 return JS_TRUE;
2682 JSBool
2683 js_InitDeflatedStringCache(JSRuntime *rt)
2685 JSHashTable *cache;
2687 /* Initialize string cache */
2688 JS_ASSERT(!rt->deflatedStringCache);
2689 cache = JS_NewHashTable(8, js_hash_string_pointer,
2690 JS_CompareValues, JS_CompareValues,
2691 NULL, NULL);
2692 if (!cache)
2693 return JS_FALSE;
2694 rt->deflatedStringCache = cache;
2696 #ifdef JS_THREADSAFE
2697 JS_ASSERT(!rt->deflatedStringCacheLock);
2698 rt->deflatedStringCacheLock = JS_NEW_LOCK();
2699 if (!rt->deflatedStringCacheLock)
2700 return JS_FALSE;
2701 #endif
2702 return JS_TRUE;
2705 #define UNIT_STRING_SPACE(sp) ((jschar *) ((sp) + UNIT_STRING_LIMIT))
2706 #define UNIT_STRING_SPACE_RT(rt) UNIT_STRING_SPACE((rt)->unitStrings)
2708 #define IN_UNIT_STRING_SPACE(sp,cp) \
2709 ((size_t)((cp) - UNIT_STRING_SPACE(sp)) < 2 * UNIT_STRING_LIMIT)
2710 #define IN_UNIT_STRING_SPACE_RT(rt,cp) \
2711 IN_UNIT_STRING_SPACE((rt)->unitStrings, cp)
2713 JSString *
2714 js_GetUnitStringForChar(JSContext *cx, jschar c)
2716 jschar *cp, i;
2717 JSRuntime *rt;
2718 JSString **sp;
2720 JS_ASSERT(c < UNIT_STRING_LIMIT);
2721 rt = cx->runtime;
2722 if (!rt->unitStrings) {
2723 sp = (JSString **) calloc(UNIT_STRING_LIMIT * sizeof(JSString *) +
2724 UNIT_STRING_LIMIT * 2 * sizeof(jschar),
2726 if (!sp) {
2727 JS_ReportOutOfMemory(cx);
2728 return NULL;
2730 cp = UNIT_STRING_SPACE(sp);
2731 for (i = 0; i < UNIT_STRING_LIMIT; i++) {
2732 *cp = i;
2733 cp += 2;
2735 JS_LOCK_GC(rt);
2736 if (!rt->unitStrings) {
2737 rt->unitStrings = sp;
2738 JS_UNLOCK_GC(rt);
2739 } else {
2740 JS_UNLOCK_GC(rt);
2741 free(sp);
2744 if (!rt->unitStrings[c]) {
2745 JSString *str;
2747 cp = UNIT_STRING_SPACE_RT(rt);
2748 str = js_NewString(cx, cp + 2 * c, 1);
2749 if (!str)
2750 return NULL;
2751 JS_LOCK_GC(rt);
2752 if (!rt->unitStrings[c])
2753 rt->unitStrings[c] = str;
2754 JS_UNLOCK_GC(rt);
2756 return rt->unitStrings[c];
2759 JSString *
2760 js_GetUnitString(JSContext *cx, JSString *str, size_t index)
2762 jschar c;
2764 JS_ASSERT(index < JSSTRING_LENGTH(str));
2765 c = JSSTRING_CHARS(str)[index];
2766 if (c >= UNIT_STRING_LIMIT)
2767 return js_NewDependentString(cx, str, index, 1);
2768 return js_GetUnitStringForChar(cx, c);
2771 void
2772 js_FinishUnitStrings(JSRuntime *rt)
2774 free(rt->unitStrings);
2775 rt->unitStrings = NULL;
2778 void
2779 js_FinishRuntimeStringState(JSContext *cx)
2781 cx->runtime->emptyString = NULL;
2784 void
2785 js_FinishDeflatedStringCache(JSRuntime *rt)
2787 if (rt->deflatedStringCache) {
2788 JS_HashTableDestroy(rt->deflatedStringCache);
2789 rt->deflatedStringCache = NULL;
2791 #ifdef JS_THREADSAFE
2792 if (rt->deflatedStringCacheLock) {
2793 JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
2794 rt->deflatedStringCacheLock = NULL;
2796 #endif
2799 JSObject *
2800 js_InitStringClass(JSContext *cx, JSObject *obj)
2802 JSObject *proto;
2804 /* Define the escape, unescape functions in the global object. */
2805 if (!JS_DefineFunctions(cx, obj, string_functions))
2806 return NULL;
2808 proto = JS_InitClass(cx, obj, NULL, &js_StringClass, String, 1,
2809 string_props, string_methods,
2810 NULL, string_static_methods);
2811 if (!proto)
2812 return NULL;
2813 STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE,
2814 STRING_TO_JSVAL(cx->runtime->emptyString));
2815 return proto;
2818 JSString *
2819 js_NewString(JSContext *cx, jschar *chars, size_t length)
2821 JSString *str;
2823 if (length > JSSTRING_LENGTH_MASK) {
2824 js_ReportAllocationOverflow(cx);
2825 return NULL;
2828 str = (JSString *) js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
2829 if (!str)
2830 return NULL;
2831 JSFLATSTR_INIT(str, chars, length);
2832 #ifdef DEBUG
2834 JSRuntime *rt = cx->runtime;
2835 JS_RUNTIME_METER(rt, liveStrings);
2836 JS_RUNTIME_METER(rt, totalStrings);
2837 JS_LOCK_RUNTIME_VOID(rt,
2838 (rt->lengthSum += (double)length,
2839 rt->lengthSquaredSum += (double)length * (double)length));
2841 #endif
2842 return str;
2845 JSString *
2846 js_NewDependentString(JSContext *cx, JSString *base, size_t start,
2847 size_t length)
2849 JSString *ds;
2851 if (length == 0)
2852 return cx->runtime->emptyString;
2854 if (start == 0 && length == JSSTRING_LENGTH(base))
2855 return base;
2857 if (start > JSSTRDEP_START_MASK ||
2858 (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
2859 return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length);
2862 ds = (JSString *)js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
2863 if (!ds)
2864 return NULL;
2865 if (start == 0)
2866 JSPREFIX_INIT(ds, base, length);
2867 else
2868 JSSTRDEP_INIT(ds, base, start, length);
2869 #ifdef DEBUG
2871 JSRuntime *rt = cx->runtime;
2872 JS_RUNTIME_METER(rt, liveDependentStrings);
2873 JS_RUNTIME_METER(rt, totalDependentStrings);
2874 JS_RUNTIME_METER(rt, liveStrings);
2875 JS_RUNTIME_METER(rt, totalStrings);
2876 JS_LOCK_RUNTIME_VOID(rt,
2877 (rt->strdepLengthSum += (double)length,
2878 rt->strdepLengthSquaredSum += (double)length * (double)length));
2879 JS_LOCK_RUNTIME_VOID(rt,
2880 (rt->lengthSum += (double)length,
2881 rt->lengthSquaredSum += (double)length * (double)length));
2883 #endif
2884 return ds;
2887 #ifdef DEBUG
2888 #include <math.h>
2890 void printJSStringStats(JSRuntime *rt)
2892 double mean, sigma;
2894 mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum,
2895 rt->lengthSquaredSum, &sigma);
2897 fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
2898 (unsigned long)rt->totalStrings, mean, sigma);
2900 mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum,
2901 rt->strdepLengthSquaredSum, &sigma);
2903 fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
2904 (unsigned long)rt->totalDependentStrings, mean, sigma);
2906 #endif
2908 JSString *
2909 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
2911 jschar *news;
2912 JSString *str;
2914 news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
2915 if (!news)
2916 return NULL;
2917 js_strncpy(news, s, n);
2918 news[n] = 0;
2919 str = js_NewString(cx, news, n);
2920 if (!str)
2921 JS_free(cx, news);
2922 return str;
2925 JSString *
2926 js_NewStringCopyZ(JSContext *cx, const jschar *s)
2928 size_t n, m;
2929 jschar *news;
2930 JSString *str;
2932 n = js_strlen(s);
2933 m = (n + 1) * sizeof(jschar);
2934 news = (jschar *) JS_malloc(cx, m);
2935 if (!news)
2936 return NULL;
2937 memcpy(news, s, m);
2938 str = js_NewString(cx, news, n);
2939 if (!str)
2940 JS_free(cx, news);
2941 return str;
2944 void
2945 js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str)
2947 JSHashNumber hash;
2948 JSHashEntry *he, **hep;
2950 hash = js_hash_string_pointer(str);
2951 JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
2952 hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str);
2953 he = *hep;
2954 if (he) {
2955 #ifdef DEBUG
2956 rt->deflatedStringCacheBytes -= JSSTRING_LENGTH(str);
2957 #endif
2958 free(he->value);
2959 JS_HashTableRawRemove(rt->deflatedStringCache, hep, he);
2961 JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
2964 static JSStringFinalizeOp str_finalizers[GCX_NTYPES - GCX_EXTERNAL_STRING] = {
2965 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
2968 intN
2969 js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
2970 JSStringFinalizeOp newop)
2972 uintN i;
2974 for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
2975 if (str_finalizers[i] == oldop) {
2976 str_finalizers[i] = newop;
2977 return (intN) i;
2980 return -1;
2984 * cx is NULL when we are called from js_FinishAtomState to force the
2985 * finalization of the permanently interned strings.
2987 void
2988 js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
2990 jschar *chars;
2991 JSBool valid;
2992 JSStringFinalizeOp finalizer;
2994 JS_RUNTIME_UNMETER(rt, liveStrings);
2995 if (JSSTRING_IS_DEPENDENT(str)) {
2996 /* A dependent string can not be external and must be valid. */
2997 JS_ASSERT(type < 0);
2998 JS_ASSERT(JSSTRDEP_BASE(str));
2999 JS_RUNTIME_UNMETER(rt, liveDependentStrings);
3000 valid = JS_TRUE;
3001 } else {
3002 /* A stillborn string has null chars, so is not valid. */
3003 chars = JSFLATSTR_CHARS(str);
3004 valid = (chars != NULL);
3005 if (valid) {
3006 if (IN_UNIT_STRING_SPACE_RT(rt, chars)) {
3007 JS_ASSERT(rt->unitStrings[*chars] == str);
3008 JS_ASSERT(type < 0);
3009 rt->unitStrings[*chars] = NULL;
3010 } else if (type < 0) {
3011 free(chars);
3012 } else {
3013 JS_ASSERT((uintN) type < JS_ARRAY_LENGTH(str_finalizers));
3014 finalizer = str_finalizers[type];
3015 if (finalizer) {
3017 * Assume that the finalizer for the permanently interned
3018 * string knows how to deal with null context.
3020 finalizer(cx, str);
3025 if (valid)
3026 js_PurgeDeflatedStringCache(rt, str);
3029 JS_FRIEND_API(const char *)
3030 js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun)
3032 JSString *str;
3034 str = v2sfun(cx, v);
3035 if (!str)
3036 return NULL;
3037 str = js_QuoteString(cx, str, 0);
3038 if (!str)
3039 return NULL;
3040 return js_GetStringBytes(cx, str);
3043 JS_FRIEND_API(JSString *)
3044 js_ValueToString(JSContext *cx, jsval v)
3046 JSObject *obj;
3047 JSString *str;
3049 if (JSVAL_IS_OBJECT(v)) {
3050 obj = JSVAL_TO_OBJECT(v);
3051 if (!obj)
3052 return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
3053 if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
3054 return NULL;
3056 if (JSVAL_IS_STRING(v)) {
3057 str = JSVAL_TO_STRING(v);
3058 } else if (JSVAL_IS_INT(v)) {
3059 str = js_NumberToString(cx, JSVAL_TO_INT(v));
3060 } else if (JSVAL_IS_DOUBLE(v)) {
3061 str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
3062 } else if (JSVAL_IS_BOOLEAN(v)) {
3063 str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
3064 } else {
3065 str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
3067 return str;
3070 JS_FRIEND_API(JSString *)
3071 js_ValueToSource(JSContext *cx, jsval v)
3073 JSTempValueRooter tvr;
3074 JSString *str;
3076 if (JSVAL_IS_VOID(v))
3077 return ATOM_TO_STRING(cx->runtime->atomState.void0Atom);
3078 if (JSVAL_IS_STRING(v))
3079 return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
3080 if (JSVAL_IS_PRIMITIVE(v)) {
3081 /* Special case to preserve negative zero, _contra_ toString. */
3082 if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
3083 /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3084 static const jschar js_negzero_ucNstr[] = {'-', '0'};
3086 return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
3088 return js_ValueToString(cx, v);
3091 JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
3092 if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
3093 cx->runtime->atomState.toSourceAtom,
3094 0, NULL, &tvr.u.value)) {
3095 str = NULL;
3096 } else {
3097 str = js_ValueToString(cx, tvr.u.value);
3099 JS_POP_TEMP_ROOT(cx, &tvr);
3100 return str;
3104 * str is not necessarily a GC thing here.
3106 uint32
3107 js_HashString(JSString *str)
3109 const jschar *s;
3110 size_t n;
3111 uint32 h;
3113 JSSTRING_CHARS_AND_LENGTH(str, s, n);
3114 for (h = 0; n; s++, n--)
3115 h = JS_ROTATE_LEFT32(h, 4) ^ *s;
3116 return h;
3120 * str is not necessarily a GC thing here.
3122 JSBool JS_FASTCALL
3123 js_EqualStrings(JSString *str1, JSString *str2)
3125 size_t n;
3126 const jschar *s1, *s2;
3128 JS_ASSERT(str1);
3129 JS_ASSERT(str2);
3131 /* Fast case: pointer equality could be a quick win. */
3132 if (str1 == str2)
3133 return JS_TRUE;
3135 n = JSSTRING_LENGTH(str1);
3136 if (n != JSSTRING_LENGTH(str2))
3137 return JS_FALSE;
3139 if (n == 0)
3140 return JS_TRUE;
3142 s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
3143 do {
3144 if (*s1 != *s2)
3145 return JS_FALSE;
3146 ++s1, ++s2;
3147 } while (--n != 0);
3149 return JS_TRUE;
3152 int32 JS_FASTCALL
3153 js_CompareStrings(JSString *str1, JSString *str2)
3155 size_t l1, l2, n, i;
3156 const jschar *s1, *s2;
3157 intN cmp;
3159 JS_ASSERT(str1);
3160 JS_ASSERT(str2);
3162 /* Fast case: pointer equality could be a quick win. */
3163 if (str1 == str2)
3164 return 0;
3166 JSSTRING_CHARS_AND_LENGTH(str1, s1, l1);
3167 JSSTRING_CHARS_AND_LENGTH(str2, s2, l2);
3168 n = JS_MIN(l1, l2);
3169 for (i = 0; i < n; i++) {
3170 cmp = s1[i] - s2[i];
3171 if (cmp != 0)
3172 return cmp;
3174 return (intN)(l1 - l2);
3177 size_t
3178 js_strlen(const jschar *s)
3180 const jschar *t;
3182 for (t = s; *t != 0; t++)
3183 continue;
3184 return (size_t)(t - s);
3187 jschar *
3188 js_strchr(const jschar *s, jschar c)
3190 while (*s != 0) {
3191 if (*s == c)
3192 return (jschar *)s;
3193 s++;
3195 return NULL;
3198 jschar *
3199 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
3201 while (s < limit) {
3202 if (*s == c)
3203 return (jschar *)s;
3204 s++;
3206 return NULL;
3209 const jschar *
3210 js_SkipWhiteSpace(const jschar *s, const jschar *end)
3212 JS_ASSERT(s <= end);
3213 while (s != end && JS_ISSPACE(*s))
3214 s++;
3215 return s;
3218 jschar *
3219 js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp)
3221 size_t nbytes, nchars, i;
3222 jschar *chars;
3223 #ifdef DEBUG
3224 JSBool ok;
3225 #endif
3227 nbytes = *lengthp;
3228 if (js_CStringsAreUTF8) {
3229 if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars))
3230 goto bad;
3231 chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof (jschar));
3232 if (!chars)
3233 goto bad;
3234 #ifdef DEBUG
3235 ok =
3236 #endif
3237 js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars);
3238 JS_ASSERT(ok);
3239 } else {
3240 nchars = nbytes;
3241 chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar));
3242 if (!chars)
3243 goto bad;
3244 for (i = 0; i < nchars; i++)
3245 chars[i] = (unsigned char) bytes[i];
3247 *lengthp = nchars;
3248 chars[nchars] = 0;
3249 return chars;
3251 bad:
3253 * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3254 * on errors.
3256 *lengthp = 0;
3257 return NULL;
3261 * May be called with null cx by js_GetStringBytes, see below.
3263 char *
3264 js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
3266 size_t nbytes, i;
3267 char *bytes;
3268 #ifdef DEBUG
3269 JSBool ok;
3270 #endif
3272 if (js_CStringsAreUTF8) {
3273 nbytes = js_GetDeflatedStringLength(cx, chars, nchars);
3274 if (nbytes == (size_t) -1)
3275 return NULL;
3276 bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1));
3277 if (!bytes)
3278 return NULL;
3279 #ifdef DEBUG
3280 ok =
3281 #endif
3282 js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes);
3283 JS_ASSERT(ok);
3284 } else {
3285 nbytes = nchars;
3286 bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1));
3287 if (!bytes)
3288 return NULL;
3289 for (i = 0; i < nbytes; i++)
3290 bytes[i] = (char) chars[i];
3292 bytes[nbytes] = 0;
3293 return bytes;
3297 * May be called with null cx through js_GetStringBytes, see below.
3299 size_t
3300 js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
3302 size_t nbytes;
3303 const jschar *end;
3304 uintN c, c2;
3305 char buffer[10];
3307 if (!js_CStringsAreUTF8)
3308 return nchars;
3310 nbytes = nchars;
3311 for (end = chars + nchars; chars != end; chars++) {
3312 c = *chars;
3313 if (c < 0x80)
3314 continue;
3315 if (0xD800 <= c && c <= 0xDFFF) {
3316 /* Surrogate pair. */
3317 chars++;
3318 if (c >= 0xDC00 || chars == end)
3319 goto bad_surrogate;
3320 c2 = *chars;
3321 if (c2 < 0xDC00 || c2 > 0xDFFF)
3322 goto bad_surrogate;
3323 c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
3325 c >>= 11;
3326 nbytes++;
3327 while (c) {
3328 c >>= 5;
3329 nbytes++;
3332 return nbytes;
3334 bad_surrogate:
3335 if (cx) {
3336 JS_snprintf(buffer, 10, "0x%x", c);
3337 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
3338 NULL, JSMSG_BAD_SURROGATE_CHAR, buffer);
3340 return (size_t) -1;
3343 JSBool
3344 js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen,
3345 char *dst, size_t *dstlenp)
3347 size_t dstlen, i, origDstlen, utf8Len;
3348 jschar c, c2;
3349 uint32 v;
3350 uint8 utf8buf[6];
3352 dstlen = *dstlenp;
3353 if (!js_CStringsAreUTF8) {
3354 if (srclen > dstlen) {
3355 for (i = 0; i < dstlen; i++)
3356 dst[i] = (char) src[i];
3357 if (cx) {
3358 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3359 JSMSG_BUFFER_TOO_SMALL);
3361 return JS_FALSE;
3363 for (i = 0; i < srclen; i++)
3364 dst[i] = (char) src[i];
3365 *dstlenp = srclen;
3366 return JS_TRUE;
3369 origDstlen = dstlen;
3370 while (srclen) {
3371 c = *src++;
3372 srclen--;
3373 if ((c >= 0xDC00) && (c <= 0xDFFF))
3374 goto badSurrogate;
3375 if (c < 0xD800 || c > 0xDBFF) {
3376 v = c;
3377 } else {
3378 if (srclen < 1)
3379 goto badSurrogate;
3380 c2 = *src;
3381 if ((c2 < 0xDC00) || (c2 > 0xDFFF))
3382 goto badSurrogate;
3383 src++;
3384 srclen--;
3385 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
3387 if (v < 0x0080) {
3388 /* no encoding necessary - performance hack */
3389 if (dstlen == 0)
3390 goto bufferTooSmall;
3391 *dst++ = (char) v;
3392 utf8Len = 1;
3393 } else {
3394 utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
3395 if (utf8Len > dstlen)
3396 goto bufferTooSmall;
3397 for (i = 0; i < utf8Len; i++)
3398 *dst++ = (char) utf8buf[i];
3400 dstlen -= utf8Len;
3402 *dstlenp = (origDstlen - dstlen);
3403 return JS_TRUE;
3405 badSurrogate:
3406 *dstlenp = (origDstlen - dstlen);
3407 /* Delegate error reporting to the measurement function. */
3408 if (cx)
3409 js_GetDeflatedStringLength(cx, src - 1, srclen + 1);
3410 return JS_FALSE;
3412 bufferTooSmall:
3413 *dstlenp = (origDstlen - dstlen);
3414 if (cx) {
3415 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3416 JSMSG_BUFFER_TOO_SMALL);
3418 return JS_FALSE;
3421 JSBool
3422 js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen,
3423 jschar *dst, size_t *dstlenp)
3425 size_t dstlen, i, origDstlen, offset, j, n;
3426 uint32 v;
3428 if (!js_CStringsAreUTF8) {
3429 if (dst) {
3430 dstlen = *dstlenp;
3431 if (srclen > dstlen) {
3432 for (i = 0; i < dstlen; i++)
3433 dst[i] = (unsigned char) src[i];
3434 if (cx) {
3435 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3436 JSMSG_BUFFER_TOO_SMALL);
3438 return JS_FALSE;
3440 for (i = 0; i < srclen; i++)
3441 dst[i] = (unsigned char) src[i];
3443 *dstlenp = srclen;
3444 return JS_TRUE;
3447 dstlen = dst ? *dstlenp : (size_t) -1;
3448 origDstlen = dstlen;
3449 offset = 0;
3451 while (srclen) {
3452 v = (uint8) *src;
3453 n = 1;
3454 if (v & 0x80) {
3455 while (v & (0x80 >> n))
3456 n++;
3457 if (n > srclen)
3458 goto bufferTooSmall;
3459 if (n == 1 || n > 6)
3460 goto badCharacter;
3461 for (j = 1; j < n; j++) {
3462 if ((src[j] & 0xC0) != 0x80)
3463 goto badCharacter;
3465 v = Utf8ToOneUcs4Char((uint8 *)src, n);
3466 if (v >= 0x10000) {
3467 v -= 0x10000;
3468 if (v > 0xFFFFF || dstlen < 2) {
3469 *dstlenp = (origDstlen - dstlen);
3470 if (cx) {
3471 char buffer[10];
3472 JS_snprintf(buffer, 10, "0x%x", v + 0x10000);
3473 JS_ReportErrorFlagsAndNumber(cx,
3474 JSREPORT_ERROR,
3475 js_GetErrorMessage, NULL,
3476 JSMSG_UTF8_CHAR_TOO_LARGE,
3477 buffer);
3479 return JS_FALSE;
3481 if (dstlen < 2)
3482 goto bufferTooSmall;
3483 if (dst) {
3484 *dst++ = (jschar)((v >> 10) + 0xD800);
3485 v = (jschar)((v & 0x3FF) + 0xDC00);
3487 dstlen--;
3490 if (!dstlen)
3491 goto bufferTooSmall;
3492 if (dst)
3493 *dst++ = (jschar) v;
3494 dstlen--;
3495 offset += n;
3496 src += n;
3497 srclen -= n;
3499 *dstlenp = (origDstlen - dstlen);
3500 return JS_TRUE;
3502 badCharacter:
3503 *dstlenp = (origDstlen - dstlen);
3504 if (cx) {
3505 char buffer[10];
3506 JS_snprintf(buffer, 10, "%d", offset);
3507 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
3508 js_GetErrorMessage, NULL,
3509 JSMSG_MALFORMED_UTF8_CHAR,
3510 buffer);
3512 return JS_FALSE;
3514 bufferTooSmall:
3515 *dstlenp = (origDstlen - dstlen);
3516 if (cx) {
3517 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3518 JSMSG_BUFFER_TOO_SMALL);
3520 return JS_FALSE;
3523 JSBool
3524 js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length)
3526 JSRuntime *rt;
3527 JSHashTable *cache;
3528 JSBool ok;
3529 JSHashNumber hash;
3530 JSHashEntry **hep;
3532 rt = cx->runtime;
3533 JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
3535 cache = rt->deflatedStringCache;
3536 hash = js_hash_string_pointer(str);
3537 hep = JS_HashTableRawLookup(cache, hash, str);
3538 JS_ASSERT(*hep == NULL);
3539 ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
3540 #ifdef DEBUG
3541 if (ok)
3542 rt->deflatedStringCacheBytes += length;
3543 #endif
3545 JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
3546 return ok;
3549 const char *
3550 js_GetStringBytes(JSContext *cx, JSString *str)
3552 JSRuntime *rt;
3553 JSHashTable *cache;
3554 char *bytes;
3555 JSHashNumber hash;
3556 JSHashEntry *he, **hep;
3558 if (cx) {
3559 rt = cx->runtime;
3560 } else {
3561 /* JS_GetStringBytes calls us with null cx. */
3562 rt = js_GetGCStringRuntime(str);
3565 #ifdef JS_THREADSAFE
3566 if (!rt->deflatedStringCacheLock) {
3568 * Called from last GC (see js_DestroyContext), after runtime string
3569 * state has been finalized. We have no choice but to leak here.
3571 return js_DeflateString(NULL, JSSTRING_CHARS(str),
3572 JSSTRING_LENGTH(str));
3574 #endif
3576 JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
3578 cache = rt->deflatedStringCache;
3579 hash = js_hash_string_pointer(str);
3580 hep = JS_HashTableRawLookup(cache, hash, str);
3581 he = *hep;
3582 if (he) {
3583 bytes = (char *) he->value;
3585 /* Try to catch failure to JS_ShutDown between runtime epochs. */
3586 if (!js_CStringsAreUTF8) {
3587 JS_ASSERT_IF(*bytes != (char) JSSTRING_CHARS(str)[0],
3588 *bytes == '\0' && JSSTRING_LENGTH(str) == 0);
3590 } else {
3591 bytes = js_DeflateString(cx, JSSTRING_CHARS(str),
3592 JSSTRING_LENGTH(str));
3593 if (bytes) {
3594 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
3595 #ifdef DEBUG
3596 rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str);
3597 #endif
3598 } else {
3599 if (cx)
3600 JS_free(cx, bytes);
3601 else
3602 free(bytes);
3603 bytes = NULL;
3608 JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
3609 return bytes;
3613 * From java.lang.Character.java:
3615 * The character properties are currently encoded into 32 bits in the
3616 * following manner:
3618 * 10 bits signed offset used for converting case
3619 * 1 bit if 1, adding the signed offset converts the character to
3620 * lowercase
3621 * 1 bit if 1, subtracting the signed offset converts the character to
3622 * uppercase
3623 * 1 bit if 1, character has a titlecase equivalent (possibly itself)
3624 * 3 bits 0 may not be part of an identifier
3625 * 1 ignorable control; may continue a Unicode identifier or JS
3626 * identifier
3627 * 2 may continue a JS identifier but not a Unicode identifier
3628 * (unused)
3629 * 3 may continue a Unicode identifier or JS identifier
3630 * 4 is a JS whitespace character
3631 * 5 may start or continue a JS identifier;
3632 * may continue but not start a Unicode identifier (_)
3633 * 6 may start or continue a JS identifier but not a Unicode
3634 * identifier ($)
3635 * 7 may start or continue a Unicode identifier or JS identifier
3636 * Thus:
3637 * 5, 6, 7 may start a JS identifier
3638 * 1, 2, 3, 5, 6, 7 may continue a JS identifier
3639 * 7 may start a Unicode identifier
3640 * 1, 3, 5, 7 may continue a Unicode identifier
3641 * 1 is ignorable within an identifier
3642 * 4 is JS whitespace
3643 * 2 bits 0 this character has no numeric property
3644 * 1 adding the digit offset to the character code and then
3645 * masking with 0x1F will produce the desired numeric value
3646 * 2 this character has a "strange" numeric value
3647 * 3 a JS supradecimal digit: adding the digit offset to the
3648 * character code, then masking with 0x1F, then adding 10
3649 * will produce the desired numeric value
3650 * 5 bits digit offset
3651 * 1 bit XML 1.0 name start character
3652 * 1 bit XML 1.0 name character
3653 * 2 bits reserved for future use
3654 * 5 bits character type
3657 /* The X table has 1024 entries for a total of 1024 bytes. */
3659 const uint8 js_X[] = {
3660 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */
3661 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */
3662 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */
3663 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */
3664 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */
3665 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */
3666 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */
3667 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */
3668 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */
3669 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */
3670 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */
3671 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */
3672 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */
3673 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */
3674 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */
3675 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */
3676 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */
3677 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */
3678 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */
3679 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */
3680 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */
3681 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */
3682 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */
3683 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */
3684 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */
3685 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */
3686 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */
3687 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */
3688 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */
3689 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */
3690 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */
3691 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */
3692 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */
3693 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */
3694 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */
3695 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */
3696 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */
3697 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */
3698 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */
3699 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */
3700 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */
3701 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */
3702 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */
3703 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */
3704 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */
3705 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */
3706 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */
3707 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */
3708 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */
3709 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */
3710 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */
3711 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */
3712 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */
3713 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */
3714 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */
3715 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */
3716 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */
3717 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */
3718 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */
3719 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */
3720 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */
3721 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */
3722 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */
3723 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */
3724 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */
3725 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */
3726 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */
3727 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */
3728 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */
3729 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */
3730 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */
3731 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */
3732 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */
3733 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */
3734 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */
3735 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */
3736 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */
3737 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */
3738 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */
3739 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */
3740 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */
3741 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */
3742 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */
3743 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */
3744 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */
3745 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */
3746 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */
3747 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */
3748 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */
3749 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */
3750 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */
3751 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */
3752 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */
3753 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */
3754 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */
3755 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */
3756 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */
3757 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */
3758 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */
3759 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */
3760 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */
3761 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */
3762 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */
3763 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */
3764 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */
3765 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */
3766 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */
3767 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */
3768 104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */
3769 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */
3770 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */
3771 104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */
3772 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */
3773 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */
3774 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */
3775 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */
3776 105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */
3777 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */
3778 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */
3779 105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */
3780 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */
3781 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */
3782 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */
3783 105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */
3784 105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */
3785 106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */
3786 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */
3787 115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */
3790 /* The Y table has 7808 entries for a total of 7808 bytes. */
3792 const uint8 js_Y[] = {
3793 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
3794 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */
3795 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
3796 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
3797 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */
3798 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */
3799 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */
3800 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */
3801 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */
3802 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
3803 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */
3804 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */
3805 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */
3806 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
3807 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */
3808 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */
3809 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
3810 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
3811 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
3812 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
3813 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */
3814 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */
3815 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */
3816 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */
3817 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
3818 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */
3819 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */
3820 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */
3821 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
3822 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */
3823 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */
3824 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */
3825 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3826 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3827 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3828 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3829 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3830 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */
3831 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */
3832 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */
3833 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */
3834 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */
3835 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
3836 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
3837 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
3838 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
3839 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */
3840 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */
3841 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */
3842 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */
3843 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */
3844 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */
3845 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */
3846 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */
3847 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */
3848 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */
3849 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */
3850 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */
3851 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */
3852 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */
3853 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
3854 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */
3855 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */
3856 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */
3857 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
3858 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
3859 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */
3860 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
3861 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
3862 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
3863 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
3864 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */
3865 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
3866 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */
3867 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */
3868 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */
3869 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */
3870 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */
3871 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */
3872 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */
3873 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */
3874 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */
3875 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */
3876 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
3877 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */
3878 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */
3879 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */
3880 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */
3881 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
3882 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */
3883 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */
3884 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */
3885 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */
3886 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */
3887 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
3888 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */
3889 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3890 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3891 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3892 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3893 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3894 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3895 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3896 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */
3897 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */
3898 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
3899 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
3900 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
3901 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */
3902 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */
3903 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */
3904 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */
3905 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */
3906 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */
3907 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */
3908 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */
3909 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */
3910 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */
3911 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */
3912 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */
3913 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */
3914 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */
3915 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */
3916 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */
3917 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */
3918 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */
3919 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */
3920 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */
3921 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */
3922 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */
3923 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
3924 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
3925 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
3926 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */
3927 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
3928 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */
3929 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
3930 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */
3931 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */
3932 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */
3933 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
3934 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
3935 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
3936 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */
3937 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */
3938 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */
3939 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3940 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3941 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3942 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3943 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3944 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */
3945 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */
3946 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */
3947 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
3948 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
3949 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */
3950 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */
3951 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */
3952 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */
3953 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3954 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3955 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3956 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3957 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3958 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */
3959 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */
3960 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */
3961 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
3962 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */
3963 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */
3964 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */
3965 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */
3966 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
3967 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
3968 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */
3969 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */
3970 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */
3971 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */
3972 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
3973 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */
3974 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
3975 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */
3976 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */
3977 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */
3978 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
3979 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
3980 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
3981 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */
3982 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */
3983 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */
3984 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */
3985 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
3986 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */
3987 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */
3988 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */
3989 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */
3990 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
3991 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */
3992 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */
3993 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */
3994 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */
3995 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */
3996 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */
3997 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */
3998 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */
3999 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4000 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */
4001 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4002 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4003 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4004 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4005 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4006 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4007 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */
4008 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */
4009 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */
4010 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */
4011 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */
4012 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */
4013 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */
4014 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */
4015 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */
4016 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */
4017 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4018 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4019 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4020 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4021 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4022 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4023 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4024 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */
4025 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */
4026 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4027 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4028 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4029 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4030 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4031 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */
4032 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */
4033 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */
4034 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */
4035 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */
4036 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */
4037 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */
4038 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */
4039 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4040 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */
4041 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */
4042 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */
4043 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */
4044 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4045 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */
4046 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */
4047 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */
4048 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */
4049 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */
4050 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */
4051 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */
4052 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */
4053 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */
4054 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */
4055 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */
4056 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */
4057 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */
4058 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */
4059 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */
4060 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4061 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */
4062 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */
4063 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */
4064 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */
4065 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */
4066 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */
4067 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4068 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */
4069 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */
4070 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */
4071 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */
4072 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */
4073 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */
4074 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */
4075 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */
4076 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4077 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */
4078 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */
4079 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */
4080 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */
4081 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */
4082 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */
4083 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4084 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4085 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */
4086 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */
4087 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4088 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */
4089 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */
4090 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */
4091 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */
4092 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4093 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */
4094 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */
4095 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */
4096 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */
4097 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */
4098 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */
4099 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */
4100 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */
4101 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */
4102 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */
4103 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4104 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */
4105 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */
4106 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4107 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */
4108 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */
4109 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */
4110 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */
4111 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */
4112 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */
4113 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */
4114 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */
4115 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */
4116 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4117 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */
4118 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */
4119 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */
4120 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */
4121 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */
4122 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */
4123 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4124 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4125 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */
4126 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */
4127 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */
4128 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */
4129 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */
4130 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */
4131 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */
4132 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4133 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */
4134 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */
4135 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4136 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */
4137 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */
4138 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */
4139 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4140 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4141 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */
4142 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */
4143 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */
4144 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */
4145 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */
4146 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */
4147 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */
4148 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */
4149 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */
4150 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */
4151 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4152 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */
4153 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */
4154 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */
4155 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4156 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4157 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4158 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */
4159 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */
4160 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */
4161 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */
4162 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */
4163 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */
4164 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4165 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */
4166 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */
4167 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4168 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */
4169 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4170 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4171 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4172 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4173 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */
4174 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */
4175 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */
4176 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */
4177 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */
4178 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */
4179 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */
4180 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */
4181 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4182 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4183 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4184 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */
4185 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */
4186 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */
4187 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */
4188 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */
4189 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */
4190 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */
4191 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */
4192 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */
4193 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */
4194 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */
4195 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */
4196 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */
4197 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4198 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4199 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4200 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */
4201 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */
4202 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */
4203 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */
4204 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */
4205 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */
4206 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */
4207 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */
4208 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */
4209 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4210 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4211 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4212 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4213 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */
4214 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */
4215 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */
4216 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */
4217 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */
4218 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */
4219 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */
4220 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4221 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4222 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */
4223 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */
4224 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */
4225 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4226 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4227 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4228 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */
4229 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4230 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4231 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4232 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */
4233 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */
4234 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */
4235 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4236 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4237 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4238 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */
4239 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */
4240 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */
4241 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4242 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4243 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4244 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4245 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4246 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4247 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4248 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */
4249 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4250 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4251 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4252 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */
4253 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4254 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4255 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4256 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */
4257 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4258 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4259 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4260 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4261 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */
4262 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4263 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4264 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */
4265 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4266 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4267 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4268 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4269 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4270 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4271 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */
4272 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */
4273 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4274 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4275 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4276 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4277 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4278 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4279 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4280 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */
4281 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4282 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4283 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */
4284 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */
4285 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4286 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4287 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4288 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */
4289 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4290 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4291 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4292 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4293 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4294 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4295 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */
4296 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */
4297 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4298 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4299 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */
4300 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */
4301 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4302 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4303 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */
4304 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */
4305 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */
4306 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */
4307 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */
4308 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */
4309 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */
4310 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */
4311 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */
4312 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */
4313 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4314 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4315 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4316 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4317 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */
4318 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */
4319 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */
4320 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */
4321 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */
4322 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */
4323 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */
4324 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */
4325 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */
4326 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */
4327 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */
4328 102, 102, 103, 103, 96, 11, 11, 46, /* 66 */
4329 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */
4330 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */
4331 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */
4332 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */
4333 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4334 105, 106, 104, 104, 104, 104, 104, 46, /* 67 */
4335 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */
4336 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */
4337 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */
4338 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4339 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4340 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4341 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */
4342 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */
4343 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */
4344 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */
4345 107, 107, 107, 107, 107, 107, 107, 107, /* 69 */
4346 107, 107, 7, 7, 7, 5, 6, 46, /* 69 */
4347 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4348 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4349 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */
4350 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */
4351 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4352 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */
4353 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4354 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4355 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */
4356 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */
4357 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */
4358 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4359 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4360 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */
4361 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */
4362 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */
4363 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */
4364 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */
4365 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */
4366 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */
4367 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */
4368 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */
4369 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
4370 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */
4371 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */
4372 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */
4373 109, 109, 109, 109, 109, 109, 109, 109, /* 72 */
4374 109, 109, 109, 109, 110, 110, 110, 110, /* 72 */
4375 111, 111, 111, 111, 111, 111, 111, 111, /* 72 */
4376 111, 111, 111, 111, 112, 112, 112, 112, /* 72 */
4377 113, 113, 113, 46, 46, 46, 46, 46, /* 73 */
4378 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */
4379 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */
4380 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
4381 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
4382 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
4383 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
4384 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */
4385 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
4386 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
4387 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */
4388 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
4389 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */
4390 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */
4391 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
4392 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */
4393 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4394 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4395 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4396 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4397 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4398 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4399 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4400 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */
4401 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4402 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4403 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4404 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4405 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4406 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */
4407 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */
4408 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */
4409 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */
4410 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */
4411 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
4412 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
4413 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */
4414 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */
4415 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
4416 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */
4417 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4418 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4419 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4420 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4421 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4422 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4423 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */
4424 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */
4425 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
4426 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
4427 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
4428 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */
4429 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */
4430 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
4431 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
4432 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */
4433 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */
4434 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */
4435 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
4436 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */
4437 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
4438 114, 114, 114, 114, 114, 114, 114, 114, /* 80 */
4439 114, 114, 114, 114, 82, 82, 82, 82, /* 80 */
4440 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */
4441 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */
4442 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
4443 115, 115, 115, 115, 115, 115, 115, 115, /* 81 */
4444 115, 115, 115, 115, 15, 15, 15, 15, /* 81 */
4445 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
4446 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */
4447 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */
4448 116, 116, 116, 116, 116, 116, 116, 116, /* 81 */
4449 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
4450 116, 116, 116, 116, 116, 116, 116, 116, /* 82 */
4451 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
4452 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
4453 117, 117, 117, 117, 117, 117, 117, 117, /* 82 */
4454 117, 117, 118, 46, 46, 46, 46, 46, /* 82 */
4455 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
4456 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */
4457 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4458 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4459 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4460 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4461 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4462 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4463 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4464 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */
4465 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4466 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4467 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */
4468 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */
4469 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4470 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4471 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4472 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */
4473 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4474 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4475 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4476 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4477 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4478 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */
4479 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
4480 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */
4481 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4482 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4483 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */
4484 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */
4485 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4486 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4487 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4488 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */
4489 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */
4490 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */
4491 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4492 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4493 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4494 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4495 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4496 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */
4497 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */
4498 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */
4499 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */
4500 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */
4501 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */
4502 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */
4503 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */
4504 119, 119, 119, 119, 119, 119, 119, 119, /* 88 */
4505 114, 114, 114, 114, 114, 114, 114, 114, /* 89 */
4506 114, 114, 83, 83, 83, 83, 83, 83, /* 89 */
4507 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */
4508 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
4509 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
4510 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */
4511 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */
4512 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */
4513 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */
4514 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */
4515 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */
4516 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */
4517 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */
4518 121, 121, 60, 60, 60, 60, 60, 60, /* 90 */
4519 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */
4520 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */
4521 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4522 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4523 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4524 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4525 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4526 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4527 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4528 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */
4529 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4530 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4531 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */
4532 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */
4533 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4534 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4535 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4536 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */
4537 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4538 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4539 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4540 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4541 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4542 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4543 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */
4544 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */
4545 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */
4546 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4547 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4548 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4549 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4550 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */
4551 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4552 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */
4553 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */
4554 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */
4555 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */
4556 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */
4557 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
4558 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
4559 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
4560 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */
4561 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
4562 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
4563 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
4564 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */
4565 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */
4566 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */
4567 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
4568 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */
4569 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */
4570 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
4571 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
4572 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */
4573 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
4574 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
4575 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */
4576 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */
4577 114, 114, 114, 114, 114, 114, 114, 114, /* 98 */
4578 114, 114, 15, 15, 15, 15, 15, 15, /* 98 */
4579 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
4580 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
4581 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
4582 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */
4583 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */
4584 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */
4585 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4586 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */
4587 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4588 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4589 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4590 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4591 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */
4592 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */
4593 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4594 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4595 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4596 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4597 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4598 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */
4599 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */
4600 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */
4601 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4602 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4603 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4604 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */
4605 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4606 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4607 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */
4608 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */
4609 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
4610 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
4611 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
4612 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */
4613 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */
4614 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
4615 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
4616 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */
4617 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
4618 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
4619 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
4620 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */
4621 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */
4622 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
4623 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
4624 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */
4625 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4626 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4627 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4628 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4629 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4630 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4631 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4632 122, 122, 122, 122, 122, 122, 122, 122, /* 104 */
4633 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4634 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4635 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4636 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4637 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4638 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4639 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4640 123, 123, 123, 123, 123, 123, 123, 123, /* 105 */
4641 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
4642 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
4643 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
4644 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
4645 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */
4646 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */
4647 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
4648 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */
4649 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */
4650 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */
4651 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */
4652 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */
4653 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */
4654 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */
4655 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */
4656 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */
4657 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */
4658 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4659 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4660 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4661 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4662 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4663 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4664 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */
4665 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4666 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4667 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4668 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4669 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4670 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */
4671 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */
4672 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */
4673 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
4674 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */
4675 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */
4676 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
4677 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
4678 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
4679 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
4680 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */
4681 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4682 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4683 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4684 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4685 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4686 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4687 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */
4688 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */
4689 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
4690 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */
4691 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4692 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4693 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4694 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4695 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4696 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */
4697 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4698 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4699 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */
4700 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4701 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4702 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4703 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4704 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */
4705 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
4706 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
4707 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
4708 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
4709 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
4710 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */
4711 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */
4712 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */
4713 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
4714 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
4715 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
4716 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
4717 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */
4718 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */
4719 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */
4720 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */
4721 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */
4722 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */
4723 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */
4724 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */
4725 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */
4726 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */
4727 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */
4728 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */
4729 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4730 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4731 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4732 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4733 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4734 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4735 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */
4736 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */
4737 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */
4738 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */
4739 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */
4740 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */
4741 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */
4742 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
4743 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */
4744 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */
4745 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */
4746 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
4747 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */
4748 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */
4749 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */
4750 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
4751 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */
4752 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */
4753 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4754 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4755 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4756 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */
4757 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4758 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4759 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */
4760 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */
4761 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
4762 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
4763 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */
4764 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */
4765 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */
4766 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */
4767 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */
4768 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */
4771 /* The A table has 124 entries for a total of 496 bytes. */
4773 const uint32 js_A[] = {
4774 0x0001000F, /* 0 Cc, ignorable */
4775 0x0004000F, /* 1 Cc, whitespace */
4776 0x0004000C, /* 2 Zs, whitespace */
4777 0x00000018, /* 3 Po */
4778 0x0006001A, /* 4 Sc, currency */
4779 0x00000015, /* 5 Ps */
4780 0x00000016, /* 6 Pe */
4781 0x00000019, /* 7 Sm */
4782 0x00000014, /* 8 Pd */
4783 0x00036089, /* 9 Nd, identifier part, decimal 16 */
4784 0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */
4785 0x0000001B, /* 11 Sk */
4786 0x00050017, /* 12 Pc, underscore */
4787 0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
4788 0x0000000C, /* 14 Zs */
4789 0x0000001C, /* 15 So */
4790 0x00070182, /* 16 Ll, identifier start */
4791 0x0000600B, /* 17 No, decimal 16 */
4792 0x0000500B, /* 18 No, decimal 8 */
4793 0x0000800B, /* 19 No, strange */
4794 0x08270181, /* 20 Lu, hasLower (add 32), identifier start */
4795 0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */
4796 0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */
4797 0x00670181, /* 23 Lu, hasLower (add 1), identifier start */
4798 0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */
4799 0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */
4800 0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */
4801 0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */
4802 0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */
4803 0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */
4804 0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */
4805 0x33670181, /* 31 Lu, hasLower (add 205), identifier start */
4806 0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */
4807 0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */
4808 0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */
4809 0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */
4810 0x34670181, /* 36 Lu, hasLower (add 209), identifier start */
4811 0x35670181, /* 37 Lu, hasLower (add 213), identifier start */
4812 0x00070181, /* 38 Lu, identifier start */
4813 0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */
4814 0x00070185, /* 40 Lo, identifier start */
4815 0x36670181, /* 41 Lu, hasLower (add 217), identifier start */
4816 0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */
4817 0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */
4818 0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
4819 0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */
4820 0x00000000, /* 46 unassigned */
4821 0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */
4822 0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */
4823 0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */
4824 0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */
4825 0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */
4826 0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */
4827 0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */
4828 0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */
4829 0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */
4830 0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */
4831 0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */
4832 0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */
4833 0x00070084, /* 59 Lm, identifier start */
4834 0x00030086, /* 60 Mn, identifier part */
4835 0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */
4836 0x09670181, /* 62 Lu, hasLower (add 37), identifier start */
4837 0x10270181, /* 63 Lu, hasLower (add 64), identifier start */
4838 0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */
4839 0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */
4840 0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */
4841 0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */
4842 0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */
4843 0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */
4844 0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */
4845 0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */
4846 0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */
4847 0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */
4848 0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */
4849 0x14270181, /* 75 Lu, hasLower (add 80), identifier start */
4850 0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */
4851 0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */
4852 0x00034089, /* 78 Nd, identifier part, decimal 0 */
4853 0x00000087, /* 79 Me */
4854 0x00030088, /* 80 Mc, identifier part */
4855 0x00037489, /* 81 Nd, identifier part, decimal 26 */
4856 0x00005A0B, /* 82 No, decimal 13 */
4857 0x00006E0B, /* 83 No, decimal 23 */
4858 0x0000740B, /* 84 No, decimal 26 */
4859 0x0000000B, /* 85 No */
4860 0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */
4861 0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */
4862 0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */
4863 0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */
4864 0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */
4865 0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */
4866 0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */
4867 0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */
4868 0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */
4869 0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */
4870 0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */
4871 0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */
4872 0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */
4873 0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */
4874 0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */
4875 0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */
4876 0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */
4877 0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */
4878 0x00010010, /* 104 Cf, ignorable */
4879 0x0004000D, /* 105 Zl, whitespace */
4880 0x0004000E, /* 106 Zp, whitespace */
4881 0x0000400B, /* 107 No, decimal 0 */
4882 0x0000440B, /* 108 No, decimal 2 */
4883 0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */
4884 0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */
4885 0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */
4886 0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */
4887 0x0007818A, /* 113 Nl, identifier start, strange */
4888 0x0000420B, /* 114 No, decimal 1 */
4889 0x0000720B, /* 115 No, decimal 25 */
4890 0x06A0001C, /* 116 So, hasLower (add 26) */
4891 0x0690001C, /* 117 So, hasUpper (subtract 26) */
4892 0x00006C0B, /* 118 No, decimal 22 */
4893 0x0000560B, /* 119 No, decimal 11 */
4894 0x0007738A, /* 120 Nl, identifier start, decimal 25 */
4895 0x0007418A, /* 121 Nl, identifier start, decimal 0 */
4896 0x00000013, /* 122 Cs */
4897 0x00000012 /* 123 Co */
4900 const jschar js_uriReservedPlusPound_ucstr[] =
4901 {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
4902 const jschar js_uriUnescaped_ucstr[] =
4903 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
4904 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
4905 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
4906 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
4907 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
4908 '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
4910 #define URI_CHUNK 64U
4912 /* Concatenate jschars onto the buffer */
4913 static JSBool
4914 AddCharsToURI(JSContext *cx, JSCharBuffer *buf,
4915 const jschar *chars, size_t length)
4917 size_t total;
4918 jschar *newchars;
4920 total = buf->length + length + 1;
4921 if (!buf->chars ||
4922 JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(buf->length + 1, URI_CHUNK)) {
4923 total = JS_ROUNDUP(total, URI_CHUNK);
4924 newchars = (jschar *) JS_realloc(cx, buf->chars,
4925 total * sizeof(jschar));
4926 if (!newchars)
4927 return JS_FALSE;
4928 buf->chars = newchars;
4930 js_strncpy(buf->chars + buf->length, chars, length);
4931 buf->length += length;
4932 buf->chars[buf->length] = 0;
4933 return JS_TRUE;
4936 static JSBool
4937 TransferBufferToString(JSContext *cx, JSCharBuffer *cb, jsval *rval)
4939 jschar *chars;
4940 size_t n;
4941 JSString *str;
4944 * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
4945 * don't worry about that case here.
4947 n = cb->length;
4948 chars = (jschar *) JS_realloc(cx, cb->chars, (n + 1) * sizeof(jschar));
4949 if (!chars)
4950 chars = cb->chars;
4951 str = js_NewString(cx, chars, n);
4952 if (!str)
4953 return JS_FALSE;
4955 /* Successful allocation transfer ownership of cb->chars to the string. */
4956 #ifdef DEBUG
4957 memset(cb, JS_FREE_PATTERN, sizeof *cb);
4958 #endif
4960 *rval = STRING_TO_JSVAL(str);
4961 return JS_TRUE;
4965 * ECMA 3, 15.1.3 URI Handling Function Properties
4967 * The following are implementations of the algorithms
4968 * given in the ECMA specification for the hidden functions
4969 * 'Encode' and 'Decode'.
4971 static JSBool
4972 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
4973 const jschar *unescapedSet2, jsval *rval)
4975 size_t length, j, k, L;
4976 JSCharBuffer cb;
4977 jschar *chars, c, c2;
4978 uint32 v;
4979 uint8 utf8buf[6];
4980 jschar hexBuf[4];
4981 static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
4983 JSSTRING_CHARS_AND_LENGTH(str, chars, length);
4984 if (length == 0) {
4985 *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
4986 return JS_TRUE;
4989 cb.length = 0;
4990 cb.chars = NULL;
4992 /* From this point the control must goto bad on failures. */
4993 hexBuf[0] = '%';
4994 hexBuf[3] = 0;
4995 for (k = 0; k < length; k++) {
4996 c = chars[k];
4997 if (js_strchr(unescapedSet, c) ||
4998 (unescapedSet2 && js_strchr(unescapedSet2, c))) {
4999 if (!AddCharsToURI(cx, &cb, &c, 1))
5000 goto bad;
5001 } else {
5002 if ((c >= 0xDC00) && (c <= 0xDFFF)) {
5003 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5004 JSMSG_BAD_URI, NULL);
5005 goto bad;
5007 if (c < 0xD800 || c > 0xDBFF) {
5008 v = c;
5009 } else {
5010 k++;
5011 if (k == length) {
5012 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5013 JSMSG_BAD_URI, NULL);
5014 goto bad;
5016 c2 = chars[k];
5017 if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
5018 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5019 JSMSG_BAD_URI, NULL);
5020 goto bad;
5022 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
5024 L = js_OneUcs4ToUtf8Char(utf8buf, v);
5025 for (j = 0; j < L; j++) {
5026 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
5027 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
5028 if (!AddCharsToURI(cx, &cb, hexBuf, 3))
5029 goto bad;
5034 if (!TransferBufferToString(cx, &cb, rval))
5035 goto bad;
5037 return JS_TRUE;
5039 bad:
5040 JS_free(cx, cb.chars);
5041 return JS_FALSE;
5044 static JSBool
5045 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
5047 size_t length, start, k;
5048 JSCharBuffer cb;
5049 jschar *chars, c, H;
5050 uint32 v;
5051 jsuint B;
5052 uint8 octets[6];
5053 intN j, n;
5055 JSSTRING_CHARS_AND_LENGTH(str, chars, length);
5056 if (length == 0) {
5057 *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
5058 return JS_TRUE;
5061 cb.length = 0;
5062 cb.chars = NULL;
5064 /* From this point the control must goto bad on failures. */
5065 for (k = 0; k < length; k++) {
5066 c = chars[k];
5067 if (c == '%') {
5068 start = k;
5069 if ((k + 2) >= length)
5070 goto report_bad_uri;
5071 if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5072 goto report_bad_uri;
5073 B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5074 k += 2;
5075 if (!(B & 0x80)) {
5076 c = (jschar)B;
5077 } else {
5078 n = 1;
5079 while (B & (0x80 >> n))
5080 n++;
5081 if (n == 1 || n > 6)
5082 goto report_bad_uri;
5083 octets[0] = (uint8)B;
5084 if (k + 3 * (n - 1) >= length)
5085 goto report_bad_uri;
5086 for (j = 1; j < n; j++) {
5087 k++;
5088 if (chars[k] != '%')
5089 goto report_bad_uri;
5090 if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5091 goto report_bad_uri;
5092 B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5093 if ((B & 0xC0) != 0x80)
5094 goto report_bad_uri;
5095 k += 2;
5096 octets[j] = (char)B;
5098 v = Utf8ToOneUcs4Char(octets, n);
5099 if (v >= 0x10000) {
5100 v -= 0x10000;
5101 if (v > 0xFFFFF)
5102 goto report_bad_uri;
5103 c = (jschar)((v & 0x3FF) + 0xDC00);
5104 H = (jschar)((v >> 10) + 0xD800);
5105 if (!AddCharsToURI(cx, &cb, &H, 1))
5106 goto bad;
5107 } else {
5108 c = (jschar)v;
5111 if (js_strchr(reservedSet, c)) {
5112 if (!AddCharsToURI(cx, &cb, &chars[start], (k - start + 1)))
5113 goto bad;
5114 } else {
5115 if (!AddCharsToURI(cx, &cb, &c, 1))
5116 goto bad;
5118 } else {
5119 if (!AddCharsToURI(cx, &cb, &c, 1))
5120 return JS_FALSE;
5124 if (!TransferBufferToString(cx, &cb, rval))
5125 goto bad;
5127 return JS_TRUE;
5129 report_bad_uri:
5130 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
5131 /* FALL THROUGH */
5133 bad:
5134 JS_free(cx, cb.chars);
5135 return JS_FALSE;
5138 static JSBool
5139 str_decodeURI(JSContext *cx, uintN argc, jsval *vp)
5141 JSString *str;
5143 str = ArgToRootedString(cx, argc, vp, 0);
5144 if (!str)
5145 return JS_FALSE;
5146 return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp);
5149 static JSBool
5150 str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp)
5152 JSString *str;
5154 str = ArgToRootedString(cx, argc, vp, 0);
5155 if (!str)
5156 return JS_FALSE;
5157 return Decode(cx, str, js_empty_ucstr, vp);
5160 static JSBool
5161 str_encodeURI(JSContext *cx, uintN argc, jsval *vp)
5163 JSString *str;
5165 str = ArgToRootedString(cx, argc, vp, 0);
5166 if (!str)
5167 return JS_FALSE;
5168 return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
5169 vp);
5172 static JSBool
5173 str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp)
5175 JSString *str;
5177 str = ArgToRootedString(cx, argc, vp, 0);
5178 if (!str)
5179 return JS_FALSE;
5180 return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp);
5184 * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5185 * least 6 bytes long. Return the number of UTF-8 bytes of data written.
5188 js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
5190 int utf8Length = 1;
5192 JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
5193 if (ucs4Char < 0x80) {
5194 *utf8Buffer = (uint8)ucs4Char;
5195 } else {
5196 int i;
5197 uint32 a = ucs4Char >> 11;
5198 utf8Length = 2;
5199 while (a) {
5200 a >>= 5;
5201 utf8Length++;
5203 i = utf8Length;
5204 while (--i) {
5205 utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
5206 ucs4Char >>= 6;
5208 *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
5210 return utf8Length;
5214 * Convert a utf8 character sequence into a UCS-4 character and return that
5215 * character. It is assumed that the caller already checked that the sequence
5216 * is valid.
5218 static uint32
5219 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
5221 uint32 ucs4Char;
5222 uint32 minucs4Char;
5223 /* from Unicode 3.1, non-shortest form is illegal */
5224 static const uint32 minucs4Table[] = {
5225 0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
5228 JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
5229 if (utf8Length == 1) {
5230 ucs4Char = *utf8Buffer;
5231 JS_ASSERT(!(ucs4Char & 0x80));
5232 } else {
5233 JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
5234 (0x100 - (1 << (8-utf8Length))));
5235 ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
5236 minucs4Char = minucs4Table[utf8Length-2];
5237 while (--utf8Length) {
5238 JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
5239 ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
5241 if (ucs4Char < minucs4Char ||
5242 ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
5243 ucs4Char = 0xFFFD;
5246 return ucs4Char;
5249 #if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
5251 JS_FRIEND_API(size_t)
5252 js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp,
5253 JSString *str, uint32 quote)
5255 jschar *chars, *charsEnd;
5256 size_t n;
5257 const char *escape;
5258 char c;
5259 uintN u, hex, shift;
5260 enum {
5261 STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
5262 } state;
5264 JS_ASSERT(quote == 0 || quote == '\'' || quote == '"');
5265 JS_ASSERT_IF(buffer, bufferSize != 0);
5266 JS_ASSERT_IF(!buffer, bufferSize == 0);
5267 JS_ASSERT_IF(fp, !buffer);
5269 JSSTRING_CHARS_AND_END(str, chars, charsEnd);
5270 n = 0;
5271 --bufferSize;
5272 state = FIRST_QUOTE;
5273 shift = 0;
5274 hex = 0;
5275 u = 0;
5276 c = 0; /* to quell GCC warnings */
5278 for (;;) {
5279 switch (state) {
5280 case STOP:
5281 goto stop;
5282 case FIRST_QUOTE:
5283 state = CHARS;
5284 goto do_quote;
5285 case LAST_QUOTE:
5286 state = STOP;
5287 do_quote:
5288 if (quote == 0)
5289 continue;
5290 c = (char)quote;
5291 break;
5292 case CHARS:
5293 if (chars == charsEnd) {
5294 state = LAST_QUOTE;
5295 continue;
5297 u = *chars++;
5298 if (u < ' ') {
5299 if (u != 0) {
5300 escape = strchr(js_EscapeMap, (int)u);
5301 if (escape) {
5302 u = escape[1];
5303 goto do_escape;
5306 goto do_hex_escape;
5308 if (u < 127) {
5309 if (u == quote || u == '\\')
5310 goto do_escape;
5311 c = (char)u;
5312 } else if (u < 0x100) {
5313 goto do_hex_escape;
5314 } else {
5315 shift = 16;
5316 hex = u;
5317 u = 'u';
5318 goto do_escape;
5320 break;
5321 do_hex_escape:
5322 shift = 8;
5323 hex = u;
5324 u = 'x';
5325 do_escape:
5326 c = '\\';
5327 state = ESCAPE_START;
5328 break;
5329 case ESCAPE_START:
5330 JS_ASSERT(' ' <= u && u < 127);
5331 c = (char)u;
5332 state = ESCAPE_MORE;
5333 break;
5334 case ESCAPE_MORE:
5335 if (shift == 0) {
5336 state = CHARS;
5337 continue;
5339 shift -= 4;
5340 u = 0xF & (hex >> shift);
5341 c = (char)(u + (u < 10 ? '0' : 'A' - 10));
5342 break;
5344 if (buffer) {
5345 if (n == bufferSize)
5346 break;
5347 buffer[n] = c;
5348 } else if (fp) {
5349 fputc(c, fp);
5351 n++;
5353 stop:
5354 if (buffer)
5355 buffer[n] = '\0';
5356 return n;
5359 #endif