Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsstr.cpp
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=99:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
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/
11  *
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.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
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.
24  *
25  * Contributor(s):
26  *
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.
38  *
39  * ***** END LICENSE BLOCK ***** */
40
41 /*
42  * JS string type implementation.
43  *
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.
50  */
51 #include <stdlib.h>
52 #include <string.h>
53 #include "jstypes.h"
54 #include "jsstdint.h"
55 #include "jsutil.h"
56 #include "jshash.h"
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 "jsfun.h"      /* for JS_ARGS_LENGTH_MAX */
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 "jsstaticcheck.h"
74 #include "jsstr.h"
75 #include "jsbit.h"
76 #include "jsvector.h"
77 #include "jsversion.h"
78
79 #include "jscntxtinlines.h"
80 #include "jsinterpinlines.h"
81 #include "jsobjinlines.h"
82 #include "jsregexpinlines.h"
83 #include "jsstrinlines.h"
84 #include "jsautooplen.h"        // generated headers last
85
86 using namespace js;
87 using namespace js::gc;
88
89 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH) <= size_t(JSVAL_INT_MAX));
90 JS_STATIC_ASSERT(JSString::MAX_LENGTH <= JSVAL_INT_MAX);
91
92 const jschar *
93 js_GetStringChars(JSContext *cx, JSString *str)
94 {
95     if (!js_MakeStringImmutable(cx, str))
96         return NULL;
97     return str->flatChars();
98 }
99
100 static JS_ALWAYS_INLINE size_t
101 RopeCapacityFor(size_t length)
102 {
103     static const size_t ROPE_DOUBLING_MAX = 1024 * 1024;
104
105     /*
106      * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
107      * next power of 2. This is similar to what we do with arrays; see
108      * JSObject::ensureDenseArrayElements.
109      */
110     if (length > ROPE_DOUBLING_MAX)
111         return length + (length / 8);
112     return RoundUpPow2(length);
113 }
114
115 static JS_ALWAYS_INLINE jschar *
116 AllocChars(JSContext *maybecx, size_t wholeCapacity)
117 {
118     /* +1 for the null char at the end. */
119     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
120     size_t bytes = (wholeCapacity + 1) * sizeof(jschar);
121     if (maybecx)
122         return (jschar *)maybecx->malloc(bytes);
123     return (jschar *)js_malloc(bytes);
124 }
125
126 const jschar *
127 JSString::flatten(JSContext *maybecx)
128 {
129     JS_ASSERT(isRope());
130
131     /*
132      * Perform a depth-first dag traversal, splatting each node's characters
133      * into a contiguous buffer. Visit each rope node three times:
134      *  1. record position in the buffer and recurse into left child;
135      *  2. recurse into the right child;
136      *  3. transform the node into a dependent string.
137      * To avoid maintaining a stack, tree nodes are mutated to indicate how
138      * many times they have been visited. Since ropes can be dags, a node may
139      * be encountered multiple times during traversal. However, step 3 above
140      * leaves a valid dependent string, so everythings works out.  This
141      * algorithm is homomorphic to TypedMarker(JSTracer *, JSString *).
142      *
143      * While ropes avoid all sorts of quadratic cases with string
144      * concatenation, they can't help when ropes are immediately flattened.
145      * One idiomatic case that we'd like to keep linear (and has traditionally
146      * been linear in SM and other JS engines) is:
147      *
148      *   while (...) {
149      *     s += ...
150      *     s.flatten
151      *   }
152      *
153      * To do this, when the buffer for a to-be-flattened rope is allocated, the
154      * allocation size is rounded up. Then, if the resulting flat string is the
155      * left-hand side of a new rope that gets flattened and there is enough
156      * capacity, the rope is flattened into the same buffer, thereby avoiding
157      * copying the left-hand side. Clearing the 'extensible' bit turns off this
158      * optimization. This is necessary, e.g., when the JSAPI hands out the raw
159      * null-terminated char array of a flat string.
160      *
161      * N.B. This optimization can create chains of dependent strings.
162      */
163     const size_t wholeLength = length();
164     size_t wholeCapacity;
165     jschar *wholeChars;
166     JSString *str = this;
167     jschar *pos;
168
169     if (u.left->isExtensible() && u.left->s.capacity >= wholeLength) {
170         wholeCapacity = u.left->s.capacity;
171         wholeChars = const_cast<jschar *>(u.left->u.chars);
172         pos = wholeChars + u.left->length();
173         u.left->finishTraversalConversion(this, wholeChars, pos);
174         goto visit_right_child;
175     }
176
177     wholeCapacity = RopeCapacityFor(wholeLength);
178     wholeChars = AllocChars(maybecx, wholeCapacity);
179     if (!wholeChars)
180         return NULL;
181
182     if (maybecx)
183         maybecx->runtime->stringMemoryUsed += wholeLength * 2;
184     pos = wholeChars;
185     first_visit_node: {
186         JSString *left = str->u.left;           /* Read before clobbered. */
187         str->u.chars = pos;
188         if (left->isRope()) {
189             left->s.parent = str;               /* Return to this when 'left' done, */
190             left->lengthAndFlags = 0x200;       /* but goto visit_right_child. */
191             str = left;
192             goto first_visit_node;
193         }
194         size_t len = left->length();
195         PodCopy(pos, left->u.chars, len);
196         pos += len;
197     }
198     visit_right_child: {
199         JSString *right = str->s.right;
200         if (right->isRope()) {
201             right->s.parent = str;              /* Return to this node when 'right' done, */
202             right->lengthAndFlags = 0x300;      /* but goto finish_node. */
203             str = right;
204             goto first_visit_node;
205         }
206         size_t len = right->length();
207         PodCopy(pos, right->u.chars, len);
208         pos += len;
209     }
210     finish_node: {
211         if (str == this) {
212             JS_ASSERT(pos == wholeChars + wholeLength);
213             *pos = '\0';
214             initFlatExtensible(wholeChars, wholeLength, wholeCapacity);
215             return wholeChars;
216         }
217         size_t progress = str->lengthAndFlags;  /* Read before clobbered. */
218         JSString *parent = str->s.parent;
219         str->finishTraversalConversion(this, wholeChars, pos);
220         str = parent;
221         if (progress == 0x200)
222             goto visit_right_child;
223         goto finish_node;
224     }
225 }
226
227 JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8);
228 JSStringFinalizeOp JSExternalString::str_finalizers[JSExternalString::TYPE_LIMIT] = {
229     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
230 };
231
232 #ifdef JS_TRACER
233
234 JSBool JS_FASTCALL
235 js_Flatten(JSContext *cx, JSString* str)
236 {
237     return !!str->flatten(cx);
238 }
239 JS_DEFINE_CALLINFO_2(extern, BOOL, js_Flatten, CONTEXT, STRING, 0, nanojit::ACCSET_STORE_ANY)
240
241 #endif /* !JS_TRACER */
242
243 JSString * JS_FASTCALL
244 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
245 {
246     JS_ASSERT_IF(!JSString::isStatic(left) && !left->isAtomized(),
247                  left->asCell()->compartment() == cx->compartment);
248     JS_ASSERT_IF(!JSString::isStatic(right) && !right->isAtomized(),
249                  right->asCell()->compartment() == cx->compartment);
250
251     size_t leftLen = left->length();
252     if (leftLen == 0)
253         return right;
254
255     size_t rightLen = right->length();
256     if (rightLen == 0)
257         return left;
258
259     size_t wholeLength = leftLen + rightLen;
260
261     if (JSShortString::fitsIntoShortString(wholeLength)) {
262         JSShortString *shortStr = js_NewGCShortString(cx);
263         if (!shortStr)
264             return NULL;
265         const jschar *leftChars = left->getChars(cx);
266         if (!leftChars)
267             return NULL;
268         const jschar *rightChars = right->getChars(cx);
269         if (!rightChars)
270             return NULL;
271
272         jschar *buf = shortStr->init(wholeLength);
273         js_short_strncpy(buf, leftChars, leftLen);
274         js_short_strncpy(buf + leftLen, rightChars, rightLen);
275         buf[wholeLength] = 0;
276         return shortStr->header();
277     }
278
279     if (wholeLength > JSString::MAX_LENGTH) {
280         if (JS_ON_TRACE(cx)) {
281             if (!CanLeaveTrace(cx))
282                 return NULL;
283             LeaveTrace(cx);
284         }
285         js_ReportAllocationOverflow(cx);
286         return NULL;
287     }
288
289     JSString *newRoot = js_NewGCString(cx);
290     if (!newRoot)
291         return NULL;
292
293     newRoot->initRopeNode(left, right, wholeLength);
294     return newRoot;
295 }
296
297 const jschar *
298 JSString::undepend(JSContext *cx)
299 {
300     size_t n, size;
301     jschar *s;
302
303     if (!ensureLinear(cx))
304         return NULL;
305
306     if (isDependent()) {
307         n = dependentLength();
308         size = (n + 1) * sizeof(jschar);
309         s = (jschar *) cx->malloc(size);
310         if (!s)
311             return NULL;
312
313         cx->runtime->stringMemoryUsed += size;
314         js_strncpy(s, dependentChars(), n);
315         s[n] = 0;
316         initFlat(s, n);
317
318 #ifdef DEBUG
319         {
320             JSRuntime *rt = cx->runtime;
321             JS_RUNTIME_UNMETER(rt, liveDependentStrings);
322             JS_RUNTIME_UNMETER(rt, totalDependentStrings);
323             JS_LOCK_RUNTIME_VOID(rt,
324                 (rt->strdepLengthSum -= (double)n,
325                  rt->strdepLengthSquaredSum -= (double)n * (double)n));
326         }
327 #endif
328     }
329
330     return flatChars();
331 }
332
333 JSBool
334 js_MakeStringImmutable(JSContext *cx, JSString *str)
335 {
336     /*
337      * Flattening a rope may result in a dependent string, so we need to flatten
338      * before undepending the string.
339      */
340     if (!str->isFlat() && !str->undepend(cx)) {
341         JS_RUNTIME_METER(cx->runtime, badUndependStrings);
342         return JS_FALSE;
343     }
344     str->flatClearExtensible();
345     return JS_TRUE;
346 }
347
348 static JSLinearString *
349 ArgToRootedString(JSContext *cx, uintN argc, Value *vp, uintN arg)
350 {
351     if (arg >= argc)
352         return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
353     vp += 2 + arg;
354
355     if (vp->isObject() && !DefaultValue(cx, &vp->toObject(), JSTYPE_STRING, vp))
356         return NULL;
357
358     JSLinearString *str;
359     if (vp->isString()) {
360         str = vp->toString()->ensureLinear(cx);
361     } else if (vp->isBoolean()) {
362         str = ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[
363                                   (int)vp->toBoolean()]);
364     } else if (vp->isNull()) {
365         str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
366     } else if (vp->isUndefined()) {
367         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
368     }
369     else {
370         str = NumberToString(cx, vp->toNumber());
371         if (!str)
372             return NULL;
373         vp->setString(str);
374     }
375     return str;
376 }
377
378 /*
379  * Forward declarations for URI encode/decode and helper routines
380  */
381 static JSBool
382 str_decodeURI(JSContext *cx, uintN argc, Value *vp);
383
384 static JSBool
385 str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp);
386
387 static JSBool
388 str_encodeURI(JSContext *cx, uintN argc, Value *vp);
389
390 static JSBool
391 str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp);
392
393 static const uint32 OVERLONG_UTF8 = UINT32_MAX;
394
395 static uint32
396 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
397
398 /*
399  * Contributions from the String class to the set of methods defined for the
400  * global object.  escape and unescape used to be defined in the Mocha library,
401  * but as ECMA decided to spec them, they've been moved to the core engine
402  * and made ECMA-compliant.  (Incomplete escapes are interpreted as literal
403  * characters by unescape.)
404  */
405
406 /*
407  * Stuff to emulate the old libmocha escape, which took a second argument
408  * giving the type of escape to perform.  Retained for compatibility, and
409  * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
410  */
411
412 #define URL_XALPHAS     ((uint8) 1)
413 #define URL_XPALPHAS    ((uint8) 2)
414 #define URL_PATH        ((uint8) 4)
415
416 static const uint8 urlCharType[256] =
417 /*      Bit 0           xalpha          -- the alphas
418  *      Bit 1           xpalpha         -- as xalpha but
419  *                             converts spaces to plus and plus to %20
420  *      Bit 2 ...       path            -- as xalphas but doesn't escape '/'
421  */
422     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
423     {    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 0x */
424          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 1x */
425          0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,       /* 2x   !"#$%&'()*+,-./  */
426          7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,       /* 3x  0123456789:;<=>?  */
427          7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 4x  @ABCDEFGHIJKLMNO  */
428          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,       /* 5X  PQRSTUVWXYZ[\]^_  */
429          0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 6x  `abcdefghijklmno  */
430          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,       /* 7X  pqrstuvwxyz{\}~  DEL */
431          0, };
432
433 /* This matches the ECMA escape set when mask is 7 (default.) */
434
435 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
436
437 /* See ECMA-262 Edition 3 B.2.1 */
438 JSBool
439 js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
440 {
441     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
442                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
443
444     jsint mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
445     if (argc > 1) {
446         double d;
447         if (!ValueToNumber(cx, vp[3], &d))
448             return JS_FALSE;
449         if (!JSDOUBLE_IS_FINITE(d) ||
450             (mask = (jsint)d) != d ||
451             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
452         {
453             char numBuf[12];
454             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
455             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
456                                  JSMSG_BAD_STRING_MASK, numBuf);
457             return JS_FALSE;
458         }
459     }
460
461     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
462     if (!str)
463         return JS_FALSE;
464
465     size_t length = str->length();
466     const jschar *chars = str->chars();
467
468     /* Take a first pass and see how big the result string will need to be. */
469     size_t newlength = length;
470     for (size_t i = 0; i < length; i++) {
471         jschar ch;
472         if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
473             continue;
474         if (ch < 256) {
475             if (mask == URL_XPALPHAS && ch == ' ')
476                 continue;   /* The character will be encoded as '+' */
477             newlength += 2; /* The character will be encoded as %XX */
478         } else {
479             newlength += 5; /* The character will be encoded as %uXXXX */
480         }
481
482         /*
483          * This overflow test works because newlength is incremented by at
484          * most 5 on each iteration.
485          */
486         if (newlength < length) {
487             js_ReportAllocationOverflow(cx);
488             return JS_FALSE;
489         }
490     }
491
492     if (newlength >= ~(size_t)0 / sizeof(jschar)) {
493         js_ReportAllocationOverflow(cx);
494         return JS_FALSE;
495     }
496
497     jschar *newchars = (jschar *) cx->malloc((newlength + 1) * sizeof(jschar));
498     if (!newchars)
499         return JS_FALSE;
500     size_t i, ni;
501     for (i = 0, ni = 0; i < length; i++) {
502         jschar ch;
503         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
504             newchars[ni++] = ch;
505         } else if (ch < 256) {
506             if (mask == URL_XPALPHAS && ch == ' ') {
507                 newchars[ni++] = '+'; /* convert spaces to pluses */
508             } else {
509                 newchars[ni++] = '%';
510                 newchars[ni++] = digits[ch >> 4];
511                 newchars[ni++] = digits[ch & 0xF];
512             }
513         } else {
514             newchars[ni++] = '%';
515             newchars[ni++] = 'u';
516             newchars[ni++] = digits[ch >> 12];
517             newchars[ni++] = digits[(ch & 0xF00) >> 8];
518             newchars[ni++] = digits[(ch & 0xF0) >> 4];
519             newchars[ni++] = digits[ch & 0xF];
520         }
521     }
522     JS_ASSERT(ni == newlength);
523     newchars[newlength] = 0;
524
525     JSString *retstr = js_NewString(cx, newchars, newlength);
526     if (!retstr) {
527         cx->free(newchars);
528         return JS_FALSE;
529     }
530     rval->setString(retstr);
531     return JS_TRUE;
532 }
533 #undef IS_OK
534
535 static JSBool
536 str_escape(JSContext *cx, uintN argc, Value *vp)
537 {
538     return js_str_escape(cx, argc, vp, vp);
539 }
540
541 /* See ECMA-262 Edition 3 B.2.2 */
542 static JSBool
543 str_unescape(JSContext *cx, uintN argc, Value *vp)
544 {
545     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
546     if (!str)
547         return false;
548
549     size_t length = str->length();
550     const jschar *chars = str->chars();
551
552     /* Don't bother allocating less space for the new string. */
553     jschar *newchars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
554     if (!newchars)
555         return false;
556     size_t ni = 0, i = 0;
557     while (i < length) {
558         jschar ch = chars[i++];
559         if (ch == '%') {
560             if (i + 1 < length &&
561                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
562             {
563                 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
564                 i += 2;
565             } else if (i + 4 < length && chars[i] == 'u' &&
566                        JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
567                        JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
568             {
569                 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
570                         + JS7_UNHEX(chars[i + 2])) << 4)
571                       + JS7_UNHEX(chars[i + 3])) << 4)
572                     + JS7_UNHEX(chars[i + 4]);
573                 i += 5;
574             }
575         }
576         newchars[ni++] = ch;
577     }
578     newchars[ni] = 0;
579
580     JSString *retstr = js_NewString(cx, newchars, ni);
581     if (!retstr) {
582         cx->free(newchars);
583         return JS_FALSE;
584     }
585     vp->setString(retstr);
586     return JS_TRUE;
587 }
588
589 #if JS_HAS_UNEVAL
590 static JSBool
591 str_uneval(JSContext *cx, uintN argc, Value *vp)
592 {
593     JSString *str;
594
595     str = js_ValueToSource(cx, argc != 0 ? vp[2] : UndefinedValue());
596     if (!str)
597         return JS_FALSE;
598     vp->setString(str);
599     return JS_TRUE;
600 }
601 #endif
602
603 const char js_escape_str[] = "escape";
604 const char js_unescape_str[] = "unescape";
605 #if JS_HAS_UNEVAL
606 const char js_uneval_str[] = "uneval";
607 #endif
608 const char js_decodeURI_str[] = "decodeURI";
609 const char js_encodeURI_str[] = "encodeURI";
610 const char js_decodeURIComponent_str[] = "decodeURIComponent";
611 const char js_encodeURIComponent_str[] = "encodeURIComponent";
612
613 static JSFunctionSpec string_functions[] = {
614     JS_FN(js_escape_str,             str_escape,                1,0),
615     JS_FN(js_unescape_str,           str_unescape,              1,0),
616 #if JS_HAS_UNEVAL
617     JS_FN(js_uneval_str,             str_uneval,                1,0),
618 #endif
619     JS_FN(js_decodeURI_str,          str_decodeURI,             1,0),
620     JS_FN(js_encodeURI_str,          str_encodeURI,             1,0),
621     JS_FN(js_decodeURIComponent_str, str_decodeURI_Component,   1,0),
622     JS_FN(js_encodeURIComponent_str, str_encodeURI_Component,   1,0),
623
624     JS_FS_END
625 };
626
627 jschar      js_empty_ucstr[]  = {0};
628 JSSubString js_EmptySubString = {0, js_empty_ucstr};
629
630 static JSBool
631 str_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
632 {
633     JSString *str;
634
635     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
636         if (obj->getClass() == &js_StringClass) {
637             /* Follow ECMA-262 by fetching intrinsic length of our string. */
638             str = obj->getPrimitiveThis().toString();
639         } else {
640             /* Preserve compatibility: convert obj to a string primitive. */
641             str = js_ValueToString(cx, ObjectValue(*obj));
642             if (!str)
643                 return JS_FALSE;
644         }
645
646         vp->setInt32(str->length());
647     }
648
649     return JS_TRUE;
650 }
651
652 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
653
654 static JSBool
655 str_enumerate(JSContext *cx, JSObject *obj)
656 {
657     JSString *str, *str1;
658     size_t i, length;
659
660     str = obj->getPrimitiveThis().toString();
661
662     length = str->length();
663     for (i = 0; i < length; i++) {
664         str1 = js_NewDependentString(cx, str, i, 1);
665         if (!str1)
666             return JS_FALSE;
667         if (!obj->defineProperty(cx, INT_TO_JSID(i), StringValue(str1),
668                                  PropertyStub, StrictPropertyStub,
669                                  STRING_ELEMENT_ATTRS)) {
670             return JS_FALSE;
671         }
672     }
673
674     return obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
675                                UndefinedValue(), NULL, NULL,
676                                JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED);
677 }
678
679 static JSBool
680 str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
681             JSObject **objp)
682 {
683     if (!JSID_IS_INT(id))
684         return JS_TRUE;
685
686     JSString *str = obj->getPrimitiveThis().toString();
687
688     jsint slot = JSID_TO_INT(id);
689     if ((size_t)slot < str->length()) {
690         JSString *str1 = JSString::getUnitString(cx, str, size_t(slot));
691         if (!str1)
692             return JS_FALSE;
693         if (!obj->defineProperty(cx, id, StringValue(str1), NULL, NULL,
694                                  STRING_ELEMENT_ATTRS)) {
695             return JS_FALSE;
696         }
697         *objp = obj;
698     }
699     return JS_TRUE;
700 }
701
702 Class js_StringClass = {
703     js_String_str,
704     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE |
705     JSCLASS_HAS_CACHED_PROTO(JSProto_String),
706     PropertyStub,         /* addProperty */
707     PropertyStub,         /* delProperty */
708     str_getProperty,
709     StrictPropertyStub,   /* setProperty */
710     str_enumerate,
711     (JSResolveOp)str_resolve,
712     ConvertStub
713 };
714
715 /*
716  * Returns a JSString * for the |this| value associated with vp, or throws a
717  * TypeError if |this| is null or undefined.  This algorithm is the same as
718  * calling CheckObjectCoercible(this), then returning ToString(this), as all
719  * String.prototype.* methods do.
720  */
721 static JS_ALWAYS_INLINE JSString *
722 ThisToStringForStringProto(JSContext *cx, Value *vp)
723 {
724     if (vp[1].isString())
725         return vp[1].toString();
726
727     if (vp[1].isObject()) {
728         JSObject *obj = &vp[1].toObject();
729         if (obj->getClass() == &js_StringClass &&
730             ClassMethodIsNative(cx, obj,
731                                 &js_StringClass,
732                                 ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
733                                 js_str_toString))
734         {
735             vp[1] = obj->getPrimitiveThis();
736             return vp[1].toString();
737         }
738     } else if (vp[1].isNullOrUndefined()) {
739         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
740                              vp[1].isNull() ? "null" : "undefined", "object");
741         return NULL;
742     }
743
744     JSString *str = js_ValueToString(cx, vp[1]);
745     if (!str)
746         return NULL;
747     vp[1].setString(str);
748     return str;
749 }
750
751 #if JS_HAS_TOSOURCE
752
753 /*
754  * String.prototype.quote is generic (as are most string methods), unlike
755  * toSource, toString, and valueOf.
756  */
757 static JSBool
758 str_quote(JSContext *cx, uintN argc, Value *vp)
759 {
760     JSString *str = ThisToStringForStringProto(cx, vp);
761     if (!str)
762         return false;
763     str = js_QuoteString(cx, str, '"');
764     if (!str)
765         return false;
766     vp->setString(str);
767     return true;
768 }
769
770 static JSBool
771 str_toSource(JSContext *cx, uintN argc, Value *vp)
772 {
773     JSString *str;
774     if (!GetPrimitiveThis(cx, vp, &str))
775         return false;
776
777     str = js_QuoteString(cx, str, '"');
778     if (!str)
779         return false;
780
781     char buf[16];
782     size_t j = JS_snprintf(buf, sizeof buf, "(new String(");
783
784     JS::Anchor<JSString *> anchor(str);
785     size_t k = str->length();
786     const jschar *s = str->getChars(cx);
787     if (!s)
788         return false;
789
790     size_t n = j + k + 2;
791     jschar *t = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
792     if (!t)
793         return false;
794
795     size_t i;
796     for (i = 0; i < j; i++)
797         t[i] = buf[i];
798     for (j = 0; j < k; i++, j++)
799         t[i] = s[j];
800     t[i++] = ')';
801     t[i++] = ')';
802     t[i] = 0;
803
804     str = js_NewString(cx, t, n);
805     if (!str) {
806         cx->free(t);
807         return false;
808     }
809     vp->setString(str);
810     return true;
811 }
812
813 #endif /* JS_HAS_TOSOURCE */
814
815 JSBool
816 js_str_toString(JSContext *cx, uintN argc, Value *vp)
817 {
818     JSString *str;
819     if (!GetPrimitiveThis(cx, vp, &str))
820         return false;
821     vp->setString(str);
822     return true;
823 }
824
825 /*
826  * Java-like string native methods.
827  */
828  
829 JS_ALWAYS_INLINE bool
830 ValueToIntegerRange(JSContext *cx, const Value &v, int32 *out)
831 {
832     if (v.isInt32()) {
833         *out = v.toInt32();
834     } else {
835         double d;
836
837         if (!ValueToNumber(cx, v, &d))
838             return false;
839
840         d = js_DoubleToInteger(d);
841         if (d > INT32_MAX)
842             *out = INT32_MAX;
843         else if (d < INT32_MIN)
844             *out = INT32_MIN;
845         else 
846             *out = int32(d);
847     }
848
849     return true;
850 }
851
852 static JSBool
853 str_substring(JSContext *cx, uintN argc, Value *vp)
854 {
855     JSString *str = ThisToStringForStringProto(cx, vp);
856     if (!str)
857         return false;
858
859     int32 length, begin, end;
860     if (argc > 0) {
861         end = length = int32(str->length());
862
863         if (!ValueToIntegerRange(cx, vp[2], &begin))
864             return false;
865
866         if (begin < 0)
867             begin = 0;
868         else if (begin > length)
869             begin = length;
870
871         if (argc > 1 && !vp[3].isUndefined()) {
872             if (!ValueToIntegerRange(cx, vp[3], &end))
873                 return false;
874
875             if (end > length) {
876                 end = length;
877             } else {
878                 if (end < 0)
879                     end = 0;
880                 if (end < begin) {
881                     int32_t tmp = begin;
882                     begin = end;
883                     end = tmp;
884                 }
885             }
886         }
887
888         str = js_NewDependentString(cx, str, size_t(begin), size_t(end - begin));
889         if (!str)
890             return false;
891     }
892
893     vp->setString(str);
894     return true;
895 }
896
897 JSString* JS_FASTCALL
898 js_toLowerCase(JSContext *cx, JSString *str)
899 {
900     size_t n = str->length();
901     const jschar *s = str->getChars(cx);
902     if (!s)
903         return NULL;
904
905     jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
906     if (!news)
907         return NULL;
908     for (size_t i = 0; i < n; i++)
909         news[i] = JS_TOLOWER(s[i]);
910     news[n] = 0;
911     str = js_NewString(cx, news, n);
912     if (!str) {
913         cx->free(news);
914         return NULL;
915     }
916     return str;
917 }
918
919 static JSBool
920 str_toLowerCase(JSContext *cx, uintN argc, Value *vp)
921 {
922     JSString *str = ThisToStringForStringProto(cx, vp);
923     if (!str)
924         return false;
925     str = js_toLowerCase(cx, str);
926     if (!str)
927         return false;
928     vp->setString(str);
929     return true;
930 }
931
932 static JSBool
933 str_toLocaleLowerCase(JSContext *cx, uintN argc, Value *vp)
934 {
935     /*
936      * Forcefully ignore the first (or any) argument and return toLowerCase(),
937      * ECMA has reserved that argument, presumably for defining the locale.
938      */
939     if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
940         JSString *str = ThisToStringForStringProto(cx, vp);
941         if (!str)
942             return false;
943         return cx->localeCallbacks->localeToLowerCase(cx, str, Jsvalify(vp));
944     }
945
946     return str_toLowerCase(cx, 0, vp);
947 }
948
949 JSString* JS_FASTCALL
950 js_toUpperCase(JSContext *cx, JSString *str)
951 {
952     size_t n = str->length();
953     const jschar *s = str->getChars(cx);
954     if (!s)
955         return NULL;
956     jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
957     if (!news)
958         return NULL;
959     for (size_t i = 0; i < n; i++)
960         news[i] = JS_TOUPPER(s[i]);
961     news[n] = 0;
962     str = js_NewString(cx, news, n);
963     if (!str) {
964         cx->free(news);
965         return NULL;
966     }
967     return str;
968 }
969
970 static JSBool
971 str_toUpperCase(JSContext *cx, uintN argc, Value *vp)
972 {
973     JSString *str = ThisToStringForStringProto(cx, vp);
974     if (!str)
975         return false;
976     str = js_toUpperCase(cx, str);
977     if (!str)
978         return false;
979     vp->setString(str);
980     return true;
981 }
982
983 static JSBool
984 str_toLocaleUpperCase(JSContext *cx, uintN argc, Value *vp)
985 {
986     /*
987      * Forcefully ignore the first (or any) argument and return toUpperCase(),
988      * ECMA has reserved that argument, presumably for defining the locale.
989      */
990     if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
991         JSString *str = ThisToStringForStringProto(cx, vp);
992         if (!str)
993             return false;
994         return cx->localeCallbacks->localeToUpperCase(cx, str, Jsvalify(vp));
995     }
996
997     return str_toUpperCase(cx, 0, vp);
998 }
999
1000 static JSBool
1001 str_localeCompare(JSContext *cx, uintN argc, Value *vp)
1002 {
1003     JSString *str = ThisToStringForStringProto(cx, vp);
1004     if (!str)
1005         return false;
1006
1007     if (argc == 0) {
1008         vp->setInt32(0);
1009     } else {
1010         JSString *thatStr = js_ValueToString(cx, vp[2]);
1011         if (!thatStr)
1012             return false;
1013         if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
1014             vp[2].setString(thatStr);
1015             return cx->localeCallbacks->localeCompare(cx, str, thatStr, Jsvalify(vp));
1016         }
1017         int32 result;
1018         if (!CompareStrings(cx, str, thatStr, &result))
1019             return false;
1020         vp->setInt32(result);
1021     }
1022     return true;
1023 }
1024
1025 JSBool
1026 js_str_charAt(JSContext *cx, uintN argc, Value *vp)
1027 {
1028     JSString *str;
1029     jsint i;
1030     jsdouble d;
1031
1032     if (vp[1].isString() && argc != 0 && vp[2].isInt32()) {
1033         str = vp[1].toString();
1034         i = vp[2].toInt32();
1035         if ((size_t)i >= str->length())
1036             goto out_of_range;
1037     } else {
1038         str = ThisToStringForStringProto(cx, vp);
1039         if (!str)
1040             return false;
1041
1042         if (argc == 0) {
1043             d = 0.0;
1044         } else {
1045             if (!ValueToNumber(cx, vp[2], &d))
1046                 return false;
1047             d = js_DoubleToInteger(d);
1048         }
1049
1050         if (d < 0 || str->length() <= d)
1051             goto out_of_range;
1052         i = (jsint) d;
1053     }
1054
1055     str = JSString::getUnitString(cx, str, size_t(i));
1056     if (!str)
1057         return false;
1058     vp->setString(str);
1059     return true;
1060
1061   out_of_range:
1062     vp->setString(cx->runtime->emptyString);
1063     return true;
1064 }
1065
1066 JSBool
1067 js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
1068 {
1069     JSString *str;
1070     jsint i;
1071     if (vp[1].isString() && argc != 0 && vp[2].isInt32()) {
1072         str = vp[1].toString();
1073         i = vp[2].toInt32();
1074         if ((size_t)i >= str->length())
1075             goto out_of_range;
1076     } else {
1077         str = ThisToStringForStringProto(cx, vp);
1078         if (!str)
1079             return false;
1080
1081         double d;
1082         if (argc == 0) {
1083             d = 0.0;
1084         } else {
1085             if (!ValueToNumber(cx, vp[2], &d))
1086                 return false;
1087             d = js_DoubleToInteger(d);
1088         }
1089
1090         if (d < 0 || str->length() <= d)
1091             goto out_of_range;
1092         i = (jsint) d;
1093     }
1094
1095     const jschar *chars;
1096     chars = str->getChars(cx);
1097     if (!chars)
1098         return false;
1099
1100     vp->setInt32(chars[i]);
1101     return true;
1102
1103 out_of_range:
1104     vp->setDouble(js_NaN);
1105     return true;
1106 }
1107
1108 jsint
1109 js_BoyerMooreHorspool(const jschar *text, jsuint textlen,
1110                       const jschar *pat, jsuint patlen)
1111 {
1112     uint8 skip[sBMHCharSetSize];
1113
1114     JS_ASSERT(0 < patlen && patlen <= sBMHPatLenMax);
1115     for (jsuint i = 0; i < sBMHCharSetSize; i++)
1116         skip[i] = (uint8)patlen;
1117     jsuint m = patlen - 1;
1118     for (jsuint i = 0; i < m; i++) {
1119         jschar c = pat[i];
1120         if (c >= sBMHCharSetSize)
1121             return sBMHBadPattern;
1122         skip[c] = (uint8)(m - i);
1123     }
1124     jschar c;
1125     for (jsuint k = m;
1126          k < textlen;
1127          k += ((c = text[k]) >= sBMHCharSetSize) ? patlen : skip[c]) {
1128         for (jsuint i = k, j = m; ; i--, j--) {
1129             if (text[i] != pat[j])
1130                 break;
1131             if (j == 0)
1132                 return static_cast<jsint>(i);  /* safe: max string size */
1133         }
1134     }
1135     return -1;
1136 }
1137
1138 struct MemCmp {
1139     typedef jsuint Extent;
1140     static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) {
1141         return (patlen - 1) * sizeof(jschar);
1142     }
1143     static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) {
1144         return memcmp(p, t, extent) == 0;
1145     }
1146 };
1147
1148 struct ManualCmp {
1149     typedef const jschar *Extent;
1150     static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) {
1151         return pat + patlen;
1152     }
1153     static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) {
1154         for (; p != extent; ++p, ++t) {
1155             if (*p != *t)
1156                 return false;
1157         }
1158         return true;
1159     }
1160 };
1161
1162 template <class InnerMatch>
1163 static jsint
1164 UnrolledMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen)
1165 {
1166     JS_ASSERT(patlen > 0 && textlen > 0);
1167     const jschar *textend = text + textlen - (patlen - 1);
1168     const jschar p0 = *pat;
1169     const jschar *const patNext = pat + 1;
1170     const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen);
1171     uint8 fixup;
1172
1173     const jschar *t = text;
1174     switch ((textend - t) & 7) {
1175       case 0: if (*t++ == p0) { fixup = 8; goto match; }
1176       case 7: if (*t++ == p0) { fixup = 7; goto match; }
1177       case 6: if (*t++ == p0) { fixup = 6; goto match; }
1178       case 5: if (*t++ == p0) { fixup = 5; goto match; }
1179       case 4: if (*t++ == p0) { fixup = 4; goto match; }
1180       case 3: if (*t++ == p0) { fixup = 3; goto match; }
1181       case 2: if (*t++ == p0) { fixup = 2; goto match; }
1182       case 1: if (*t++ == p0) { fixup = 1; goto match; }
1183     }
1184     while (t != textend) {
1185       if (t[0] == p0) { t += 1; fixup = 8; goto match; }
1186       if (t[1] == p0) { t += 2; fixup = 7; goto match; }
1187       if (t[2] == p0) { t += 3; fixup = 6; goto match; }
1188       if (t[3] == p0) { t += 4; fixup = 5; goto match; }
1189       if (t[4] == p0) { t += 5; fixup = 4; goto match; }
1190       if (t[5] == p0) { t += 6; fixup = 3; goto match; }
1191       if (t[6] == p0) { t += 7; fixup = 2; goto match; }
1192       if (t[7] == p0) { t += 8; fixup = 1; goto match; }
1193         t += 8;
1194         continue;
1195         do {
1196             if (*t++ == p0) {
1197               match:
1198                 if (!InnerMatch::match(patNext, t, extent))
1199                     goto failed_match;
1200                 return t - text - 1;
1201             }
1202           failed_match:;
1203         } while (--fixup > 0);
1204     }
1205     return -1;
1206 }
1207
1208 static JS_ALWAYS_INLINE jsint
1209 StringMatch(const jschar *text, jsuint textlen,
1210             const jschar *pat, jsuint patlen)
1211 {
1212     if (patlen == 0)
1213         return 0;
1214     if (textlen < patlen)
1215         return -1;
1216
1217 #if defined(__i386__) || defined(_M_IX86) || defined(__i386)
1218     /*
1219      * Given enough registers, the unrolled loop below is faster than the
1220      * following loop. 32-bit x86 does not have enough registers.
1221      */
1222     if (patlen == 1) {
1223         const jschar p0 = *pat;
1224         for (const jschar *c = text, *end = text + textlen; c != end; ++c) {
1225             if (*c == p0)
1226                 return c - text;
1227         }
1228         return -1;
1229     }
1230 #endif
1231
1232     /*
1233      * If the text or pattern string is short, BMH will be more expensive than
1234      * the basic linear scan due to initialization cost and a more complex loop
1235      * body. While the correct threshold is input-dependent, we can make a few
1236      * conservative observations:
1237      *  - When |textlen| is "big enough", the initialization time will be
1238      *    proportionally small, so the worst-case slowdown is minimized.
1239      *  - When |patlen| is "too small", even the best case for BMH will be
1240      *    slower than a simple scan for large |textlen| due to the more complex
1241      *    loop body of BMH.
1242      * From this, the values for "big enough" and "too small" are determined
1243      * empirically. See bug 526348.
1244      */
1245     if (textlen >= 512 && patlen >= 11 && patlen <= sBMHPatLenMax) {
1246         jsint index = js_BoyerMooreHorspool(text, textlen, pat, patlen);
1247         if (index != sBMHBadPattern)
1248             return index;
1249     }
1250
1251     /*
1252      * For big patterns with large potential overlap we want the SIMD-optimized
1253      * speed of memcmp. For small patterns, a simple loop is faster.
1254      *
1255      * FIXME: Linux memcmp performance is sad and the manual loop is faster.
1256      */
1257     return
1258 #if !defined(__linux__)
1259            patlen > 128 ? UnrolledMatch<MemCmp>(text, textlen, pat, patlen)
1260                         :
1261 #endif
1262                           UnrolledMatch<ManualCmp>(text, textlen, pat, patlen);
1263 }
1264
1265 static const size_t sRopeMatchThresholdRatioLog2 = 5;
1266
1267 /*
1268  * RopeMatch takes the text to search, the patern to search for in the text.
1269  * RopeMatch returns false on OOM and otherwise returns the match index through
1270  * the 'match' outparam (-1 for not found).
1271  */
1272 static bool
1273 RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, jsint *match)
1274 {
1275     JS_ASSERT(textstr->isRope());
1276
1277     if (patlen == 0) {
1278         *match = 0;
1279         return true;
1280     }
1281     if (textstr->length() < patlen) {
1282         *match = -1;
1283         return true;
1284     }
1285
1286     /*
1287      * List of leaf nodes in the rope. If we run out of memory when trying to
1288      * append to this list, we can still fall back to StringMatch, so use the
1289      * system allocator so we don't report OOM in that case.
1290      */
1291     Vector<JSString *, 16, SystemAllocPolicy> strs;
1292
1293     /*
1294      * We don't want to do rope matching if there is a poor node-to-char ratio,
1295      * since this means spending a lot of time in the match loop below. We also
1296      * need to build the list of leaf nodes. Do both here: iterate over the
1297      * nodes so long as there are not too many.
1298      */
1299     {
1300         size_t textstrlen = textstr->length();
1301         size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
1302         StringSegmentRange r(cx);
1303         if (!r.init(textstr))
1304             return false;
1305         while (!r.empty()) {
1306             if (threshold-- == 0 || !strs.append(r.front())) {
1307                 const jschar *chars = textstr->getChars(cx);
1308                 if (!chars)
1309                     return false;
1310                 *match = StringMatch(chars, textstrlen, pat, patlen);
1311                 return true;
1312             }
1313             if (!r.popFront())
1314                 return false;
1315         }
1316     }
1317
1318     /* Absolute offset from the beginning of the logical string textstr. */
1319     jsint pos = 0;
1320
1321     // TODO: consider branching to a simple loop if patlen == 1
1322
1323     for (JSString **outerp = strs.begin(); outerp != strs.end(); ++outerp) {
1324         /* First try to match without spanning two nodes. */
1325         JSString *outer = *outerp;
1326         const jschar *chars = outer->nonRopeChars();
1327         size_t len = outer->length();
1328         jsint matchResult = StringMatch(chars, len, pat, patlen);
1329         if (matchResult != -1) {
1330             *match = pos + matchResult;
1331             return true;
1332         }
1333
1334         /* Test the overlap. */
1335         JSString **innerp = outerp;
1336
1337         /*
1338          * Start searching at the first place where StringMatch wouldn't have
1339          * found the match.
1340          */
1341         const jschar *const text = chars + (patlen > len ? 0 : len - patlen + 1);
1342         const jschar *const textend = chars + len;
1343         const jschar p0 = *pat;
1344         const jschar *const p1 = pat + 1;
1345         const jschar *const patend = pat + patlen;
1346         for (const jschar *t = text; t != textend; ) {
1347             if (*t++ != p0)
1348                 continue;
1349             const jschar *ttend = textend;
1350             for (const jschar *pp = p1, *tt = t; pp != patend; ++pp, ++tt) {
1351                 while (tt == ttend) {
1352                     if (++innerp == strs.end()) {
1353                         *match = -1;
1354                         return true;
1355                     }
1356                     JSString *inner = *innerp;
1357                     tt = inner->nonRopeChars();
1358                     ttend = tt + inner->length();
1359                 }
1360                 if (*pp != *tt)
1361                     goto break_continue;
1362             }
1363
1364             /* Matched! */
1365             *match = pos + (t - chars) - 1;  /* -1 because of *t++ above */
1366             return true;
1367
1368           break_continue:;
1369         }
1370
1371         pos += len;
1372     }
1373
1374     *match = -1;
1375     return true;
1376 }
1377
1378 static JSBool
1379 str_indexOf(JSContext *cx, uintN argc, Value *vp)
1380 {
1381     JSString *str = ThisToStringForStringProto(cx, vp);
1382     if (!str)
1383         return false;
1384
1385     JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0);
1386     if (!patstr)
1387         return false;
1388
1389     jsuint textlen = str->length();
1390     const jschar *text = str->getChars(cx);
1391     if (!text)
1392         return false;
1393
1394     jsuint patlen = patstr->length();
1395     const jschar *pat = patstr->chars();
1396
1397     jsuint start;
1398     if (argc > 1) {
1399         if (vp[3].isInt32()) {
1400             jsint i = vp[3].toInt32();
1401             if (i <= 0) {
1402                 start = 0;
1403             } else if (jsuint(i) > textlen) {
1404                 start = textlen;
1405                 textlen = 0;
1406             } else {
1407                 start = i;
1408                 text += start;
1409                 textlen -= start;
1410             }
1411         } else {
1412             jsdouble d;
1413             if (!ValueToNumber(cx, vp[3], &d))
1414                 return JS_FALSE;
1415             d = js_DoubleToInteger(d);
1416             if (d <= 0) {
1417                 start = 0;
1418             } else if (d > textlen) {
1419                 start = textlen;
1420                 textlen = 0;
1421             } else {
1422                 start = (jsint)d;
1423                 text += start;
1424                 textlen -= start;
1425             }
1426         }
1427     } else {
1428         start = 0;
1429     }
1430
1431     jsint match = StringMatch(text, textlen, pat, patlen);
1432     vp->setInt32((match == -1) ? -1 : start + match);
1433     return true;
1434 }
1435
1436 static JSBool
1437 str_lastIndexOf(JSContext *cx, uintN argc, Value *vp)
1438 {
1439     JSString *textstr = ThisToStringForStringProto(cx, vp);
1440     if (!textstr)
1441         return false;
1442     size_t textlen = textstr->length();
1443     const jschar *text = textstr->getChars(cx);
1444     if (!text)
1445         return false;
1446
1447     JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0);
1448     if (!patstr)
1449         return false;
1450
1451     size_t patlen = patstr->length();
1452     const jschar *pat = patstr->chars();
1453
1454     jsint i = textlen - patlen; // Start searching here
1455     if (i < 0) {
1456         vp->setInt32(-1);
1457         return true;
1458     }
1459
1460     if (argc > 1) {
1461         if (vp[3].isInt32()) {
1462             jsint j = vp[3].toInt32();
1463             if (j <= 0)
1464                 i = 0;
1465             else if (j < i)
1466                 i = j;
1467         } else {
1468             double d;
1469             if (!ValueToNumber(cx, vp[3], &d))
1470                 return false;
1471             if (!JSDOUBLE_IS_NaN(d)) {
1472                 d = js_DoubleToInteger(d);
1473                 if (d <= 0)
1474                     i = 0;
1475                 else if (d < i)
1476                     i = (jsint)d;
1477             }
1478         }
1479     }
1480
1481     if (patlen == 0) {
1482         vp->setInt32(i);
1483         return true;
1484     }
1485
1486     const jschar *t = text + i;
1487     const jschar *textend = text - 1;
1488     const jschar p0 = *pat;
1489     const jschar *patNext = pat + 1;
1490     const jschar *patEnd = pat + patlen;
1491
1492     for (; t != textend; --t) {
1493         if (*t == p0) {
1494             const jschar *t1 = t + 1;
1495             for (const jschar *p1 = patNext; p1 != patEnd; ++p1, ++t1) {
1496                 if (*t1 != *p1)
1497                     goto break_continue;
1498             }
1499             vp->setInt32(t - text);
1500             return true;
1501         }
1502       break_continue:;
1503     }
1504
1505     vp->setInt32(-1);
1506     return true;
1507 }
1508
1509 static JSBool
1510 js_TrimString(JSContext *cx, Value *vp, JSBool trimLeft, JSBool trimRight)
1511 {
1512     JSString *str = ThisToStringForStringProto(cx, vp);
1513     if (!str)
1514         return false;
1515     size_t length = str->length();
1516     const jschar *chars = str->getChars(cx);
1517     if (!chars)
1518         return false;
1519
1520     size_t begin = 0;
1521     size_t end = length;
1522
1523     if (trimLeft) {
1524         while (begin < length && JS_ISSPACE(chars[begin]))
1525             ++begin;
1526     }
1527
1528     if (trimRight) {
1529         while (end > begin && JS_ISSPACE(chars[end-1]))
1530             --end;
1531     }
1532
1533     str = js_NewDependentString(cx, str, begin, end - begin);
1534     if (!str)
1535         return false;
1536
1537     vp->setString(str);
1538     return true;
1539 }
1540
1541 static JSBool
1542 str_trim(JSContext *cx, uintN argc, Value *vp)
1543 {
1544     return js_TrimString(cx, vp, JS_TRUE, JS_TRUE);
1545 }
1546
1547 static JSBool
1548 str_trimLeft(JSContext *cx, uintN argc, Value *vp)
1549 {
1550     return js_TrimString(cx, vp, JS_TRUE, JS_FALSE);
1551 }
1552
1553 static JSBool
1554 str_trimRight(JSContext *cx, uintN argc, Value *vp)
1555 {
1556     return js_TrimString(cx, vp, JS_FALSE, JS_TRUE);
1557 }
1558
1559 /*
1560  * Perl-inspired string functions.
1561  */
1562
1563 /* Result of a successfully performed flat match. */
1564 class FlatMatch
1565 {
1566     JSLinearString  *patstr;
1567     const jschar    *pat;
1568     size_t          patlen;
1569     int32           match_;
1570
1571     friend class RegExpGuard;
1572
1573   public:
1574     FlatMatch() : patstr(NULL) {} /* Old GCC wants this initialization. */
1575     JSString *pattern() const { return patstr; }
1576     size_t patternLength() const { return patlen; }
1577
1578     /*
1579      * Note: The match is -1 when the match is performed successfully,
1580      * but no match is found.
1581      */
1582     int32 match() const { return match_; }
1583 };
1584
1585 /* A regexp and optional associated object. */
1586 class RegExpPair
1587 {
1588     AutoRefCount<RegExp>    re_;
1589     JSObject                *reobj_;
1590
1591     explicit RegExpPair(RegExpPair &);
1592
1593   public:
1594     explicit RegExpPair(JSContext *cx) : re_(cx) {}
1595
1596     void reset(JSObject &obj) {
1597         reobj_ = &obj;
1598         RegExp *re = RegExp::extractFrom(reobj_);
1599         JS_ASSERT(re);
1600         re_.reset(NeedsIncRef<RegExp>(re));
1601     }
1602
1603     void reset(AlreadyIncRefed<RegExp> re) {
1604         reobj_ = NULL;
1605         re_.reset(re);
1606     }
1607
1608     /* Note: May be null. */
1609     JSObject *reobj() const { return reobj_; }
1610     bool hasRegExp() const { return !re_.null(); }
1611     RegExp &re() const { JS_ASSERT(hasRegExp()); return *re_; }
1612 };
1613
1614 /*
1615  * RegExpGuard factors logic out of String regexp operations.
1616  *
1617  * @param optarg    Indicates in which argument position RegExp
1618  *                  flags will be found, if present. This is a Mozilla
1619  *                  extension and not part of any ECMA spec.
1620  */
1621 class RegExpGuard
1622 {
1623     RegExpGuard(const RegExpGuard &);
1624     void operator=(const RegExpGuard &);
1625
1626     JSContext   *cx;
1627     RegExpPair  rep;
1628     FlatMatch   fm;
1629
1630     /*
1631      * Upper bound on the number of characters we are willing to potentially
1632      * waste on searching for RegExp meta-characters.
1633      */
1634     static const size_t MAX_FLAT_PAT_LEN = 256;
1635
1636     static JSString *flattenPattern(JSContext *cx, JSLinearString *patstr) {
1637         StringBuffer sb(cx);
1638         if (!sb.reserve(patstr->length()))
1639             return NULL;
1640
1641         static const jschar ESCAPE_CHAR = '\\';
1642         const jschar *chars = patstr->chars();
1643         size_t len = patstr->length();
1644         for (const jschar *it = chars; it != chars + len; ++it) {
1645             if (RegExp::isMetaChar(*it)) {
1646                 if (!sb.append(ESCAPE_CHAR) || !sb.append(*it))
1647                     return NULL;
1648             } else {
1649                 if (!sb.append(*it))
1650                     return NULL;
1651             }
1652         }
1653         return sb.finishString();
1654     }
1655
1656   public:
1657     explicit RegExpGuard(JSContext *cx) : cx(cx), rep(cx) {}
1658     ~RegExpGuard() {}
1659
1660     /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
1661     bool
1662     init(uintN argc, Value *vp)
1663     {
1664         if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) {
1665             rep.reset(vp[2].toObject());
1666         } else {
1667             fm.patstr = ArgToRootedString(cx, argc, vp, 0);
1668             if (!fm.patstr)
1669                 return false;
1670         }
1671         return true;
1672     }
1673
1674     /*
1675      * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the
1676      * pattern string, or a lengthy pattern string can thwart this process.
1677      *
1678      * @param checkMetaChars    Look for regexp metachars in the pattern string.
1679      * @return                  Whether flat matching could be used.
1680      *
1681      * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->isExceptionPending().
1682      */
1683     const FlatMatch *
1684     tryFlatMatch(JSContext *cx, JSString *textstr, uintN optarg, uintN argc,
1685                  bool checkMetaChars = true)
1686     {
1687         if (rep.hasRegExp())
1688             return NULL;
1689
1690         fm.pat = fm.patstr->chars();
1691         fm.patlen = fm.patstr->length();
1692
1693         if (optarg < argc)
1694             return NULL;
1695
1696         if (checkMetaChars &&
1697             (fm.patlen > MAX_FLAT_PAT_LEN || RegExp::hasMetaChars(fm.pat, fm.patlen))) {
1698             return NULL;
1699         }
1700
1701         /*
1702          * textstr could be a rope, so we want to avoid flattening it for as
1703          * long as possible.
1704          */
1705         if (textstr->isRope()) {
1706             if (!RopeMatch(cx, textstr, fm.pat, fm.patlen, &fm.match_))
1707                 return NULL;
1708         } else {
1709             const jschar *text = textstr->nonRopeChars();
1710             size_t textlen = textstr->length();
1711             fm.match_ = StringMatch(text, textlen, fm.pat, fm.patlen);
1712         }
1713         return &fm;
1714     }
1715
1716     /* If the pattern is not already a regular expression, make it so. */
1717     const RegExpPair *
1718     normalizeRegExp(bool flat, uintN optarg, uintN argc, Value *vp)
1719     {
1720         if (rep.hasRegExp())
1721             return &rep;
1722
1723         /* Build RegExp from pattern string. */
1724         JSString *opt;
1725         if (optarg < argc) {
1726             opt = js_ValueToString(cx, vp[2 + optarg]);
1727             if (!opt)
1728                 return NULL;
1729         } else {
1730             opt = NULL;
1731         }
1732
1733         JSString *patstr;
1734         if (flat) {
1735             patstr = flattenPattern(cx, fm.patstr);
1736             if (!patstr)
1737                 return false;
1738         } else {
1739             patstr = fm.patstr;
1740         }
1741         JS_ASSERT(patstr);
1742
1743         AlreadyIncRefed<RegExp> re = RegExp::createFlagged(cx, patstr, opt);
1744         if (!re)
1745             return NULL;
1746         rep.reset(re);
1747         return &rep;
1748     }
1749
1750 #if DEBUG
1751     bool hasRegExpPair() const { return rep.hasRegExp(); }
1752 #endif
1753 };
1754
1755 /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
1756 static JS_ALWAYS_INLINE bool
1757 Matched(bool test, const Value &v)
1758 {
1759     return test ? v.isTrue() : !v.isNull();
1760 }
1761
1762 typedef bool (*DoMatchCallback)(JSContext *cx, RegExpStatics *res, size_t count, void *data);
1763
1764 /*
1765  * BitOR-ing these flags allows the DoMatch caller to control when how the
1766  * RegExp engine is called and when callbacks are fired.
1767  */
1768 enum MatchControlFlags {
1769    TEST_GLOBAL_BIT         = 0x1, /* use RegExp.test for global regexps */
1770    TEST_SINGLE_BIT         = 0x2, /* use RegExp.test for non-global regexps */
1771    CALLBACK_ON_SINGLE_BIT  = 0x4, /* fire callback on non-global match */
1772
1773    MATCH_ARGS    = TEST_GLOBAL_BIT,
1774    MATCHALL_ARGS = CALLBACK_ON_SINGLE_BIT,
1775    REPLACE_ARGS  = TEST_GLOBAL_BIT | TEST_SINGLE_BIT | CALLBACK_ON_SINGLE_BIT
1776 };
1777
1778 /* Factor out looping and matching logic. */
1779 static bool
1780 DoMatch(JSContext *cx, RegExpStatics *res, Value *vp, JSString *str, const RegExpPair &rep,
1781         DoMatchCallback callback, void *data, MatchControlFlags flags)
1782 {
1783     RegExp &re = rep.re();
1784     if (re.global()) {
1785         /* global matching ('g') */
1786         bool testGlobal = flags & TEST_GLOBAL_BIT;
1787         if (rep.reobj())
1788             rep.reobj()->zeroRegExpLastIndex();
1789         for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
1790             if (!re.execute(cx, res, str, &i, testGlobal, vp))
1791                 return false;
1792             if (!Matched(testGlobal, *vp))
1793                 break;
1794             if (!callback(cx, res, count, data))
1795                 return false;
1796             if (!res->matched())
1797                 ++i;
1798         }
1799     } else {
1800         /* single match */
1801         bool testSingle = !!(flags & TEST_SINGLE_BIT),
1802              callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
1803         size_t i = 0;
1804         if (!re.execute(cx, res, str, &i, testSingle, vp))
1805             return false;
1806         if (callbackOnSingle && Matched(testSingle, *vp) && !callback(cx, res, 0, data))
1807             return false;
1808     }
1809     return true;
1810 }
1811
1812 static bool
1813 BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value *vp)
1814 {
1815     if (fm.match() < 0) {
1816         vp->setNull();
1817         return true;
1818     }
1819
1820     /* For this non-global match, produce a RegExp.exec-style array. */
1821     JSObject *obj = NewSlowEmptyArray(cx);
1822     if (!obj)
1823         return false;
1824     vp->setObject(*obj);
1825
1826     return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(fm.pattern())) &&
1827            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom),
1828                                Int32Value(fm.match())) &&
1829            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom),
1830                                StringValue(textstr));
1831 }
1832
1833 typedef JSObject **MatchArgType;
1834
1835 /*
1836  * DoMatch will only callback on global matches, hence this function builds
1837  * only the "array of matches" returned by match on global regexps.
1838  */
1839 static bool
1840 MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
1841 {
1842     JS_ASSERT(count <= JSID_INT_MAX);  /* by max string length */
1843
1844     JSObject *&arrayobj = *static_cast<MatchArgType>(p);
1845     if (!arrayobj) {
1846         arrayobj = NewDenseEmptyArray(cx);
1847         if (!arrayobj)
1848             return false;
1849     }
1850
1851     Value v;
1852     if (!res->createLastMatch(cx, &v))
1853         return false;
1854
1855     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
1856     return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false);
1857 }
1858
1859 static JSBool
1860 str_match(JSContext *cx, uintN argc, Value *vp)
1861 {
1862     JSString *str = ThisToStringForStringProto(cx, vp);
1863     if (!str)
1864         return false;
1865
1866     RegExpGuard g(cx);
1867     if (!g.init(argc, vp))
1868         return false;
1869     if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc))
1870         return BuildFlatMatchArray(cx, str, *fm, vp);
1871     if (cx->isExceptionPending())  /* from tryFlatMatch */
1872         return false;
1873
1874     const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
1875     if (!rep)
1876         return false;
1877
1878     AutoObjectRooter array(cx);
1879     MatchArgType arg = array.addr();
1880     RegExpStatics *res = cx->regExpStatics();
1881     if (!DoMatch(cx, res, vp, str, *rep, MatchCallback, arg, MATCH_ARGS))
1882         return false;
1883
1884     /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
1885     if (rep->re().global())
1886         vp->setObjectOrNull(array.object());
1887     return true;
1888 }
1889
1890 static JSBool
1891 str_search(JSContext *cx, uintN argc, Value *vp)
1892 {
1893     JSString *str = ThisToStringForStringProto(cx, vp);
1894     if (!str)
1895         return false;
1896
1897     RegExpGuard g(cx);
1898     if (!g.init(argc, vp))
1899         return false;
1900     if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc)) {
1901         vp->setInt32(fm->match());
1902         return true;
1903     }
1904     if (cx->isExceptionPending())  /* from tryFlatMatch */
1905         return false;
1906     const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
1907     if (!rep)
1908         return false;
1909
1910     RegExpStatics *res = cx->regExpStatics();
1911     size_t i = 0;
1912     if (!rep->re().execute(cx, res, str, &i, true, vp))
1913         return false;
1914
1915     if (vp->isTrue())
1916         vp->setInt32(res->matchStart());
1917     else
1918         vp->setInt32(-1);
1919     return true;
1920 }
1921
1922 struct ReplaceData
1923 {
1924     ReplaceData(JSContext *cx)
1925      : g(cx), sb(cx)
1926     {}
1927
1928     JSString           *str;           /* 'this' parameter object as a string */
1929     RegExpGuard        g;              /* regexp parameter object and private data */
1930     JSObject           *lambda;        /* replacement function object or null */
1931     JSObject           *elembase;      /* object for function(a){return b[a]} replace */
1932     JSLinearString     *repstr;        /* replacement string */
1933     const jschar       *dollar;        /* null or pointer to first $ in repstr */
1934     const jschar       *dollarEnd;     /* limit pointer for js_strchr_limit */
1935     jsint              leftIndex;      /* left context index in str->chars */
1936     JSSubString        dollarStr;      /* for "$$" InterpretDollar result */
1937     bool               calledBack;     /* record whether callback has been called */
1938     InvokeSessionGuard session;        /* arguments for repeated lambda Invoke call */
1939     InvokeArgsGuard    singleShot;     /* arguments for single lambda Invoke call */
1940     StringBuffer       sb;             /* buffer built during DoMatch */
1941 };
1942
1943 static bool
1944 InterpretDollar(JSContext *cx, RegExpStatics *res, const jschar *dp, const jschar *ep,
1945                 ReplaceData &rdata, JSSubString *out, size_t *skip)
1946 {
1947     JS_ASSERT(*dp == '$');
1948
1949     /* If there is only a dollar, bail now */
1950     if (dp + 1 >= ep)
1951         return false;
1952
1953     /* Interpret all Perl match-induced dollar variables. */
1954     jschar dc = dp[1];
1955     if (JS7_ISDEC(dc)) {
1956         /* ECMA-262 Edition 3: 1-9 or 01-99 */
1957         uintN num = JS7_UNDEC(dc);
1958         if (num > res->parenCount())
1959             return false;
1960
1961         const jschar *cp = dp + 2;
1962         if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
1963             uintN tmp = 10 * num + JS7_UNDEC(dc);
1964             if (tmp <= res->parenCount()) {
1965                 cp++;
1966                 num = tmp;
1967             }
1968         }
1969         if (num == 0)
1970             return false;
1971
1972         *skip = cp - dp;
1973
1974         JS_ASSERT(num <= res->parenCount());
1975
1976         /* 
1977          * Note: we index to get the paren with the (1-indexed) pair
1978          * number, as opposed to a (0-indexed) paren number.
1979          */
1980         res->getParen(num, out);
1981         return true;
1982     }
1983
1984     *skip = 2;
1985     switch (dc) {
1986       case '$':
1987         rdata.dollarStr.chars = dp;
1988         rdata.dollarStr.length = 1;
1989         *out = rdata.dollarStr;
1990         return true;
1991       case '&':
1992         res->getLastMatch(out);
1993         return true;
1994       case '+':
1995         res->getLastParen(out);
1996         return true;
1997       case '`':
1998         res->getLeftContext(out);
1999         return true;
2000       case '\'':
2001         res->getRightContext(out);
2002         return true;
2003     }
2004     return false;
2005 }
2006
2007 static bool
2008 FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
2009 {
2010     JSObject *base = rdata.elembase;
2011     if (base) {
2012         /*
2013          * The base object is used when replace was passed a lambda which looks like
2014          * 'function(a) { return b[a]; }' for the base object b.  b will not change
2015          * in the course of the replace unless we end up making a scripted call due
2016          * to accessing a scripted getter or a value with a scripted toString.
2017          */
2018         JS_ASSERT(rdata.lambda);
2019         JS_ASSERT(!base->getOps()->lookupProperty);
2020         JS_ASSERT(!base->getOps()->getProperty);
2021
2022         Value match;
2023         if (!res->createLastMatch(cx, &match))
2024             return false;
2025         JSString *str = match.toString();
2026
2027         JSAtom *atom;
2028         if (str->isAtomized()) {
2029             atom = STRING_TO_ATOM(str);
2030         } else {
2031             atom = js_AtomizeString(cx, str, 0);
2032             if (!atom)
2033                 return false;
2034         }
2035         jsid id = ATOM_TO_JSID(atom);
2036
2037         JSObject *holder;
2038         JSProperty *prop = NULL;
2039         if (js_LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop) < 0)
2040             return false;
2041
2042         /* Only handle the case where the property exists and is on this object. */
2043         if (prop && holder == base) {
2044             Shape *shape = (Shape *) prop;
2045             if (shape->slot != SHAPE_INVALID_SLOT && shape->hasDefaultGetter()) {
2046                 Value value = base->getSlot(shape->slot);
2047                 if (value.isString()) {
2048                     rdata.repstr = value.toString()->ensureLinear(cx);
2049                     if (!rdata.repstr)
2050                         return false;
2051                     *sizep = rdata.repstr->length();
2052                     return true;
2053                 }
2054             }
2055         }
2056
2057         /*
2058          * Couldn't handle this property, fall through and despecialize to the
2059          * general lambda case.
2060          */
2061         rdata.elembase = NULL;
2062     }
2063
2064     JSObject *lambda = rdata.lambda;
2065     if (lambda) {
2066         /*
2067          * In the lambda case, not only do we find the replacement string's
2068          * length, we compute repstr and return it via rdata for use within
2069          * DoReplace.  The lambda is called with arguments ($&, $1, $2, ...,
2070          * index, input), i.e., all the properties of a regexp match array.
2071          * For $&, etc., we must create string jsvals from cx->regExpStatics.
2072          * We grab up stack space to keep the newborn strings GC-rooted.
2073          */
2074         uintN p = res->parenCount();
2075         uintN argc = 1 + p + 2;
2076
2077         InvokeSessionGuard &session = rdata.session;
2078         if (!session.started()) {
2079             Value lambdav = ObjectValue(*lambda);
2080             if (!session.start(cx, lambdav, UndefinedValue(), argc))
2081                 return false;
2082         }
2083
2084         PreserveRegExpStatics staticsGuard(res);
2085         if (!staticsGuard.init(cx))
2086             return false;
2087
2088         /* Push $&, $1, $2, ... */
2089         uintN argi = 0;
2090         if (!res->createLastMatch(cx, &session[argi++]))
2091             return false;
2092
2093         for (size_t i = 0; i < res->parenCount(); ++i) {
2094             if (!res->createParen(cx, i + 1, &session[argi++]))
2095                 return false;
2096         }
2097
2098         /* Push match index and input string. */
2099         session[argi++].setInt32(res->matchStart());
2100         session[argi].setString(rdata.str);
2101
2102         if (!session.invoke(cx))
2103             return false;
2104
2105         /* root repstr: rdata is on the stack, so scanned by conservative gc. */
2106         JSString *repstr = ValueToString_TestForStringInline(cx, session.rval());
2107         if (!repstr)
2108             return false;
2109         rdata.repstr = repstr->ensureLinear(cx);
2110         if (!rdata.repstr)
2111             return false;
2112         *sizep = rdata.repstr->length();
2113         return true;
2114     }
2115
2116     JSString *repstr = rdata.repstr;
2117     size_t replen = repstr->length();
2118     for (const jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp;
2119          dp = js_strchr_limit(dp, '$', ep)) {
2120         JSSubString sub;
2121         size_t skip;
2122         if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) {
2123             replen += sub.length - skip;
2124             dp += skip;
2125         } else {
2126             dp++;
2127         }
2128     }
2129     *sizep = replen;
2130     return true;
2131 }
2132
2133 /* 
2134  * Precondition: |rdata.sb| already has necessary growth space reserved (as
2135  * derived from FindReplaceLength).
2136  */
2137 static void
2138 DoReplace(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
2139 {
2140     JSLinearString *repstr = rdata.repstr;
2141     const jschar *cp;
2142     const jschar *bp = cp = repstr->chars();
2143
2144     const jschar *dp = rdata.dollar;
2145     const jschar *ep = rdata.dollarEnd;
2146     for (; dp; dp = js_strchr_limit(dp, '$', ep)) {
2147         /* Move one of the constant portions of the replacement value. */
2148         size_t len = dp - cp;
2149         JS_ALWAYS_TRUE(rdata.sb.append(cp, len));
2150         cp = dp;
2151
2152         JSSubString sub;
2153         size_t skip;
2154         if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) {
2155             len = sub.length;
2156             JS_ALWAYS_TRUE(rdata.sb.append(sub.chars, len));
2157             cp += skip;
2158             dp += skip;
2159         } else {
2160             dp++;
2161         }
2162     }
2163     JS_ALWAYS_TRUE(rdata.sb.append(cp, repstr->length() - (cp - bp)));
2164 }
2165
2166 static bool
2167 ReplaceRegExpCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
2168 {
2169     ReplaceData &rdata = *static_cast<ReplaceData *>(p);
2170
2171     rdata.calledBack = true;
2172     JSLinearString *str = rdata.str->assertIsLinear();  /* flattened for regexp */
2173     size_t leftoff = rdata.leftIndex;
2174     const jschar *left = str->chars() + leftoff;
2175     size_t leftlen = res->matchStart() - leftoff;
2176     rdata.leftIndex = res->matchLimit();
2177
2178     size_t replen = 0;  /* silence 'unused' warning */
2179     if (!FindReplaceLength(cx, res, rdata, &replen))
2180         return false;
2181
2182     size_t growth = leftlen + replen;
2183     if (!rdata.sb.reserve(rdata.sb.length() + growth))
2184         return false;
2185     JS_ALWAYS_TRUE(rdata.sb.append(left, leftlen)); /* skipped-over portion of the search value */
2186     DoReplace(cx, res, rdata);
2187     return true;
2188 }
2189
2190 static bool
2191 BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr,
2192                      const FlatMatch &fm, Value *vp)
2193 {
2194     RopeBuilder builder(cx);
2195     size_t match = fm.match();
2196     size_t matchEnd = match + fm.patternLength();
2197
2198     if (textstr->isRope()) {
2199         /*
2200          * If we are replacing over a rope, avoid flattening it by iterating
2201          * through it, building a new rope.
2202          */
2203         StringSegmentRange r(cx);
2204         if (!r.init(textstr))
2205             return false;
2206         size_t pos = 0;
2207         while (!r.empty()) {
2208             JSString *str = r.front();
2209             size_t len = str->length();
2210             size_t strEnd = pos + len;
2211             if (pos < matchEnd && strEnd > match) {
2212                 /*
2213                  * We need to special-case any part of the rope that overlaps
2214                  * with the replacement string.
2215                  */
2216                 if (match >= pos) {
2217                     /*
2218                      * If this part of the rope overlaps with the left side of
2219                      * the pattern, then it must be the only one to overlap with
2220                      * the first character in the pattern, so we include the
2221                      * replacement string here.
2222                      */
2223                     JSString *leftSide = js_NewDependentString(cx, str, 0, match - pos);
2224                     if (!leftSide ||
2225                         !builder.append(leftSide) ||
2226                         !builder.append(repstr)) {
2227                         return false;
2228                     }
2229                 }
2230
2231                 /*
2232                  * If str runs off the end of the matched string, append the
2233                  * last part of str.
2234                  */
2235                 if (strEnd > matchEnd) {
2236                     JSString *rightSide = js_NewDependentString(cx, str, matchEnd - pos,
2237                                                                 strEnd - matchEnd);
2238                     if (!rightSide || !builder.append(rightSide))
2239                         return false;
2240                 }
2241             } else {
2242                 if (!builder.append(str))
2243                     return false;
2244             }
2245             pos += str->length();
2246             if (!r.popFront())
2247                 return false;
2248         }
2249     } else {
2250         JSString *leftSide = js_NewDependentString(cx, textstr, 0, match);
2251         if (!leftSide)
2252             return false;
2253         JSString *rightSide = js_NewDependentString(cx, textstr, match + fm.patternLength(),
2254                                                     textstr->length() - match - fm.patternLength());
2255         if (!rightSide ||
2256             !builder.append(leftSide) ||
2257             !builder.append(repstr) ||
2258             !builder.append(rightSide)) {
2259             return false;
2260         }
2261     }
2262
2263     vp->setString(builder.result());
2264     return true;
2265 }
2266
2267 /*
2268  * Perform a linear-scan dollar substitution on the replacement text,
2269  * constructing a result string that looks like:
2270  *
2271  *      newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:]
2272  */
2273 static inline bool
2274 BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *repstr,
2275                        const jschar *firstDollar, const FlatMatch &fm, Value *vp)
2276 {
2277     JSLinearString *textstr = textstrArg->ensureLinear(cx);
2278     if (!textstr)
2279         return NULL;
2280
2281     JS_ASSERT(repstr->chars() <= firstDollar && firstDollar < repstr->chars() + repstr->length());
2282     size_t matchStart = fm.match();
2283     size_t matchLimit = matchStart + fm.patternLength();
2284
2285     /*
2286      * Most probably:
2287      *
2288      *      len(newstr) >= len(orig) - len(match) + len(replacement)
2289      *
2290      * Note that dollar vars _could_ make the resulting text smaller than this.
2291      */
2292     StringBuffer newReplaceChars(cx);
2293     if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))
2294         return false;
2295
2296     /* Move the pre-dollar chunk in bulk. */
2297     JS_ALWAYS_TRUE(newReplaceChars.append(repstr->chars(), firstDollar));
2298
2299     /* Move the rest char-by-char, interpreting dollars as we encounter them. */
2300 #define ENSURE(__cond) if (!(__cond)) return false;
2301     const jschar *repstrLimit = repstr->chars() + repstr->length();
2302     for (const jschar *it = firstDollar; it < repstrLimit; ++it) {
2303         if (*it != '$' || it == repstrLimit - 1) {
2304             ENSURE(newReplaceChars.append(*it));
2305             continue;
2306         }
2307
2308         switch (*(it + 1)) {
2309           case '$': /* Eat one of the dollars. */
2310             ENSURE(newReplaceChars.append(*it));
2311             break;
2312           case '&':
2313             ENSURE(newReplaceChars.append(textstr->chars() + matchStart,
2314                                           textstr->chars() + matchLimit));
2315             break;
2316           case '`':
2317             ENSURE(newReplaceChars.append(textstr->chars(), textstr->chars() + matchStart));
2318             break;
2319           case '\'':
2320             ENSURE(newReplaceChars.append(textstr->chars() + matchLimit,
2321                                           textstr->chars() + textstr->length()));
2322             break;
2323           default: /* The dollar we saw was not special (no matter what its mother told it). */
2324             ENSURE(newReplaceChars.append(*it));
2325             continue;
2326         }
2327         ++it; /* We always eat an extra char in the above switch. */
2328     }
2329
2330     JSString *leftSide = js_NewDependentString(cx, textstr, 0, matchStart);
2331     ENSURE(leftSide);
2332
2333     JSString *newReplace = newReplaceChars.finishString();
2334     ENSURE(newReplace);
2335
2336     JS_ASSERT(textstr->length() >= matchLimit);
2337     JSString *rightSide = js_NewDependentString(cx, textstr, matchLimit,
2338                                                 textstr->length() - matchLimit);
2339     ENSURE(rightSide);
2340
2341     RopeBuilder builder(cx);
2342     ENSURE(builder.append(leftSide) &&
2343            builder.append(newReplace) &&
2344            builder.append(rightSide));
2345 #undef ENSURE
2346
2347     vp->setString(builder.result());
2348     return true;
2349 }
2350
2351 static inline bool
2352 str_replace_regexp(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata)
2353 {
2354     const RegExpPair *rep = rdata.g.normalizeRegExp(true, 2, argc, vp);
2355     if (!rep)
2356         return false;
2357
2358     rdata.leftIndex = 0;
2359     rdata.calledBack = false;
2360
2361     RegExpStatics *res = cx->regExpStatics();
2362     if (!DoMatch(cx, res, vp, rdata.str, *rep, ReplaceRegExpCallback, &rdata, REPLACE_ARGS))
2363         return false;
2364
2365     if (!rdata.calledBack) {
2366         /* Didn't match, so the string is unmodified. */
2367         vp->setString(rdata.str);
2368         return true;
2369     }
2370
2371     JSSubString sub;
2372     res->getRightContext(&sub);
2373     if (!rdata.sb.append(sub.chars, sub.length))
2374         return false;
2375
2376     JSString *retstr = rdata.sb.finishString();
2377     if (!retstr)
2378         return false;
2379
2380     vp->setString(retstr);
2381     return true;
2382 }
2383
2384 static inline bool
2385 str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata,
2386                         const FlatMatch &fm)
2387 {
2388     JS_ASSERT(fm.match() >= 0);
2389     LeaveTrace(cx);
2390
2391     JSString *matchStr = js_NewDependentString(cx, rdata.str, fm.match(), fm.patternLength());
2392     if (!matchStr)
2393         return false;
2394
2395     /* lambda(matchStr, matchStart, textstr) */
2396     static const uint32 lambdaArgc = 3;
2397     if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.singleShot))
2398         return false;
2399
2400     CallArgs &args = rdata.singleShot;
2401     args.callee().setObject(*rdata.lambda);
2402     args.thisv().setUndefined();
2403
2404     Value *sp = args.argv();
2405     sp[0].setString(matchStr);
2406     sp[1].setInt32(fm.match());
2407     sp[2].setString(rdata.str);
2408
2409     if (!Invoke(cx, rdata.singleShot, 0))
2410         return false;
2411
2412     JSString *repstr = js_ValueToString(cx, args.rval());
2413     if (!repstr)
2414         return false;
2415
2416     JSString *leftSide = js_NewDependentString(cx, rdata.str, 0, fm.match());
2417     if (!leftSide)
2418         return false;
2419
2420     size_t matchLimit = fm.match() + fm.patternLength();
2421     JSString *rightSide = js_NewDependentString(cx, rdata.str, matchLimit,
2422                                                 rdata.str->length() - matchLimit);
2423     if (!rightSide)
2424         return false;
2425
2426     RopeBuilder builder(cx);
2427     if (!(builder.append(leftSide) &&
2428           builder.append(repstr) &&
2429           builder.append(rightSide))) {
2430         return false;
2431     }
2432
2433     vp->setString(builder.result());
2434     return true;
2435 }
2436
2437 JSBool
2438 js::str_replace(JSContext *cx, uintN argc, Value *vp)
2439 {
2440     ReplaceData rdata(cx);
2441     rdata.str = ThisToStringForStringProto(cx, vp);
2442     if (!rdata.str)
2443         return false;
2444     static const uint32 optarg = 2;
2445
2446     /* Extract replacement string/function. */
2447     if (argc >= optarg && js_IsCallable(vp[3])) {
2448         rdata.lambda = &vp[3].toObject();
2449         rdata.elembase = NULL;
2450         rdata.repstr = NULL;
2451         rdata.dollar = rdata.dollarEnd = NULL;
2452
2453         if (rdata.lambda->isFunction()) {
2454             JSFunction *fun = rdata.lambda->getFunctionPrivate();
2455             if (fun->isInterpreted()) {
2456                 /*
2457                  * Pattern match the script to check if it is is indexing into a
2458                  * particular object, e.g. 'function(a) { return b[a]; }'.  Avoid
2459                  * calling the script in such cases, which are used by javascript
2460                  * packers (particularly the popular Dean Edwards packer) to efficiently
2461                  * encode large scripts.  We only handle the code patterns generated
2462                  * by such packers here.
2463                  */
2464                 JSScript *script = fun->u.i.script;
2465                 jsbytecode *pc = script->code;
2466
2467                 Value table = UndefinedValue();
2468                 if (JSOp(*pc) == JSOP_GETFCSLOT) {
2469                     table = rdata.lambda->getFlatClosureUpvar(GET_UINT16(pc));
2470                     pc += JSOP_GETFCSLOT_LENGTH;
2471                 }
2472
2473                 if (table.isObject() &&
2474                     JSOp(*pc) == JSOP_GETARG && GET_SLOTNO(pc) == 0 &&
2475                     JSOp(*(pc + JSOP_GETARG_LENGTH)) == JSOP_GETELEM &&
2476                     JSOp(*(pc + JSOP_GETARG_LENGTH + JSOP_GETELEM_LENGTH)) == JSOP_RETURN) {
2477                     Class *clasp = table.toObject().getClass();
2478                     if (clasp->isNative() &&
2479                         !clasp->ops.lookupProperty &&
2480                         !clasp->ops.getProperty) {
2481                         rdata.elembase = &table.toObject();
2482                     }
2483                 }
2484             }
2485         }
2486     } else {
2487         rdata.lambda = NULL;
2488         rdata.elembase = NULL;
2489         rdata.repstr = ArgToRootedString(cx, argc, vp, 1);
2490         if (!rdata.repstr)
2491             return false;
2492
2493         /* We're about to store pointers into the middle of our string. */
2494         if (!js_MakeStringImmutable(cx, rdata.repstr))
2495             return false;
2496         rdata.dollarEnd = rdata.repstr->chars() + rdata.repstr->length();
2497         rdata.dollar = js_strchr_limit(rdata.repstr->chars(), '$',
2498                                        rdata.dollarEnd);
2499     }
2500
2501     if (!rdata.g.init(argc, vp))
2502         return false;
2503
2504     /*
2505      * Unlike its |String.prototype| brethren, |replace| doesn't convert
2506      * its input to a regular expression. (Even if it contains metachars.)
2507      *
2508      * However, if the user invokes our (non-standard) |flags| argument
2509      * extension then we revert to creating a regular expression. Note that
2510      * this is observable behavior through the side-effect mutation of the
2511      * |RegExp| statics.
2512      */
2513
2514     const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, optarg, argc, false);
2515     if (!fm) {
2516         if (cx->isExceptionPending())  /* oom in RopeMatch in tryFlatMatch */
2517             return false;
2518         JS_ASSERT_IF(!rdata.g.hasRegExpPair(), argc > optarg);
2519         return str_replace_regexp(cx, argc, vp, rdata);
2520     }
2521
2522     if (fm->match() < 0) {
2523         vp->setString(rdata.str);
2524         return true;
2525     }
2526
2527     if (rdata.lambda)
2528         return str_replace_flat_lambda(cx, argc, vp, rdata, *fm);
2529
2530     /* 
2531      * Note: we could optimize the text.length == pattern.length case if we wanted,
2532      * even in the presence of dollar metachars.
2533      */
2534     if (rdata.dollar)
2535         return BuildDollarReplacement(cx, rdata.str, rdata.repstr, rdata.dollar, *fm, vp);
2536
2537     return BuildFlatReplacement(cx, rdata.str, rdata.repstr, *fm, vp);
2538 }
2539
2540 /*
2541  * Subroutine used by str_split to find the next split point in str, starting
2542  * at offset *ip and looking either for the separator substring given by sep, or
2543  * for the next re match.  In the re case, return the matched separator in *sep,
2544  * and the possibly updated offset in *ip.
2545  *
2546  * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
2547  * separator occurrence if found, or str->length if no separator is found.
2548  */
2549 static jsint
2550 find_split(JSContext *cx, RegExpStatics *res, JSString *str, js::RegExp *re, jsint *ip,
2551            JSSubString *sep)
2552 {
2553     /*
2554      * Stop if past end of string.  If at end of string, we will compare the
2555      * null char stored there (by js_NewString*) to sep->chars[j] in the while
2556      * loop at the end of this function, so that
2557      *
2558      *  "ab,".split(',') => ["ab", ""]
2559      *
2560      * and the resulting array converts back to the string "ab," for symmetry.
2561      * However, we ape Perl and do this only if there is a sufficiently large
2562      * limit argument (see str_split).
2563      */
2564     jsint i = *ip;
2565     size_t length = str->length();
2566     if ((size_t)i > length)
2567         return -1;
2568
2569     const jschar *chars = str->getChars(cx);
2570     if (!chars)
2571         return -2;
2572
2573     /*
2574      * Match a regular expression against the separator at or above index i.
2575      * Call js_ExecuteRegExp with true for the test argument.  On successful
2576      * match, get the separator from cx->regExpStatics.lastMatch.
2577      */
2578     if (re) {
2579         size_t index;
2580         Value rval;
2581
2582       again:
2583         /* JS1.2 deviated from Perl by never matching at end of string. */
2584         index = (size_t)i;
2585         if (!re->execute(cx, res, str, &index, true, &rval))
2586             return -2;
2587         if (!rval.isTrue()) {
2588             /* Mismatch: ensure our caller advances i past end of string. */
2589             sep->length = 1;
2590             return length;
2591         }
2592         i = (jsint)index;
2593         JS_ASSERT(sep);
2594         res->getLastMatch(sep);
2595         if (sep->length == 0) {
2596             /*
2597              * Empty string match: never split on an empty match at the start
2598              * of a find_split cycle.  Same rule as for an empty global match
2599              * in DoMatch.
2600              */
2601             if (i == *ip) {
2602                 /*
2603                  * "Bump-along" to avoid sticking at an empty match, but don't
2604                  * bump past end of string -- our caller must do that by adding
2605                  * sep->length to our return value.
2606                  */
2607                 if ((size_t)i == length)
2608                     return -1;
2609                 i++;
2610                 goto again;
2611             }
2612             if ((size_t)i == length) {
2613                 /*
2614                  * If there was a trivial zero-length match at the end of the
2615                  * split, then we shouldn't output the matched string at the end
2616                  * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
2617                  */
2618                 sep->chars = NULL;
2619             }
2620         }
2621         JS_ASSERT((size_t)i >= sep->length);
2622         return i - sep->length;
2623     }
2624
2625     /*
2626      * Special case: if sep is the empty string, split str into one character
2627      * substrings.  Let our caller worry about whether to split once at end of
2628      * string into an empty substring.
2629      */
2630     if (sep->length == 0)
2631         return ((size_t)i == length) ? -1 : i + 1;
2632
2633     /*
2634      * Now that we know sep is non-empty, search starting at i in str for an
2635      * occurrence of all of sep's chars.  If we find them, return the index of
2636      * the first separator char.  Otherwise, return length.
2637      */
2638     jsint match = StringMatch(chars + i, length - i, sep->chars, sep->length);
2639     return match == -1 ? length : match + i;
2640 }
2641
2642 static JSBool
2643 str_split(JSContext *cx, uintN argc, Value *vp)
2644 {
2645     JSString *str = ThisToStringForStringProto(cx, vp);
2646     if (!str)
2647         return false;
2648
2649     if (argc == 0) {
2650         Value v = StringValue(str);
2651         JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
2652         if (!aobj)
2653             return false;
2654         vp->setObject(*aobj);
2655         return true;
2656     }
2657
2658     RegExp *re;
2659     JSSubString *sep, tmp;
2660     if (VALUE_IS_REGEXP(cx, vp[2])) {
2661         re = static_cast<RegExp *>(vp[2].toObject().getPrivate());
2662         sep = &tmp;
2663
2664         /* Set a magic value so we can detect a successful re match. */
2665         sep->chars = NULL;
2666         sep->length = 0;
2667     } else {
2668         JSString *sepstr = js_ValueToString(cx, vp[2]);
2669         if (!sepstr)
2670             return false;
2671         vp[2].setString(sepstr);
2672
2673         /*
2674          * Point sep at a local copy of sepstr's header because find_split
2675          * will modify sep->length.
2676          */
2677         tmp.length = sepstr->length();
2678         tmp.chars = sepstr->getChars(cx);
2679         if (!tmp.chars)
2680             return false;
2681         re = NULL;
2682         sep = &tmp;
2683     }
2684
2685     /* Use the second argument as the split limit, if given. */
2686     uint32 limit = 0; /* Avoid warning. */
2687     bool limited = (argc > 1) && !vp[3].isUndefined();
2688     if (limited) {
2689         jsdouble d;
2690         if (!ValueToNumber(cx, vp[3], &d))
2691             return false;
2692
2693         /* Clamp limit between 0 and 1 + string length. */
2694         limit = js_DoubleToECMAUint32(d);
2695         if (limit > str->length())
2696             limit = 1 + str->length();
2697     }
2698
2699     AutoValueVector splits(cx);
2700
2701     RegExpStatics *res = cx->regExpStatics();
2702     jsint i, j;
2703     uint32 len = i = 0;
2704     while ((j = find_split(cx, res, str, re, &i, sep)) >= 0) {
2705         if (limited && len >= limit)
2706             break;
2707
2708         JSString *sub = js_NewDependentString(cx, str, i, size_t(j - i));
2709         if (!sub || !splits.append(StringValue(sub)))
2710             return false;
2711         len++;
2712
2713         /*
2714          * Imitate perl's feature of including parenthesized substrings that
2715          * matched part of the delimiter in the new array, after the split
2716          * substring that was delimited.
2717          */
2718         if (re && sep->chars) {
2719             for (uintN num = 0; num < res->parenCount(); num++) {
2720                 if (limited && len >= limit)
2721                     break;
2722                 JSSubString parsub;
2723                 res->getParen(num + 1, &parsub);
2724                 sub = js_NewStringCopyN(cx, parsub.chars, parsub.length);
2725                 if (!sub || !splits.append(StringValue(sub)))
2726                     return false;
2727                 len++;
2728             }
2729             sep->chars = NULL;
2730         }
2731         i = j + sep->length;
2732     }
2733
2734     if (j == -2)
2735         return false;
2736
2737     JSObject *aobj = NewDenseCopiedArray(cx, splits.length(), splits.begin());
2738     if (!aobj)
2739         return false;
2740     vp->setObject(*aobj);
2741     return true;
2742 }
2743
2744 #if JS_HAS_PERL_SUBSTR
2745 static JSBool
2746 str_substr(JSContext *cx, uintN argc, Value *vp)
2747 {
2748     JSString *str = ThisToStringForStringProto(cx, vp);
2749     if (!str)
2750         return false;
2751
2752     int32 length, len, begin;
2753     if (argc > 0) {
2754         length = int32(str->length());
2755         if (!ValueToIntegerRange(cx, vp[2], &begin))
2756             return false;
2757
2758         if (begin >= length) {
2759             str = cx->runtime->emptyString;
2760             goto out;
2761         }
2762         if (begin < 0) {
2763             begin += length; /* length + INT_MIN will always be less then 0 */
2764             if (begin < 0)
2765                 begin = 0;
2766         }
2767
2768         if (argc == 1 || vp[3].isUndefined()) {
2769             len = length - begin;
2770         } else {
2771             if (!ValueToIntegerRange(cx, vp[3], &len))  
2772                 return false;
2773
2774             if (len <= 0) {
2775                 str = cx->runtime->emptyString;
2776                 goto out;
2777             }
2778
2779             if (uint32(length) < uint32(begin + len))
2780                 len = length - begin;
2781         }
2782
2783         str = js_NewDependentString(cx, str, size_t(begin), size_t(len));
2784         if (!str)
2785             return false;
2786     }
2787
2788 out:
2789     vp->setString(str);
2790     return true;
2791 }
2792 #endif /* JS_HAS_PERL_SUBSTR */
2793
2794 /*
2795  * Python-esque sequence operations.
2796  */
2797 static JSBool
2798 str_concat(JSContext *cx, uintN argc, Value *vp)
2799 {
2800     JSString *str = ThisToStringForStringProto(cx, vp);
2801     if (!str)
2802         return false;
2803
2804     /* Set vp (aka rval) early to handle the argc == 0 case. */
2805     vp->setString(str);
2806
2807     Value *argv;
2808     uintN i;
2809     for (i = 0, argv = vp + 2; i < argc; i++) {
2810         JSString *str2 = js_ValueToString(cx, argv[i]);
2811         if (!str2)
2812             return false;
2813         argv[i].setString(str2);
2814
2815         str = js_ConcatStrings(cx, str, str2);
2816         if (!str)
2817             return false;
2818         vp->setString(str);
2819     }
2820
2821     return true;
2822 }
2823
2824 static JSBool
2825 str_slice(JSContext *cx, uintN argc, Value *vp)
2826 {
2827     if (argc == 1 && vp[1].isString() && vp[2].isInt32()) {
2828         size_t begin, end, length;
2829
2830         JSString *str = vp[1].toString();
2831         begin = vp[2].toInt32();
2832         end = str->length();
2833         if (begin <= end) {
2834             length = end - begin;
2835             if (length == 0) {
2836                 str = cx->runtime->emptyString;
2837             } else {
2838                 str = (length == 1)
2839                       ? JSString::getUnitString(cx, str, begin)
2840                       : js_NewDependentString(cx, str, begin, length);
2841                 if (!str)
2842                     return JS_FALSE;
2843             }
2844             vp->setString(str);
2845             return JS_TRUE;
2846         }
2847     }
2848
2849     JSString *str = ThisToStringForStringProto(cx, vp);
2850     if (!str)
2851         return false;
2852
2853     if (argc != 0) {
2854         double begin, end, length;
2855
2856         if (!ValueToNumber(cx, vp[2], &begin))
2857             return JS_FALSE;
2858         begin = js_DoubleToInteger(begin);
2859         length = str->length();
2860         if (begin < 0) {
2861             begin += length;
2862             if (begin < 0)
2863                 begin = 0;
2864         } else if (begin > length) {
2865             begin = length;
2866         }
2867
2868         if (argc == 1 || vp[3].isUndefined()) {
2869             end = length;
2870         } else {
2871             if (!ValueToNumber(cx, vp[3], &end))
2872                 return JS_FALSE;
2873             end = js_DoubleToInteger(end);
2874             if (end < 0) {
2875                 end += length;
2876                 if (end < 0)
2877                     end = 0;
2878             } else if (end > length) {
2879                 end = length;
2880             }
2881             if (end < begin)
2882                 end = begin;
2883         }
2884
2885         str = js_NewDependentString(cx, str,
2886                                     (size_t)begin,
2887                                     (size_t)(end - begin));
2888         if (!str)
2889             return JS_FALSE;
2890     }
2891     vp->setString(str);
2892     return JS_TRUE;
2893 }
2894
2895 #if JS_HAS_STR_HTML_HELPERS
2896 /*
2897  * HTML composition aids.
2898  */
2899 static bool
2900 tagify(JSContext *cx, const char *begin, JSLinearString *param, const char *end,
2901        Value *vp)
2902 {
2903     JSString *thisstr = ThisToStringForStringProto(cx, vp);
2904     if (!thisstr)
2905         return false;
2906     JSLinearString *str = thisstr->ensureLinear(cx);
2907     if (!str)
2908         return false;
2909
2910     if (!end)
2911         end = begin;
2912
2913     size_t beglen = strlen(begin);
2914     size_t taglen = 1 + beglen + 1;                     /* '<begin' + '>' */
2915     size_t parlen = 0; /* Avoid warning. */
2916     if (param) {
2917         parlen = param->length();
2918         taglen += 2 + parlen + 1;                       /* '="param"' */
2919     }
2920     size_t endlen = strlen(end);
2921     taglen += str->length() + 2 + endlen + 1;           /* 'str</end>' */
2922
2923     if (taglen >= ~(size_t)0 / sizeof(jschar)) {
2924         js_ReportAllocationOverflow(cx);
2925         return false;
2926     }
2927
2928     jschar *tagbuf = (jschar *) cx->malloc((taglen + 1) * sizeof(jschar));
2929     if (!tagbuf)
2930         return false;
2931
2932     size_t j = 0;
2933     tagbuf[j++] = '<';
2934     for (size_t i = 0; i < beglen; i++)
2935         tagbuf[j++] = (jschar)begin[i];
2936     if (param) {
2937         tagbuf[j++] = '=';
2938         tagbuf[j++] = '"';
2939         js_strncpy(&tagbuf[j], param->chars(), parlen);
2940         j += parlen;
2941         tagbuf[j++] = '"';
2942     }
2943     tagbuf[j++] = '>';
2944
2945     js_strncpy(&tagbuf[j], str->chars(), str->length());
2946     j += str->length();
2947     tagbuf[j++] = '<';
2948     tagbuf[j++] = '/';
2949     for (size_t i = 0; i < endlen; i++)
2950         tagbuf[j++] = (jschar)end[i];
2951     tagbuf[j++] = '>';
2952     JS_ASSERT(j == taglen);
2953     tagbuf[j] = 0;
2954
2955     JSString *retstr = js_NewString(cx, tagbuf, taglen);
2956     if (!retstr) {
2957         js_free((char *)tagbuf);
2958         return false;
2959     }
2960     vp->setString(retstr);
2961     return true;
2962 }
2963
2964 static JSBool
2965 tagify_value(JSContext *cx, uintN argc, Value *vp,
2966              const char *begin, const char *end)
2967 {
2968     JSLinearString *param = ArgToRootedString(cx, argc, vp, 0);
2969     if (!param)
2970         return JS_FALSE;
2971     return tagify(cx, begin, param, end, vp);
2972 }
2973
2974 static JSBool
2975 str_bold(JSContext *cx, uintN argc, Value *vp)
2976 {
2977     return tagify(cx, "b", NULL, NULL, vp);
2978 }
2979
2980 static JSBool
2981 str_italics(JSContext *cx, uintN argc, Value *vp)
2982 {
2983     return tagify(cx, "i", NULL, NULL, vp);
2984 }
2985
2986 static JSBool
2987 str_fixed(JSContext *cx, uintN argc, Value *vp)
2988 {
2989     return tagify(cx, "tt", NULL, NULL, vp);
2990 }
2991
2992 static JSBool
2993 str_fontsize(JSContext *cx, uintN argc, Value *vp)
2994 {
2995     return tagify_value(cx, argc, vp, "font size", "font");
2996 }
2997
2998 static JSBool
2999 str_fontcolor(JSContext *cx, uintN argc, Value *vp)
3000 {
3001     return tagify_value(cx, argc, vp, "font color", "font");
3002 }
3003
3004 static JSBool
3005 str_link(JSContext *cx, uintN argc, Value *vp)
3006 {
3007     return tagify_value(cx, argc, vp, "a href", "a");
3008 }
3009
3010 static JSBool
3011 str_anchor(JSContext *cx, uintN argc, Value *vp)
3012 {
3013     return tagify_value(cx, argc, vp, "a name", "a");
3014 }
3015
3016 static JSBool
3017 str_strike(JSContext *cx, uintN argc, Value *vp)
3018 {
3019     return tagify(cx, "strike", NULL, NULL, vp);
3020 }
3021
3022 static JSBool
3023 str_small(JSContext *cx, uintN argc, Value *vp)
3024 {
3025     return tagify(cx, "small", NULL, NULL, vp);
3026 }
3027
3028 static JSBool
3029 str_big(JSContext *cx, uintN argc, Value *vp)
3030 {
3031     return tagify(cx, "big", NULL, NULL, vp);
3032 }
3033
3034 static JSBool
3035 str_blink(JSContext *cx, uintN argc, Value *vp)
3036 {
3037     return tagify(cx, "blink", NULL, NULL, vp);
3038 }
3039
3040 static JSBool
3041 str_sup(JSContext *cx, uintN argc, Value *vp)
3042 {
3043     return tagify(cx, "sup", NULL, NULL, vp);
3044 }
3045
3046 static JSBool
3047 str_sub(JSContext *cx, uintN argc, Value *vp)
3048 {
3049     return tagify(cx, "sub", NULL, NULL, vp);
3050 }
3051 #endif /* JS_HAS_STR_HTML_HELPERS */
3052
3053 #ifdef JS_TRACER
3054 JSString* FASTCALL
3055 js_String_getelem(JSContext* cx, JSString* str, int32 i)
3056 {
3057     if ((size_t)i >= str->length())
3058         return NULL;
3059     return JSString::getUnitString(cx, str, size_t(i));
3060 }
3061 #endif
3062
3063 JS_DEFINE_TRCINFO_1(str_concat,
3064     (3, (extern, STRING_RETRY, js_ConcatStrings, CONTEXT, THIS_STRING, STRING,
3065          1, nanojit::ACCSET_NONE)))
3066
3067 static JSFunctionSpec string_methods[] = {
3068 #if JS_HAS_TOSOURCE
3069     JS_FN("quote",             str_quote,             0,JSFUN_GENERIC_NATIVE),
3070     JS_FN(js_toSource_str,     str_toSource,          0,0),
3071 #endif
3072
3073     /* Java-like methods. */
3074     JS_FN(js_toString_str,     js_str_toString,       0,0),
3075     JS_FN(js_valueOf_str,      js_str_toString,       0,0),
3076     JS_FN(js_toJSON_str,       js_str_toString,       0,0),
3077     JS_FN("substring",         str_substring,         2,JSFUN_GENERIC_NATIVE),
3078     JS_FN("toLowerCase",       str_toLowerCase,       0,JSFUN_GENERIC_NATIVE),
3079     JS_FN("toUpperCase",       str_toUpperCase,       0,JSFUN_GENERIC_NATIVE),
3080     JS_FN("charAt",            js_str_charAt,         1,JSFUN_GENERIC_NATIVE),
3081     JS_FN("charCodeAt",        js_str_charCodeAt,     1,JSFUN_GENERIC_NATIVE),
3082     JS_FN("indexOf",           str_indexOf,           1,JSFUN_GENERIC_NATIVE),
3083     JS_FN("lastIndexOf",       str_lastIndexOf,       1,JSFUN_GENERIC_NATIVE),
3084     JS_FN("trim",              str_trim,              0,JSFUN_GENERIC_NATIVE),
3085     JS_FN("trimLeft",          str_trimLeft,          0,JSFUN_GENERIC_NATIVE),
3086     JS_FN("trimRight",         str_trimRight,         0,JSFUN_GENERIC_NATIVE),
3087     JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE),
3088     JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE),
3089     JS_FN("localeCompare",     str_localeCompare,     1,JSFUN_GENERIC_NATIVE),
3090
3091     /* Perl-ish methods (search is actually Python-esque). */
3092     JS_FN("match",             str_match,             1,JSFUN_GENERIC_NATIVE),
3093     JS_FN("search",            str_search,            1,JSFUN_GENERIC_NATIVE),
3094     JS_FN("replace",           str_replace,           2,JSFUN_GENERIC_NATIVE),
3095     JS_FN("split",             str_split,             2,JSFUN_GENERIC_NATIVE),
3096 #if JS_HAS_PERL_SUBSTR
3097     JS_FN("substr",            str_substr,            2,JSFUN_GENERIC_NATIVE),
3098 #endif
3099
3100     /* Python-esque sequence methods. */
3101     JS_TN("concat",            str_concat,            1,JSFUN_GENERIC_NATIVE, &str_concat_trcinfo),
3102     JS_FN("slice",             str_slice,             2,JSFUN_GENERIC_NATIVE),
3103
3104     /* HTML string methods. */
3105 #if JS_HAS_STR_HTML_HELPERS
3106     JS_FN("bold",              str_bold,              0,0),
3107     JS_FN("italics",           str_italics,           0,0),
3108     JS_FN("fixed",             str_fixed,             0,0),
3109     JS_FN("fontsize",          str_fontsize,          1,0),
3110     JS_FN("fontcolor",         str_fontcolor,         1,0),
3111     JS_FN("link",              str_link,              1,0),
3112     JS_FN("anchor",            str_anchor,            1,0),
3113     JS_FN("strike",            str_strike,            0,0),
3114     JS_FN("small",             str_small,             0,0),
3115     JS_FN("big",               str_big,               0,0),
3116     JS_FN("blink",             str_blink,             0,0),
3117     JS_FN("sup",               str_sup,               0,0),
3118     JS_FN("sub",               str_sub,               0,0),
3119 #endif
3120
3121     JS_FS_END
3122 };
3123
3124 /*
3125  * Set up some tools to make it easier to generate large tables. After constant
3126  * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
3127  * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
3128  * To use this, define R appropriately, then use Rn(0) (for some value of n), then
3129  * undefine R.
3130  */
3131 #define R2(n)  R(n),   R((n) + (1 << 0)),    R((n) + (2 << 0)),    R((n) + (3 << 0))
3132 #define R4(n)  R2(n),  R2((n) + (1 << 2)),   R2((n) + (2 << 2)),   R2((n) + (3 << 2))
3133 #define R6(n)  R4(n),  R4((n) + (1 << 4)),   R4((n) + (2 << 4)),   R4((n) + (3 << 4))
3134 #define R8(n)  R6(n),  R6((n) + (1 << 6)),   R6((n) + (2 << 6)),   R6((n) + (3 << 6))
3135 #define R10(n) R8(n),  R8((n) + (1 << 8)),   R8((n) + (2 << 8)),   R8((n) + (3 << 8))
3136 #define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
3137
3138 #define R3(n) R2(n), R2((n) + (1 << 2))
3139 #define R7(n) R6(n), R6((n) + (1 << 6))
3140
3141 #define BUILD_LENGTH_AND_FLAGS(length, flags)                                 \
3142     (((length) << JSString::LENGTH_SHIFT) | (flags))
3143
3144 /*
3145  * Declare unit strings. Pack the string data itself into the mInlineChars
3146  * place in the header.
3147  */
3148 #define R(c) {                                                                \
3149     BUILD_LENGTH_AND_FLAGS(1, JSString::FLAT | JSString::ATOMIZED),           \
3150     { (jschar *)(((char *)(unitStringTable + (c))) +                          \
3151       offsetof(JSString, inlineStorage)) },                                   \
3152     { {(c), 0x00} } }
3153
3154 #ifdef __SUNPRO_CC
3155 #pragma pack(8)
3156 #else
3157 #pragma pack(push, 8)
3158 #endif
3159
3160 const JSString JSString::unitStringTable[]
3161 #ifdef __GNUC__
3162 __attribute__ ((aligned (8)))
3163 #endif
3164 = { R8(0) };
3165
3166 #ifdef __SUNPRO_CC
3167 #pragma pack(0)
3168 #else
3169 #pragma pack(pop)
3170 #endif
3171
3172 #undef R
3173
3174 /*
3175  * Declare length-2 strings. We only store strings where both characters are
3176  * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
3177  * the lowercase letters, and the next 26 are the uppercase letters.
3178  */
3179 #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' :              \
3180                           (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 :         \
3181                           (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 :         \
3182                           JSString::INVALID_SMALL_CHAR)
3183
3184 #define R TO_SMALL_CHAR
3185
3186 const JSString::SmallChar JSString::toSmallChar[] = { R7(0) };
3187
3188 #undef R
3189
3190 /*
3191  * This is used when we generate our table of short strings, so the compiler is
3192  * happier if we use |c| as few times as possible.
3193  */
3194 #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' :      \
3195                                    (c) < 36 ? 'a' - 10 : \
3196                                    'A' - 36))
3197 #define R FROM_SMALL_CHAR
3198
3199 const jschar JSString::fromSmallChar[] = { R6(0) };
3200
3201 #undef R
3202
3203 /*
3204  * For code-generation ease, length-2 strings are encoded as 12-bit int values,
3205  * where the upper 6 bits is the first character and the lower 6 bits is the
3206  * second character.
3207  */
3208 #define R(c) {                                                                \
3209     BUILD_LENGTH_AND_FLAGS(2, JSString::FLAT | JSString::ATOMIZED),           \
3210     { (jschar *)(((char *)(length2StringTable + (c))) +                       \
3211       offsetof(JSString, inlineStorage)) },                                   \
3212     { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
3213
3214 #ifdef __SUNPRO_CC
3215 #pragma pack(8)
3216 #else
3217 #pragma pack(push, 8)
3218 #endif
3219
3220 const JSString JSString::length2StringTable[]
3221 #ifdef __GNUC__
3222 __attribute__ ((aligned (8)))
3223 #endif
3224 = { R12(0) };
3225
3226 #ifdef __SUNPRO_CC
3227 #pragma pack(0)
3228 #else
3229 #pragma pack(pop)
3230 #endif
3231
3232 #undef R
3233
3234 /*
3235  * Declare int strings. Only int strings from 100 to 255 actually have to be
3236  * generated, since the rest are either unit strings or length-2 strings. To
3237  * avoid the runtime cost of figuring out where to look for the string for a
3238  * particular integer, we precompute a table of JSString*s which refer to the
3239  * correct location of the int string.
3240  */
3241 #define R(c) {                                                                \
3242     BUILD_LENGTH_AND_FLAGS(3, JSString::FLAT | JSString::ATOMIZED),           \
3243     { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) +               \
3244       offsetof(JSString, inlineStorage)) },                                   \
3245     { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
3246
3247
3248 JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
3249
3250 #ifdef __SUNPRO_CC
3251 #pragma pack(8)
3252 #else
3253 #pragma pack(push, 8)
3254 #endif
3255
3256 const JSString JSString::hundredStringTable[]
3257 #ifdef __GNUC__
3258 __attribute__ ((aligned (8)))
3259 #endif
3260 = { R7(100), /* 100 through 227 */
3261     R4(100 + (1 << 7)), /* 228 through 243 */
3262     R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
3263     R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
3264 };
3265
3266 #undef R
3267
3268 #define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') :            \
3269               (c) < 100 ? JSString::length2StringTable +                      \
3270               ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) +                \
3271               TO_SMALL_CHAR(((c) % 10) + '0') :                               \
3272               JSString::hundredStringTable + ((c) - 100))
3273
3274 const JSString *const JSString::intStringTable[] = { R8(0) };
3275
3276 #undef R
3277
3278 #ifdef __SUNPRO_CC
3279 #pragma pack(0)
3280 #else
3281 #pragma pack(pop)
3282 #endif
3283
3284 #undef R2
3285 #undef R4
3286 #undef R6
3287 #undef R8
3288 #undef R10
3289 #undef R12
3290
3291 #undef R3
3292 #undef R7
3293
3294 JSBool
3295 js_String(JSContext *cx, uintN argc, Value *vp)
3296 {
3297     Value *argv = vp + 2;
3298
3299     JSString *str;
3300     if (argc > 0) {
3301         str = js_ValueToString(cx, argv[0]);
3302         if (!str)
3303             return false;
3304     } else {
3305         str = cx->runtime->emptyString;
3306     }
3307
3308     if (IsConstructing(vp)) {
3309         JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
3310         if (!obj)
3311             return false;
3312         obj->setPrimitiveThis(StringValue(str));
3313         vp->setObject(*obj);
3314     } else {
3315         vp->setString(str);
3316     }
3317     return true;
3318 }
3319
3320 static JSBool
3321 str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
3322 {
3323     Value *argv;
3324     uintN i;
3325     jschar *chars;
3326     JSString *str;
3327
3328     argv = vp + 2;
3329     JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
3330     if (argc == 1) {
3331         uint16_t code;
3332         if (!ValueToUint16(cx, argv[0], &code))
3333             return JS_FALSE;
3334         if (code < UNIT_STRING_LIMIT) {
3335             str = JSString::unitString(code);
3336             if (!str)
3337                 return JS_FALSE;
3338             vp->setString(str);
3339             return JS_TRUE;
3340         }
3341         argv[0].setInt32(code);
3342     }
3343     chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar));
3344     if (!chars)
3345         return JS_FALSE;
3346     for (i = 0; i < argc; i++) {
3347         uint16_t code;
3348         if (!ValueToUint16(cx, argv[i], &code)) {
3349             cx->free(chars);
3350             return JS_FALSE;
3351         }
3352         chars[i] = (jschar)code;
3353     }
3354     chars[i] = 0;
3355     str = js_NewString(cx, chars, argc);
3356     if (!str) {
3357         cx->free(chars);
3358         return JS_FALSE;
3359     }
3360     vp->setString(str);
3361     return JS_TRUE;
3362 }
3363
3364 #ifdef JS_TRACER
3365 static JSString* FASTCALL
3366 String_fromCharCode(JSContext* cx, int32 i)
3367 {
3368     JS_ASSERT(JS_ON_TRACE(cx));
3369     jschar c = (jschar)i;
3370     if (c < UNIT_STRING_LIMIT)
3371         return JSString::unitString(c);
3372     return js_NewStringCopyN(cx, &c, 1);
3373 }
3374 #endif
3375
3376 JS_DEFINE_TRCINFO_1(str_fromCharCode,
3377     (2, (static, STRING_RETRY, String_fromCharCode, CONTEXT, INT32, 1, nanojit::ACCSET_NONE)))
3378
3379 static JSFunctionSpec string_static_methods[] = {
3380     JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo),
3381     JS_FS_END
3382 };
3383
3384 JSObject *
3385 js_InitStringClass(JSContext *cx, JSObject *obj)
3386 {
3387     JSObject *proto;
3388
3389     /* Define the escape, unescape functions in the global object. */
3390     if (!JS_DefineFunctions(cx, obj, string_functions))
3391         return NULL;
3392
3393     proto = js_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1,
3394                          NULL, string_methods,
3395                          NULL, string_static_methods);
3396     if (!proto)
3397         return NULL;
3398     proto->setPrimitiveThis(StringValue(cx->runtime->emptyString));
3399     if (!js_DefineNativeProperty(cx, proto, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
3400                                  UndefinedValue(), NULL, NULL,
3401                                  JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0,
3402                                  NULL)) {
3403         return JS_FALSE;
3404     }
3405
3406     return proto;
3407 }
3408
3409 JSFlatString *
3410 js_NewString(JSContext *cx, jschar *chars, size_t length)
3411 {
3412     JSString *str;
3413
3414     if (length > JSString::MAX_LENGTH) {
3415         if (JS_ON_TRACE(cx)) {
3416             /*
3417              * If we can't leave the trace, signal OOM condition, otherwise
3418              * exit from trace before throwing.
3419              */
3420             if (!CanLeaveTrace(cx))
3421                 return NULL;
3422
3423             LeaveTrace(cx);
3424         }
3425         js_ReportAllocationOverflow(cx);
3426         return NULL;
3427     }
3428
3429     str = js_NewGCString(cx);
3430     if (!str)
3431         return NULL;
3432     str->initFlat(chars, length);
3433     cx->runtime->stringMemoryUsed += length * 2;
3434 #ifdef DEBUG
3435   {
3436     JSRuntime *rt = cx->runtime;
3437     JS_RUNTIME_METER(rt, liveStrings);
3438     JS_RUNTIME_METER(rt, totalStrings);
3439     JS_LOCK_RUNTIME_VOID(rt,
3440         (rt->lengthSum += (double)length,
3441          rt->lengthSquaredSum += (double)length * (double)length));
3442   }
3443 #endif
3444     return str->assertIsFlat();
3445 }
3446
3447 static JS_ALWAYS_INLINE JSFlatString *
3448 NewShortString(JSContext *cx, const jschar *chars, size_t length)
3449 {
3450     JS_ASSERT(JSShortString::fitsIntoShortString(length));
3451     JSShortString *str = js_NewGCShortString(cx);
3452     if (!str)
3453         return NULL;
3454     jschar *storage = str->init(length);
3455     js_short_strncpy(storage, chars, length);
3456     storage[length] = 0;
3457     return str->header()->assertIsFlat();
3458 }
3459
3460 static JSFlatString *
3461 NewShortString(JSContext *cx, const char *chars, size_t length)
3462 {
3463     JS_ASSERT(JSShortString::fitsIntoShortString(length));
3464     JSShortString *str = js_NewGCShortString(cx);
3465     if (!str)
3466         return NULL;
3467     jschar *storage = str->init(length);
3468
3469     if (js_CStringsAreUTF8) {
3470 #ifdef DEBUG
3471         size_t oldLength = length;
3472 #endif
3473         if (!js_InflateStringToBuffer(cx, chars, length, storage, &length))
3474             return NULL;
3475         JS_ASSERT(length <= oldLength);
3476         storage[length] = 0;
3477         str->resetLength(length);
3478     } else {
3479         size_t n = length;
3480         jschar *p = storage;
3481         while (n--)
3482             *p++ = (unsigned char)*chars++;
3483         *p = 0;
3484     }
3485     return str->header()->assertIsFlat();
3486 }
3487
3488 static const size_t sMinWasteSize = 16;
3489
3490 JSFlatString *
3491 StringBuffer::finishString()
3492 {
3493     JSContext *cx = context();
3494     if (cb.empty())
3495         return ATOM_TO_STRING(cx->runtime->atomState.emptyAtom);
3496
3497     size_t length = cb.length();
3498     if (!checkLength(length))
3499         return NULL;
3500
3501     JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH < CharBuffer::InlineLength);
3502     if (JSShortString::fitsIntoShortString(length))
3503         return NewShortString(cx, cb.begin(), length);
3504
3505     if (!cb.append('\0'))
3506         return NULL;
3507
3508     size_t capacity = cb.capacity();
3509
3510     jschar *buf = cb.extractRawBuffer();
3511     if (!buf)
3512         return NULL;
3513
3514     /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
3515     JS_ASSERT(capacity >= length);
3516     if (capacity > sMinWasteSize && capacity - length > (length >> 2)) {
3517         size_t bytes = sizeof(jschar) * (length + 1);
3518         jschar *tmp = (jschar *)cx->realloc(buf, bytes);
3519         if (!tmp) {
3520             cx->free(buf);
3521             return NULL;
3522         }
3523         buf = tmp;
3524     }
3525
3526     JSFlatString *str = js_NewString(cx, buf, length);
3527     if (!str)
3528         cx->free(buf);
3529     return str;
3530 }
3531
3532 JSLinearString *
3533 js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start,
3534                       size_t length)
3535 {
3536     JSString *ds;
3537
3538     if (length == 0)
3539         return cx->runtime->emptyString;
3540
3541     JSLinearString *base = baseArg->ensureLinear(cx);
3542     if (!base)
3543         return NULL;
3544
3545     if (start == 0 && length == base->length())
3546         return base;
3547
3548     const jschar *chars = base->chars() + start;
3549
3550     JSLinearString *staticStr = JSString::lookupStaticString(chars, length);
3551     if (staticStr)
3552         return staticStr;
3553
3554     /* Try to avoid long chains of dependent strings. */
3555     while (base->isDependent())
3556         base = base->dependentBase();
3557
3558     JS_ASSERT(base->isFlat());
3559
3560     ds = js_NewGCString(cx);
3561     if (!ds)
3562         return NULL;
3563     ds->initDependent(base, chars, length);
3564 #ifdef DEBUG
3565   {
3566     JSRuntime *rt = cx->runtime;
3567     JS_RUNTIME_METER(rt, liveDependentStrings);
3568     JS_RUNTIME_METER(rt, totalDependentStrings);
3569     JS_RUNTIME_METER(rt, liveStrings);
3570     JS_RUNTIME_METER(rt, totalStrings);
3571     JS_LOCK_RUNTIME_VOID(rt,
3572         (rt->strdepLengthSum += (double)length,
3573          rt->strdepLengthSquaredSum += (double)length * (double)length));
3574     JS_LOCK_RUNTIME_VOID(rt,
3575         (rt->lengthSum += (double)length,
3576          rt->lengthSquaredSum += (double)length * (double)length));
3577   }
3578 #endif
3579     return ds->assertIsLinear();
3580 }
3581
3582 #ifdef DEBUG
3583 #include <math.h>
3584
3585 void printJSStringStats(JSRuntime *rt)
3586 {
3587     double mean, sigma;
3588
3589     mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum,
3590                             rt->lengthSquaredSum, &sigma);
3591
3592     fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
3593             (unsigned long)rt->totalStrings, mean, sigma);
3594
3595     mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum,
3596                             rt->strdepLengthSquaredSum, &sigma);
3597
3598     fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
3599             (unsigned long)rt->totalDependentStrings, mean, sigma);
3600 }
3601 #endif
3602
3603 JSFlatString *
3604 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
3605 {
3606     if (JSShortString::fitsIntoShortString(n))
3607         return NewShortString(cx, s, n);
3608
3609     jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
3610     if (!news)
3611         return NULL;
3612     js_strncpy(news, s, n);
3613     news[n] = 0;
3614     JSFlatString *str = js_NewString(cx, news, n);
3615     if (!str)
3616         cx->free(news);
3617     return str;
3618 }
3619
3620 JSFlatString *
3621 js_NewStringCopyN(JSContext *cx, const char *s, size_t n)
3622 {
3623     if (JSShortString::fitsIntoShortString(n))
3624         return NewShortString(cx, s, n);
3625
3626     jschar *chars = js_InflateString(cx, s, &n);
3627     if (!chars)
3628         return NULL;
3629     JSFlatString *str = js_NewString(cx, chars, n);
3630     if (!str)
3631         cx->free(chars);
3632     return str;
3633 }
3634
3635 JSFlatString *
3636 js_NewStringCopyZ(JSContext *cx, const jschar *s)
3637 {
3638     size_t n = js_strlen(s);
3639     if (JSShortString::fitsIntoShortString(n))
3640         return NewShortString(cx, s, n);
3641
3642     size_t m = (n + 1) * sizeof(jschar);
3643     jschar *news = (jschar *) cx->malloc(m);
3644     if (!news)
3645         return NULL;
3646     memcpy(news, s, m);
3647     JSFlatString *str = js_NewString(cx, news, n);
3648     if (!str)
3649         cx->free(news);
3650     return str;
3651 }
3652
3653 JSFlatString *
3654 js_NewStringCopyZ(JSContext *cx, const char *s)
3655 {
3656     return js_NewStringCopyN(cx, s, strlen(s));
3657 }
3658
3659 const char *
3660 js_ValueToPrintable(JSContext *cx, const Value &v, JSAutoByteString *bytes, bool asSource)
3661 {
3662     JSString *str;
3663
3664     str = (asSource ? js_ValueToSource : js_ValueToString)(cx, v);
3665     if (!str)
3666         return NULL;
3667     str = js_QuoteString(cx, str, 0);
3668     if (!str)
3669         return NULL;
3670     return bytes->encode(cx, str);
3671 }
3672
3673 JSString *
3674 js_ValueToString(JSContext *cx, const Value &arg)
3675 {
3676     Value v = arg;
3677     if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v))
3678         return NULL;
3679
3680     JSString *str;
3681     if (v.isString()) {
3682         str = v.toString();
3683     } else if (v.isInt32()) {
3684         str = js_IntToString(cx, v.toInt32());
3685     } else if (v.isDouble()) {
3686         str = js_NumberToString(cx, v.toDouble());
3687     } else if (v.isBoolean()) {
3688         str = js_BooleanToString(cx, v.toBoolean());
3689     } else if (v.isNull()) {
3690         str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
3691     } else {
3692         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
3693     }
3694     return str;
3695 }
3696
3697 /* This function implements E-262-3 section 9.8, toString. */
3698 bool
3699 js::ValueToStringBuffer(JSContext *cx, const Value &arg, StringBuffer &sb)
3700 {
3701     Value v = arg;
3702     if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v))
3703         return false;
3704
3705     if (v.isString()) {
3706         JSString *str = v.toString();
3707         size_t length = str->length();
3708         const jschar *chars = str->getChars(cx);
3709         if (!chars)
3710             return false;
3711         return sb.append(chars, length);
3712     }
3713     if (v.isNumber())
3714         return NumberValueToStringBuffer(cx, v, sb);
3715     if (v.isBoolean())
3716         return BooleanToStringBuffer(cx, v.toBoolean(), sb);
3717     if (v.isNull())
3718         return sb.append(cx->runtime->atomState.nullAtom);
3719     JS_ASSERT(v.isUndefined());
3720     return sb.append(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
3721 }
3722
3723 JS_FRIEND_API(JSString *)
3724 js_ValueToSource(JSContext *cx, const Value &v)
3725 {
3726     if (v.isUndefined())
3727         return ATOM_TO_STRING(cx->runtime->atomState.void0Atom);
3728     if (v.isString())
3729         return js_QuoteString(cx, v.toString(), '"');
3730     if (v.isPrimitive()) {
3731         /* Special case to preserve negative zero, _contra_ toString. */
3732         if (v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble())) {
3733             /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
3734             static const jschar js_negzero_ucNstr[] = {'-', '0'};
3735
3736             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
3737         }
3738         return js_ValueToString(cx, v);
3739     }
3740
3741     JSAtom *atom = cx->runtime->atomState.toSourceAtom;
3742     AutoValueRooter tvr(cx);
3743     if (!js_TryMethod(cx, &v.toObject(), atom, 0, NULL, tvr.addr()))
3744         return NULL;
3745     return js_ValueToString(cx, tvr.value());
3746 }
3747
3748 namespace js {
3749
3750 /*
3751  * str is not necessarily a GC thing here.
3752  */
3753 static JS_ALWAYS_INLINE bool
3754 EqualStringsTail(JSLinearString *str1, size_t length1, JSLinearString *str2)
3755 {
3756     const jschar *s1 = str1->chars();
3757     const jschar *s1end = s1 + length1;
3758     const jschar *s2 = str2->chars();
3759     do {
3760         if (*s1 != *s2) {
3761             return false;
3762         }
3763         ++s1, ++s2;
3764     } while (s1 != s1end);
3765
3766     return true;
3767 }
3768
3769 bool
3770 EqualStrings(JSContext *cx, JSString *str1, JSString *str2, JSBool *result)
3771 {
3772     if (str1 == str2) {
3773         *result = true;
3774         return true;
3775     }
3776
3777     size_t length1 = str1->length();
3778     if (length1 != str2->length()) {
3779         *result = false;
3780         return true;
3781     }
3782
3783     if (length1 == 0) {
3784         *result = true;
3785         return true;
3786     }
3787
3788     JSLinearString *linear1 = str1->ensureLinear(cx);
3789     if (!linear1)
3790         return false;
3791     JSLinearString *linear2 = str2->ensureLinear(cx);
3792     if (!linear2)
3793         return false;
3794
3795     *result = EqualStringsTail(linear1, length1, linear2);
3796     return true;
3797 }
3798
3799 bool
3800 EqualStrings(JSLinearString *str1, JSLinearString *str2)
3801 {
3802     if (str1 == str2)
3803         return true;
3804
3805     size_t length1 = str1->length();
3806     if (length1 != str2->length())
3807         return false;
3808
3809     if (length1 == 0)
3810         return true;
3811
3812     return EqualStringsTail(str1, length1, str2);
3813 }
3814
3815 }  /* namespace js */
3816
3817 JSBool JS_FASTCALL
3818 js_EqualStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2)
3819 {
3820     JSBool result;
3821     return EqualStrings(cx, str1, str2, &result) ? result : JS_NEITHER;
3822 }
3823 JS_DEFINE_CALLINFO_3(extern, BOOL, js_EqualStringsOnTrace,
3824                      CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE)
3825
3826 namespace js {
3827
3828 static bool
3829 CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
3830 {
3831     JS_ASSERT(str1);
3832     JS_ASSERT(str2);
3833
3834     if (str1 == str2) {
3835         *result = 0;
3836         return true;
3837     }
3838
3839     size_t l1 = str1->length();
3840     const jschar *s1 = str1->getChars(cx);
3841     if (!s1)
3842         return false;
3843
3844     size_t l2 = str2->length();
3845     const jschar *s2 = str2->getChars(cx);
3846     if (!s2)
3847         return false;
3848
3849     size_t n = JS_MIN(l1, l2);
3850     for (size_t i = 0; i < n; i++) {
3851         if (int32 cmp = s1[i] - s2[i]) {
3852             *result = cmp;
3853             return true;
3854         }
3855     }
3856     *result = (int32)(l1 - l2);
3857     return true;
3858 }
3859
3860 bool
3861 CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
3862 {
3863     return CompareStringsImpl(cx, str1, str2, result);
3864 }
3865
3866 }  /* namespace js */
3867
3868 int32 JS_FASTCALL
3869 js_CompareStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2)
3870 {
3871     int32 result;
3872     if (!CompareStringsImpl(cx, str1, str2, &result))
3873         return INT32_MIN;
3874     JS_ASSERT(result != INT32_MIN);
3875     return result;
3876 }
3877 JS_DEFINE_CALLINFO_3(extern, INT32, js_CompareStringsOnTrace,
3878                      CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE)
3879
3880 namespace js {
3881
3882 bool
3883 StringEqualsAscii(JSLinearString *str, const char *asciiBytes)
3884 {
3885     size_t length = strlen(asciiBytes);
3886 #ifdef DEBUG
3887     for (size_t i = 0; i != length; ++i)
3888         JS_ASSERT(unsigned(asciiBytes[i]) <= 127);
3889 #endif
3890     if (length != str->length())
3891         return false;
3892     const jschar *chars = str->chars();
3893     for (size_t i = 0; i != length; ++i) {
3894         if (unsigned(asciiBytes[i]) != unsigned(chars[i]))
3895             return false;
3896     }
3897     return true;
3898 }
3899
3900 } /* namespacejs */
3901
3902 size_t
3903 js_strlen(const jschar *s)
3904 {
3905     const jschar *t;
3906
3907     for (t = s; *t != 0; t++)
3908         continue;
3909     return (size_t)(t - s);
3910 }
3911
3912 jschar *
3913 js_strchr(const jschar *s, jschar c)
3914 {
3915     while (*s != 0) {
3916         if (*s == c)
3917             return (jschar *)s;
3918         s++;
3919     }
3920     return NULL;
3921 }
3922
3923 jschar *
3924 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
3925 {
3926     while (s < limit) {
3927         if (*s == c)
3928             return (jschar *)s;
3929         s++;
3930     }
3931     return NULL;
3932 }
3933
3934 jschar *
3935 js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp)
3936 {
3937     size_t nbytes, nchars, i;
3938     jschar *chars;
3939 #ifdef DEBUG
3940     JSBool ok;
3941 #endif
3942
3943     nbytes = *lengthp;
3944     if (js_CStringsAreUTF8) {
3945         if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars))
3946             goto bad;
3947         chars = (jschar *) cx->malloc((nchars + 1) * sizeof (jschar));
3948         if (!chars)
3949             goto bad;
3950 #ifdef DEBUG
3951         ok =
3952 #endif
3953             js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars);
3954         JS_ASSERT(ok);
3955     } else {
3956         nchars = nbytes;
3957         chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
3958         if (!chars)
3959             goto bad;
3960         for (i = 0; i < nchars; i++)
3961             chars[i] = (unsigned char) bytes[i];
3962     }
3963     *lengthp = nchars;
3964     chars[nchars] = 0;
3965     return chars;
3966
3967   bad:
3968     /*
3969      * For compatibility with callers of JS_DecodeBytes we must zero lengthp
3970      * on errors.
3971      */
3972     *lengthp = 0;
3973     return NULL;
3974 }
3975
3976 /*
3977  * May be called with null cx.
3978  */
3979 char *
3980 js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
3981 {
3982     size_t nbytes, i;
3983     char *bytes;
3984 #ifdef DEBUG
3985     JSBool ok;
3986 #endif
3987
3988     if (js_CStringsAreUTF8) {
3989         nbytes = js_GetDeflatedStringLength(cx, chars, nchars);
3990         if (nbytes == (size_t) -1)
3991             return NULL;
3992         bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
3993         if (!bytes)
3994             return NULL;
3995 #ifdef DEBUG
3996         ok =
3997 #endif
3998             js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes);
3999         JS_ASSERT(ok);
4000     } else {
4001         nbytes = nchars;
4002         bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
4003         if (!bytes)
4004             return NULL;
4005         for (i = 0; i < nbytes; i++)
4006             bytes[i] = (char) chars[i];
4007     }
4008     bytes[nbytes] = 0;
4009     return bytes;
4010 }
4011
4012 size_t
4013 js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
4014 {
4015     if (!js_CStringsAreUTF8)
4016         return nchars;
4017
4018     return js_GetDeflatedUTF8StringLength(cx, chars, nchars);
4019 }
4020
4021 /*
4022  * May be called with null cx through public API, see below.
4023  */
4024 size_t
4025 js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars)
4026 {
4027     size_t nbytes;
4028     const jschar *end;
4029     uintN c, c2;
4030     char buffer[10];
4031
4032     nbytes = nchars;
4033     for (end = chars + nchars; chars != end; chars++) {
4034         c = *chars;
4035         if (c < 0x80)
4036             continue;
4037         if (0xD800 <= c && c <= 0xDFFF) {
4038             /* Surrogate pair. */
4039             chars++;
4040
4041             /* nbytes sets 1 length since this is surrogate pair. */
4042             nbytes--;
4043             if (c >= 0xDC00 || chars == end)
4044                 goto bad_surrogate;
4045             c2 = *chars;
4046             if (c2 < 0xDC00 || c2 > 0xDFFF)
4047                 goto bad_surrogate;
4048             c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
4049         }
4050         c >>= 11;
4051         nbytes++;
4052         while (c) {
4053             c >>= 5;
4054             nbytes++;
4055         }
4056     }
4057     return nbytes;
4058
4059   bad_surrogate:
4060     if (cx) {
4061         JS_snprintf(buffer, 10, "0x%x", c);
4062         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
4063                                      NULL, JSMSG_BAD_SURROGATE_CHAR, buffer);
4064     }
4065     return (size_t) -1;
4066 }
4067
4068 JSBool
4069 js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen,
4070                          char *dst, size_t *dstlenp)
4071 {
4072     size_t dstlen, i;
4073
4074     dstlen = *dstlenp;
4075     if (!js_CStringsAreUTF8) {
4076         if (srclen > dstlen) {
4077             for (i = 0; i < dstlen; i++)
4078                 dst[i] = (char) src[i];
4079             if (cx) {
4080                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4081                                      JSMSG_BUFFER_TOO_SMALL);
4082             }
4083             return JS_FALSE;
4084         }
4085         for (i = 0; i < srclen; i++)
4086             dst[i] = (char) src[i];
4087         *dstlenp = srclen;
4088         return JS_TRUE;
4089     }
4090
4091     return js_DeflateStringToUTF8Buffer(cx, src, srclen, dst, dstlenp);
4092 }
4093
4094 JSBool
4095 js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *src, size_t srclen,
4096                              char *dst, size_t *dstlenp)
4097 {
4098     size_t dstlen, i, origDstlen, utf8Len;
4099     jschar c, c2;
4100     uint32 v;
4101     uint8 utf8buf[6];
4102
4103     dstlen = *dstlenp;
4104     origDstlen = dstlen;
4105     while (srclen) {
4106         c = *src++;
4107         srclen--;
4108         if ((c >= 0xDC00) && (c <= 0xDFFF))
4109             goto badSurrogate;
4110         if (c < 0xD800 || c > 0xDBFF) {
4111             v = c;
4112         } else {
4113             if (srclen < 1)
4114                 goto badSurrogate;
4115             c2 = *src;
4116             if ((c2 < 0xDC00) || (c2 > 0xDFFF))
4117                 goto badSurrogate;
4118             src++;
4119             srclen--;
4120             v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
4121         }
4122         if (v < 0x0080) {
4123             /* no encoding necessary - performance hack */
4124             if (dstlen == 0)
4125                 goto bufferTooSmall;
4126             *dst++ = (char) v;
4127             utf8Len = 1;
4128         } else {
4129             utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
4130             if (utf8Len > dstlen)
4131                 goto bufferTooSmall;
4132             for (i = 0; i < utf8Len; i++)
4133                 *dst++ = (char) utf8buf[i];
4134         }
4135         dstlen -= utf8Len;
4136     }
4137     *dstlenp = (origDstlen - dstlen);
4138     return JS_TRUE;
4139
4140 badSurrogate:
4141     *dstlenp = (origDstlen - dstlen);
4142     /* Delegate error reporting to the measurement function. */
4143     if (cx)
4144         js_GetDeflatedStringLength(cx, src - 1, srclen + 1);
4145     return JS_FALSE;
4146
4147 bufferTooSmall:
4148     *dstlenp = (origDstlen - dstlen);
4149     if (cx) {
4150         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4151                              JSMSG_BUFFER_TOO_SMALL);
4152     }
4153     return JS_FALSE;
4154 }
4155
4156 JSBool
4157 js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen,
4158                          jschar *dst, size_t *dstlenp)
4159 {
4160     size_t dstlen, i;
4161
4162     if (!js_CStringsAreUTF8) {
4163         if (dst) {
4164             dstlen = *dstlenp;
4165             if (srclen > dstlen) {
4166                 for (i = 0; i < dstlen; i++)
4167                     dst[i] = (unsigned char) src[i];
4168                 if (cx) {
4169                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4170                                          JSMSG_BUFFER_TOO_SMALL);
4171                 }
4172                 return JS_FALSE;
4173             }
4174             for (i = 0; i < srclen; i++)
4175                 dst[i] = (unsigned char) src[i];
4176         }
4177         *dstlenp = srclen;
4178         return JS_TRUE;
4179     }
4180
4181     return js_InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp);
4182 }
4183
4184 JSBool
4185 js_InflateUTF8StringToBuffer(JSContext *cx, const char *src, size_t srclen,
4186                              jschar *dst, size_t *dstlenp)
4187 {
4188     size_t dstlen, origDstlen, offset, j, n;
4189     uint32 v;
4190
4191     dstlen = dst ? *dstlenp : (size_t) -1;
4192     origDstlen = dstlen;
4193     offset = 0;
4194
4195     while (srclen) {
4196         v = (uint8) *src;
4197         n = 1;
4198         if (v & 0x80) {
4199             while (v & (0x80 >> n))
4200                 n++;
4201             if (n > srclen)
4202                 goto bufferTooSmall;
4203             if (n == 1 || n > 4)
4204                 goto badCharacter;
4205             for (j = 1; j < n; j++) {
4206                 if ((src[j] & 0xC0) != 0x80)
4207                     goto badCharacter;
4208             }
4209             v = Utf8ToOneUcs4Char((uint8 *)src, n);
4210             if (v >= 0x10000) {
4211                 v -= 0x10000;
4212                 if (v > 0xFFFFF || dstlen < 2) {
4213                     *dstlenp = (origDstlen - dstlen);
4214                     if (cx) {
4215                         char buffer[10];
4216                         JS_snprintf(buffer, 10, "0x%x", v + 0x10000);
4217                         JS_ReportErrorFlagsAndNumber(cx,
4218                                                      JSREPORT_ERROR,
4219                                                      js_GetErrorMessage, NULL,
4220                                                      JSMSG_UTF8_CHAR_TOO_LARGE,
4221                                                      buffer);
4222                     }
4223                     return JS_FALSE;
4224                 }
4225                 if (dst) {
4226                     *dst++ = (jschar)((v >> 10) + 0xD800);
4227                     v = (jschar)((v & 0x3FF) + 0xDC00);
4228                 }
4229                 dstlen--;
4230             }
4231         }
4232         if (!dstlen)
4233             goto bufferTooSmall;
4234         if (dst)
4235             *dst++ = (jschar) v;
4236         dstlen--;
4237         offset += n;
4238         src += n;
4239         srclen -= n;
4240     }
4241     *dstlenp = (origDstlen - dstlen);
4242     return JS_TRUE;
4243
4244 badCharacter:
4245     *dstlenp = (origDstlen - dstlen);
4246     if (cx) {
4247         char buffer[10];
4248         JS_snprintf(buffer, 10, "%d", offset);
4249         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
4250                                      js_GetErrorMessage, NULL,
4251                                      JSMSG_MALFORMED_UTF8_CHAR,
4252                                      buffer);
4253     }
4254     return JS_FALSE;
4255
4256 bufferTooSmall:
4257     *dstlenp = (origDstlen - dstlen);
4258     if (cx) {
4259         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4260                              JSMSG_BUFFER_TOO_SMALL);
4261     }
4262     return JS_FALSE;
4263 }
4264
4265 /*
4266  * From java.lang.Character.java:
4267  *
4268  * The character properties are currently encoded into 32 bits in the
4269  * following manner:
4270  *
4271  * 10 bits      signed offset used for converting case
4272  *  1 bit       if 1, adding the signed offset converts the character to
4273  *              lowercase
4274  *  1 bit       if 1, subtracting the signed offset converts the character to
4275  *              uppercase
4276  *  1 bit       if 1, character has a titlecase equivalent (possibly itself)
4277  *  3 bits      0  may not be part of an identifier
4278  *              1  ignorable control; may continue a Unicode identifier or JS
4279  *                 identifier
4280  *              2  may continue a JS identifier but not a Unicode identifier
4281  *                 (unused)
4282  *              3  may continue a Unicode identifier or JS identifier
4283  *              4  is a JS whitespace character
4284  *              5  may start or continue a JS identifier;
4285  *                 may continue but not start a Unicode identifier (_)
4286  *              6  may start or continue a JS identifier but not a Unicode
4287  *                 identifier ($)
4288  *              7  may start or continue a Unicode identifier or JS identifier
4289  *              Thus:
4290  *                 5, 6, 7 may start a JS identifier
4291  *                 1, 2, 3, 5, 6, 7 may continue a JS identifier
4292  *                 7 may start a Unicode identifier
4293  *                 1, 3, 5, 7 may continue a Unicode identifier
4294  *                 1 is ignorable within an identifier
4295  *                 4 is JS whitespace
4296  *  2 bits      0  this character has no numeric property
4297  *              1  adding the digit offset to the character code and then
4298  *                 masking with 0x1F will produce the desired numeric value
4299  *              2  this character has a "strange" numeric value
4300  *              3  a JS supradecimal digit: adding the digit offset to the
4301  *                 character code, then masking with 0x1F, then adding 10
4302  *                 will produce the desired numeric value
4303  *  5 bits      digit offset
4304  *  1 bit       XML 1.0 name start character
4305  *  1 bit       XML 1.0 name character
4306  *  2 bits      reserved for future use
4307  *  5 bits      character type
4308  */
4309
4310 /* The X table has 1024 entries for a total of 1024 bytes. */
4311
4312 const uint8 js_X[] = {
4313   0,   1,   2,   3,   4,   5,   6,   7,  /*  0x0000 */
4314   8,   9,  10,  11,  12,  13,  14,  15,  /*  0x0200 */
4315  16,  17,  18,  19,  20,  21,  22,  23,  /*  0x0400 */
4316  24,  25,  26,  27,  28,  28,  28,  28,  /*  0x0600 */
4317  28,  28,  28,  28,  29,  30,  31,  32,  /*  0x0800 */
4318  33,  34,  35,  36,  37,  38,  39,  40,  /*  0x0A00 */
4319  41,  42,  43,  44,  45,  46,  28,  28,  /*  0x0C00 */
4320  47,  48,  49,  50,  51,  52,  53,  28,  /*  0x0E00 */
4321  28,  28,  54,  55,  56,  57,  58,  59,  /*  0x1000 */
4322  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1200 */
4323  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1400 */
4324  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1600 */
4325  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1800 */
4326  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1A00 */
4327  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1C00 */
4328  60,  60,  61,  62,  63,  64,  65,  66,  /*  0x1E00 */
4329  67,  68,  69,  70,  71,  72,  73,  74,  /*  0x2000 */
4330  75,  75,  75,  76,  77,  78,  28,  28,  /*  0x2200 */
4331  79,  80,  81,  82,  83,  83,  84,  85,  /*  0x2400 */
4332  86,  85,  28,  28,  87,  88,  89,  28,  /*  0x2600 */
4333  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2800 */
4334  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2A00 */
4335  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2C00 */
4336  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2E00 */
4337  90,  91,  92,  93,  94,  56,  95,  28,  /*  0x3000 */
4338  96,  97,  98,  99,  83, 100,  83, 101,  /*  0x3200 */
4339  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3400 */
4340  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3600 */
4341  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3800 */
4342  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3A00 */
4343  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3C00 */
4344  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3E00 */
4345  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4000 */
4346  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4200 */
4347  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4400 */
4348  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4600 */
4349  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4800 */
4350  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4A00 */
4351  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4C00 */
4352  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x4E00 */
4353  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5000 */
4354  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5200 */
4355  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5400 */
4356  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5600 */
4357  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5800 */
4358  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5A00 */
4359  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5C00 */
4360  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5E00 */
4361  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6000 */
4362  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6200 */
4363  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6400 */
4364  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6600 */
4365  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6800 */
4366  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6A00 */
4367  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6C00 */
4368  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6E00 */
4369  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7000 */
4370  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7200 */
4371  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7400 */
4372  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7600 */
4373  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7800 */
4374  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7A00 */
4375  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7C00 */
4376  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7E00 */
4377  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8000 */
4378  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8200 */
4379  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8400 */
4380  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8600 */
4381  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8800 */
4382  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8A00 */
4383  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8C00 */
4384  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8E00 */
4385  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9000 */
4386  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9200 */
4387  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9400 */
4388  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9600 */
4389  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9800 */
4390  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9A00 */
4391  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9C00 */
4392  56,  56,  56,  56,  56,  56, 102,  28,  /*  0x9E00 */
4393  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA000 */
4394  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA200 */
4395  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA400 */
4396  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA600 */
4397  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA800 */
4398  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xAA00 */
4399  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAC00 */
4400  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAE00 */
4401  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB000 */
4402  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB200 */
4403  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB400 */
4404  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB600 */
4405  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB800 */
4406  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBA00 */
4407  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBC00 */
4408  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBE00 */
4409  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC000 */
4410  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC200 */
4411  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC400 */
4412  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC600 */
4413  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC800 */
4414  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCA00 */
4415  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCC00 */
4416  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCE00 */
4417  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD000 */
4418  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD200 */
4419  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD400 */
4420  56,  56,  56,  56,  56,  56, 103,  28,  /*  0xD600 */
4421 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xD800 */
4422 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDA00 */
4423 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDC00 */
4424 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDE00 */
4425 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE000 */
4426 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE200 */
4427 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE400 */
4428 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE600 */
4429 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE800 */
4430 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEA00 */
4431 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEC00 */
4432 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEE00 */
4433 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF000 */
4434 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF200 */
4435 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF400 */
4436 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF600 */
4437 105, 105, 105, 105,  56,  56,  56,  56,  /*  0xF800 */
4438 106,  28,  28,  28, 107, 108, 109, 110,  /*  0xFA00 */
4439  56,  56,  56,  56, 111, 112, 113, 114,  /*  0xFC00 */
4440 115, 116,  56, 117, 118, 119, 120, 121   /*  0xFE00 */
4441 };
4442
4443 /* The Y table has 7808 entries for a total of 7808 bytes. */
4444
4445 const uint8 js_Y[] = {
4446   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
4447   0,   1,   1,   1,   1,   1,   0,   0,  /*    0 */
4448   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
4449   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
4450   2,   3,   3,   3,   4,   3,   3,   3,  /*    0 */
4451   5,   6,   3,   7,   3,   8,   3,   3,  /*    0 */
4452   9,   9,   9,   9,   9,   9,   9,   9,  /*    0 */
4453   9,   9,   3,   3,   7,   7,   7,   3,  /*    0 */
4454   3,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
4455  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
4456  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
4457  10,  10,  10,   5,   3,   6,  11,  12,  /*    1 */
4458  11,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
4459  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
4460  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
4461  13,  13,  13,   5,   7,   6,   7,   0,  /*    1 */
4462   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
4463   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
4464   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
4465   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
4466   2,   3,   4,   4,   4,   4,  15,  15,  /*    2 */
4467  11,  15,  16,   5,   7,   8,  15,  11,  /*    2 */
4468  15,   7,  17,  17,  11,  16,  15,   3,  /*    2 */
4469  11,  18,  16,   6,  19,  19,  19,   3,  /*    2 */
4470  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
4471  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
4472  20,  20,  20,  20,  20,  20,  20,   7,  /*    3 */
4473  20,  20,  20,  20,  20,  20,  20,  16,  /*    3 */
4474  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
4475  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
4476  21,  21,  21,  21,  21,  21,  21,   7,  /*    3 */
4477  21,  21,  21,  21,  21,  21,  21,  22,  /*    3 */
4478  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4479  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4480  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4481  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4482  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4483  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
4484  25,  26,  23,  24,  23,  24,  23,  24,  /*    4 */
4485  16,  23,  24,  23,  24,  23,  24,  23,  /*    4 */
4486  24,  23,  24,  23,  24,  23,  24,  23,  /*    5 */
4487  24,  16,  23,  24,  23,  24,  23,  24,  /*    5 */
4488  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
4489  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
4490  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
4491  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
4492  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
4493  27,  23,  24,  23,  24,  23,  24,  28,  /*    5 */
4494  16,  29,  23,  24,  23,  24,  30,  23,  /*    6 */
4495  24,  31,  31,  23,  24,  16,  32,  32,  /*    6 */
4496  33,  23,  24,  31,  34,  16,  35,  36,  /*    6 */
4497  23,  24,  16,  16,  35,  37,  16,  38,  /*    6 */
4498  23,  24,  23,  24,  23,  24,  38,  23,  /*    6 */
4499  24,  39,  40,  16,  23,  24,  39,  23,  /*    6 */
4500  24,  41,  41,  23,  24,  23,  24,  42,  /*    6 */
4501  23,  24,  16,  40,  23,  24,  40,  40,  /*    6 */
4502  40,  40,  40,  40,  43,  44,  45,  43,  /*    7 */
4503  44,  45,  43,  44,  45,  23,  24,  23,  /*    7 */
4504  24,  23,  24,  23,  24,  23,  24,  23,  /*    7 */
4505  24,  23,  24,  23,  24,  16,  23,  24,  /*    7 */
4506  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
4507  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
4508  16,  43,  44,  45,  23,  24,  46,  46,  /*    7 */
4509  46,  46,  23,  24,  23,  24,  23,  24,  /*    7 */
4510  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
4511  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
4512  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
4513  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
4514  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
4515  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
4516  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
4517  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
4518  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
4519  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
4520  16,  16,  16,  47,  48,  16,  49,  49,  /*    9 */
4521  50,  50,  16,  51,  16,  16,  16,  16,  /*    9 */
4522  49,  16,  16,  52,  16,  16,  16,  16,  /*    9 */
4523  53,  54,  16,  16,  16,  16,  16,  54,  /*    9 */
4524  16,  16,  55,  16,  16,  16,  16,  16,  /*    9 */
4525  16,  16,  16,  16,  16,  16,  16,  16,  /*    9 */
4526  16,  16,  16,  56,  16,  16,  16,  16,  /*   10 */
4527  56,  16,  57,  57,  16,  16,  16,  16,  /*   10 */
4528  16,  16,  58,  16,  16,  16,  16,  16,  /*   10 */
4529  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
4530  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
4531  16,  46,  46,  46,  46,  46,  46,  46,  /*   10 */
4532  59,  59,  59,  59,  59,  59,  59,  59,  /*   10 */
4533  59,  11,  11,  59,  59,  59,  59,  59,  /*   10 */
4534  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
4535  11,  11,  11,  11,  11,  11,  11,  11,  /*   11 */
4536  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
4537  11,  11,  11,  11,  11,  11,  11,  46,  /*   11 */
4538  59,  59,  59,  59,  59,  11,  11,  11,  /*   11 */
4539  11,  11,  46,  46,  46,  46,  46,  46,  /*   11 */
4540  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
4541  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
4542  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4543  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4544  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4545  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4546  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4547  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4548  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4549  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
4550  60,  60,  60,  60,  60,  60,  46,  46,  /*   13 */
4551  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
4552  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
4553  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
4554  60,  60,  46,  46,  46,  46,  46,  46,  /*   13 */
4555  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
4556  46,  46,  46,  46,   3,   3,  46,  46,  /*   13 */
4557  46,  46,  59,  46,  46,  46,   3,  46,  /*   13 */
4558  46,  46,  46,  46,  11,  11,  61,   3,  /*   14 */
4559  62,  62,  62,  46,  63,  46,  64,  64,  /*   14 */
4560  16,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
4561  20,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
4562  20,  20,  46,  20,  20,  20,  20,  20,  /*   14 */
4563  20,  20,  20,  20,  65,  66,  66,  66,  /*   14 */
4564  16,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
4565  21,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
4566  21,  21,  16,  21,  21,  21,  21,  21,  /*   15 */
4567  21,  21,  21,  21,  67,  68,  68,  46,  /*   15 */
4568  69,  70,  38,  38,  38,  71,  72,  46,  /*   15 */
4569  46,  46,  38,  46,  38,  46,  38,  46,  /*   15 */
4570  38,  46,  23,  24,  23,  24,  23,  24,  /*   15 */
4571  23,  24,  23,  24,  23,  24,  23,  24,  /*   15 */
4572  73,  74,  16,  40,  46,  46,  46,  46,  /*   15 */
4573  46,  46,  46,  46,  46,  46,  46,  46,  /*   15 */
4574  46,  75,  75,  75,  75,  75,  75,  75,  /*   16 */
4575  75,  75,  75,  75,  75,  46,  75,  75,  /*   16 */
4576  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
4577  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
4578  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
4579  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
4580  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
4581  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
4582  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
4583  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
4584  46,  74,  74,  74,  74,  74,  74,  74,  /*   17 */
4585  74,  74,  74,  74,  74,  46,  74,  74,  /*   17 */
4586  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
4587  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
4588  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
4589  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
4590  23,  24,  15,  60,  60,  60,  60,  46,  /*   18 */
4591  46,  46,  46,  46,  46,  46,  46,  46,  /*   18 */
4592  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4593  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4594  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4595  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4596  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4597  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
4598  40,  23,  24,  23,  24,  46,  46,  23,  /*   19 */
4599  24,  46,  46,  23,  24,  46,  46,  46,  /*   19 */
4600  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
4601  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
4602  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
4603  23,  24,  23,  24,  46,  46,  23,  24,  /*   19 */
4604  23,  24,  23,  24,  23,  24,  46,  46,  /*   19 */
4605  23,  24,  46,  46,  46,  46,  46,  46,  /*   19 */
4606  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4607  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4608  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4609  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4610  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4611  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
4612  46,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
4613  76,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
4614  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
4615  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
4616  76,  76,  76,  76,  76,  76,  76,  46,  /*   21 */
4617  46,  59,   3,   3,   3,   3,   3,   3,  /*   21 */
4618  46,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
4619  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
4620  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
4621  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
4622  77,  77,  77,  77,  77,  77,  77,  16,  /*   22 */
4623  46,   3,  46,  46,  46,  46,  46,  46,  /*   22 */
4624  46,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
4625  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
4626  60,  60,  46,  60,  60,  60,  60,  60,  /*   22 */
4627  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
4628  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
4629  60,  60,  46,  60,  60,  60,   3,  60,  /*   22 */
4630   3,  60,  60,   3,  60,  46,  46,  46,  /*   23 */
4631  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
4632  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
4633  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
4634  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
4635  40,  40,  40,  46,  46,  46,  46,  46,  /*   23 */
4636  40,  40,  40,   3,   3,  46,  46,  46,  /*   23 */
4637  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
4638  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
4639  46,  46,  46,  46,   3,  46,  46,  46,  /*   24 */
4640  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
4641  46,  46,  46,   3,  46,  46,  46,   3,  /*   24 */
4642  46,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
4643  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
4644  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
4645  40,  40,  40,  46,  46,  46,  46,  46,  /*   24 */
4646  59,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
4647  40,  40,  40,  60,  60,  60,  60,  60,  /*   25 */
4648  60,  60,  60,  46,  46,  46,  46,  46,  /*   25 */
4649  46,  46,  46,  46,  46,  46,  46,  46,  /*   25 */
4650  78,  78,  78,  78,  78,  78,  78,  78,  /*   25 */
4651  78,  78,   3,   3,   3,   3,  46,  46,  /*   25 */
4652  60,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
4653  40,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
4654  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4655  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4656  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4657  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4658  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4659  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4660  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
4661  46,  46,  40,  40,  40,  40,  40,  46,  /*   26 */
4662  40,  40,  40,  40,  40,  40,  40,  40,  /*   27 */
4663  40,  40,  40,  40,  40,  40,  40,  46,  /*   27 */
4664  40,  40,  40,  40,   3,  40,  60,  60,  /*   27 */
4665  60,  60,  60,  60,  60,  79,  79,  60,  /*   27 */
4666  60,  60,  60,  60,  60,  59,  59,  60,  /*   27 */
4667  60,  15,  60,  60,  60,  60,  46,  46,  /*   27 */
4668   9,   9,   9,   9,   9,   9,   9,   9,  /*   27 */
4669   9,   9,  46,  46,  46,  46,  46,  46,  /*   27 */
4670  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4671  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4672  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4673  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4674  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4675  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4676  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4677  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
4678  46,  60,  60,  80,  46,  40,  40,  40,  /*   29 */
4679  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4680  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4681  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4682  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4683  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4684  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
4685  40,  40,  46,  46,  60,  40,  80,  80,  /*   29 */
4686  80,  60,  60,  60,  60,  60,  60,  60,  /*   30 */
4687  60,  80,  80,  80,  80,  60,  46,  46,  /*   30 */
4688  15,  60,  60,  60,  60,  46,  46,  46,  /*   30 */
4689  40,  40,  40,  40,  40,  40,  40,  40,  /*   30 */
4690  40,  40,  60,  60,   3,   3,  81,  81,  /*   30 */
4691  81,  81,  81,  81,  81,  81,  81,  81,  /*   30 */
4692   3,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
4693  46,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
4694  46,  60,  80,  80,  46,  40,  40,  40,  /*   31 */
4695  40,  40,  40,  40,  40,  46,  46,  40,  /*   31 */
4696  40,  46,  46,  40,  40,  40,  40,  40,  /*   31 */
4697  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
4698  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
4699  40,  46,  40,  40,  40,  40,  40,  40,  /*   31 */
4700  40,  46,  40,  46,  46,  46,  40,  40,  /*   31 */
4701  40,  40,  46,  46,  60,  46,  80,  80,  /*   31 */
4702  80,  60,  60,  60,  60,  46,  46,  80,  /*   32 */
4703  80,  46,  46,  80,  80,  60,  46,  46,  /*   32 */
4704  46,  46,  46,  46,  46,  46,  46,  80,  /*   32 */
4705  46,  46,  46,  46,  40,  40,  46,  40,  /*   32 */
4706  40,  40,  60,  60,  46,  46,  81,  81,  /*   32 */
4707  81,  81,  81,  81,  81,  81,  81,  81,  /*   32 */
4708  40,  40,   4,   4,  82,  82,  82,  82,  /*   32 */
4709  19,  83,  15,  46,  46,  46,  46,  46,  /*   32 */
4710  46,  46,  60,  46,  46,  40,  40,  40,  /*   33 */
4711  40,  40,  40,  46,  46,  46,  46,  40,  /*   33 */
4712  40,  46,  46,  40,  40,  40,  40,  40,  /*   33 */
4713  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
4714  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
4715  40,  46,  40,  40,  40,  40,  40,  40,  /*   33 */
4716  40,  46,  40,  40,  46,  40,  40,  46,  /*   33 */
4717  40,  40,  46,  46,  60,  46,  80,  80,  /*   33 */
4718  80,  60,  60,  46,  46,  46,  46,  60,  /*   34 */
4719  60,  46,  46,  60,  60,  60,  46,  46,  /*   34 */
4720  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
4721  46,  40,  40,  40,  40,  46,  40,  46,  /*   34 */
4722  46,  46,  46,  46,  46,  46,  81,  81,  /*   34 */
4723  81,  81,  81,  81,  81,  81,  81,  81,  /*   34 */
4724  60,  60,  40,  40,  40,  46,  46,  46,  /*   34 */
4725  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
4726  46,  60,  60,  80,  46,  40,  40,  40,  /*   35 */
4727  40,  40,  40,  40,  46,  40,  46,  40,  /*   35 */
4728  40,  40,  46,  40,  40,  40,  40,  40,  /*   35 */
4729  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
4730  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
4731  40,  46,  40,  40,  40,  40,  40,  40,  /*   35 */
4732  40,  46,  40,  40,  46,  40,  40,  40,  /*   35 */
4733  40,  40,  46,  46,  60,  40,  80,  80,  /*   35 */
4734  80,  60,  60,  60,  60,  60,  46,  60,  /*   36 */
4735  60,  80,  46,  80,  80,  60,  46,  46,  /*   36 */
4736  15,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
4737  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
4738  40,  46,  46,  46,  46,  46,  81,  81,  /*   36 */
4739  81,  81,  81,  81,  81,  81,  81,  81,  /*   36 */
4740  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
4741  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
4742  46,  60,  80,  80,  46,  40,  40,  40,  /*   37 */
4743  40,  40,  40,  40,  40,  46,  46,  40,  /*   37 */
4744  40,  46,  46,  40,  40,  40,  40,  40,  /*   37 */
4745  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
4746  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
4747  40,  46,  40,  40,  40,  40,  40,  40,  /*   37 */
4748  40,  46,  40,  40,  46,  46,  40,  40,  /*   37 */
4749  40,  40,  46,  46,  60,  40,  80,  60,  /*   37 */
4750  80,  60,  60,  60,  46,  46,  46,  80,  /*   38 */
4751  80,  46,  46,  80,  80,  60,  46,  46,  /*   38 */
4752  46,  46,  46,  46,  46,  46,  60,  80,  /*   38 */
4753  46,  46,  46,  46,  40,  40,  46,  40,  /*   38 */
4754  40,  40,  46,  46,  46,  46,  81,  81,  /*   38 */
4755  81,  81,  81,  81,  81,  81,  81,  81,  /*   38 */
4756  15,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
4757  46,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
4758  46,  46,  60,  80,  46,  40,  40,  40,  /*   39 */
4759  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
4760  40,  46,  40,  40,  40,  40,  46,  46,  /*   39 */
4761  46,  40,  40,  46,  40,  46,  40,  40,  /*   39 */
4762  46,  46,  46,  40,  40,  46,  46,  46,  /*   39 */
4763  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
4764  40,  40,  40,  40,  40,  40,  46,  40,  /*   39 */
4765  40,  40,  46,  46,  46,  46,  80,  80,  /*   39 */
4766  60,  80,  80,  46,  46,  46,  80,  80,  /*   40 */
4767  80,  46,  80,  80,  80,  60,  46,  46,  /*   40 */
4768  46,  46,  46,  46,  46,  46,  46,  80,  /*   40 */
4769  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
4770  46,  46,  46,  46,  46,  46,  46,  81,  /*   40 */
4771  81,  81,  81,  81,  81,  81,  81,  81,  /*   40 */
4772  84,  19,  19,  46,  46,  46,  46,  46,  /*   40 */
4773  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
4774  46,  80,  80,  80,  46,  40,  40,  40,  /*   41 */
4775  40,  40,  40,  40,  40,  46,  40,  40,  /*   41 */
4776  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
4777  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
4778  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
4779  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
4780  40,  40,  40,  40,  46,  40,  40,  40,  /*   41 */
4781  40,  40,  46,  46,  46,  46,  60,  60,  /*   41 */
4782  60,  80,  80,  80,  80,  46,  60,  60,  /*   42 */
4783  60,  46,  60,  60,  60,  60,  46,  46,  /*   42 */
4784  46,  46,  46,  46,  46,  60,  60,  46,  /*   42 */
4785  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
4786  40,  40,  46,  46,  46,  46,  81,  81,  /*   42 */
4787  81,  81,  81,  81,  81,  81,  81,  81,  /*   42 */
4788  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
4789  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
4790  46,  46,  80,  80,  46,  40,  40,  40,  /*   43 */
4791  40,  40,  40,  40,  40,  46,  40,  40,  /*   43 */
4792  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
4793  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
4794  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
4795  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
4796  40,  40,  40,  40,  46,  40,  40,  40,  /*   43 */
4797  40,  40,  46,  46,  46,  46,  80,  60,  /*   43 */
4798  80,  80,  80,  80,  80,  46,  60,  80,  /*   44 */
4799  80,  46,  80,  80,  60,  60,  46,  46,  /*   44 */
4800  46,  46,  46,  46,  46,  80,  80,  46,  /*   44 */
4801  46,  46,  46,  46,  46,  46,  40,  46,  /*   44 */
4802  40,  40,  46,  46,  46,  46,  81,  81,  /*   44 */
4803  81,  81,  81,  81,  81,  81,  81,  81,  /*   44 */
4804  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
4805  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
4806  46,  46,  80,  80,  46,  40,  40,  40,  /*   45 */
4807  40,  40,  40,  40,  40,  46,  40,  40,  /*   45 */
4808  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
4809  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
4810  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
4811  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
4812  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
4813  40,  40,  46,  46,  46,  46,  80,  80,  /*   45 */
4814  80,  60,  60,  60,  46,  46,  80,  80,  /*   46 */
4815  80,  46,  80,  80,  80,  60,  46,  46,  /*   46 */
4816  46,  46,  46,  46,  46,  46,  46,  80,  /*   46 */
4817  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
4818  40,  40,  46,  46,  46,  46,  81,  81,  /*   46 */
4819  81,  81,  81,  81,  81,  81,  81,  81,  /*   46 */
4820  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
4821  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
4822  46,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
4823  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
4824  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
4825  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
4826  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
4827  40,  40,  40,  40,  40,  40,  40,   3,  /*   47 */
4828  40,  60,  40,  40,  60,  60,  60,  60,  /*   47 */
4829  60,  60,  60,  46,  46,  46,  46,   4,  /*   47 */
4830  40,  40,  40,  40,  40,  40,  59,  60,  /*   48 */
4831  60,  60,  60,  60,  60,  60,  60,  15,  /*   48 */
4832   9,   9,   9,   9,   9,   9,   9,   9,  /*   48 */
4833   9,   9,   3,   3,  46,  46,  46,  46,  /*   48 */
4834  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
4835  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
4836  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
4837  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
4838  46,  40,  40,  46,  40,  46,  46,  40,  /*   49 */
4839  40,  46,  40,  46,  46,  40,  46,  46,  /*   49 */
4840  46,  46,  46,  46,  40,  40,  40,  40,  /*   49 */
4841  46,  40,  40,  40,  40,  40,  40,  40,  /*   49 */
4842  46,  40,  40,  40,  46,  40,  46,  40,  /*   49 */
4843  46,  46,  40,  40,  46,  40,  40,   3,  /*   49 */
4844  40,  60,  40,  40,  60,  60,  60,  60,  /*   49 */
4845  60,  60,  46,  60,  60,  40,  46,  46,  /*   49 */
4846  40,  40,  40,  40,  40,  46,  59,  46,  /*   50 */
4847  60,  60,  60,  60,  60,  60,  46,  46,  /*   50 */
4848   9,   9,   9,   9,   9,   9,   9,   9,  /*   50 */
4849   9,   9,  46,  46,  40,  40,  46,  46,  /*   50 */
4850  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
4851  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
4852  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
4853  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
4854  15,  15,  15,  15,   3,   3,   3,   3,  /*   51 */
4855   3,   3,   3,   3,   3,   3,   3,   3,  /*   51 */
4856   3,   3,   3,  15,  15,  15,  15,  15,  /*   51 */
4857  60,  60,  15,  15,  15,  15,  15,  15,  /*   51 */
4858  78,  78,  78,  78,  78,  78,  78,  78,  /*   51 */
4859  78,  78,  85,  85,  85,  85,  85,  85,  /*   51 */
4860  85,  85,  85,  85,  15,  60,  15,  60,  /*   51 */
4861  15,  60,   5,   6,   5,   6,  80,  80,  /*   51 */
4862  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
4863  46,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
4864  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
4865  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
4866  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
4867  40,  40,  46,  46,  46,  46,  46,  46,  /*   52 */
4868  46,  60,  60,  60,  60,  60,  60,  60,  /*   52 */
4869  60,  60,  60,  60,  60,  60,  60,  80,  /*   52 */
4870  60,  60,  60,  60,  60,   3,  60,  60,  /*   53 */
4871  60,  60,  60,  60,  46,  46,  46,  46,  /*   53 */
4872  60,  60,  60,  60,  60,  60,  46,  60,  /*   53 */
4873  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
4874  60,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
4875  60,  60,  60,  60,  60,  60,  46,  46,  /*   53 */
4876  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
4877  46,  60,  46,  46,  46,  46,  46,  46,  /*   53 */
4878  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
4879  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
4880  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
4881  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
4882  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
4883  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
4884  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
4885  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
4886  76,  76,  76,  76,  76,  76,  46,  46,  /*   55 */
4887  46,  46,  46,  46,  46,  46,  46,  46,  /*   55 */
4888  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
4889  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
4890  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
4891  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
4892  16,  16,  16,  16,  16,  16,  16,  46,  /*   55 */
4893  46,  46,  46,   3,  46,  46,  46,  46,  /*   55 */
4894  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4895  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4896  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4897  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4898  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4899  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4900  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4901  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
4902  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4903  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4904  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4905  40,  40,  46,  46,  46,  46,  46,  40,  /*   57 */
4906  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4907  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4908  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4909  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
4910  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4911  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4912  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4913  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4914  40,  40,  40,  46,  46,  46,  46,  46,  /*   58 */
4915  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4916  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4917  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
4918  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4919  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4920  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4921  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4922  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4923  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4924  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
4925  40,  40,  46,  46,  46,  46,  46,  46,  /*   59 */
4926  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4927  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4928  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4929  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4930  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4931  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4932  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4933  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
4934  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4935  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4936  23,  24,  23,  24,  23,  24,  16,  16,  /*   61 */
4937  16,  16,  16,  16,  46,  46,  46,  46,  /*   61 */
4938  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4939  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4940  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4941  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
4942  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4943  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4944  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4945  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4946  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4947  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4948  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
4949  23,  24,  46,  46,  46,  46,  46,  46,  /*   62 */
4950  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
4951  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
4952  86,  86,  86,  86,  86,  86,  46,  46,  /*   63 */
4953  87,  87,  87,  87,  87,  87,  46,  46,  /*   63 */
4954  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
4955  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
4956  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
4957  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
4958  86,  86,  86,  86,  86,  86,  46,  46,  /*   64 */
4959  87,  87,  87,  87,  87,  87,  46,  46,  /*   64 */
4960  16,  86,  16,  86,  16,  86,  16,  86,  /*   64 */
4961  46,  87,  46,  87,  46,  87,  46,  87,  /*   64 */
4962  86,  86,  86,  86,  86,  86,  86,  86,  /*   64 */
4963  87,  87,  87,  87,  87,  87,  87,  87,  /*   64 */
4964  88,  88,  89,  89,  89,  89,  90,  90,  /*   64 */
4965  91,  91,  92,  92,  93,  93,  46,  46,  /*   64 */
4966  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
4967  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
4968  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
4969  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
4970  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
4971  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
4972  86,  86,  16,  94,  16,  46,  16,  16,  /*   65 */
4973  87,  87,  95,  95,  96,  11,  38,  11,  /*   65 */
4974  11,  11,  16,  94,  16,  46,  16,  16,  /*   66 */
4975  97,  97,  97,  97,  96,  11,  11,  11,  /*   66 */
4976  86,  86,  16,  16,  46,  46,  16,  16,  /*   66 */
4977  87,  87,  98,  98,  46,  11,  11,  11,  /*   66 */
4978  86,  86,  16,  16,  16,  99,  16,  16,  /*   66 */
4979  87,  87, 100, 100, 101,  11,  11,  11,  /*   66 */
4980  46,  46,  16,  94,  16,  46,  16,  16,  /*   66 */
4981 102, 102, 103, 103,  96,  11,  11,  46,  /*   66 */
4982   2,   2,   2,   2,   2,   2,   2,   2,  /*   67 */
4983   2,   2,   2,   2, 104, 104, 104, 104,  /*   67 */
4984   8,   8,   8,   8,   8,   8,   3,   3,  /*   67 */
4985   5,   6,   5,   5,   5,   6,   5,   5,  /*   67 */
4986   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
4987 105, 106, 104, 104, 104, 104, 104,  46,  /*   67 */
4988   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
4989   3,   5,   6,   3,   3,   3,   3,  12,  /*   67 */
4990  12,   3,   3,   3,   7,   5,   6,  46,  /*   68 */
4991  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
4992  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
4993  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
4994  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
4995  46,  46, 104, 104, 104, 104, 104, 104,  /*   68 */
4996  17,  46,  46,  46,  17,  17,  17,  17,  /*   68 */
4997  17,  17,   7,   7,   7,   5,   6,  16,  /*   68 */
4998 107, 107, 107, 107, 107, 107, 107, 107,  /*   69 */
4999 107, 107,   7,   7,   7,   5,   6,  46,  /*   69 */
5000  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
5001  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
5002   4,   4,   4,   4,   4,   4,   4,   4,  /*   69 */
5003   4,   4,   4,   4,  46,  46,  46,  46,  /*   69 */
5004  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
5005  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
5006  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
5007  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
5008  60,  60,  60,  60,  60,  60,  60,  60,  /*   70 */
5009  60,  60,  60,  60,  60,  79,  79,  79,  /*   70 */
5010  79,  60,  46,  46,  46,  46,  46,  46,  /*   70 */
5011  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
5012  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
5013  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
5014  15,  15,  38,  15,  15,  15,  15,  38,  /*   71 */
5015  15,  15,  16,  38,  38,  38,  16,  16,  /*   71 */
5016  38,  38,  38,  16,  15,  38,  15,  15,  /*   71 */
5017  38,  38,  38,  38,  38,  38,  15,  15,  /*   71 */
5018  15,  15,  15,  15,  38,  15,  38,  15,  /*   71 */
5019  38,  15,  38,  38,  38,  38,  16,  16,  /*   71 */
5020  38,  38,  15,  38,  16,  40,  40,  40,  /*   71 */
5021  40,  46,  46,  46,  46,  46,  46,  46,  /*   71 */
5022  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
5023  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
5024  46,  46,  46,  19,  19,  19,  19,  19,  /*   72 */
5025  19,  19,  19,  19,  19,  19,  19, 108,  /*   72 */
5026 109, 109, 109, 109, 109, 109, 109, 109,  /*   72 */
5027 109, 109, 109, 109, 110, 110, 110, 110,  /*   72 */
5028 111, 111, 111, 111, 111, 111, 111, 111,  /*   72 */
5029 111, 111, 111, 111, 112, 112, 112, 112,  /*   72 */
5030 113, 113, 113,  46,  46,  46,  46,  46,  /*   73 */
5031  46,  46,  46,  46,  46,  46,  46,  46,  /*   73 */
5032   7,   7,   7,   7,   7,  15,  15,  15,  /*   73 */
5033  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
5034  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
5035  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
5036  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
5037  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
5038  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
5039  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
5040  15,  15,   7,  15,   7,  15,  15,  15,  /*   74 */
5041  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
5042  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
5043  15,  15,  15,  46,  46,  46,  46,  46,  /*   74 */
5044  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
5045  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
5046   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5047   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5048   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5049   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5050   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5051   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5052   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5053   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
5054   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5055   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5056   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5057   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5058   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5059   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
5060   7,   7,  46,  46,  46,  46,  46,  46,  /*   76 */
5061  46,  46,  46,  46,  46,  46,  46,  46,  /*   76 */
5062  15,  46,  15,  15,  15,  15,  15,  15,  /*   77 */
5063   7,   7,   7,   7,  15,  15,  15,  15,  /*   77 */
5064  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
5065  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
5066   7,   7,  15,  15,  15,  15,  15,  15,  /*   77 */
5067  15,   5,   6,  15,  15,  15,  15,  15,  /*   77 */
5068  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
5069  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
5070  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5071  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5072  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5073  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5074  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5075  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5076  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
5077  15,  15,  15,  46,  46,  46,  46,  46,  /*   78 */
5078  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
5079  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
5080  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
5081  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
5082  15,  15,  15,  15,  15,  46,  46,  46,  /*   79 */
5083  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
5084  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
5085  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
5086  15,  15,  15,  15,  15,  15,  15,  15,  /*   80 */
5087  15,  15,  15,  46,  46,  46,  46,  46,  /*   80 */
5088  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
5089  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
5090 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
5091 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
5092 114, 114, 114, 114,  82,  82,  82,  82,  /*   80 */
5093  82,  82,  82,  82,  82,  82,  82,  82,  /*   80 */
5094  82,  82,  82,  82,  82,  82,  82,  82,  /*   81 */
5095 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
5096 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
5097 115, 115, 115, 115,  15,  15,  15,  15,  /*   81 */
5098  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
5099  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
5100  15,  15,  15,  15,  15,  15, 116, 116,  /*   81 */
5101 116, 116, 116, 116, 116, 116, 116, 116,  /*   81 */
5102 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
5103 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
5104 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
5105 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
5106 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
5107 117, 117, 118,  46,  46,  46,  46,  46,  /*   82 */
5108  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
5109  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
5110  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5111  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5112  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5113  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5114  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5115  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5116  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5117  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
5118  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5119  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5120  15,  15,  15,  15,  15,  15,  46,  46,  /*   84 */
5121  46,  46,  46,  46,  46,  46,  46,  46,  /*   84 */
5122  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5123  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5124  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5125  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
5126  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5127  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5128  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5129  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5130  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5131  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
5132  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
5133  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
5134  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5135  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5136  15,  15,  15,  15,  46,  46,  46,  46,  /*   86 */
5137  46,  46,  15,  15,  15,  15,  15,  15,  /*   86 */
5138  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5139  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5140  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5141  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
5142  46,  15,  15,  15,  15,  46,  15,  15,  /*   87 */
5143  15,  15,  46,  46,  15,  15,  15,  15,  /*   87 */
5144  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5145  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5146  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5147  46,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5148  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5149  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
5150  15,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
5151  15,  15,  15,  15,  46,  15,  46,  15,  /*   88 */
5152  15,  15,  15,  46,  46,  46,  15,  46,  /*   88 */
5153  15,  15,  15,  15,  15,  15,  15,  46,  /*   88 */
5154  46,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
5155  46,  46,  46,  46,  46,  46,  46,  46,  /*   88 */
5156  46,  46,  46,  46,  46,  46, 119, 119,  /*   88 */
5157 119, 119, 119, 119, 119, 119, 119, 119,  /*   88 */
5158 114, 114, 114, 114, 114, 114, 114, 114,  /*   89 */
5159 114, 114,  83,  83,  83,  83,  83,  83,  /*   89 */
5160  83,  83,  83,  83,  15,  46,  46,  46,  /*   89 */
5161  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
5162  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
5163  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
5164  46,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
5165  15,  15,  15,  15,  15,  15,  15,  46,  /*   89 */
5166   2,   3,   3,   3,  15,  59,   3, 120,  /*   90 */
5167   5,   6,   5,   6,   5,   6,   5,   6,  /*   90 */
5168   5,   6,  15,  15,   5,   6,   5,   6,  /*   90 */
5169   5,   6,   5,   6,   8,   5,   6,   5,  /*   90 */
5170  15, 121, 121, 121, 121, 121, 121, 121,  /*   90 */
5171 121, 121,  60,  60,  60,  60,  60,  60,  /*   90 */
5172   8,  59,  59,  59,  59,  59,  15,  15,  /*   90 */
5173  46,  46,  46,  46,  46,  46,  46,  15,  /*   90 */
5174  46,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5175  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5176  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5177  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5178  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5179  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5180  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5181  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
5182  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5183  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5184  40,  40,  40,  40,  40,  46,  46,  46,  /*   92 */
5185  46,  60,  60,  59,  59,  59,  59,  46,  /*   92 */
5186  46,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5187  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5188  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5189  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
5190  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5191  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5192  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5193  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5194  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5195  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5196  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
5197  40,  40,  40,   3,  59,  59,  59,  46,  /*   93 */
5198  46,  46,  46,  46,  46,  40,  40,  40,  /*   94 */
5199  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5200  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5201  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5202  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5203  40,  40,  40,  40,  40,  46,  46,  46,  /*   94 */
5204  46,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5205  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
5206  40,  40,  40,  40,  40,  40,  40,  40,  /*   95 */
5207  40,  40,  40,  40,  40,  40,  40,  46,  /*   95 */
5208  15,  15,  85,  85,  85,  85,  15,  15,  /*   95 */
5209  15,  15,  15,  15,  15,  15,  15,  15,  /*   95 */
5210  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
5211  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
5212  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
5213  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
5214  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
5215  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
5216  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
5217  15,  15,  15,  15,  15,  46,  46,  46,  /*   96 */
5218  85,  85,  85,  85,  85,  85,  85,  85,  /*   96 */
5219  85,  85,  15,  15,  15,  15,  15,  15,  /*   96 */
5220  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
5221  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
5222  15,  15,  15,  15,  46,  46,  46,  46,  /*   97 */
5223  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
5224  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
5225  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
5226  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
5227  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
5228  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
5229  15,  15,  15,  15,  46,  46,  46,  15,  /*   97 */
5230 114, 114, 114, 114, 114, 114, 114, 114,  /*   98 */
5231 114, 114,  15,  15,  15,  15,  15,  15,  /*   98 */
5232  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
5233  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
5234  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
5235  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
5236  15,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
5237  46,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
5238  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5239  15,  15,  15,  15,  46,  46,  46,  46,  /*   99 */
5240  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5241  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5242  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5243  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5244  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
5245  15,  15,  15,  15,  15,  15,  15,  46,  /*   99 */
5246  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5247  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5248  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5249  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5250  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5251  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
5252  15,  15,  15,  15,  15,  15,  15,  46,  /*  100 */
5253  46,  46,  46,  15,  15,  15,  15,  15,  /*  100 */
5254  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5255  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5256  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5257  15,  15,  15,  15,  15,  15,  46,  46,  /*  101 */
5258  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5259  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5260  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
5261  15,  15,  15,  15,  15,  15,  15,  46,  /*  101 */
5262  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
5263  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
5264  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
5265  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
5266  40,  40,  40,  40,  40,  40,  46,  46,  /*  102 */
5267  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
5268  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
5269  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
5270  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
5271  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
5272  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
5273  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
5274  40,  40,  40,  40,  46,  46,  46,  46,  /*  103 */
5275  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
5276  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
5277  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
5278 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5279 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5280 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5281 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5282 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5283 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5284 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5285 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
5286 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5287 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5288 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5289 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5290 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5291 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5292 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5293 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
5294  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
5295  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
5296  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
5297  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
5298  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
5299  40,  40,  40,  40,  40,  40,  46,  46,  /*  106 */
5300  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
5301  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
5302  16,  16,  16,  16,  16,  16,  16,  46,  /*  107 */
5303  46,  46,  46,  46,  46,  46,  46,  46,  /*  107 */
5304  46,  46,  46,  16,  16,  16,  16,  16,  /*  107 */
5305  46,  46,  46,  46,  46,  46,  60,  40,  /*  107 */
5306  40,  40,  40,  40,  40,  40,  40,  40,  /*  107 */
5307  40,   7,  40,  40,  40,  40,  40,  40,  /*  107 */
5308  40,  40,  40,  40,  40,  40,  40,  46,  /*  107 */
5309  40,  40,  40,  40,  40,  46,  40,  46,  /*  107 */
5310  40,  40,  46,  40,  40,  46,  40,  40,  /*  108 */
5311  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5312  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5313  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5314  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5315  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5316  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5317  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
5318  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5319  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5320  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5321  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5322  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5323  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
5324  40,  40,  46,  46,  46,  46,  46,  46,  /*  109 */
5325  46,  46,  46,  46,  46,  46,  46,  46,  /*  109 */
5326  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
5327  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
5328  46,  46,  46,  40,  40,  40,  40,  40,  /*  110 */
5329  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
5330  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
5331  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
5332  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
5333  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
5334  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5335  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5336  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5337  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5338  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5339  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5340  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
5341  40,  40,  40,  40,  40,  40,   5,   6,  /*  111 */
5342  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
5343  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
5344  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5345  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5346  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5347  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5348  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5349  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
5350  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5351  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5352  46,  46,  40,  40,  40,  40,  40,  40,  /*  113 */
5353  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5354  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5355  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5356  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5357  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
5358  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
5359  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
5360  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
5361  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
5362  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
5363  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
5364  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
5365  40,  40,  40,  40,  46,  46,  46,  46,  /*  114 */
5366  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
5367  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
5368  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
5369  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
5370  60,  60,  60,  60,  46,  46,  46,  46,  /*  115 */
5371  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
5372   3,   8,   8,  12,  12,   5,   6,   5,  /*  115 */
5373   6,   5,   6,   5,   6,   5,   6,   5,  /*  115 */
5374   6,   5,   6,   5,   6,  46,  46,  46,  /*  116 */
5375  46,   3,   3,   3,   3,  12,  12,  12,  /*  116 */
5376   3,   3,   3,  46,   3,   3,   3,   3,  /*  116 */
5377   8,   5,   6,   5,   6,   5,   6,   3,  /*  116 */
5378   3,   3,   7,   8,   7,   7,   7,  46,  /*  116 */
5379   3,   4,   3,   3,  46,  46,  46,  46,  /*  116 */
5380  40,  40,  40,  46,  40,  46,  40,  40,  /*  116 */
5381  40,  40,  40,  40,  40,  40,  40,  40,  /*  116 */
5382  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5383  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5384  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5385  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5386  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5387  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5388  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
5389  40,  40,  40,  40,  40,  46,  46, 104,  /*  117 */
5390  46,   3,   3,   3,   4,   3,   3,   3,  /*  118 */
5391   5,   6,   3,   7,   3,   8,   3,   3,  /*  118 */
5392   9,   9,   9,   9,   9,   9,   9,   9,  /*  118 */
5393   9,   9,   3,   3,   7,   7,   7,   3,  /*  118 */
5394   3,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
5395  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
5396  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
5397  10,  10,  10,   5,   3,   6,  11,  12,  /*  118 */
5398  11,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
5399  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
5400  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
5401  13,  13,  13,   5,   7,   6,   7,  46,  /*  119 */
5402  46,   3,   5,   6,   3,   3,  40,  40,  /*  119 */
5403  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
5404  59,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
5405  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
5406  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5407  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5408  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5409  40,  40,  40,  40,  40,  40,  59,  59,  /*  120 */
5410  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5411  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5412  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
5413  40,  40,  40,  40,  40,  40,  40,  46,  /*  120 */
5414  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
5415  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
5416  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
5417  46,  46,  40,  40,  40,  46,  46,  46,  /*  121 */
5418   4,   4,   7,  11,  15,   4,   4,  46,  /*  121 */
5419   7,   7,   7,   7,   7,  15,  15,  46,  /*  121 */
5420  46,  46,  46,  46,  46,  46,  46,  46,  /*  121 */
5421  46,  46,  46,  46,  46,  15,  46,  46   /*  121 */
5422 };
5423
5424 /* The A table has 124 entries for a total of 496 bytes. */
5425
5426 const uint32 js_A[] = {
5427 0x0001000F,  /*    0   Cc, ignorable */
5428 0x0004000F,  /*    1   Cc, whitespace */
5429 0x0004000C,  /*    2   Zs, whitespace */
5430 0x00000018,  /*    3   Po */
5431 0x0006001A,  /*    4   Sc, currency */
5432 0x00000015,  /*    5   Ps */
5433 0x00000016,  /*    6   Pe */
5434 0x00000019,  /*    7   Sm */
5435 0x00000014,  /*    8   Pd */
5436 0x00036089,  /*    9   Nd, identifier part, decimal 16 */
5437 0x0827FF81,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
5438 0x0000001B,  /*   11   Sk */
5439 0x00050017,  /*   12   Pc, underscore */
5440 0x0817FF82,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
5441 0x0000000C,  /*   14   Zs */
5442 0x0000001C,  /*   15   So */
5443 0x00070182,  /*   16   Ll, identifier start */
5444 0x0000600B,  /*   17   No, decimal 16 */
5445 0x0000500B,  /*   18   No, decimal 8 */
5446 0x0000800B,  /*   19   No, strange */
5447 0x08270181,  /*   20   Lu, hasLower (add 32), identifier start */
5448 0x08170182,  /*   21   Ll, hasUpper (subtract 32), identifier start */
5449 0xE1D70182,  /*   22   Ll, hasUpper (subtract -121), identifier start */
5450 0x00670181,  /*   23   Lu, hasLower (add 1), identifier start */
5451 0x00570182,  /*   24   Ll, hasUpper (subtract 1), identifier start */
5452 0xCE670181,  /*   25   Lu, hasLower (add -199), identifier start */
5453 0x3A170182,  /*   26   Ll, hasUpper (subtract 232), identifier start */
5454 0xE1E70181,  /*   27   Lu, hasLower (add -121), identifier start */
5455 0x4B170182,  /*   28   Ll, hasUpper (subtract 300), identifier start */
5456 0x34A70181,  /*   29   Lu, hasLower (add 210), identifier start */
5457 0x33A70181,  /*   30   Lu, hasLower (add 206), identifier start */
5458 0x33670181,  /*   31   Lu, hasLower (add 205), identifier start */
5459 0x32A70181,  /*   32   Lu, hasLower (add 202), identifier start */
5460 0x32E70181,  /*   33   Lu, hasLower (add 203), identifier start */
5461 0x33E70181,  /*   34   Lu, hasLower (add 207), identifier start */
5462 0x34E70181,  /*   35   Lu, hasLower (add 211), identifier start */
5463 0x34670181,  /*   36   Lu, hasLower (add 209), identifier start */
5464 0x35670181,  /*   37   Lu, hasLower (add 213), identifier start */
5465 0x00070181,  /*   38   Lu, identifier start */
5466 0x36A70181,  /*   39   Lu, hasLower (add 218), identifier start */
5467 0x00070185,  /*   40   Lo, identifier start */
5468 0x36670181,  /*   41   Lu, hasLower (add 217), identifier start */
5469 0x36E70181,  /*   42   Lu, hasLower (add 219), identifier start */
5470 0x00AF0181,  /*   43   Lu, hasLower (add 2), hasTitle, identifier start */
5471 0x007F0183,  /*   44   Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
5472 0x009F0182,  /*   45   Ll, hasUpper (subtract 2), hasTitle, identifier start */
5473 0x00000000,  /*   46   unassigned */
5474 0x34970182,  /*   47   Ll, hasUpper (subtract 210), identifier start */
5475 0x33970182,  /*   48   Ll, hasUpper (subtract 206), identifier start */
5476 0x33570182,  /*   49   Ll, hasUpper (subtract 205), identifier start */
5477 0x32970182,  /*   50   Ll, hasUpper (subtract 202), identifier start */
5478 0x32D70182,  /*   51   Ll, hasUpper (subtract 203), identifier start */
5479 0x33D70182,  /*   52   Ll, hasUpper (subtract 207), identifier start */
5480 0x34570182,  /*   53   Ll, hasUpper (subtract 209), identifier start */
5481 0x34D70182,  /*   54   Ll, hasUpper (subtract 211), identifier start */
5482 0x35570182,  /*   55   Ll, hasUpper (subtract 213), identifier start */
5483 0x36970182,  /*   56   Ll, hasUpper (subtract 218), identifier start */
5484 0x36570182,  /*   57   Ll, hasUpper (subtract 217), identifier start */
5485 0x36D70182,  /*   58   Ll, hasUpper (subtract 219), identifier start */
5486 0x00070084,  /*   59   Lm, identifier start */
5487 0x00030086,  /*   60   Mn, identifier part */
5488 0x09A70181,  /*   61   Lu, hasLower (add 38), identifier start */
5489 0x09670181,  /*   62   Lu, hasLower (add 37), identifier start */
5490 0x10270181,  /*   63   Lu, hasLower (add 64), identifier start */
5491 0x0FE70181,  /*   64   Lu, hasLower (add 63), identifier start */
5492 0x09970182,  /*   65   Ll, hasUpper (subtract 38), identifier start */
5493 0x09570182,  /*   66   Ll, hasUpper (subtract 37), identifier start */
5494 0x10170182,  /*   67   Ll, hasUpper (subtract 64), identifier start */
5495 0x0FD70182,  /*   68   Ll, hasUpper (subtract 63), identifier start */
5496 0x0F970182,  /*   69   Ll, hasUpper (subtract 62), identifier start */
5497 0x0E570182,  /*   70   Ll, hasUpper (subtract 57), identifier start */
5498 0x0BD70182,  /*   71   Ll, hasUpper (subtract 47), identifier start */
5499 0x0D970182,  /*   72   Ll, hasUpper (subtract 54), identifier start */
5500 0x15970182,  /*   73   Ll, hasUpper (subtract 86), identifier start */
5501 0x14170182,  /*   74   Ll, hasUpper (subtract 80), identifier start */
5502 0x14270181,  /*   75   Lu, hasLower (add 80), identifier start */
5503 0x0C270181,  /*   76   Lu, hasLower (add 48), identifier start */
5504 0x0C170182,  /*   77   Ll, hasUpper (subtract 48), identifier start */
5505 0x00034089,  /*   78   Nd, identifier part, decimal 0 */
5506 0x00000087,  /*   79   Me */
5507 0x00030088,  /*   80   Mc, identifier part */
5508 0x00037489,  /*   81   Nd, identifier part, decimal 26 */
5509 0x00005A0B,  /*   82   No, decimal 13 */
5510 0x00006E0B,  /*   83   No, decimal 23 */
5511 0x0000740B,  /*   84   No, decimal 26 */
5512 0x0000000B,  /*   85   No */
5513 0xFE170182,  /*   86   Ll, hasUpper (subtract -8), identifier start */
5514 0xFE270181,  /*   87   Lu, hasLower (add -8), identifier start */
5515 0xED970182,  /*   88   Ll, hasUpper (subtract -74), identifier start */
5516 0xEA970182,  /*   89   Ll, hasUpper (subtract -86), identifier start */
5517 0xE7170182,  /*   90   Ll, hasUpper (subtract -100), identifier start */
5518 0xE0170182,  /*   91   Ll, hasUpper (subtract -128), identifier start */
5519 0xE4170182,  /*   92   Ll, hasUpper (subtract -112), identifier start */
5520 0xE0970182,  /*   93   Ll, hasUpper (subtract -126), identifier start */
5521 0xFDD70182,  /*   94   Ll, hasUpper (subtract -9), identifier start */
5522 0xEDA70181,  /*   95   Lu, hasLower (add -74), identifier start */
5523 0xFDE70181,  /*   96   Lu, hasLower (add -9), identifier start */
5524 0xEAA70181,  /*   97   Lu, hasLower (add -86), identifier start */
5525 0xE7270181,  /*   98   Lu, hasLower (add -100), identifier start */
5526 0xFE570182,  /*   99   Ll, hasUpper (subtract -7), identifier start */
5527 0xE4270181,  /*  100   Lu, hasLower (add -112), identifier start */
5528 0xFE670181,  /*  101   Lu, hasLower (add -7), identifier start */
5529 0xE0270181,  /*  102   Lu, hasLower (add -128), identifier start */
5530 0xE0A70181,  /*  103   Lu, hasLower (add -126), identifier start */
5531 0x00010010,  /*  104   Cf, ignorable */
5532 0x0004000D,  /*  105   Zl, whitespace */
5533 0x0004000E,  /*  106   Zp, whitespace */
5534 0x0000400B,  /*  107   No, decimal 0 */
5535 0x0000440B,  /*  108   No, decimal 2 */
5536 0x0427438A,  /*  109   Nl, hasLower (add 16), identifier start, decimal 1 */
5537 0x0427818A,  /*  110   Nl, hasLower (add 16), identifier start, strange */
5538 0x0417638A,  /*  111   Nl, hasUpper (subtract 16), identifier start, decimal 17 */
5539 0x0417818A,  /*  112   Nl, hasUpper (subtract 16), identifier start, strange */
5540 0x0007818A,  /*  113   Nl, identifier start, strange */
5541 0x0000420B,  /*  114   No, decimal 1 */
5542 0x0000720B,  /*  115   No, decimal 25 */
5543 0x06A0001C,  /*  116   So, hasLower (add 26) */
5544 0x0690001C,  /*  117   So, hasUpper (subtract 26) */
5545 0x00006C0B,  /*  118   No, decimal 22 */
5546 0x0000560B,  /*  119   No, decimal 11 */
5547 0x0007738A,  /*  120   Nl, identifier start, decimal 25 */
5548 0x0007418A,  /*  121   Nl, identifier start, decimal 0 */
5549 0x00000013,  /*  122   Cs */
5550 0x00000012   /*  123   Co */
5551 };
5552
5553 const jschar js_uriReservedPlusPound_ucstr[] =
5554     {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
5555 const jschar js_uriUnescaped_ucstr[] =
5556     {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
5557      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
5558      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
5559      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5560      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
5561      '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
5562
5563 /*
5564  * This table allows efficient testing for the regular expression \w which is
5565  * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z].
5566  */
5567 const bool js_alnum[] = {
5568 /*       0      1      2      3      4      5      5      7      8      9      */
5569 /*  0 */ false, false, false, false, false, false, false, false, false, false,
5570 /*  1 */ false, false, false, false, false, false, false, false, false, false,
5571 /*  2 */ false, false, false, false, false, false, false, false, false, false,
5572 /*  3 */ false, false, false, false, false, false, false, false, false, false,
5573 /*  4 */ false, false, false, false, false, false, false, false, true,  true,
5574 /*  5 */ true,  true,  true,  true,  true,  true,  true,  true,  false, false,
5575 /*  6 */ false, false, false, false, false, true,  true,  true,  true,  true,
5576 /*  7 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
5577 /*  8 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
5578 /*  9 */ true,  false, false, false, false, true,  false, true,  true,  true,
5579 /* 10 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
5580 /* 11 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
5581 /* 12 */ true,  true,  true,  false, false, false, false, false
5582 };
5583
5584 #define URI_CHUNK 64U
5585
5586 static inline bool
5587 TransferBufferToString(JSContext *cx, StringBuffer &sb, Value *rval)
5588 {
5589     JSString *str = sb.finishString();
5590     if (!str)
5591         return false;
5592     rval->setString(str);
5593     return true;;
5594 }
5595
5596 /*
5597  * ECMA 3, 15.1.3 URI Handling Function Properties
5598  *
5599  * The following are implementations of the algorithms
5600  * given in the ECMA specification for the hidden functions
5601  * 'Encode' and 'Decode'.
5602  */
5603 static JSBool
5604 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
5605        const jschar *unescapedSet2, Value *rval)
5606 {
5607     static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
5608
5609     size_t length = str->length();
5610     const jschar *chars = str->getChars(cx);
5611     if (!chars)
5612         return JS_FALSE;
5613
5614     if (length == 0) {
5615         rval->setString(cx->runtime->emptyString);
5616         return JS_TRUE;
5617     }
5618
5619     StringBuffer sb(cx);
5620     jschar hexBuf[4];
5621     hexBuf[0] = '%';
5622     hexBuf[3] = 0;
5623     for (size_t k = 0; k < length; k++) {
5624         jschar c = chars[k];
5625         if (js_strchr(unescapedSet, c) ||
5626             (unescapedSet2 && js_strchr(unescapedSet2, c))) {
5627             if (!sb.append(c))
5628                 return JS_FALSE;
5629         } else {
5630             if ((c >= 0xDC00) && (c <= 0xDFFF)) {
5631                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5632                                  JSMSG_BAD_URI, NULL);
5633                 return JS_FALSE;
5634             }
5635             uint32 v;
5636             if (c < 0xD800 || c > 0xDBFF) {
5637                 v = c;
5638             } else {
5639                 k++;
5640                 if (k == length) {
5641                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5642                                      JSMSG_BAD_URI, NULL);
5643                     return JS_FALSE;
5644                 }
5645                 jschar c2 = chars[k];
5646                 if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
5647                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5648                                      JSMSG_BAD_URI, NULL);
5649                     return JS_FALSE;
5650                 }
5651                 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
5652             }
5653             uint8 utf8buf[4];
5654             size_t L = js_OneUcs4ToUtf8Char(utf8buf, v);
5655             for (size_t j = 0; j < L; j++) {
5656                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
5657                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
5658                 if (!sb.append(hexBuf, 3))
5659                     return JS_FALSE;
5660             }
5661         }
5662     }
5663
5664     return TransferBufferToString(cx, sb, rval);
5665 }
5666
5667 static JSBool
5668 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, Value *rval)
5669 {
5670     size_t length = str->length();
5671     const jschar *chars = str->getChars(cx);
5672     if (!chars)
5673         return JS_FALSE;
5674
5675     if (length == 0) {
5676         rval->setString(cx->runtime->emptyString);
5677         return JS_TRUE;
5678     }
5679
5680     StringBuffer sb(cx);
5681     for (size_t k = 0; k < length; k++) {
5682         jschar c = chars[k];
5683         if (c == '%') {
5684             size_t start = k;
5685             if ((k + 2) >= length)
5686                 goto report_bad_uri;
5687             if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5688                 goto report_bad_uri;
5689             jsuint B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5690             k += 2;
5691             if (!(B & 0x80)) {
5692                 c = (jschar)B;
5693             } else {
5694                 intN n = 1;
5695                 while (B & (0x80 >> n))
5696                     n++;
5697                 if (n == 1 || n > 4)
5698                     goto report_bad_uri;
5699                 uint8 octets[4];
5700                 octets[0] = (uint8)B;
5701                 if (k + 3 * (n - 1) >= length)
5702                     goto report_bad_uri;
5703                 for (intN j = 1; j < n; j++) {
5704                     k++;
5705                     if (chars[k] != '%')
5706                         goto report_bad_uri;
5707                     if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
5708                         goto report_bad_uri;
5709                     B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
5710                     if ((B & 0xC0) != 0x80)
5711                         goto report_bad_uri;
5712                     k += 2;
5713                     octets[j] = (char)B;
5714                 }
5715                 uint32 v = Utf8ToOneUcs4Char(octets, n);
5716                 if (v >= 0x10000) {
5717                     v -= 0x10000;
5718                     if (v > 0xFFFFF)
5719                         goto report_bad_uri;
5720                     c = (jschar)((v & 0x3FF) + 0xDC00);
5721                     jschar H = (jschar)((v >> 10) + 0xD800);
5722                     if (!sb.append(H))
5723                         return JS_FALSE;
5724                 } else {
5725                     c = (jschar)v;
5726                 }
5727             }
5728             if (js_strchr(reservedSet, c)) {
5729                 if (!sb.append(chars + start, k - start + 1))
5730                     return JS_FALSE;
5731             } else {
5732                 if (!sb.append(c))
5733                     return JS_FALSE;
5734             }
5735         } else {
5736             if (!sb.append(c))
5737                 return JS_FALSE;
5738         }
5739     }
5740
5741     return TransferBufferToString(cx, sb, rval);
5742
5743   report_bad_uri:
5744     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
5745     /* FALL THROUGH */
5746
5747     return JS_FALSE;
5748 }
5749
5750 static JSBool
5751 str_decodeURI(JSContext *cx, uintN argc, Value *vp)
5752 {
5753     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5754     if (!str)
5755         return JS_FALSE;
5756     return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp);
5757 }
5758
5759 static JSBool
5760 str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp)
5761 {
5762     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5763     if (!str)
5764         return JS_FALSE;
5765     return Decode(cx, str, js_empty_ucstr, vp);
5766 }
5767
5768 static JSBool
5769 str_encodeURI(JSContext *cx, uintN argc, Value *vp)
5770 {
5771     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5772     if (!str)
5773         return JS_FALSE;
5774     return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
5775                   vp);
5776 }
5777
5778 static JSBool
5779 str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp)
5780 {
5781     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
5782     if (!str)
5783         return JS_FALSE;
5784     return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp);
5785 }
5786
5787 /*
5788  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
5789  * least 4 bytes long.  Return the number of UTF-8 bytes of data written.
5790  */
5791 int
5792 js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
5793 {
5794     int utf8Length = 1;
5795
5796     JS_ASSERT(ucs4Char <= 0x10FFFF);
5797     if (ucs4Char < 0x80) {
5798         *utf8Buffer = (uint8)ucs4Char;
5799     } else {
5800         int i;
5801         uint32 a = ucs4Char >> 11;
5802         utf8Length = 2;
5803         while (a) {
5804             a >>= 5;
5805             utf8Length++;
5806         }
5807         i = utf8Length;
5808         while (--i) {
5809             utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
5810             ucs4Char >>= 6;
5811         }
5812         *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
5813     }
5814     return utf8Length;
5815 }
5816
5817 /*
5818  * Convert a utf8 character sequence into a UCS-4 character and return that
5819  * character.  It is assumed that the caller already checked that the sequence
5820  * is valid.
5821  */
5822 static uint32
5823 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
5824 {
5825     uint32 ucs4Char;
5826     uint32 minucs4Char;
5827     /* from Unicode 3.1, non-shortest form is illegal */
5828     static const uint32 minucs4Table[] = {
5829         0x00000080, 0x00000800, 0x00010000
5830     };
5831
5832     JS_ASSERT(utf8Length >= 1 && utf8Length <= 4);
5833     if (utf8Length == 1) {
5834         ucs4Char = *utf8Buffer;
5835         JS_ASSERT(!(ucs4Char & 0x80));
5836     } else {
5837         JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
5838                   (0x100 - (1 << (8-utf8Length))));
5839         ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
5840         minucs4Char = minucs4Table[utf8Length-2];
5841         while (--utf8Length) {
5842             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
5843             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
5844         }
5845         if (JS_UNLIKELY(ucs4Char < minucs4Char)) {
5846             ucs4Char = OVERLONG_UTF8;
5847         } else if (ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
5848             ucs4Char = 0xFFFD;
5849         }
5850     }
5851     return ucs4Char;
5852 }
5853
5854 namespace js {
5855
5856 size_t
5857 PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, JSLinearString *str, uint32 quote)
5858 {
5859     enum {
5860         STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
5861     } state;
5862
5863     JS_ASSERT(quote == 0 || quote == '\'' || quote == '"');
5864     JS_ASSERT_IF(!buffer, bufferSize == 0);
5865     JS_ASSERT_IF(fp, !buffer);
5866
5867     if (bufferSize == 0)
5868         buffer = NULL;
5869     else
5870         bufferSize--;
5871
5872     const jschar *chars = str->chars();
5873     const jschar *charsEnd = chars + str->length();
5874     size_t n = 0;
5875     state = FIRST_QUOTE;
5876     uintN shift = 0;
5877     uintN hex = 0;
5878     uintN u = 0;
5879     char c = 0;  /* to quell GCC warnings */
5880
5881     for (;;) {
5882         switch (state) {
5883           case STOP:
5884             goto stop;
5885           case FIRST_QUOTE:
5886             state = CHARS;
5887             goto do_quote;
5888           case LAST_QUOTE:
5889             state = STOP;
5890           do_quote:
5891             if (quote == 0)
5892                 continue;
5893             c = (char)quote;
5894             break;
5895           case CHARS:
5896             if (chars == charsEnd) {
5897                 state = LAST_QUOTE;
5898                 continue;
5899             }
5900             u = *chars++;
5901             if (u < ' ') {
5902                 if (u != 0) {
5903                     const char *escape = strchr(js_EscapeMap, (int)u);
5904                     if (escape) {
5905                         u = escape[1];
5906                         goto do_escape;
5907                     }
5908                 }
5909                 goto do_hex_escape;
5910             }
5911             if (u < 127) {
5912                 if (u == quote || u == '\\')
5913                     goto do_escape;
5914                 c = (char)u;
5915             } else if (u < 0x100) {
5916                 goto do_hex_escape;
5917             } else {
5918                 shift = 16;
5919                 hex = u;
5920                 u = 'u';
5921                 goto do_escape;
5922             }
5923             break;
5924           do_hex_escape:
5925             shift = 8;
5926             hex = u;
5927             u = 'x';
5928           do_escape:
5929             c = '\\';
5930             state = ESCAPE_START;
5931             break;
5932           case ESCAPE_START:
5933             JS_ASSERT(' ' <= u && u < 127);
5934             c = (char)u;
5935             state = ESCAPE_MORE;
5936             break;
5937           case ESCAPE_MORE:
5938             if (shift == 0) {
5939                 state = CHARS;
5940                 continue;
5941             }
5942             shift -= 4;
5943             u = 0xF & (hex >> shift);
5944             c = (char)(u + (u < 10 ? '0' : 'A' - 10));
5945             break;
5946         }
5947         if (buffer) {
5948             JS_ASSERT(n <= bufferSize);
5949             if (n != bufferSize) {
5950                 buffer[n] = c;
5951             } else {
5952                 buffer[n] = '\0';
5953                 buffer = NULL;
5954             }
5955         } else if (fp) {
5956             if (fputc(c, fp) < 0)
5957                 return size_t(-1);
5958         }
5959         n++;
5960     }
5961   stop:
5962     if (buffer)
5963         buffer[n] = '\0';
5964     return n;
5965 }
5966
5967 } /* namespace js */