Back to index

lightning-sunbird  0.9+nobinonly
jsstr.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=80:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042  * JS string type implementation.
00043  *
00044  * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
00045  * native methods store strings (possibly newborn) converted from their 'this'
00046  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
00047  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
00048  * of rooting things that might lose their newborn root due to subsequent GC
00049  * allocations in the same native method.
00050  */
00051 #include "jsstddef.h"
00052 #include <stdlib.h>
00053 #include <string.h>
00054 #include "jstypes.h"
00055 #include "jsutil.h" /* Added by JSIFY */
00056 #include "jshash.h" /* Added by JSIFY */
00057 #include "jsprf.h"
00058 #include "jsapi.h"
00059 #include "jsarray.h"
00060 #include "jsatom.h"
00061 #include "jsbool.h"
00062 #include "jscntxt.h"
00063 #include "jsconfig.h"
00064 #include "jsgc.h"
00065 #include "jsinterp.h"
00066 #include "jslock.h"
00067 #include "jsnum.h"
00068 #include "jsobj.h"
00069 #include "jsopcode.h"
00070 #include "jsregexp.h"
00071 #include "jsstr.h"
00072 
00073 #define JSSTRDEP_RECURSION_LIMIT        100
00074 
00075 size_t
00076 js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
00077 {
00078     JSString *base;
00079     size_t start, length;
00080 
00081     JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
00082     base = JSSTRDEP_BASE(str);
00083     start = JSSTRDEP_START(str);
00084     if (JSSTRING_IS_DEPENDENT(base)) {
00085         if (level < JSSTRDEP_RECURSION_LIMIT) {
00086             start += js_MinimizeDependentStrings(base, level + 1, &base);
00087         } else {
00088             do {
00089                 start += JSSTRDEP_START(base);
00090                 base = JSSTRDEP_BASE(base);
00091             } while (JSSTRING_IS_DEPENDENT(base));
00092         }
00093         if (start == 0) {
00094             JS_ASSERT(JSSTRING_IS_PREFIX(str));
00095             JSPREFIX_SET_BASE(str, base);
00096         } else if (start <= JSSTRDEP_START_MASK) {
00097             length = JSSTRDEP_LENGTH(str);
00098             JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
00099             JSSTRDEP_SET_BASE(str, base);
00100         }
00101     }
00102     *basep = base;
00103     return start;
00104 }
00105 
00106 jschar *
00107 js_GetDependentStringChars(JSString *str)
00108 {
00109     size_t start;
00110     JSString *base;
00111 
00112     start = js_MinimizeDependentStrings(str, 0, &base);
00113     JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
00114     JS_ASSERT(start < base->length);
00115     return base->chars + start;
00116 }
00117 
00118 jschar *
00119 js_GetStringChars(JSString *str)
00120 {
00121     if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(NULL, str))
00122         return NULL;
00123 
00124     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
00125     return str->chars;
00126 }
00127 
00128 JSString *
00129 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
00130 {
00131     size_t rn, ln, lrdist, n;
00132     jschar *rs, *ls, *s;
00133     JSDependentString *ldep;    /* non-null if left should become dependent */
00134     JSString *str;
00135 
00136     if (JSSTRING_IS_DEPENDENT(right)) {
00137         rn = JSSTRDEP_LENGTH(right);
00138         rs = JSSTRDEP_CHARS(right);
00139     } else {
00140         rn = right->length;
00141         rs = right->chars;
00142     }
00143     if (rn == 0)
00144         return left;
00145 
00146     if (JSSTRING_IS_DEPENDENT(left) ||
00147         !(*js_GetGCThingFlags(left) & GCF_MUTABLE)) {
00148         /* We must copy if left does not own a buffer to realloc. */
00149         ln = JSSTRING_LENGTH(left);
00150         if (ln == 0)
00151             return right;
00152         ls = JSSTRING_CHARS(left);
00153         s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
00154         if (!s)
00155             return NULL;
00156         js_strncpy(s, ls, ln);
00157         ldep = NULL;
00158     } else {
00159         /* We can realloc left's space and make it depend on our result. */
00160         ln = left->length;
00161         if (ln == 0)
00162             return right;
00163         ls = left->chars;
00164         s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
00165         if (!s)
00166             return NULL;
00167 
00168         /* Take care: right could depend on left! */
00169         lrdist = (size_t)(rs - ls);
00170         if (lrdist < ln)
00171             rs = s + lrdist;
00172         left->chars = ls = s;
00173         ldep = JSSTRDEP(left);
00174     }
00175 
00176     js_strncpy(s + ln, rs, rn);
00177     n = ln + rn;
00178     s[n] = 0;
00179     str = js_NewString(cx, s, n, GCF_MUTABLE);
00180     if (!str) {
00181         /* Out of memory: clean up any space we (re-)allocated. */
00182         if (!ldep) {
00183             JS_free(cx, s);
00184         } else {
00185             s = JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
00186             if (s)
00187                 left->chars = s;
00188         }
00189     } else {
00190         /* Morph left into a dependent prefix if we realloc'd its buffer. */
00191         if (ldep) {
00192             JSPREFIX_SET_LENGTH(ldep, ln);
00193             JSPREFIX_SET_BASE(ldep, str);
00194 #ifdef DEBUG
00195           {
00196             JSRuntime *rt = cx->runtime;
00197             JS_RUNTIME_METER(rt, liveDependentStrings);
00198             JS_RUNTIME_METER(rt, totalDependentStrings);
00199             JS_LOCK_RUNTIME_VOID(rt,
00200                 (rt->strdepLengthSum += (double)ln,
00201                  rt->strdepLengthSquaredSum += (double)ln * (double)ln));
00202           }
00203 #endif
00204         }
00205     }
00206 
00207     return str;
00208 }
00209 
00210 /*
00211  * May be called with null cx by js_GetStringChars, above; and by the jslock.c
00212  * MAKE_STRING_IMMUTABLE file-local macro.
00213  */
00214 const jschar *
00215 js_UndependString(JSContext *cx, JSString *str)
00216 {
00217     size_t n, size;
00218     jschar *s;
00219 
00220     if (JSSTRING_IS_DEPENDENT(str)) {
00221         n = JSSTRDEP_LENGTH(str);
00222         size = (n + 1) * sizeof(jschar);
00223         s = (jschar *) (cx ? JS_malloc(cx, size) : malloc(size));
00224         if (!s)
00225             return NULL;
00226 
00227         js_strncpy(s, JSSTRDEP_CHARS(str), n);
00228         s[n] = 0;
00229         str->length = n;
00230         str->chars = s;
00231 
00232 #ifdef DEBUG
00233         if (cx) {
00234             JSRuntime *rt = cx->runtime;
00235             JS_RUNTIME_UNMETER(rt, liveDependentStrings);
00236             JS_RUNTIME_UNMETER(rt, totalDependentStrings);
00237             JS_LOCK_RUNTIME_VOID(rt,
00238                 (rt->strdepLengthSum -= (double)n,
00239                  rt->strdepLengthSquaredSum -= (double)n * (double)n));
00240         }
00241 #endif
00242     }
00243 
00244     return str->chars;
00245 }
00246 
00247 /*
00248  * Forward declarations for URI encode/decode and helper routines
00249  */
00250 static JSBool
00251 str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00252               jsval *rval);
00253 
00254 static JSBool
00255 str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00256                         jsval *rval);
00257 
00258 static JSBool
00259 str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00260               jsval *rval);
00261 
00262 static JSBool
00263 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00264                         jsval *rval);
00265 
00266 static uint32
00267 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
00268 
00269 /*
00270  * Contributions from the String class to the set of methods defined for the
00271  * global object.  escape and unescape used to be defined in the Mocha library,
00272  * but as ECMA decided to spec them, they've been moved to the core engine
00273  * and made ECMA-compliant.  (Incomplete escapes are interpreted as literal
00274  * characters by unescape.)
00275  */
00276 
00277 /*
00278  * Stuff to emulate the old libmocha escape, which took a second argument
00279  * giving the type of escape to perform.  Retained for compatibility, and
00280  * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
00281  */
00282 
00283 #define URL_XALPHAS     ((uint8) 1)
00284 #define URL_XPALPHAS    ((uint8) 2)
00285 #define URL_PATH        ((uint8) 4)
00286 
00287 static const uint8 urlCharType[256] =
00288 /*      Bit 0           xalpha          -- the alphas
00289  *      Bit 1           xpalpha         -- as xalpha but
00290  *                             converts spaces to plus and plus to %20
00291  *      Bit 2 ...       path            -- as xalphas but doesn't escape '/'
00292  */
00293     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
00294     {    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 0x */
00295          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 1x */
00296          0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,       /* 2x   !"#$%&'()*+,-./  */
00297          7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,       /* 3x  0123456789:;<=>?  */
00298          7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 4x  @ABCDEFGHIJKLMNO  */
00299          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,       /* 5X  PQRSTUVWXYZ[\]^_  */
00300          0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 6x  `abcdefghijklmno  */
00301          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,       /* 7X  pqrstuvwxyz{\}~  DEL */
00302          0, };
00303 
00304 /* This matches the ECMA escape set when mask is 7 (default.) */
00305 
00306 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
00307 
00308 /* See ECMA-262 15.1.2.4. */
00309 JSBool
00310 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00311 {
00312     JSString *str;
00313     size_t i, ni, length, newlength;
00314     const jschar *chars;
00315     jschar *newchars;
00316     jschar ch;
00317     jsint mask;
00318     jsdouble d;
00319     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
00320                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00321 
00322     mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
00323     if (argc > 1) {
00324         if (!js_ValueToNumber(cx, argv[1], &d))
00325             return JS_FALSE;
00326         if (!JSDOUBLE_IS_FINITE(d) ||
00327             (mask = (jsint)d) != d ||
00328             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
00329         {
00330             char numBuf[12];
00331             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
00332             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
00333                                  JSMSG_BAD_STRING_MASK, numBuf);
00334             return JS_FALSE;
00335         }
00336     }
00337 
00338     str = js_ValueToString(cx, argv[0]);
00339     if (!str)
00340         return JS_FALSE;
00341     argv[0] = STRING_TO_JSVAL(str);
00342 
00343     chars = JSSTRING_CHARS(str);
00344     length = newlength = JSSTRING_LENGTH(str);
00345 
00346     /* Take a first pass and see how big the result string will need to be. */
00347     for (i = 0; i < length; i++) {
00348         if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
00349             continue;
00350         if (ch < 256) {
00351             if (mask == URL_XPALPHAS && ch == ' ')
00352                 continue;   /* The character will be encoded as '+' */
00353             newlength += 2; /* The character will be encoded as %XX */
00354         } else {
00355             newlength += 5; /* The character will be encoded as %uXXXX */
00356         }
00357 
00358         /*
00359          * This overflow test works because newlength is incremented by at
00360          * most 5 on each iteration.
00361          */
00362         if (newlength < length) {
00363             JS_ReportOutOfMemory(cx);
00364             return JS_FALSE;
00365         }
00366     }
00367 
00368     if (newlength >= ~(size_t)0 / sizeof(jschar)) {
00369         JS_ReportOutOfMemory(cx);
00370         return JS_FALSE;
00371     }
00372 
00373     newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
00374     if (!newchars)
00375         return JS_FALSE;
00376     for (i = 0, ni = 0; i < length; i++) {
00377         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
00378             newchars[ni++] = ch;
00379         } else if (ch < 256) {
00380             if (mask == URL_XPALPHAS && ch == ' ') {
00381                 newchars[ni++] = '+'; /* convert spaces to pluses */
00382             } else {
00383                 newchars[ni++] = '%';
00384                 newchars[ni++] = digits[ch >> 4];
00385                 newchars[ni++] = digits[ch & 0xF];
00386             }
00387         } else {
00388             newchars[ni++] = '%';
00389             newchars[ni++] = 'u';
00390             newchars[ni++] = digits[ch >> 12];
00391             newchars[ni++] = digits[(ch & 0xF00) >> 8];
00392             newchars[ni++] = digits[(ch & 0xF0) >> 4];
00393             newchars[ni++] = digits[ch & 0xF];
00394         }
00395     }
00396     JS_ASSERT(ni == newlength);
00397     newchars[newlength] = 0;
00398 
00399     str = js_NewString(cx, newchars, newlength, 0);
00400     if (!str) {
00401         JS_free(cx, newchars);
00402         return JS_FALSE;
00403     }
00404     *rval = STRING_TO_JSVAL(str);
00405     return JS_TRUE;
00406 }
00407 #undef IS_OK
00408 
00409 /* See ECMA-262 15.1.2.5 */
00410 static JSBool
00411 str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00412 {
00413     JSString *str;
00414     size_t i, ni, length;
00415     const jschar *chars;
00416     jschar *newchars;
00417     jschar ch;
00418 
00419     str = js_ValueToString(cx, argv[0]);
00420     if (!str)
00421         return JS_FALSE;
00422     argv[0] = STRING_TO_JSVAL(str);
00423 
00424     chars = JSSTRING_CHARS(str);
00425     length = JSSTRING_LENGTH(str);
00426 
00427     /* Don't bother allocating less space for the new string. */
00428     newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
00429     if (!newchars)
00430         return JS_FALSE;
00431     ni = i = 0;
00432     while (i < length) {
00433         ch = chars[i++];
00434         if (ch == '%') {
00435             if (i + 1 < length &&
00436                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
00437             {
00438                 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
00439                 i += 2;
00440             } else if (i + 4 < length && chars[i] == 'u' &&
00441                        JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
00442                        JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
00443             {
00444                 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
00445                         + JS7_UNHEX(chars[i + 2])) << 4)
00446                       + JS7_UNHEX(chars[i + 3])) << 4)
00447                     + JS7_UNHEX(chars[i + 4]);
00448                 i += 5;
00449             }
00450         }
00451         newchars[ni++] = ch;
00452     }
00453     newchars[ni] = 0;
00454 
00455     str = js_NewString(cx, newchars, ni, 0);
00456     if (!str) {
00457         JS_free(cx, newchars);
00458         return JS_FALSE;
00459     }
00460     *rval = STRING_TO_JSVAL(str);
00461     return JS_TRUE;
00462 }
00463 
00464 #if JS_HAS_UNEVAL
00465 static JSBool
00466 str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00467 {
00468     JSString *str;
00469 
00470     str = js_ValueToSource(cx, argv[0]);
00471     if (!str)
00472         return JS_FALSE;
00473     *rval = STRING_TO_JSVAL(str);
00474     return JS_TRUE;
00475 }
00476 #endif
00477 
00478 const char js_escape_str[] = "escape";
00479 const char js_unescape_str[] = "unescape";
00480 #if JS_HAS_UNEVAL
00481 const char js_uneval_str[] = "uneval";
00482 #endif
00483 const char js_decodeURI_str[] = "decodeURI";
00484 const char js_encodeURI_str[] = "encodeURI";
00485 const char js_decodeURIComponent_str[] = "decodeURIComponent";
00486 const char js_encodeURIComponent_str[] = "encodeURIComponent";
00487 
00488 static JSFunctionSpec string_functions[] = {
00489     {js_escape_str,             js_str_escape,              1,0,0},
00490     {js_unescape_str,           str_unescape,               1,0,0},
00491 #if JS_HAS_UNEVAL
00492     {js_uneval_str,             str_uneval,                 1,0,0},
00493 #endif
00494     {js_decodeURI_str,          str_decodeURI,              1,0,0},
00495     {js_encodeURI_str,          str_encodeURI,              1,0,0},
00496     {js_decodeURIComponent_str, str_decodeURI_Component,    1,0,0},
00497     {js_encodeURIComponent_str, str_encodeURI_Component,    1,0,0},
00498 
00499     {0,0,0,0,0}
00500 };
00501 
00502 jschar      js_empty_ucstr[]  = {0};
00503 JSSubString js_EmptySubString = {0, js_empty_ucstr};
00504 
00505 enum string_tinyid {
00506     STRING_LENGTH = -1
00507 };
00508 
00509 static JSPropertySpec string_props[] = {
00510     {js_length_str,     STRING_LENGTH,
00511                         JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0},
00512     {0,0,0,0,0}
00513 };
00514 
00515 static JSBool
00516 str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00517 {
00518     jsval v;
00519     JSString *str;
00520     jsint slot;
00521 
00522     if (!JSVAL_IS_INT(id))
00523         return JS_TRUE;
00524 
00525     slot = JSVAL_TO_INT(id);
00526     if (slot == STRING_LENGTH) {
00527         if (OBJ_GET_CLASS(cx, obj) == &js_StringClass) {
00528             /* Follow ECMA-262 by fetching intrinsic length of our string. */
00529             v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00530             JS_ASSERT(JSVAL_IS_STRING(v));
00531             str = JSVAL_TO_STRING(v);
00532         } else {
00533             /* Preserve compatibility: convert obj to a string primitive. */
00534             str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00535             if (!str)
00536                 return JS_FALSE;
00537         }
00538 
00539         *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
00540     }
00541     return JS_TRUE;
00542 }
00543 
00544 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
00545 
00546 static JSBool
00547 str_enumerate(JSContext *cx, JSObject *obj)
00548 {
00549     jsval v;
00550     JSString *str, *str1;
00551     size_t i, length;
00552 
00553     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00554     JS_ASSERT(JSVAL_IS_STRING(v));
00555     str = JSVAL_TO_STRING(v);
00556 
00557     length = JSSTRING_LENGTH(str);
00558     for (i = 0; i < length; i++) {
00559         str1 = js_NewDependentString(cx, str, i, 1, 0);
00560         if (!str1)
00561             return JS_FALSE;
00562         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(i),
00563                                  STRING_TO_JSVAL(str1), NULL, NULL,
00564                                  STRING_ELEMENT_ATTRS, NULL)) {
00565             return JS_FALSE;
00566         }
00567     }
00568     return JS_TRUE;
00569 }
00570 
00571 static JSBool
00572 str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
00573             JSObject **objp)
00574 {
00575     jsval v;
00576     JSString *str, *str1;
00577     jsint slot;
00578 
00579     if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING))
00580         return JS_TRUE;
00581 
00582     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00583     JS_ASSERT(JSVAL_IS_STRING(v));
00584     str = JSVAL_TO_STRING(v);
00585 
00586     slot = JSVAL_TO_INT(id);
00587     if ((size_t)slot < JSSTRING_LENGTH(str)) {
00588         str1 = js_NewDependentString(cx, str, (size_t)slot, 1, 0);
00589         if (!str1)
00590             return JS_FALSE;
00591         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(slot),
00592                                  STRING_TO_JSVAL(str1), NULL, NULL,
00593                                  STRING_ELEMENT_ATTRS, NULL)) {
00594             return JS_FALSE;
00595         }
00596         *objp = obj;
00597     }
00598     return JS_TRUE;
00599 }
00600 
00601 JSClass js_StringClass = {
00602     js_String_str,
00603     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
00604     JSCLASS_HAS_CACHED_PROTO(JSProto_String),
00605     JS_PropertyStub,   JS_PropertyStub,   str_getProperty,   JS_PropertyStub,
00606     str_enumerate, (JSResolveOp)str_resolve, JS_ConvertStub, JS_FinalizeStub,
00607     JSCLASS_NO_OPTIONAL_MEMBERS
00608 };
00609 
00610 #if JS_HAS_TOSOURCE
00611 
00612 /*
00613  * String.prototype.quote is generic (as are most string methods), unlike
00614  * toSource, toString, and valueOf.
00615  */
00616 static JSBool
00617 str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00618 {
00619     JSString *str;
00620 
00621     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00622     if (!str)
00623         return JS_FALSE;
00624     argv[-1] = STRING_TO_JSVAL(str);
00625 
00626     str = js_QuoteString(cx, str, '"');
00627     if (!str)
00628         return JS_FALSE;
00629     *rval = STRING_TO_JSVAL(str);
00630     return JS_TRUE;
00631 }
00632 
00633 static JSBool
00634 str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00635 {
00636     jsval v;
00637     JSString *str;
00638     size_t i, j, k, n;
00639     char buf[16];
00640     jschar *s, *t;
00641 
00642     if (JSVAL_IS_STRING((jsval)obj)) {
00643         v = (jsval)obj;
00644     } else {
00645         if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
00646             return JS_FALSE;
00647         v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00648         if (!JSVAL_IS_STRING(v))
00649             return js_obj_toSource(cx, obj, argc, argv, rval);
00650     }
00651     str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
00652     if (!str)
00653         return JS_FALSE;
00654     j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name);
00655     s = JSSTRING_CHARS(str);
00656     k = JSSTRING_LENGTH(str);
00657     n = j + k + 2;
00658     t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
00659     if (!t)
00660         return JS_FALSE;
00661     for (i = 0; i < j; i++)
00662         t[i] = buf[i];
00663     for (j = 0; j < k; i++, j++)
00664         t[i] = s[j];
00665     t[i++] = ')';
00666     t[i++] = ')';
00667     t[i] = 0;
00668     str = js_NewString(cx, t, n, 0);
00669     if (!str) {
00670         JS_free(cx, t);
00671         return JS_FALSE;
00672     }
00673     *rval = STRING_TO_JSVAL(str);
00674     return JS_TRUE;
00675 }
00676 
00677 #endif /* JS_HAS_TOSOURCE */
00678 
00679 static JSBool
00680 str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00681 {
00682     jsval v;
00683 
00684     if (JSVAL_IS_STRING((jsval)obj)) {
00685         *rval = (jsval)obj;
00686         return JS_TRUE;
00687     }
00688     if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
00689         return JS_FALSE;
00690     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00691     if (!JSVAL_IS_STRING(v))
00692         return js_obj_toString(cx, obj, argc, argv, rval);
00693     *rval = v;
00694     return JS_TRUE;
00695 }
00696 
00697 static JSBool
00698 str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00699 {
00700     if (JSVAL_IS_STRING((jsval)obj)) {
00701         *rval = (jsval)obj;
00702         return JS_TRUE;
00703     }
00704     if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
00705         return JS_FALSE;
00706     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
00707     return JS_TRUE;
00708 }
00709 
00710 /*
00711  * Java-like string native methods.
00712  */
00713 static JSBool
00714 str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00715               jsval *rval)
00716 {
00717     JSString *str;
00718     jsdouble d;
00719     jsdouble length, begin, end;
00720 
00721     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00722     if (!str)
00723         return JS_FALSE;
00724     argv[-1] = STRING_TO_JSVAL(str);
00725 
00726     if (argc != 0) {
00727         if (!js_ValueToNumber(cx, argv[0], &d))
00728             return JS_FALSE;
00729         length = JSSTRING_LENGTH(str);
00730         begin = js_DoubleToInteger(d);
00731         if (begin < 0)
00732             begin = 0;
00733         else if (begin > length)
00734             begin = length;
00735 
00736         if (argc == 1) {
00737             end = length;
00738         } else {
00739             if (!js_ValueToNumber(cx, argv[1], &d))
00740                 return JS_FALSE;
00741             end = js_DoubleToInteger(d);
00742             if (end < 0)
00743                 end = 0;
00744             else if (end > length)
00745                 end = length;
00746             if (end < begin) {
00747                 /* ECMA emulates old JDK1.0 java.lang.String.substring. */
00748                 jsdouble tmp = begin;
00749                 begin = end;
00750                 end = tmp;
00751             }
00752         }
00753 
00754         str = js_NewDependentString(cx, str, (size_t)begin,
00755                                     (size_t)(end - begin), 0);
00756         if (!str)
00757             return JS_FALSE;
00758     }
00759     *rval = STRING_TO_JSVAL(str);
00760     return JS_TRUE;
00761 }
00762 
00763 static JSBool
00764 str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00765                 jsval *rval)
00766 {
00767     JSString *str;
00768     size_t i, n;
00769     jschar *s, *news;
00770 
00771     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00772     if (!str)
00773         return JS_FALSE;
00774     argv[-1] = STRING_TO_JSVAL(str);
00775 
00776     n = JSSTRING_LENGTH(str);
00777     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
00778     if (!news)
00779         return JS_FALSE;
00780     s = JSSTRING_CHARS(str);
00781     for (i = 0; i < n; i++)
00782         news[i] = JS_TOLOWER(s[i]);
00783     news[n] = 0;
00784     str = js_NewString(cx, news, n, 0);
00785     if (!str) {
00786         JS_free(cx, news);
00787         return JS_FALSE;
00788     }
00789     *rval = STRING_TO_JSVAL(str);
00790     return JS_TRUE;
00791 }
00792 
00793 static JSBool
00794 str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00795                 jsval *rval)
00796 {
00797     JSString *str;
00798 
00799     /*
00800      * Forcefully ignore the first (or any) argument and return toLowerCase(),
00801      * ECMA has reserved that argument, presumably for defining the locale.
00802      */
00803     if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
00804         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00805         if (!str)
00806             return JS_FALSE;
00807         argv[-1] = STRING_TO_JSVAL(str);
00808         return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
00809     }
00810     return str_toLowerCase(cx, obj, 0, argv, rval);
00811 }
00812 
00813 static JSBool
00814 str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00815                 jsval *rval)
00816 {
00817     JSString *str;
00818     size_t i, n;
00819     jschar *s, *news;
00820 
00821     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00822     if (!str)
00823         return JS_FALSE;
00824     argv[-1] = STRING_TO_JSVAL(str);
00825 
00826     n = JSSTRING_LENGTH(str);
00827     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
00828     if (!news)
00829         return JS_FALSE;
00830     s = JSSTRING_CHARS(str);
00831     for (i = 0; i < n; i++)
00832         news[i] = JS_TOUPPER(s[i]);
00833     news[n] = 0;
00834     str = js_NewString(cx, news, n, 0);
00835     if (!str) {
00836         JS_free(cx, news);
00837         return JS_FALSE;
00838     }
00839     *rval = STRING_TO_JSVAL(str);
00840     return JS_TRUE;
00841 }
00842 
00843 static JSBool
00844 str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00845                 jsval *rval)
00846 {
00847     JSString *str;
00848 
00849     /*
00850      * Forcefully ignore the first (or any) argument and return toUpperCase(),
00851      * ECMA has reserved that argument, presumbaly for defining the locale.
00852      */
00853     if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
00854         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00855         if (!str)
00856             return JS_FALSE;
00857         argv[-1] = STRING_TO_JSVAL(str);
00858         return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
00859     }
00860     return str_toUpperCase(cx, obj, 0, argv, rval);
00861 }
00862 
00863 static JSBool
00864 str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00865                   jsval *rval)
00866 {
00867     JSString *str, *thatStr;
00868 
00869     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00870     if (!str)
00871         return JS_FALSE;
00872     argv[-1] = STRING_TO_JSVAL(str);
00873 
00874     if (argc == 0) {
00875         *rval = JSVAL_ZERO;
00876     } else {
00877         thatStr = js_ValueToString(cx, argv[0]);
00878         if (!thatStr)
00879             return JS_FALSE;
00880         if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
00881             argv[0] = STRING_TO_JSVAL(thatStr);
00882             return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
00883         }
00884         *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
00885     }
00886     return JS_TRUE;
00887 }
00888 
00889 static JSBool
00890 str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00891 {
00892     JSString *str;
00893     jsdouble d;
00894     size_t index;
00895 
00896     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00897     if (!str)
00898         return JS_FALSE;
00899     argv[-1] = STRING_TO_JSVAL(str);
00900 
00901     if (argc == 0) {
00902         d = 0.0;
00903     } else {
00904         if (!js_ValueToNumber(cx, argv[0], &d))
00905             return JS_FALSE;
00906         d = js_DoubleToInteger(d);
00907     }
00908 
00909     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
00910         *rval = JS_GetEmptyStringValue(cx);
00911     } else {
00912         index = (size_t)d;
00913         str = js_NewDependentString(cx, str, index, 1, 0);
00914         if (!str)
00915             return JS_FALSE;
00916         *rval = STRING_TO_JSVAL(str);
00917     }
00918     return JS_TRUE;
00919 }
00920 
00921 static JSBool
00922 str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00923                jsval *rval)
00924 {
00925     JSString *str;
00926     jsdouble d;
00927     size_t index;
00928 
00929     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00930     if (!str)
00931         return JS_FALSE;
00932     argv[-1] = STRING_TO_JSVAL(str);
00933 
00934     if (argc == 0) {
00935         d = 0.0;
00936     } else {
00937         if (!js_ValueToNumber(cx, argv[0], &d))
00938             return JS_FALSE;
00939         d = js_DoubleToInteger(d);
00940     }
00941 
00942     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
00943         *rval = JS_GetNaNValue(cx);
00944     } else {
00945         index = (size_t)d;
00946         *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]);
00947     }
00948     return JS_TRUE;
00949 }
00950 
00951 jsint
00952 js_BoyerMooreHorspool(const jschar *text, jsint textlen,
00953                       const jschar *pat, jsint patlen,
00954                       jsint start)
00955 {
00956     jsint i, j, k, m;
00957     uint8 skip[BMH_CHARSET_SIZE];
00958     jschar c;
00959 
00960     JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
00961     for (i = 0; i < BMH_CHARSET_SIZE; i++)
00962         skip[i] = (uint8)patlen;
00963     m = patlen - 1;
00964     for (i = 0; i < m; i++) {
00965         c = pat[i];
00966         if (c >= BMH_CHARSET_SIZE)
00967             return BMH_BAD_PATTERN;
00968         skip[c] = (uint8)(m - i);
00969     }
00970     for (k = start + m;
00971          k < textlen;
00972          k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
00973         for (i = k, j = m; ; i--, j--) {
00974             if (j < 0)
00975                 return i + 1;
00976             if (text[i] != pat[j])
00977                 break;
00978         }
00979     }
00980     return -1;
00981 }
00982 
00983 static JSBool
00984 str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00985 {
00986     JSString *str, *str2;
00987     jsint i, j, index, textlen, patlen;
00988     const jschar *text, *pat;
00989     jsdouble d;
00990 
00991     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
00992     if (!str)
00993         return JS_FALSE;
00994     argv[-1] = STRING_TO_JSVAL(str);
00995     text = JSSTRING_CHARS(str);
00996     textlen = (jsint) JSSTRING_LENGTH(str);
00997 
00998     str2 = js_ValueToString(cx, argv[0]);
00999     if (!str2)
01000         return JS_FALSE;
01001     argv[0] = STRING_TO_JSVAL(str2);
01002     pat = JSSTRING_CHARS(str2);
01003     patlen = (jsint) JSSTRING_LENGTH(str2);
01004 
01005     if (argc > 1) {
01006         if (!js_ValueToNumber(cx, argv[1], &d))
01007             return JS_FALSE;
01008         d = js_DoubleToInteger(d);
01009         if (d < 0)
01010             i = 0;
01011         else if (d > textlen)
01012             i = textlen;
01013         else
01014             i = (jsint)d;
01015     } else {
01016         i = 0;
01017     }
01018     if (patlen == 0) {
01019         *rval = INT_TO_JSVAL(i);
01020         return JS_TRUE;
01021     }
01022 
01023     /* XXX tune the BMH threshold (512) */
01024     if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) {
01025         index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
01026         if (index != BMH_BAD_PATTERN)
01027             goto out;
01028     }
01029 
01030     index = -1;
01031     j = 0;
01032     while (i + j < textlen) {
01033         if (text[i + j] == pat[j]) {
01034             if (++j == patlen) {
01035                 index = i;
01036                 break;
01037             }
01038         } else {
01039             i++;
01040             j = 0;
01041         }
01042     }
01043 
01044 out:
01045     *rval = INT_TO_JSVAL(index);
01046     return JS_TRUE;
01047 }
01048 
01049 static JSBool
01050 str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
01051                   jsval *rval)
01052 {
01053     JSString *str, *str2;
01054     const jschar *text, *pat;
01055     jsint i, j, textlen, patlen;
01056     jsdouble d;
01057 
01058     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
01059     if (!str)
01060         return JS_FALSE;
01061     argv[-1] = STRING_TO_JSVAL(str);
01062     text = JSSTRING_CHARS(str);
01063     textlen = (jsint) JSSTRING_LENGTH(str);
01064 
01065     str2 = js_ValueToString(cx, argv[0]);
01066     if (!str2)
01067         return JS_FALSE;
01068     argv[0] = STRING_TO_JSVAL(str2);
01069     pat = JSSTRING_CHARS(str2);
01070     patlen = (jsint) JSSTRING_LENGTH(str2);
01071 
01072     if (argc > 1) {
01073         if (!js_ValueToNumber(cx, argv[1], &d))
01074             return JS_FALSE;
01075         if (JSDOUBLE_IS_NaN(d)) {
01076             i = textlen;
01077         } else {
01078             d = js_DoubleToInteger(d);
01079             if (d < 0)
01080                 i = 0;
01081             else if (d > textlen)
01082                 i = textlen;
01083             else
01084                 i = (jsint)d;
01085         }
01086     } else {
01087         i = textlen;
01088     }
01089 
01090     if (patlen == 0) {
01091         *rval = INT_TO_JSVAL(i);
01092         return JS_TRUE;
01093     }
01094 
01095     j = 0;
01096     while (i >= 0) {
01097         /* Don't assume that text is NUL-terminated: it could be dependent. */
01098         if (i + j < textlen && text[i + j] == pat[j]) {
01099             if (++j == patlen)
01100                 break;
01101         } else {
01102             i--;
01103             j = 0;
01104         }
01105     }
01106     *rval = INT_TO_JSVAL(i);
01107     return JS_TRUE;
01108 }
01109 
01110 /*
01111  * Perl-inspired string functions.
01112  */
01113 typedef struct GlobData {
01114     uintN       flags;          /* inout: mode and flag bits, see below */
01115     uintN       optarg;         /* in: index of optional flags argument */
01116     JSString    *str;           /* out: 'this' parameter object as string */
01117     JSRegExp    *regexp;        /* out: regexp parameter object private data */
01118 } GlobData;
01119 
01120 /*
01121  * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
01122  */
01123 #define MODE_MATCH      0x00    /* in: return match array on success */
01124 #define MODE_REPLACE    0x01    /* in: match and replace */
01125 #define MODE_SEARCH     0x02    /* in: search only, return match index or -1 */
01126 #define GET_MODE(f)     ((f) & 0x03)
01127 #define FORCE_FLAT      0x04    /* in: force flat (non-regexp) string match */
01128 #define KEEP_REGEXP     0x08    /* inout: keep GlobData.regexp alive for caller
01129                                           of match_or_replace; if set on input
01130                                           but clear on output, regexp ownership
01131                                           does not pass to caller */
01132 #define GLOBAL_REGEXP   0x10    /* out: regexp had the 'g' flag */
01133 
01134 static JSBool
01135 match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
01136                  JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
01137                  GlobData *data, jsval *rval)
01138 {
01139     JSString *str, *src, *opt;
01140     JSObject *reobj;
01141     JSRegExp *re;
01142     size_t index, length;
01143     JSBool ok, test;
01144     jsint count;
01145 
01146     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
01147     if (!str)
01148         return JS_FALSE;
01149     argv[-1] = STRING_TO_JSVAL(str);
01150     data->str = str;
01151 
01152     if (JSVAL_IS_REGEXP(cx, argv[0])) {
01153         reobj = JSVAL_TO_OBJECT(argv[0]);
01154         re = (JSRegExp *) JS_GetPrivate(cx, reobj);
01155     } else {
01156         src = js_ValueToString(cx, argv[0]);
01157         if (!src)
01158             return JS_FALSE;
01159         if (data->optarg < argc) {
01160             argv[0] = STRING_TO_JSVAL(src);
01161             opt = js_ValueToString(cx, argv[data->optarg]);
01162             if (!opt)
01163                 return JS_FALSE;
01164         } else {
01165             opt = NULL;
01166         }
01167         re = js_NewRegExpOpt(cx, NULL, src, opt,
01168                              (data->flags & FORCE_FLAT) != 0);
01169         if (!re)
01170             return JS_FALSE;
01171         reobj = NULL;
01172     }
01173     /* From here on, all control flow must reach the matching DROP. */
01174     data->regexp = re;
01175     HOLD_REGEXP(cx, re);
01176 
01177     if (re->flags & JSREG_GLOB)
01178         data->flags |= GLOBAL_REGEXP;
01179     index = 0;
01180     if (GET_MODE(data->flags) == MODE_SEARCH) {
01181         ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
01182         if (ok) {
01183             *rval = (*rval == JSVAL_TRUE)
01184                     ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
01185                     : INT_TO_JSVAL(-1);
01186         }
01187     } else if (data->flags & GLOBAL_REGEXP) {
01188         if (reobj) {
01189             /* Set the lastIndex property's reserved slot to 0. */
01190             ok = js_SetLastIndex(cx, reobj, 0);
01191         } else {
01192             ok = JS_TRUE;
01193         }
01194         if (ok) {
01195             length = JSSTRING_LENGTH(str);
01196             for (count = 0; index <= length; count++) {
01197                 ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
01198                 if (!ok || *rval != JSVAL_TRUE)
01199                     break;
01200                 ok = glob(cx, count, data);
01201                 if (!ok)
01202                     break;
01203                 if (cx->regExpStatics.lastMatch.length == 0) {
01204                     if (index == length)
01205                         break;
01206                     index++;
01207                 }
01208             }
01209         }
01210     } else {
01211         if (GET_MODE(data->flags) == MODE_REPLACE) {
01212             test = JS_TRUE;
01213         } else {
01214             /*
01215              * MODE_MATCH implies str_match is being called from a script or a
01216              * scripted function.  If the caller cares only about testing null
01217              * vs. non-null return value, optimize away the array object that
01218              * would normally be returned in *rval.
01219              */
01220             JSStackFrame *fp = cx->fp->down;
01221 
01222             /* Skip Function.prototype.call and .apply frames. */
01223             while (fp && !fp->pc) {
01224                 JS_ASSERT(!fp->script);
01225                 fp = fp->down;
01226             }
01227 
01228             /* Assume a full array result is required, then prove otherwise. */
01229             test = JS_FALSE;
01230             if (fp) {
01231                 JS_ASSERT(*fp->pc == JSOP_CALL || *fp->pc == JSOP_NEW);
01232                 JS_ASSERT(js_CodeSpec[*fp->pc].length == 3);
01233                 switch (fp->pc[3]) {
01234                   case JSOP_POP:
01235                   case JSOP_IFEQ:
01236                   case JSOP_IFNE:
01237                   case JSOP_IFEQX:
01238                   case JSOP_IFNEX:
01239                     test = JS_TRUE;
01240                     break;
01241                   default:;
01242                 }
01243             }
01244         }
01245         ok = js_ExecuteRegExp(cx, re, str, &index, test, rval);
01246     }
01247 
01248     DROP_REGEXP(cx, re);
01249     if (reobj) {
01250         /* Tell our caller that it doesn't need to destroy data->regexp. */
01251         data->flags &= ~KEEP_REGEXP;
01252     } else if (!(data->flags & KEEP_REGEXP)) {
01253         /* Caller didn't want to keep data->regexp, so null and destroy it.  */
01254         data->regexp = NULL;
01255         js_DestroyRegExp(cx, re);
01256     }
01257 
01258     return ok;
01259 }
01260 
01261 typedef struct MatchData {
01262     GlobData    base;
01263     jsval       *arrayval;      /* NB: local root pointer */
01264 } MatchData;
01265 
01266 static JSBool
01267 match_glob(JSContext *cx, jsint count, GlobData *data)
01268 {
01269     MatchData *mdata;
01270     JSObject *arrayobj;
01271     JSSubString *matchsub;
01272     JSString *matchstr;
01273     jsval v;
01274 
01275     mdata = (MatchData *)data;
01276     arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
01277     if (!arrayobj) {
01278         arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
01279         if (!arrayobj)
01280             return JS_FALSE;
01281         *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
01282     }
01283     matchsub = &cx->regExpStatics.lastMatch;
01284     matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length, 0);
01285     if (!matchstr)
01286         return JS_FALSE;
01287     v = STRING_TO_JSVAL(matchstr);
01288     return js_SetProperty(cx, arrayobj, INT_TO_JSID(count), &v);
01289 }
01290 
01291 static JSBool
01292 str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01293 {
01294     MatchData mdata;
01295     JSBool ok;
01296 
01297     mdata.base.flags = MODE_MATCH;
01298     mdata.base.optarg = 1;
01299     mdata.arrayval = &argv[2];
01300     *mdata.arrayval = JSVAL_NULL;
01301     ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
01302     if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
01303         *rval = *mdata.arrayval;
01304     return ok;
01305 }
01306 
01307 static JSBool
01308 str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01309 {
01310     GlobData data;
01311 
01312     data.flags = MODE_SEARCH;
01313     data.optarg = 1;
01314     return match_or_replace(cx, obj, argc, argv, NULL, &data, rval);
01315 }
01316 
01317 typedef struct ReplaceData {
01318     GlobData    base;           /* base struct state */
01319     JSObject    *lambda;        /* replacement function object or null */
01320     JSString    *repstr;        /* replacement string */
01321     jschar      *dollar;        /* null or pointer to first $ in repstr */
01322     jschar      *dollarEnd;     /* limit pointer for js_strchr_limit */
01323     jschar      *chars;         /* result chars, null initially */
01324     size_t      length;         /* result length, 0 initially */
01325     jsint       index;          /* index in result of next replacement */
01326     jsint       leftIndex;      /* left context index in base.str->chars */
01327     JSSubString dollarStr;      /* for "$$" interpret_dollar result */
01328 } ReplaceData;
01329 
01330 static JSSubString *
01331 interpret_dollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData *rdata,
01332                  size_t *skip)
01333 {
01334     JSRegExpStatics *res;
01335     jschar dc, *cp;
01336     uintN num, tmp;
01337 
01338     JS_ASSERT(*dp == '$');
01339 
01340     /* If there is only a dollar, bail now */
01341     if (dp + 1 >= ep)
01342         return NULL;
01343 
01344     /* Interpret all Perl match-induced dollar variables. */
01345     res = &cx->regExpStatics;
01346     dc = dp[1];
01347     if (JS7_ISDEC(dc)) {
01348         /* ECMA-262 Edition 3: 1-9 or 01-99 */
01349         num = JS7_UNDEC(dc);
01350         if (num > res->parenCount)
01351             return NULL;
01352 
01353         cp = dp + 2;
01354         if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
01355             tmp = 10 * num + JS7_UNDEC(dc);
01356             if (tmp <= res->parenCount) {
01357                 cp++;
01358                 num = tmp;
01359             }
01360         }
01361         if (num == 0)
01362             return NULL;
01363 
01364         /* Adjust num from 1 $n-origin to 0 array-index-origin. */
01365         num--;
01366         *skip = cp - dp;
01367         return REGEXP_PAREN_SUBSTRING(res, num);
01368     }
01369 
01370     *skip = 2;
01371     switch (dc) {
01372       case '$':
01373         rdata->dollarStr.chars = dp;
01374         rdata->dollarStr.length = 1;
01375         return &rdata->dollarStr;
01376       case '&':
01377         return &res->lastMatch;
01378       case '+':
01379         return &res->lastParen;
01380       case '`':
01381         return &res->leftContext;
01382       case '\'':
01383         return &res->rightContext;
01384     }
01385     return NULL;
01386 }
01387 
01388 static JSBool
01389 find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
01390 {
01391     JSString *repstr;
01392     size_t replen, skip;
01393     jschar *dp, *ep;
01394     JSSubString *sub;
01395     JSObject *lambda;
01396 
01397     lambda = rdata->lambda;
01398     if (lambda) {
01399         uintN argc, i, j, m, n, p;
01400         jsval *sp, *oldsp, rval;
01401         void *mark;
01402         JSStackFrame *fp;
01403         JSBool ok;
01404 
01405         /*
01406          * Save the regExpStatics from the current regexp, since they may be
01407          * clobbered by a RegExp usage in the lambda function.  Note that all
01408          * members of JSRegExpStatics are JSSubStrings, so not GC roots, save
01409          * input, which is rooted otherwise via argv[-1] in str_replace.
01410          */
01411         JSRegExpStatics save = cx->regExpStatics;
01412         JSBool freeMoreParens = JS_FALSE;
01413 
01414         /*
01415          * In the lambda case, not only do we find the replacement string's
01416          * length, we compute repstr and return it via rdata for use within
01417          * do_replace.  The lambda is called with arguments ($&, $1, $2, ...,
01418          * index, input), i.e., all the properties of a regexp match array.
01419          * For $&, etc., we must create string jsvals from cx->regExpStatics.
01420          * We grab up stack space to keep the newborn strings GC-rooted.
01421          */
01422         p = rdata->base.regexp->parenCount;
01423         argc = 1 + p + 2;
01424         sp = js_AllocStack(cx, 2 + argc, &mark);
01425         if (!sp)
01426             return JS_FALSE;
01427 
01428         /* Push lambda and its 'this' parameter. */
01429         *sp++ = OBJECT_TO_JSVAL(lambda);
01430         *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
01431 
01432 #define PUSH_REGEXP_STATIC(sub)                                               \
01433     JS_BEGIN_MACRO                                                            \
01434         JSString *str = js_NewStringCopyN(cx,                                 \
01435                                           cx->regExpStatics.sub.chars,        \
01436                                           cx->regExpStatics.sub.length,       \
01437                                           0);                                 \
01438         if (!str) {                                                           \
01439             ok = JS_FALSE;                                                    \
01440             goto lambda_out;                                                  \
01441         }                                                                     \
01442         *sp++ = STRING_TO_JSVAL(str);                                         \
01443     JS_END_MACRO
01444 
01445         /* Push $&, $1, $2, ... */
01446         PUSH_REGEXP_STATIC(lastMatch);
01447         i = 0;
01448         m = cx->regExpStatics.parenCount;
01449         n = JS_MIN(m, 9);
01450         for (j = 0; i < n; i++, j++)
01451             PUSH_REGEXP_STATIC(parens[j]);
01452         for (j = 0; i < m; i++, j++)
01453             PUSH_REGEXP_STATIC(moreParens[j]);
01454 
01455         /*
01456          * We need to clear moreParens in the top-of-stack cx->regExpStatics
01457          * to it won't be possibly realloc'ed, leaving the bottom-of-stack
01458          * moreParens pointing to freed memory.
01459          */
01460         cx->regExpStatics.moreParens = NULL;
01461         freeMoreParens = JS_TRUE;
01462 
01463 #undef PUSH_REGEXP_STATIC
01464 
01465         /* Make sure to push undefined for any unmatched parens. */
01466         for (; i < p; i++)
01467             *sp++ = JSVAL_VOID;
01468 
01469         /* Push match index and input string. */
01470         *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
01471         *sp++ = STRING_TO_JSVAL(rdata->base.str);
01472 
01473         /* Lift current frame to include the args and do the call. */
01474         fp = cx->fp;
01475         oldsp = fp->sp;
01476         fp->sp = sp;
01477         ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
01478         rval = fp->sp[-1];
01479         fp->sp = oldsp;
01480 
01481         if (ok) {
01482             /*
01483              * NB: we count on the newborn string root to hold any string
01484              * created by this js_ValueToString that would otherwise be GC-
01485              * able, until we use rdata->repstr in do_replace.
01486              */
01487             repstr = js_ValueToString(cx, rval);
01488             if (!repstr) {
01489                 ok = JS_FALSE;
01490             } else {
01491                 rdata->repstr = repstr;
01492                 *sizep = JSSTRING_LENGTH(repstr);
01493             }
01494         }
01495 
01496       lambda_out:
01497         js_FreeStack(cx, mark);
01498         if (freeMoreParens)
01499             JS_free(cx, cx->regExpStatics.moreParens);
01500         cx->regExpStatics = save;
01501         return ok;
01502     }
01503 
01504     repstr = rdata->repstr;
01505     replen = JSSTRING_LENGTH(repstr);
01506     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
01507          dp = js_strchr_limit(dp, '$', ep)) {
01508         sub = interpret_dollar(cx, dp, ep, rdata, &skip);
01509         if (sub) {
01510             replen += sub->length - skip;
01511             dp += skip;
01512         }
01513         else
01514             dp++;
01515     }
01516     *sizep = replen;
01517     return JS_TRUE;
01518 }
01519 
01520 static void
01521 do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
01522 {
01523     JSString *repstr;
01524     jschar *bp, *cp, *dp, *ep;
01525     size_t len, skip;
01526     JSSubString *sub;
01527 
01528     repstr = rdata->repstr;
01529     bp = cp = JSSTRING_CHARS(repstr);
01530     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
01531          dp = js_strchr_limit(dp, '$', ep)) {
01532         len = dp - cp;
01533         js_strncpy(chars, cp, len);
01534         chars += len;
01535         cp = dp;
01536         sub = interpret_dollar(cx, dp, ep, rdata, &skip);
01537         if (sub) {
01538             len = sub->length;
01539             js_strncpy(chars, sub->chars, len);
01540             chars += len;
01541             cp += skip;
01542             dp += skip;
01543         } else {
01544             dp++;
01545         }
01546     }
01547     js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
01548 }
01549 
01550 static JSBool
01551 replace_glob(JSContext *cx, jsint count, GlobData *data)
01552 {
01553     ReplaceData *rdata;
01554     JSString *str;
01555     size_t leftoff, leftlen, replen, growth;
01556     const jschar *left;
01557     jschar *chars;
01558 
01559     rdata = (ReplaceData *)data;
01560     str = data->str;
01561     leftoff = rdata->leftIndex;
01562     left = JSSTRING_CHARS(str) + leftoff;
01563     leftlen = cx->regExpStatics.lastMatch.chars - left;
01564     rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
01565     rdata->leftIndex += cx->regExpStatics.lastMatch.length;
01566     if (!find_replen(cx, rdata, &replen))
01567         return JS_FALSE;
01568     growth = leftlen + replen;
01569     chars = (jschar *)
01570         (rdata->chars
01571          ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1)
01572                                         * sizeof(jschar))
01573          : JS_malloc(cx, (growth + 1) * sizeof(jschar)));
01574     if (!chars) {
01575         JS_free(cx, rdata->chars);
01576         rdata->chars = NULL;
01577         return JS_FALSE;
01578     }
01579     rdata->chars = chars;
01580     rdata->length += growth;
01581     chars += rdata->index;
01582     rdata->index += growth;
01583     js_strncpy(chars, left, leftlen);
01584     chars += leftlen;
01585     do_replace(cx, rdata, chars);
01586     return JS_TRUE;
01587 }
01588 
01589 static JSBool
01590 str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01591 {
01592     JSObject *lambda;
01593     JSString *repstr, *str;
01594     ReplaceData rdata;
01595     JSBool ok;
01596     jschar *chars;
01597     size_t leftlen, rightlen, length;
01598 
01599     if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {
01600         lambda = JSVAL_TO_OBJECT(argv[1]);
01601         repstr = NULL;
01602     } else {
01603         if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))
01604             return JS_FALSE;
01605         repstr = JSVAL_TO_STRING(argv[1]);
01606         lambda = NULL;
01607     }
01608 
01609     /*
01610      * For ECMA Edition 3, the first argument is to be converted to a string
01611      * to match in a "flat" sense (without regular expression metachars having
01612      * special meanings) UNLESS the first arg is a RegExp object.
01613      */
01614     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP | FORCE_FLAT;
01615     rdata.base.optarg = 2;
01616 
01617     rdata.lambda = lambda;
01618     rdata.repstr = repstr;
01619     if (repstr) {
01620         rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
01621         rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
01622                                        rdata.dollarEnd);
01623     } else {
01624         rdata.dollar = rdata.dollarEnd = NULL;
01625     }
01626     rdata.chars = NULL;
01627     rdata.length = 0;
01628     rdata.index = 0;
01629     rdata.leftIndex = 0;
01630 
01631     ok = match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval);
01632     if (!ok)
01633         return JS_FALSE;
01634 
01635     if (!rdata.chars) {
01636         if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) {
01637             /* Didn't match even once. */
01638             *rval = STRING_TO_JSVAL(rdata.base.str);
01639             goto out;
01640         }
01641         leftlen = cx->regExpStatics.leftContext.length;
01642         ok = find_replen(cx, &rdata, &length);
01643         if (!ok)
01644             goto out;
01645         length += leftlen;
01646         chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
01647         if (!chars) {
01648             ok = JS_FALSE;
01649             goto out;
01650         }
01651         js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
01652         do_replace(cx, &rdata, chars + leftlen);
01653         rdata.chars = chars;
01654         rdata.length = length;
01655     }
01656 
01657     rightlen = cx->regExpStatics.rightContext.length;
01658     length = rdata.length + rightlen;
01659     chars = (jschar *)
01660         JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
01661     if (!chars) {
01662         JS_free(cx, rdata.chars);
01663         ok = JS_FALSE;
01664         goto out;
01665     }
01666     js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
01667                rightlen);
01668     chars[length] = 0;
01669 
01670     str = js_NewString(cx, chars, length, 0);
01671     if (!str) {
01672         JS_free(cx, chars);
01673         ok = JS_FALSE;
01674         goto out;
01675     }
01676     *rval = STRING_TO_JSVAL(str);
01677 
01678 out:
01679     /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
01680     if (rdata.base.flags & KEEP_REGEXP)
01681         js_DestroyRegExp(cx, rdata.base.regexp);
01682     return ok;
01683 }
01684 
01685 /*
01686  * Subroutine used by str_split to find the next split point in str, starting
01687  * at offset *ip and looking either for the separator substring given by sep,
01688  * or for the next re match.  In the re case, return the matched separator in
01689  * *sep, and the possibly updated offset in *ip.
01690  *
01691  * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
01692  * separator occurrence if found, or str->length if no separator is found.
01693  */
01694 static jsint
01695 find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
01696            JSSubString *sep)
01697 {
01698     jsint i, j, k;
01699     size_t length;
01700     jschar *chars;
01701 
01702     /*
01703      * Stop if past end of string.  If at end of string, we will compare the
01704      * null char stored there (by js_NewString*) to sep->chars[j] in the while
01705      * loop at the end of this function, so that
01706      *
01707      *  "ab,".split(',') => ["ab", ""]
01708      *
01709      * and the resulting array converts back to the string "ab," for symmetry.
01710      * However, we ape Perl and do this only if there is a sufficiently large
01711      * limit argument (see str_split).
01712      */
01713     i = *ip;
01714     length = JSSTRING_LENGTH(str);
01715     if ((size_t)i > length)
01716         return -1;
01717 
01718     chars = JSSTRING_CHARS(str);
01719 
01720     /*
01721      * Match a regular expression against the separator at or above index i.
01722      * Call js_ExecuteRegExp with true for the test argument.  On successful
01723      * match, get the separator from cx->regExpStatics.lastMatch.
01724      */
01725     if (re) {
01726         size_t index;
01727         jsval rval;
01728 
01729       again:
01730         /* JS1.2 deviated from Perl by never matching at end of string. */
01731         index = (size_t)i;
01732         if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
01733             return -2;
01734         if (rval != JSVAL_TRUE) {
01735             /* Mismatch: ensure our caller advances i past end of string. */
01736             sep->length = 1;
01737             return length;
01738         }
01739         i = (jsint)index;
01740         *sep = cx->regExpStatics.lastMatch;
01741         if (sep->length == 0) {
01742             /*
01743              * Empty string match: never split on an empty match at the start
01744              * of a find_split cycle.  Same rule as for an empty global match
01745              * in match_or_replace.
01746              */
01747             if (i == *ip) {
01748                 /*
01749                  * "Bump-along" to avoid sticking at an empty match, but don't
01750                  * bump past end of string -- our caller must do that by adding
01751                  * sep->length to our return value.
01752                  */
01753                 if ((size_t)i == length)
01754                     return -1;
01755                 i++;
01756                 goto again;
01757             }
01758             if ((size_t)i == length) {
01759                 /*
01760                  * If there was a trivial zero-length match at the end of the
01761                  * split, then we shouldn't output the matched string at the end
01762                  * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
01763                  */
01764                 sep->chars = NULL;
01765             }
01766         }
01767         JS_ASSERT((size_t)i >= sep->length);
01768         return i - sep->length;
01769     }
01770 
01771     /*
01772      * Deviate from ECMA by never splitting an empty string by any separator
01773      * string into a non-empty array (an array of length 1 that contains the
01774      * empty string).
01775      */
01776     if (!JS_VERSION_IS_ECMA(cx) && length == 0)
01777         return -1;
01778 
01779     /*
01780      * Special case: if sep is the empty string, split str into one character
01781      * substrings.  Let our caller worry about whether to split once at end of
01782      * string into an empty substring.
01783      */
01784     if (sep->length == 0)
01785         return ((size_t)i == length) ? -1 : i + 1;
01786 
01787     /*
01788      * Now that we know sep is non-empty, search starting at i in str for an
01789      * occurrence of all of sep's chars.  If we find them, return the index of
01790      * the first separator char.  Otherwise, return length.
01791      */
01792     j = 0;
01793     while ((size_t)(k = i + j) < length) {
01794         if (chars[k] == sep->chars[j]) {
01795             if ((size_t)++j == sep->length)
01796                 return i;
01797         } else {
01798             i++;
01799             j = 0;
01800         }
01801     }
01802     return k;
01803 }
01804 
01805 static JSBool
01806 str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01807 {
01808     JSString *str, *sub;
01809     JSObject *arrayobj;
01810     jsval v;
01811     JSBool ok, limited;
01812     JSRegExp *re;
01813     JSSubString *sep, tmp;
01814     jsdouble d;
01815     jsint i, j;
01816     uint32 len, limit;
01817 
01818     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
01819     if (!str)
01820         return JS_FALSE;
01821     argv[-1] = STRING_TO_JSVAL(str);
01822 
01823     arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
01824     if (!arrayobj)
01825         return JS_FALSE;
01826     *rval = OBJECT_TO_JSVAL(arrayobj);
01827 
01828     if (argc == 0) {
01829         v = STRING_TO_JSVAL(str);
01830         ok = JS_SetElement(cx, arrayobj, 0, &v);
01831     } else {
01832         if (JSVAL_IS_REGEXP(cx, argv[0])) {
01833             re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
01834             sep = &tmp;
01835 
01836             /* Set a magic value so we can detect a successful re match. */
01837             sep->chars = NULL;
01838             sep->length = 0;
01839         } else {
01840             JSString *str2 = js_ValueToString(cx, argv[0]);
01841             if (!str2)
01842                 return JS_FALSE;
01843             argv[0] = STRING_TO_JSVAL(str2);
01844 
01845             /*
01846              * Point sep at a local copy of str2's header because find_split
01847              * will modify sep->length.
01848              */
01849             tmp.length = JSSTRING_LENGTH(str2);
01850             tmp.chars = JSSTRING_CHARS(str2);
01851             sep = &tmp;
01852             re = NULL;
01853         }
01854 
01855         /* Use the second argument as the split limit, if given. */
01856         limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]);
01857         limit = 0; /* Avoid warning. */
01858         if (limited) {
01859             if (!js_ValueToNumber(cx, argv[1], &d))
01860                 return JS_FALSE;
01861 
01862             /* Clamp limit between 0 and 1 + string length. */
01863             if (!js_DoubleToECMAUint32(cx, d, &limit))
01864                 return JS_FALSE;
01865             if (limit > JSSTRING_LENGTH(str))
01866                 limit = 1 + JSSTRING_LENGTH(str);
01867         }
01868 
01869         len = i = 0;
01870         while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
01871             if (limited && len >= limit)
01872                 break;
01873             sub = js_NewDependentString(cx, str, i, (size_t)(j - i), 0);
01874             if (!sub)
01875                 return JS_FALSE;
01876             v = STRING_TO_JSVAL(sub);
01877             if (!JS_SetElement(cx, arrayobj, len, &v))
01878                 return JS_FALSE;
01879             len++;
01880 
01881             /*
01882              * Imitate perl's feature of including parenthesized substrings
01883              * that matched part of the delimiter in the new array, after the
01884              * split substring that was delimited.
01885              */
01886             if (re && sep->chars) {
01887                 uintN num;
01888                 JSSubString *parsub;
01889 
01890                 for (num = 0; num < cx->regExpStatics.parenCount; num++) {
01891                     if (limited && len >= limit)
01892                         break;
01893                     parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
01894                     sub = js_NewStringCopyN(cx, parsub->chars, parsub->length,
01895                                             0);
01896                     if (!sub)
01897                         return JS_FALSE;
01898                     v = STRING_TO_JSVAL(sub);
01899                     if (!JS_SetElement(cx, arrayobj, len, &v))
01900                         return JS_FALSE;
01901                     len++;
01902                 }
01903                 sep->chars = NULL;
01904             }
01905 
01906             i = j + sep->length;
01907             if (!JS_VERSION_IS_ECMA(cx)) {
01908                 /*
01909                  * Deviate from ECMA to imitate Perl, which omits a final
01910                  * split unless a limit argument is given and big enough.
01911                  */
01912                 if (!limited && (size_t)i == JSSTRING_LENGTH(str))
01913                     break;
01914             }
01915         }
01916         ok = (j != -2);
01917     }
01918     return ok;
01919 }
01920 
01921 #if JS_HAS_PERL_SUBSTR
01922 static JSBool
01923 str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01924 {
01925     JSString *str;
01926     jsdouble d;
01927     jsdouble length, begin, end;
01928 
01929     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
01930     if (!str)
01931         return JS_FALSE;
01932     argv[-1] = STRING_TO_JSVAL(str);
01933 
01934     if (argc != 0) {
01935         if (!js_ValueToNumber(cx, argv[0], &d))
01936             return JS_FALSE;
01937         length = JSSTRING_LENGTH(str);
01938         begin = js_DoubleToInteger(d);
01939         if (begin < 0) {
01940             begin += length;
01941             if (begin < 0)
01942                 begin = 0;
01943         } else if (begin > length) {
01944             begin = length;
01945         }
01946 
01947         if (argc == 1) {
01948             end = length;
01949         } else {
01950             if (!js_ValueToNumber(cx, argv[1], &d))
01951                 return JS_FALSE;
01952             end = js_DoubleToInteger(d);
01953             if (end < 0)
01954                 end = 0;
01955             end += begin;
01956             if (end > length)
01957                 end = length;
01958         }
01959 
01960         str = js_NewDependentString(cx, str, (size_t)begin,
01961                                     (size_t)(end - begin), 0);
01962         if (!str)
01963             return JS_FALSE;
01964     }
01965     *rval = STRING_TO_JSVAL(str);
01966     return JS_TRUE;
01967 }
01968 #endif /* JS_HAS_PERL_SUBSTR */
01969 
01970 /*
01971  * Python-esque sequence operations.
01972  */
01973 static JSBool
01974 str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01975 {
01976     JSString *str, *str2;
01977     uintN i;
01978 
01979     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
01980     if (!str)
01981         return JS_FALSE;
01982     argv[-1] = STRING_TO_JSVAL(str);
01983 
01984     for (i = 0; i < argc; i++) {
01985         str2 = js_ValueToString(cx, argv[i]);
01986         if (!str2)
01987             return JS_FALSE;
01988         argv[i] = STRING_TO_JSVAL(str2);
01989 
01990         str = js_ConcatStrings(cx, str, str2);
01991         if (!str)
01992             return JS_FALSE;
01993     }
01994 
01995     *rval = STRING_TO_JSVAL(str);
01996     return JS_TRUE;
01997 }
01998 
01999 static JSBool
02000 str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02001 {
02002     JSString *str;
02003     jsdouble d;
02004     jsdouble length, begin, end;
02005 
02006     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
02007     if (!str)
02008         return JS_FALSE;
02009     argv[-1] = STRING_TO_JSVAL(str);
02010 
02011     if (argc != 0) {
02012         if (!js_ValueToNumber(cx, argv[0], &d))
02013             return JS_FALSE;
02014         length = JSSTRING_LENGTH(str);
02015         begin = js_DoubleToInteger(d);
02016         if (begin < 0) {
02017             begin += length;
02018             if (begin < 0)
02019                 begin = 0;
02020         } else if (begin > length) {
02021             begin = length;
02022         }
02023 
02024         if (argc == 1) {
02025             end = length;
02026         } else {
02027             if (!js_ValueToNumber(cx, argv[1], &d))
02028                 return JS_FALSE;
02029             end = js_DoubleToInteger(d);
02030             if (end < 0) {
02031                 end += length;
02032                 if (end < 0)
02033                     end = 0;
02034             } else if (end > length) {
02035                 end = length;
02036             }
02037             if (end < begin)
02038                 end = begin;
02039         }
02040 
02041         str = js_NewDependentString(cx, str, (size_t)begin,
02042                                     (size_t)(end - begin), 0);
02043         if (!str)
02044             return JS_FALSE;
02045     }
02046     *rval = STRING_TO_JSVAL(str);
02047     return JS_TRUE;
02048 }
02049 
02050 #if JS_HAS_STR_HTML_HELPERS
02051 /*
02052  * HTML composition aids.
02053  */
02054 static JSBool
02055 tagify(JSContext *cx, JSObject *obj, jsval *argv,
02056        const char *begin, JSString *param, const char *end,
02057        jsval *rval)
02058 {
02059     JSString *str;
02060     jschar *tagbuf;
02061     size_t beglen, endlen, parlen, taglen;
02062     size_t i, j;
02063 
02064     if (JSVAL_IS_STRING((jsval)obj)) {
02065         str = JSVAL_TO_STRING((jsval)obj);
02066     } else {
02067         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
02068         if (!str)
02069             return JS_FALSE;
02070         argv[-1] = STRING_TO_JSVAL(str);
02071     }
02072 
02073     if (!end)
02074         end = begin;
02075 
02076     beglen = strlen(begin);
02077     taglen = 1 + beglen + 1;                            /* '<begin' + '>' */
02078     parlen = 0; /* Avoid warning. */
02079     if (param) {
02080         parlen = JSSTRING_LENGTH(param);
02081         taglen += 2 + parlen + 1;                       /* '="param"' */
02082     }
02083     endlen = strlen(end);
02084     taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1;    /* 'str</end>' */
02085 
02086     if (taglen >= ~(size_t)0 / sizeof(jschar)) {
02087         JS_ReportOutOfMemory(cx);
02088         return JS_FALSE;
02089     }
02090 
02091     tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
02092     if (!tagbuf)
02093         return JS_FALSE;
02094 
02095     j = 0;
02096     tagbuf[j++] = '<';
02097     for (i = 0; i < beglen; i++)
02098         tagbuf[j++] = (jschar)begin[i];
02099     if (param) {
02100         tagbuf[j++] = '=';
02101         tagbuf[j++] = '"';
02102         js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen);
02103         j += parlen;
02104         tagbuf[j++] = '"';
02105     }
02106     tagbuf[j++] = '>';
02107     js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
02108     j += JSSTRING_LENGTH(str);
02109     tagbuf[j++] = '<';
02110     tagbuf[j++] = '/';
02111     for (i = 0; i < endlen; i++)
02112         tagbuf[j++] = (jschar)end[i];
02113     tagbuf[j++] = '>';
02114     JS_ASSERT(j == taglen);
02115     tagbuf[j] = 0;
02116 
02117     str = js_NewString(cx, tagbuf, taglen, 0);
02118     if (!str) {
02119         free((char *)tagbuf);
02120         return JS_FALSE;
02121     }
02122     *rval = STRING_TO_JSVAL(str);
02123     return JS_TRUE;
02124 }
02125 
02126 static JSBool
02127 tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
02128              const char *begin, const char *end,
02129              jsval *rval)
02130 {
02131     JSString *param;
02132 
02133     param = js_ValueToString(cx, argv[0]);
02134     if (!param)
02135         return JS_FALSE;
02136     argv[0] = STRING_TO_JSVAL(param);
02137     return tagify(cx, obj, argv, begin, param, end, rval);
02138 }
02139 
02140 static JSBool
02141 str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02142 {
02143     return tagify(cx, obj, argv, "b", NULL, NULL, rval);
02144 }
02145 
02146 static JSBool
02147 str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02148 {
02149     return tagify(cx, obj, argv, "i", NULL, NULL, rval);
02150 }
02151 
02152 static JSBool
02153 str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02154 {
02155     return tagify(cx, obj, argv, "tt", NULL, NULL, rval);
02156 }
02157 
02158 static JSBool
02159 str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02160 {
02161     return tagify_value(cx, obj, argv, "font size", "font", rval);
02162 }
02163 
02164 static JSBool
02165 str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
02166               jsval *rval)
02167 {
02168     return tagify_value(cx, obj, argv, "font color", "font", rval);
02169 }
02170 
02171 static JSBool
02172 str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02173 {
02174     return tagify_value(cx, obj, argv, "a href", "a", rval);
02175 }
02176 
02177 static JSBool
02178 str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02179 {
02180     return tagify_value(cx, obj, argv, "a name", "a", rval);
02181 }
02182 
02183 static JSBool
02184 str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02185 {
02186     return tagify(cx, obj, argv, "strike", NULL, NULL, rval);
02187 }
02188 
02189 static JSBool
02190 str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02191 {
02192     return tagify(cx, obj, argv, "small", NULL, NULL, rval);
02193 }
02194 
02195 static JSBool
02196 str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02197 {
02198     return tagify(cx, obj, argv, "big", NULL, NULL, rval);
02199 }
02200 
02201 static JSBool
02202 str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02203 {
02204     return tagify(cx, obj, argv, "blink", NULL, NULL, rval);
02205 }
02206 
02207 static JSBool
02208 str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02209 {
02210     return tagify(cx, obj, argv, "sup", NULL, NULL, rval);
02211 }
02212 
02213 static JSBool
02214 str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02215 {
02216     return tagify(cx, obj, argv, "sub", NULL, NULL, rval);
02217 }
02218 #endif /* JS_HAS_STR_HTML_HELPERS */
02219 
02220 static JSFunctionSpec string_methods[] = {
02221 #if JS_HAS_TOSOURCE
02222     {"quote",               str_quote,              0,JSFUN_GENERIC_NATIVE|
02223                                                       JSFUN_THISP_PRIMITIVE,0},
02224     {js_toSource_str,       str_toSource,           0,JSFUN_THISP_STRING,0},
02225 #endif
02226 
02227     /* Java-like methods. */
02228     {js_toString_str,       str_toString,           0,JSFUN_THISP_STRING,0},
02229     {js_valueOf_str,        str_valueOf,            0,JSFUN_THISP_STRING,0},
02230     {"substring",           str_substring,          2,JSFUN_GENERIC_NATIVE|
02231                                                       JSFUN_THISP_PRIMITIVE,0},
02232     {"toLowerCase",         str_toLowerCase,        0,JSFUN_GENERIC_NATIVE|
02233                                                       JSFUN_THISP_PRIMITIVE,0},
02234     {"toUpperCase",         str_toUpperCase,        0,JSFUN_GENERIC_NATIVE|
02235                                                       JSFUN_THISP_PRIMITIVE,0},
02236     {"charAt",              str_charAt,             1,JSFUN_GENERIC_NATIVE|
02237                                                       JSFUN_THISP_PRIMITIVE,0},
02238     {"charCodeAt",          str_charCodeAt,         1,JSFUN_GENERIC_NATIVE|
02239                                                       JSFUN_THISP_PRIMITIVE,0},
02240     {"indexOf",             str_indexOf,            1,JSFUN_GENERIC_NATIVE|
02241                                                       JSFUN_THISP_PRIMITIVE,0},
02242     {"lastIndexOf",         str_lastIndexOf,        1,JSFUN_GENERIC_NATIVE|
02243                                                       JSFUN_THISP_PRIMITIVE,0},
02244     {"toLocaleLowerCase",   str_toLocaleLowerCase,  0,JSFUN_GENERIC_NATIVE|
02245                                                       JSFUN_THISP_PRIMITIVE,0},
02246     {"toLocaleUpperCase",   str_toLocaleUpperCase,  0,JSFUN_GENERIC_NATIVE|
02247                                                       JSFUN_THISP_PRIMITIVE,0},
02248     {"localeCompare",       str_localeCompare,      1,JSFUN_GENERIC_NATIVE|
02249                                                       JSFUN_THISP_PRIMITIVE,0},
02250 
02251     /* Perl-ish methods (search is actually Python-esque). */
02252     {"match",               str_match,              1,JSFUN_GENERIC_NATIVE|
02253                                                       JSFUN_THISP_PRIMITIVE,2},
02254     {"search",              str_search,             1,JSFUN_GENERIC_NATIVE|
02255                                                       JSFUN_THISP_PRIMITIVE,0},
02256     {"replace",             str_replace,            2,JSFUN_GENERIC_NATIVE|
02257                                                       JSFUN_THISP_PRIMITIVE,0},
02258     {"split",               str_split,              2,JSFUN_GENERIC_NATIVE|
02259                                                       JSFUN_THISP_PRIMITIVE,0},
02260 #if JS_HAS_PERL_SUBSTR
02261     {"substr",              str_substr,             2,JSFUN_GENERIC_NATIVE|
02262                                                       JSFUN_THISP_PRIMITIVE,0},
02263 #endif
02264 
02265     /* Python-esque sequence methods. */
02266     {"concat",              str_concat,             0,JSFUN_GENERIC_NATIVE|
02267                                                       JSFUN_THISP_PRIMITIVE,0},
02268     {"slice",               str_slice,              0,JSFUN_GENERIC_NATIVE|
02269                                                       JSFUN_THISP_PRIMITIVE,0},
02270 
02271     /* HTML string methods. */
02272 #if JS_HAS_STR_HTML_HELPERS
02273     {"bold",                str_bold,               0,JSFUN_THISP_PRIMITIVE,0},
02274     {"italics",             str_italics,            0,JSFUN_THISP_PRIMITIVE,0},
02275     {"fixed",               str_fixed,              0,JSFUN_THISP_PRIMITIVE,0},
02276     {"fontsize",            str_fontsize,           1,JSFUN_THISP_PRIMITIVE,0},
02277     {"fontcolor",           str_fontcolor,          1,JSFUN_THISP_PRIMITIVE,0},
02278     {"link",                str_link,               1,JSFUN_THISP_PRIMITIVE,0},
02279     {"anchor",              str_anchor,             1,JSFUN_THISP_PRIMITIVE,0},
02280     {"strike",              str_strike,             0,JSFUN_THISP_PRIMITIVE,0},
02281     {"small",               str_small,              0,JSFUN_THISP_PRIMITIVE,0},
02282     {"big",                 str_big,                0,JSFUN_THISP_PRIMITIVE,0},
02283     {"blink",               str_blink,              0,JSFUN_THISP_PRIMITIVE,0},
02284     {"sup",                 str_sup,                0,JSFUN_THISP_PRIMITIVE,0},
02285     {"sub",                 str_sub,                0,JSFUN_THISP_PRIMITIVE,0},
02286 #endif
02287 
02288     {0,0,0,0,0}
02289 };
02290 
02291 static JSBool
02292 String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02293 {
02294     JSString *str;
02295 
02296     if (argc > 0) {
02297         str = js_ValueToString(cx, argv[0]);
02298         if (!str)
02299             return JS_FALSE;
02300         argv[0] = STRING_TO_JSVAL(str);
02301     } else {
02302         str = cx->runtime->emptyString;
02303     }
02304     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
02305         *rval = STRING_TO_JSVAL(str);
02306         return JS_TRUE;
02307     }
02308     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
02309     return JS_TRUE;
02310 }
02311 
02312 static JSBool
02313 str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
02314                  jsval *rval)
02315 {
02316     jschar *chars;
02317     uintN i;
02318     uint16 code;
02319     JSString *str;
02320 
02321     JS_ASSERT(argc < ARRAY_INIT_LIMIT);
02322     chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
02323     if (!chars)
02324         return JS_FALSE;
02325     for (i = 0; i < argc; i++) {
02326         if (!js_ValueToUint16(cx, argv[i], &code)) {
02327             JS_free(cx, chars);
02328             return JS_FALSE;
02329         }
02330         chars[i] = (jschar)code;
02331     }
02332     chars[i] = 0;
02333     str = js_NewString(cx, chars, argc, 0);
02334     if (!str) {
02335         JS_free(cx, chars);
02336         return JS_FALSE;
02337     }
02338     *rval = STRING_TO_JSVAL(str);
02339     return JS_TRUE;
02340 }
02341 
02342 static JSFunctionSpec string_static_methods[] = {
02343     {"fromCharCode",    str_fromCharCode,       1,0,0},
02344     {0,0,0,0,0}
02345 };
02346 
02347 JSBool
02348 js_InitRuntimeStringState(JSContext *cx)
02349 {
02350     JSRuntime *rt;
02351     JSString *empty;
02352     JSAtom *atom;
02353 
02354     rt = cx->runtime;
02355 
02356     /* Initialize string cache */
02357 #ifdef JS_THREADSAFE
02358     JS_ASSERT(!rt->deflatedStringCacheLock);
02359     rt->deflatedStringCacheLock = JS_NEW_LOCK();
02360     if (!rt->deflatedStringCacheLock)
02361         return JS_FALSE;
02362 #endif
02363 
02364     /* Make a permanently locked empty string. */
02365     JS_ASSERT(!rt->emptyString);
02366     empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
02367     if (!empty)
02368         goto bad;
02369 
02370     /* Atomize it for scripts that use '' + x to convert x to string. */
02371     atom = js_AtomizeString(cx, empty, ATOM_PINNED);
02372     if (!atom)
02373         goto bad;
02374 
02375     rt->emptyString = empty;
02376     rt->atomState.emptyAtom = atom;
02377 
02378     return JS_TRUE;
02379 
02380   bad:
02381 #ifdef JS_THREADSAFE
02382     JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
02383     rt->deflatedStringCacheLock = NULL;
02384 #endif
02385     return JS_FALSE;
02386 
02387 }
02388 
02389 void
02390 js_FinishRuntimeStringState(JSContext *cx)
02391 {
02392     JSRuntime *rt = cx->runtime;
02393 
02394     js_UnlockGCThingRT(rt, rt->emptyString);
02395     rt->emptyString = NULL;
02396 }
02397 
02398 void
02399 js_FinishDeflatedStringCache(JSRuntime *rt)
02400 {
02401     if (rt->deflatedStringCache) {
02402         JS_HashTableDestroy(rt->deflatedStringCache);
02403         rt->deflatedStringCache = NULL;
02404     }
02405 #ifdef JS_THREADSAFE
02406     if (rt->deflatedStringCacheLock) {
02407         JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
02408         rt->deflatedStringCacheLock = NULL;
02409     }
02410 #endif
02411 }
02412 
02413 JSObject *
02414 js_InitStringClass(JSContext *cx, JSObject *obj)
02415 {
02416     JSObject *proto;
02417 
02418     /* Define the escape, unescape functions in the global object. */
02419     if (!JS_DefineFunctions(cx, obj, string_functions))
02420         return NULL;
02421 
02422     proto = JS_InitClass(cx, obj, NULL, &js_StringClass, String, 1,
02423                          string_props, string_methods,
02424                          NULL, string_static_methods);
02425     if (!proto)
02426         return NULL;
02427     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE,
02428                  STRING_TO_JSVAL(cx->runtime->emptyString));
02429     return proto;
02430 }
02431 
02432 JSString *
02433 js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
02434 {
02435     JSString *str;
02436 
02437     if (length > JSSTRING_LENGTH_MASK) {
02438         JS_ReportOutOfMemory(cx);
02439         return NULL;
02440     }
02441 
02442     str = (JSString *) js_NewGCThing(cx, gcflag | GCX_STRING, sizeof(JSString));
02443     if (!str)
02444         return NULL;
02445     str->length = length;
02446     str->chars = chars;
02447 #ifdef DEBUG
02448   {
02449     JSRuntime *rt = cx->runtime;
02450     JS_RUNTIME_METER(rt, liveStrings);
02451     JS_RUNTIME_METER(rt, totalStrings);
02452     JS_LOCK_RUNTIME_VOID(rt,
02453         (rt->lengthSum += (double)length,
02454          rt->lengthSquaredSum += (double)length * (double)length));
02455   }
02456 #endif
02457     return str;
02458 }
02459 
02460 JSString *
02461 js_NewDependentString(JSContext *cx, JSString *base, size_t start,
02462                       size_t length, uintN gcflag)
02463 {
02464     JSDependentString *ds;
02465 
02466     if (length == 0)
02467         return cx->runtime->emptyString;
02468 
02469     if (start == 0 && length == JSSTRING_LENGTH(base))
02470         return base;
02471 
02472     if (start > JSSTRDEP_START_MASK ||
02473         (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
02474         return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length,
02475                                  gcflag);
02476     }
02477 
02478     ds = (JSDependentString *)
02479          js_NewGCThing(cx, gcflag | GCX_MUTABLE_STRING, sizeof(JSString));
02480     if (!ds)
02481         return NULL;
02482     if (start == 0) {
02483         JSPREFIX_SET_LENGTH(ds, length);
02484         JSPREFIX_SET_BASE(ds, base);
02485     } else {
02486         JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
02487         JSSTRDEP_SET_BASE(ds, base);
02488     }
02489 #ifdef DEBUG
02490   {
02491     JSRuntime *rt = cx->runtime;
02492     JS_RUNTIME_METER(rt, liveDependentStrings);
02493     JS_RUNTIME_METER(rt, totalDependentStrings);
02494     JS_RUNTIME_METER(rt, liveStrings);
02495     JS_RUNTIME_METER(rt, totalStrings);
02496     JS_LOCK_RUNTIME_VOID(rt,
02497         (rt->strdepLengthSum += (double)length,
02498          rt->strdepLengthSquaredSum += (double)length * (double)length));
02499     JS_LOCK_RUNTIME_VOID(rt,
02500         (rt->lengthSum += (double)length,
02501          rt->lengthSquaredSum += (double)length * (double)length));
02502   }
02503 #endif
02504     return (JSString *)ds;
02505 }
02506 
02507 #ifdef DEBUG
02508 #include <math.h>
02509 
02510 void printJSStringStats(JSRuntime *rt) {
02511     double mean = 0., var = 0., sigma = 0.;
02512     jsrefcount count = rt->totalStrings;
02513     if (count > 0 && rt->lengthSum >= 0) {
02514         mean = rt->lengthSum / count;
02515         var = count * rt->lengthSquaredSum - rt->lengthSum * rt->lengthSum;
02516         if (var < 0.0 || count <= 1)
02517             var = 0.0;
02518         else
02519             var /= count * (count - 1);
02520 
02521         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
02522         sigma = (var != 0.) ? sqrt(var) : 0.;
02523     }
02524     fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
02525             (unsigned long)count, mean, sigma);
02526 
02527     mean = var = sigma = 0.;
02528     count = rt->totalDependentStrings;
02529     if (count > 0 && rt->strdepLengthSum >= 0) {
02530         mean = rt->strdepLengthSum / count;
02531         var = count * rt->strdepLengthSquaredSum
02532             - rt->strdepLengthSum * rt->strdepLengthSum;
02533         if (var < 0.0 || count <= 1)
02534             var = 0.0;
02535         else
02536             var /= count * (count - 1);
02537 
02538         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
02539         sigma = (var != 0.) ? sqrt(var) : 0.;
02540     }
02541     fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
02542             (unsigned long)count, mean, sigma);
02543 }
02544 #endif
02545 
02546 JSString *
02547 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag)
02548 {
02549     jschar *news;
02550     JSString *str;
02551 
02552     news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar));
02553     if (!news)
02554         return NULL;
02555     js_strncpy(news, s, n);
02556     news[n] = 0;
02557     str = js_NewString(cx, news, n, gcflag);
02558     if (!str)
02559         JS_free(cx, news);
02560     return str;
02561 }
02562 
02563 JSString *
02564 js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
02565 {
02566     size_t n, m;
02567     jschar *news;
02568     JSString *str;
02569 
02570     n = js_strlen(s);
02571     m = (n + 1) * sizeof(jschar);
02572     news = (jschar *) JS_malloc(cx, m);
02573     if (!news)
02574         return NULL;
02575     memcpy(news, s, m);
02576     str = js_NewString(cx, news, n, gcflag);
02577     if (!str)
02578         JS_free(cx, news);
02579     return str;
02580 }
02581 
02582 JS_STATIC_DLL_CALLBACK(JSHashNumber)
02583 js_hash_string_pointer(const void *key)
02584 {
02585     return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
02586 }
02587 
02588 void
02589 js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str)
02590 {
02591     JSHashNumber hash;
02592     JSHashEntry *he, **hep;
02593 
02594     if (!rt->deflatedStringCache)
02595         return;
02596 
02597     hash = js_hash_string_pointer(str);
02598     JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
02599     hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str);
02600     he = *hep;
02601     if (he) {
02602 #ifdef DEBUG
02603         rt->deflatedStringCacheBytes -= JSSTRING_LENGTH(str);
02604 #endif
02605         free(he->value);
02606         JS_HashTableRawRemove(rt->deflatedStringCache, hep, he);
02607     }
02608     JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
02609 }
02610 
02611 void
02612 js_FinalizeString(JSContext *cx, JSString *str)
02613 {
02614     js_FinalizeStringRT(cx->runtime, str);
02615 }
02616 
02617 void
02618 js_FinalizeStringRT(JSRuntime *rt, JSString *str)
02619 {
02620     JSBool valid;
02621 
02622     JS_RUNTIME_UNMETER(rt, liveStrings);
02623     if (JSSTRING_IS_DEPENDENT(str)) {
02624         /* If JSSTRFLAG_DEPENDENT is set, this string must be valid. */
02625         JS_ASSERT(JSSTRDEP_BASE(str));
02626         JS_RUNTIME_UNMETER(rt, liveDependentStrings);
02627         valid = JS_TRUE;
02628     } else {
02629         /* A stillborn string has null chars, so is not valid. */
02630         valid = (str->chars != NULL);
02631         if (valid)
02632             free(str->chars);
02633     }
02634     if (valid) {
02635         js_PurgeDeflatedStringCache(rt, str);
02636         str->chars = NULL;
02637     }
02638     str->length = 0;
02639 }
02640 
02641 JSObject *
02642 js_StringToObject(JSContext *cx, JSString *str)
02643 {
02644     JSObject *obj;
02645 
02646     obj = js_NewObject(cx, &js_StringClass, NULL, NULL);
02647     if (!obj)
02648         return NULL;
02649     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
02650     return obj;
02651 }
02652 
02653 JS_FRIEND_API(const char *)
02654 js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun)
02655 {
02656     JSString *str;
02657     const char *bytes;
02658 
02659     str = v2sfun(cx, v);
02660     if (!str)
02661         return NULL;
02662     str = js_QuoteString(cx, str, 0);
02663     if (!str)
02664         return NULL;
02665     bytes = js_GetStringBytes(cx->runtime, str);
02666     if (!bytes)
02667         JS_ReportOutOfMemory(cx);
02668     return bytes;
02669 }
02670 
02671 JS_FRIEND_API(JSString *)
02672 js_ValueToString(JSContext *cx, jsval v)
02673 {
02674     JSObject *obj;
02675     JSString *str;
02676 
02677     if (JSVAL_IS_OBJECT(v)) {
02678         obj = JSVAL_TO_OBJECT(v);
02679         if (!obj)
02680             return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
02681         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
02682             return NULL;
02683     }
02684     if (JSVAL_IS_STRING(v)) {
02685         str = JSVAL_TO_STRING(v);
02686     } else if (JSVAL_IS_INT(v)) {
02687         str = js_NumberToString(cx, JSVAL_TO_INT(v));
02688     } else if (JSVAL_IS_DOUBLE(v)) {
02689         str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
02690     } else if (JSVAL_IS_BOOLEAN(v)) {
02691         str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
02692     } else {
02693         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
02694     }
02695     return str;
02696 }
02697 
02698 JS_FRIEND_API(JSString *)
02699 js_ValueToSource(JSContext *cx, jsval v)
02700 {
02701     JSTempValueRooter tvr;
02702     JSString *str;
02703 
02704     if (JSVAL_IS_STRING(v))
02705         return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
02706     if (JSVAL_IS_PRIMITIVE(v)) {
02707         /* Special case to preserve negative zero, _contra_ toString. */
02708         if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
02709             /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
02710             static const jschar js_negzero_ucNstr[] = {'-', '0'};
02711 
02712             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2, 0);
02713         }
02714         return js_ValueToString(cx, v);
02715     }
02716 
02717     JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
02718     if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
02719                       cx->runtime->atomState.toSourceAtom,
02720                       0, NULL, &tvr.u.value)) {
02721         str = NULL;
02722     } else {
02723         str = js_ValueToString(cx, tvr.u.value);
02724     }
02725     JS_POP_TEMP_ROOT(cx, &tvr);
02726     return str;
02727 }
02728 
02729 JSHashNumber
02730 js_HashString(JSString *str)
02731 {
02732     JSHashNumber h;
02733     const jschar *s;
02734     size_t n;
02735 
02736     h = 0;
02737     for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
02738         h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
02739     return h;
02740 }
02741 
02742 intN
02743 js_CompareStrings(JSString *str1, JSString *str2)
02744 {
02745     size_t l1, l2, n, i;
02746     const jschar *s1, *s2;
02747     intN cmp;
02748 
02749     JS_ASSERT(str1);
02750     JS_ASSERT(str2);
02751 
02752     /* Fast case: pointer equality could be a quick win. */
02753     if (str1 == str2)
02754         return 0;
02755 
02756     l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
02757     s1 = JSSTRING_CHARS(str1),  s2 = JSSTRING_CHARS(str2);
02758     n = JS_MIN(l1, l2);
02759     for (i = 0; i < n; i++) {
02760         cmp = s1[i] - s2[i];
02761         if (cmp != 0)
02762             return cmp;
02763     }
02764     return (intN)(l1 - l2);
02765 }
02766 
02767 JSBool
02768 js_EqualStrings(JSString *str1, JSString *str2)
02769 {
02770     size_t n;
02771     const jschar *s1, *s2;
02772 
02773     JS_ASSERT(str1);
02774     JS_ASSERT(str2);
02775 
02776     /* Fast case: pointer equality could be a quick win. */
02777     if (str1 == str2)
02778         return JS_TRUE;
02779 
02780     n = JSSTRING_LENGTH(str1);
02781     if (n != JSSTRING_LENGTH(str2))
02782         return JS_FALSE;
02783 
02784     if (n == 0)
02785         return JS_TRUE;
02786 
02787     s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
02788     do {
02789         if (*s1 != *s2)
02790             return JS_FALSE;
02791         ++s1, ++s2;
02792     } while (--n != 0);
02793 
02794     return JS_TRUE;
02795 }
02796 
02797 size_t
02798 js_strlen(const jschar *s)
02799 {
02800     const jschar *t;
02801 
02802     for (t = s; *t != 0; t++)
02803         continue;
02804     return (size_t)(t - s);
02805 }
02806 
02807 jschar *
02808 js_strchr(const jschar *s, jschar c)
02809 {
02810     while (*s != 0) {
02811         if (*s == c)
02812             return (jschar *)s;
02813         s++;
02814     }
02815     return NULL;
02816 }
02817 
02818 jschar *
02819 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
02820 {
02821     while (s < limit) {
02822         if (*s == c)
02823             return (jschar *)s;
02824         s++;
02825     }
02826     return NULL;
02827 }
02828 
02829 const jschar *
02830 js_SkipWhiteSpace(const jschar *s)
02831 {
02832     /* JS_ISSPACE is false on a null. */
02833     while (JS_ISSPACE(*s))
02834         s++;
02835     return s;
02836 }
02837 
02838 #ifdef JS_C_STRINGS_ARE_UTF8
02839 
02840 jschar *
02841 js_InflateString(JSContext *cx, const char *bytes, size_t *length)
02842 {
02843     jschar *chars = NULL;
02844     size_t dstlen = 0;
02845 
02846     if (!js_InflateStringToBuffer(cx, bytes, *length, NULL, &dstlen))
02847         return NULL;
02848     chars = (jschar *) JS_malloc(cx, (dstlen + 1) * sizeof (jschar));
02849     if (!chars)
02850         return NULL;
02851     js_InflateStringToBuffer(cx, bytes, *length, chars, &dstlen);
02852     chars[dstlen] = 0;
02853     *length = dstlen;
02854     return chars;
02855 }
02856 
02857 /*
02858  * May be called with null cx by js_GetStringBytes, see below.
02859  */
02860 char *
02861 js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
02862 {
02863     size_t size = 0;
02864     char *bytes = NULL;
02865     if (!js_DeflateStringToBuffer(cx, chars, length, NULL, &size))
02866         return NULL;
02867     bytes = (char *) (cx ? JS_malloc(cx, size+1) : malloc(size+1));
02868     if (!bytes)
02869         return NULL;
02870     js_DeflateStringToBuffer(cx, chars, length, bytes, &size);
02871     bytes[size] = 0;
02872     return bytes;
02873 }
02874 
02875 JSBool
02876 js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen,
02877                          char *dst, size_t *dstlenp)
02878 {
02879     size_t i, utf8Len, dstlen = *dstlenp, origDstlen = dstlen;
02880     jschar c, c2;
02881     uint32 v;
02882     uint8 utf8buf[6];
02883 
02884     if (!dst)
02885         dstlen = origDstlen = (size_t) -1;
02886 
02887     while (srclen) {
02888         c = *src++;
02889         srclen--;
02890         if ((c >= 0xDC00) && (c <= 0xDFFF))
02891             goto badSurrogate;
02892         if (c < 0xD800 || c > 0xDBFF) {
02893             v = c;
02894         } else {
02895             if (srclen < 1)
02896                 goto bufferTooSmall;
02897             c2 = *src++;
02898             srclen--;
02899             if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
02900                 c = c2;
02901                 goto badSurrogate;
02902             }
02903             v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
02904         }
02905         if (v < 0x0080) {
02906             /* no encoding necessary - performance hack */
02907             if (!dstlen)
02908                 goto bufferTooSmall;
02909             if (dst)
02910                 *dst++ = (char) v;
02911             utf8Len = 1;
02912         } else {
02913             utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
02914             if (utf8Len > dstlen)
02915                 goto bufferTooSmall;
02916             if (dst) {
02917                 for (i = 0; i < utf8Len; i++)
02918                     *dst++ = (char) utf8buf[i];
02919             }
02920         }
02921         dstlen -= utf8Len;
02922     }
02923     *dstlenp = (origDstlen - dstlen);
02924     return JS_TRUE;
02925 
02926 badSurrogate:
02927     *dstlenp = (origDstlen - dstlen);
02928     if (cx) {
02929         char buffer[10];
02930         JS_snprintf(buffer, 10, "0x%x", c);
02931         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
02932                                      js_GetErrorMessage, NULL,
02933                                      JSMSG_BAD_SURROGATE_CHAR,
02934                                      buffer);
02935     }
02936     return JS_FALSE;
02937 
02938 bufferTooSmall:
02939     *dstlenp = (origDstlen - dstlen);
02940     if (cx) {
02941         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
02942                              JSMSG_BUFFER_TOO_SMALL);
02943     }
02944     return JS_FALSE;
02945 }
02946 
02947 JSBool
02948 js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen,
02949                          jschar *dst, size_t *dstlenp)
02950 {
02951     uint32 v;
02952     size_t offset = 0, j, n, dstlen = *dstlenp, origDstlen = dstlen;
02953 
02954     if (!dst)
02955         dstlen = origDstlen = (size_t) -1;
02956 
02957     while (srclen) {
02958         v = (uint8) *src;
02959         n = 1;
02960         if (v & 0x80) {
02961             while (v & (0x80 >> n))
02962                 n++;
02963             if (n > srclen)
02964                 goto bufferTooSmall;
02965             if (n == 1 || n > 6)
02966                 goto badCharacter;
02967             for (j = 1; j < n; j++) {
02968                 if ((src[j] & 0xC0) != 0x80)
02969                     goto badCharacter;
02970             }
02971             v = Utf8ToOneUcs4Char(src, n);
02972             if (v >= 0x10000) {
02973                 v -= 0x10000;
02974                 if (v > 0xFFFFF || dstlen < 2) {
02975                     *dstlenp = (origDstlen - dstlen);
02976                     if (cx) {
02977                         char buffer[10];
02978                         JS_snprintf(buffer, 10, "0x%x", v + 0x10000);
02979                         JS_ReportErrorFlagsAndNumber(cx,
02980                                                      JSREPORT_ERROR,
02981                                                      js_GetErrorMessage, NULL,
02982                                                      JSMSG_UTF8_CHAR_TOO_LARGE,
02983                                                      buffer);
02984                     }
02985                     return JS_FALSE;
02986                 }
02987                 if (dstlen < 2)
02988                     goto bufferTooSmall;
02989                 if (dst) {
02990                     *dst++ = (jschar)((v >> 10) + 0xD800);
02991                     v = (jschar)((v & 0x3FF) + 0xDC00);
02992                 }
02993                 dstlen--;
02994             }
02995         }
02996         if (!dstlen)
02997             goto bufferTooSmall;
02998         if (dst)
02999             *dst++ = (jschar) v;
03000         dstlen--;
03001         offset += n;
03002         src += n;
03003         srclen -= n;
03004     }
03005     *dstlenp = (origDstlen - dstlen);
03006     return JS_TRUE;
03007 
03008 badCharacter:
03009     *dstlenp = (origDstlen - dstlen);
03010     if (cx) {
03011         char buffer[10];
03012         JS_snprintf(buffer, 10, "%d", offset);
03013         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
03014                                      js_GetErrorMessage, NULL,
03015                                      JSMSG_MALFORMED_UTF8_CHAR,
03016                                      buffer);
03017     }
03018     return JS_FALSE;
03019 
03020 bufferTooSmall:
03021     *dstlenp = (origDstlen - dstlen);
03022     if (cx) {
03023         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
03024                              JSMSG_BUFFER_TOO_SMALL);
03025     }
03026     return JS_FALSE;
03027 }
03028 
03029 #else
03030 
03031 JSBool
03032 js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length,
03033                          jschar *chars, size_t* charsLength)
03034 {
03035     size_t i;
03036 
03037     if (length > *charsLength) {
03038         for (i = 0; i < *charsLength; i++)
03039             chars[i] = (unsigned char) bytes[i];
03040         if (cx) {
03041             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
03042                                  JSMSG_BUFFER_TOO_SMALL);
03043         }
03044         return JS_FALSE;
03045     }
03046     for (i = 0; i < length; i++)
03047         chars[i] = (unsigned char) bytes[i];
03048     *charsLength = length;
03049     return JS_TRUE;
03050 }
03051 
03052 jschar *
03053 js_InflateString(JSContext *cx, const char *bytes, size_t *bytesLength)
03054 {
03055     jschar *chars;
03056     size_t i, length = *bytesLength;
03057 
03058     chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
03059     if (!chars) {
03060         *bytesLength = 0;
03061         return NULL;
03062     }
03063     for (i = 0; i < length; i++)
03064         chars[i] = (unsigned char) bytes[i];
03065     chars[length] = 0;
03066     *bytesLength = length;
03067     return chars;
03068 }
03069 
03070 JSBool
03071 js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t length,
03072                          char *bytes, size_t* bytesLength)
03073 {
03074     size_t i;
03075 
03076     if (length > *bytesLength) {
03077         for (i = 0; i < *bytesLength; i++)
03078             bytes[i] = (char) chars[i];
03079         if (cx) {
03080             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
03081                                  JSMSG_BUFFER_TOO_SMALL);
03082         }
03083         return JS_FALSE;
03084     }
03085     for (i = 0; i < length; i++)
03086         bytes[i] = (char) chars[i];
03087     *bytesLength = length;
03088     return JS_TRUE;
03089 }
03090 
03091 /*
03092  * May be called with null cx by js_GetStringBytes, see below.
03093  */
03094 char *
03095 js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
03096 {
03097     size_t i, size;
03098     char *bytes;
03099 
03100     size = (length + 1) * sizeof(char);
03101     bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
03102     if (!bytes)
03103         return NULL;
03104 
03105     for (i = 0; i < length; i++)
03106         bytes[i] = (char) chars[i];
03107 
03108     bytes[length] = 0;
03109     return bytes;
03110 }
03111 
03112 #endif
03113 
03114 static JSHashTable *
03115 GetDeflatedStringCache(JSRuntime *rt)
03116 {
03117     JSHashTable *cache;
03118 
03119     cache = rt->deflatedStringCache;
03120     if (!cache) {
03121         cache = JS_NewHashTable(8, js_hash_string_pointer,
03122                                 JS_CompareValues, JS_CompareValues,
03123                                 NULL, NULL);
03124         rt->deflatedStringCache = cache;
03125     }
03126     return cache;
03127 }
03128 
03129 JSBool
03130 js_SetStringBytes(JSRuntime *rt, JSString *str, char *bytes, size_t length)
03131 {
03132     JSHashTable *cache;
03133     JSBool ok;
03134     JSHashNumber hash;
03135     JSHashEntry **hep;
03136 
03137     JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
03138 
03139     cache = GetDeflatedStringCache(rt);
03140     if (!cache) {
03141         ok = JS_FALSE;
03142     } else {
03143         hash = js_hash_string_pointer(str);
03144         hep = JS_HashTableRawLookup(cache, hash, str);
03145         JS_ASSERT(*hep == NULL);
03146         ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
03147 #ifdef DEBUG
03148         if (ok)
03149             rt->deflatedStringCacheBytes += length;
03150 #endif
03151     }
03152 
03153     JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
03154     return ok;
03155 }
03156 
03157 char *
03158 js_GetStringBytes(JSRuntime *rt, JSString *str)
03159 {
03160     JSHashTable *cache;
03161     char *bytes;
03162     JSHashNumber hash;
03163     JSHashEntry *he, **hep;
03164 
03165     JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
03166 
03167     cache = GetDeflatedStringCache(rt);
03168     if (!cache) {
03169         bytes = NULL;
03170     } else {
03171         hash = js_hash_string_pointer(str);
03172         hep = JS_HashTableRawLookup(cache, hash, str);
03173         he = *hep;
03174         if (he) {
03175             bytes = (char *) he->value;
03176 
03177             /* Try to catch failure to JS_ShutDown between runtime epochs. */
03178             JS_ASSERT((*bytes == '\0' && JSSTRING_LENGTH(str) == 0) ||
03179                       *bytes == (char) JSSTRING_CHARS(str)[0]);
03180         } else {
03181             bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
03182                                            JSSTRING_LENGTH(str));
03183             if (bytes) {
03184                 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
03185 #ifdef DEBUG
03186                     rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str);
03187 #endif
03188                 } else {
03189                     free(bytes);
03190                     bytes = NULL;
03191                 }
03192             }
03193         }
03194     }
03195 
03196     JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
03197     return bytes;
03198 }
03199 
03200 /*
03201  * From java.lang.Character.java:
03202  *
03203  * The character properties are currently encoded into 32 bits in the
03204  * following manner:
03205  *
03206  * 10 bits      signed offset used for converting case
03207  *  1 bit       if 1, adding the signed offset converts the character to
03208  *              lowercase
03209  *  1 bit       if 1, subtracting the signed offset converts the character to
03210  *              uppercase
03211  *  1 bit       if 1, character has a titlecase equivalent (possibly itself)
03212  *  3 bits      0  may not be part of an identifier
03213  *              1  ignorable control; may continue a Unicode identifier or JS
03214  *                 identifier
03215  *              2  may continue a JS identifier but not a Unicode identifier
03216  *                 (unused)
03217  *              3  may continue a Unicode identifier or JS identifier
03218  *              4  is a JS whitespace character
03219  *              5  may start or continue a JS identifier;
03220  *                 may continue but not start a Unicode identifier (_)
03221  *              6  may start or continue a JS identifier but not a Unicode
03222  *                 identifier ($)
03223  *              7  may start or continue a Unicode identifier or JS identifier
03224  *              Thus:
03225  *                 5, 6, 7 may start a JS identifier
03226  *                 1, 2, 3, 5, 6, 7 may continue a JS identifier
03227  *                 7 may start a Unicode identifier
03228  *                 1, 3, 5, 7 may continue a Unicode identifier
03229  *                 1 is ignorable within an identifier
03230  *                 4 is JS whitespace
03231  *  2 bits      0  this character has no numeric property
03232  *              1  adding the digit offset to the character code and then
03233  *                 masking with 0x1F will produce the desired numeric value
03234  *              2  this character has a "strange" numeric value
03235  *              3  a JS supradecimal digit: adding the digit offset to the
03236  *                 character code, then masking with 0x1F, then adding 10
03237  *                 will produce the desired numeric value
03238  *  5 bits      digit offset
03239  *  1 bit       XML 1.0 name start character
03240  *  1 bit       XML 1.0 name character
03241  *  2 bits      reserved for future use
03242  *  5 bits      character type
03243  */
03244 
03245 /* The X table has 1024 entries for a total of 1024 bytes. */
03246 
03247 const uint8 js_X[] = {
03248   0,   1,   2,   3,   4,   5,   6,   7,  /*  0x0000 */
03249   8,   9,  10,  11,  12,  13,  14,  15,  /*  0x0200 */
03250  16,  17,  18,  19,  20,  21,  22,  23,  /*  0x0400 */
03251  24,  25,  26,  27,  28,  28,  28,  28,  /*  0x0600 */
03252  28,  28,  28,  28,  29,  30,  31,  32,  /*  0x0800 */
03253  33,  34,  35,  36,  37,  38,  39,  40,  /*  0x0A00 */
03254  41,  42,  43,  44,  45,  46,  28,  28,  /*  0x0C00 */
03255  47,  48,  49,  50,  51,  52,  53,  28,  /*  0x0E00 */
03256  28,  28,  54,  55,  56,  57,  58,  59,  /*  0x1000 */
03257  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1200 */
03258  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1400 */
03259  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1600 */
03260  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1800 */
03261  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1A00 */
03262  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1C00 */
03263  60,  60,  61,  62,  63,  64,  65,  66,  /*  0x1E00 */
03264  67,  68,  69,  70,  71,  72,  73,  74,  /*  0x2000 */
03265  75,  75,  75,  76,  77,  78,  28,  28,  /*  0x2200 */
03266  79,  80,  81,  82,  83,  83,  84,  85,  /*  0x2400 */
03267  86,  85,  28,  28,  87,  88,  89,  28,  /*  0x2600 */
03268  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2800 */
03269  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2A00 */
03270  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2C00 */
03271  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2E00 */
03272  90,  91,  92,  93,  94,  56,  95,  28,  /*  0x3000 */
03273  96,  97,  98,  99,  83, 100,  83, 101,  /*  0x3200 */
03274  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3400 */
03275  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3600 */
03276  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3800 */
03277  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3A00 */
03278  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3C00 */
03279  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3E00 */
03280  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4000 */
03281  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4200 */
03282  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4400 */
03283  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4600 */
03284  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4800 */
03285  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4A00 */
03286  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4C00 */
03287  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x4E00 */
03288  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5000 */
03289  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5200 */
03290  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5400 */
03291  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5600 */
03292  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5800 */
03293  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5A00 */
03294  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5C00 */
03295  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5E00 */
03296  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6000 */
03297  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6200 */
03298  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6400 */
03299  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6600 */
03300  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6800 */
03301  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6A00 */
03302  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6C00 */
03303  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6E00 */
03304  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7000 */
03305  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7200 */
03306  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7400 */
03307  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7600 */
03308  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7800 */
03309  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7A00 */
03310  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7C00 */
03311  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7E00 */
03312  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8000 */
03313  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8200 */
03314  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8400 */
03315  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8600 */
03316  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8800 */
03317  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8A00 */
03318  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8C00 */
03319  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8E00 */
03320  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9000 */
03321  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9200 */
03322  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9400 */
03323  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9600 */
03324  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9800 */
03325  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9A00 */
03326  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9C00 */
03327  56,  56,  56,  56,  56,  56, 102,  28,  /*  0x9E00 */
03328  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA000 */
03329  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA200 */
03330  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA400 */
03331  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA600 */
03332  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA800 */
03333  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xAA00 */
03334  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAC00 */
03335  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAE00 */
03336  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB000 */
03337  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB200 */
03338  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB400 */
03339  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB600 */
03340  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB800 */
03341  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBA00 */
03342  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBC00 */
03343  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBE00 */
03344  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC000 */
03345  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC200 */
03346  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC400 */
03347  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC600 */
03348  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC800 */
03349  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCA00 */
03350  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCC00 */
03351  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCE00 */
03352  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD000 */
03353  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD200 */
03354  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD400 */
03355  56,  56,  56,  56,  56,  56, 103,  28,  /*  0xD600 */
03356 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xD800 */
03357 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDA00 */
03358 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDC00 */
03359 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDE00 */
03360 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE000 */
03361 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE200 */
03362 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE400 */
03363 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE600 */
03364 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE800 */
03365 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEA00 */
03366 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEC00 */
03367 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEE00 */
03368 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF000 */
03369 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF200 */
03370 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF400 */
03371 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF600 */
03372 105, 105, 105, 105,  56,  56,  56,  56,  /*  0xF800 */
03373 106,  28,  28,  28, 107, 108, 109, 110,  /*  0xFA00 */
03374  56,  56,  56,  56, 111, 112, 113, 114,  /*  0xFC00 */
03375 115, 116,  56, 117, 118, 119, 120, 121   /*  0xFE00 */
03376 };
03377 
03378 /* The Y table has 7808 entries for a total of 7808 bytes. */
03379 
03380 const uint8 js_Y[] = {
03381   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
03382   0,   1,   1,   1,   1,   1,   0,   0,  /*    0 */
03383   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
03384   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
03385   2,   3,   3,   3,   4,   3,   3,   3,  /*    0 */
03386   5,   6,   3,   7,   3,   8,   3,   3,  /*    0 */
03387   9,   9,   9,   9,   9,   9,   9,   9,  /*    0 */
03388   9,   9,   3,   3,   7,   7,   7,   3,  /*    0 */
03389   3,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
03390  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
03391  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
03392  10,  10,  10,   5,   3,   6,  11,  12,  /*    1 */
03393  11,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
03394  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
03395  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
03396  13,  13,  13,   5,   7,   6,   7,   0,  /*    1 */
03397   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
03398   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
03399   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
03400   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
03401   2,   3,   4,   4,   4,   4,  15,  15,  /*    2 */
03402  11,  15,  16,   5,   7,   8,  15,  11,  /*    2 */
03403  15,   7,  17,  17,  11,  16,  15,   3,  /*    2 */
03404  11,  18,  16,   6,  19,  19,  19,   3,  /*    2 */
03405  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
03406  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
03407  20,  20,  20,  20,  20,  20,  20,   7,  /*    3 */
03408  20,  20,  20,  20,  20,  20,  20,  16,  /*    3 */
03409  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
03410  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
03411  21,  21,  21,  21,  21,  21,  21,   7,  /*    3 */
03412  21,  21,  21,  21,  21,  21,  21,  22,  /*    3 */
03413  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03414  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03415  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03416  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03417  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03418  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
03419  25,  26,  23,  24,  23,  24,  23,  24,  /*    4 */
03420  16,  23,  24,  23,  24,  23,  24,  23,  /*    4 */
03421  24,  23,  24,  23,  24,  23,  24,  23,  /*    5 */
03422  24,  16,  23,  24,  23,  24,  23,  24,  /*    5 */
03423  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
03424  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
03425  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
03426  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
03427  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
03428  27,  23,  24,  23,  24,  23,  24,  28,  /*    5 */
03429  16,  29,  23,  24,  23,  24,  30,  23,  /*    6 */
03430  24,  31,  31,  23,  24,  16,  32,  32,  /*    6 */
03431  33,  23,  24,  31,  34,  16,  35,  36,  /*    6 */
03432  23,  24,  16,  16,  35,  37,  16,  38,  /*    6 */
03433  23,  24,  23,  24,  23,  24,  38,  23,  /*    6 */
03434  24,  39,  40,  16,  23,  24,  39,  23,  /*    6 */
03435  24,  41,  41,  23,  24,  23,  24,  42,  /*    6 */
03436  23,  24,  16,  40,  23,  24,  40,  40,  /*    6 */
03437  40,  40,  40,  40,  43,  44,  45,  43,  /*    7 */
03438  44,  45,  43,  44,  45,  23,  24,  23,  /*    7 */
03439  24,  23,  24,  23,  24,  23,  24,  23,  /*    7 */
03440  24,  23,  24,  23,  24,  16,  23,  24,  /*    7 */
03441  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
03442  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
03443  16,  43,  44,  45,  23,  24,  46,  46,  /*    7 */
03444  46,  46,  23,  24,  23,  24,  23,  24,  /*    7 */
03445  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
03446  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
03447  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
03448  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
03449  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
03450  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
03451  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
03452  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
03453  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
03454  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
03455  16,  16,  16,  47,  48,  16,  49,  49,  /*    9 */
03456  50,  50,  16,  51,  16,  16,  16,  16,  /*    9 */
03457  49,  16,  16,  52,  16,  16,  16,  16,  /*    9 */
03458  53,  54,  16,  16,  16,  16,  16,  54,  /*    9 */
03459  16,  16,  55,  16,  16,  16,  16,  16,  /*    9 */
03460  16,  16,  16,  16,  16,  16,  16,  16,  /*    9 */
03461  16,  16,  16,  56,  16,  16,  16,  16,  /*   10 */
03462  56,  16,  57,  57,  16,  16,  16,  16,  /*   10 */
03463  16,  16,  58,  16,  16,  16,  16,  16,  /*   10 */
03464  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
03465  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
03466  16,  46,  46,  46,  46,  46,  46,  46,  /*   10 */
03467  59,  59,  59,  59,  59,  59,  59,  59,  /*   10 */
03468  59,  11,  11,  59,  59,  59,  59,  59,  /*   10 */
03469  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
03470  11,  11,  11,  11,  11,  11,  11,  11,  /*   11 */
03471  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
03472  11,  11,  11,  11,  11,  11,  11,  46,  /*   11 */
03473  59,  59,  59,  59,  59,  11,  11,  11,  /*   11 */
03474  11,  11,  46,  46,  46,  46,  46,  46,  /*   11 */
03475  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
03476  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
03477  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03478  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03479  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03480  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03481  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03482  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03483  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03484  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
03485  60,  60,  60,  60,  60,  60,  46,  46,  /*   13 */
03486  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
03487  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
03488  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
03489  60,  60,  46,  46,  46,  46,  46,  46,  /*   13 */
03490  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
03491  46,  46,  46,  46,   3,   3,  46,  46,  /*   13 */
03492  46,  46,  59,  46,  46,  46,   3,  46,  /*   13 */
03493  46,  46,  46,  46,  11,  11,  61,   3,  /*   14 */
03494  62,  62,  62,  46,  63,  46,  64,  64,  /*   14 */
03495  16,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
03496  20,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
03497  20,  20,  46,  20,  20,  20,  20,  20,  /*   14 */
03498  20,  20,  20,  20,  65,  66,  66,  66,  /*   14 */
03499  16,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
03500  21,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
03501  21,  21,  16,  21,  21,  21,  21,  21,  /*   15 */
03502  21,  21,  21,  21,  67,  68,  68,  46,  /*   15 */
03503  69,  70,  38,  38,  38,  71,  72,  46,  /*   15 */
03504  46,  46,  38,  46,  38,  46,  38,  46,  /*   15 */
03505  38,  46,  23,  24,  23,  24,  23,  24,  /*   15 */
03506  23,  24,  23,  24,  23,  24,  23,  24,  /*   15 */
03507  73,  74,  16,  40,  46,  46,  46,  46,  /*   15 */
03508  46,  46,  46,  46,  46,  46,  46,  46,  /*   15 */
03509  46,  75,  75,  75,  75,  75,  75,  75,  /*   16 */
03510  75,  75,  75,  75,  75,  46,  75,  75,  /*   16 */
03511  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
03512  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
03513  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
03514  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
03515  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
03516  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
03517  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
03518  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
03519  46,  74,  74,  74,  74,  74,  74,  74,  /*   17 */
03520  74,  74,  74,  74,  74,  46,  74,  74,  /*   17 */
03521  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
03522  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
03523  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
03524  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
03525  23,  24,  15,  60,  60,  60,  60,  46,  /*   18 */
03526  46,  46,  46,  46,  46,  46,  46,  46,  /*   18 */
03527  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03528  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03529  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03530  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03531  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03532  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
03533  40,  23,  24,  23,  24,  46,  46,  23,  /*   19 */
03534  24,  46,  46,  23,  24,  46,  46,  46,  /*   19 */
03535  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
03536  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
03537  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
03538  23,  24,  23,  24,  46,  46,  23,  24,  /*   19 */
03539  23,  24,  23,  24,  23,  24,  46,  46,  /*   19 */
03540  23,  24,  46,  46,  46,  46,  46,  46,  /*   19 */
03541  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03542  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03543  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03544  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03545  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03546  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
03547  46,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
03548  76,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
03549  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
03550  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
03551  76,  76,  76,  76,  76,  76,  76,  46,  /*   21 */
03552  46,  59,   3,   3,   3,   3,   3,   3,  /*   21 */
03553  46,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
03554  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
03555  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
03556  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
03557  77,  77,  77,  77,  77,  77,  77,  16,  /*   22 */
03558  46,   3,  46,  46,  46,  46,  46,  46,  /*   22 */
03559  46,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
03560  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
03561  60,  60,  46,  60,  60,  60,  60,  60,  /*   22 */
03562  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
03563  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
03564  60,  60,  46,  60,  60,  60,   3,  60,  /*   22 */
03565   3,  60,  60,   3,  60,  46,  46,  46,  /*   23 */
03566  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
03567  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
03568  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
03569  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
03570  40,  40,  40,  46,  46,  46,  46,  46,  /*   23 */
03571  40,  40,  40,   3,   3,  46,  46,  46,  /*   23 */
03572  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
03573  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
03574  46,  46,  46,  46,   3,  46,  46,  46,  /*   24 */
03575  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
03576  46,  46,  46,   3,  46,  46,  46,   3,  /*   24 */
03577  46,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
03578  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
03579  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
03580  40,  40,  40,  46,  46,  46,  46,  46,  /*   24 */
03581  59,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
03582  40,  40,  40,  60,  60,  60,  60,  60,  /*   25 */
03583  60,  60,  60,  46,  46,  46,  46,  46,  /*   25 */
03584  46,  46,  46,  46,  46,  46,  46,  46,  /*   25 */
03585  78,  78,  78,  78,  78,  78,  78,  78,  /*   25 */
03586  78,  78,   3,   3,   3,   3,  46,  46,  /*   25 */
03587  60,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
03588  40,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
03589  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03590  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03591  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03592  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03593  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03594  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03595  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
03596  46,  46,  40,  40,  40,  40,  40,  46,  /*   26 */
03597  40,  40,  40,  40,  40,  40,  40,  40,  /*   27 */
03598  40,  40,  40,  40,  40,  40,  40,  46,  /*   27 */
03599  40,  40,  40,  40,   3,  40,  60,  60,  /*   27 */
03600  60,  60,  60,  60,  60,  79,  79,  60,  /*   27 */
03601  60,  60,  60,  60,  60,  59,  59,  60,  /*   27 */
03602  60,  15,  60,  60,  60,  60,  46,  46,  /*   27 */
03603   9,   9,   9,   9,   9,   9,   9,   9,  /*   27 */
03604   9,   9,  46,  46,  46,  46,  46,  46,  /*   27 */
03605  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03606  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03607  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03608  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03609  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03610  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03611  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03612  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
03613  46,  60,  60,  80,  46,  40,  40,  40,  /*   29 */
03614  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03615  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03616  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03617  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03618  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03619  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
03620  40,  40,  46,  46,  60,  40,  80,  80,  /*   29 */
03621  80,  60,  60,  60,  60,  60,  60,  60,  /*   30 */
03622  60,  80,  80,  80,  80,  60,  46,  46,  /*   30 */
03623  15,  60,  60,  60,  60,  46,  46,  46,  /*   30 */
03624  40,  40,  40,  40,  40,  40,  40,  40,  /*   30 */
03625  40,  40,  60,  60,   3,   3,  81,  81,  /*   30 */
03626  81,  81,  81,  81,  81,  81,  81,  81,  /*   30 */
03627   3,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
03628  46,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
03629  46,  60,  80,  80,  46,  40,  40,  40,  /*   31 */
03630  40,  40,  40,  40,  40,  46,  46,  40,  /*   31 */
03631  40,  46,  46,  40,  40,  40,  40,  40,  /*   31 */
03632  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
03633  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
03634  40,  46,  40,  40,  40,  40,  40,  40,  /*   31 */
03635  40,  46,  40,  46,  46,  46,  40,  40,  /*   31 */
03636  40,  40,  46,  46,  60,  46,  80,  80,  /*   31 */
03637  80,  60,  60,  60,  60,  46,  46,  80,  /*   32 */
03638  80,  46,  46,  80,  80,  60,  46,  46,  /*   32 */
03639  46,  46,  46,  46,  46,  46,  46,  80,  /*   32 */
03640  46,  46,  46,  46,  40,  40,  46,  40,  /*   32 */
03641  40,  40,  60,  60,  46,  46,  81,  81,  /*   32 */
03642  81,  81,  81,  81,  81,  81,  81,  81,  /*   32 */
03643  40,  40,   4,   4,  82,  82,  82,  82,  /*   32 */
03644  19,  83,  15,  46,  46,  46,  46,  46,  /*   32 */
03645  46,  46,  60,  46,  46,  40,  40,  40,  /*   33 */
03646  40,  40,  40,  46,  46,  46,  46,  40,  /*   33 */
03647  40,  46,  46,  40,  40,  40,  40,  40,  /*   33 */
03648  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
03649  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
03650  40,  46,  40,  40,  40,  40,  40,  40,  /*   33 */
03651  40,  46,  40,  40,  46,  40,  40,  46,  /*   33 */
03652  40,  40,  46,  46,  60,  46,  80,  80,  /*   33 */
03653  80,  60,  60,  46,  46,  46,  46,  60,  /*   34 */
03654  60,  46,  46,  60,  60,  60,  46,  46,  /*   34 */
03655  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
03656  46,  40,  40,  40,  40,  46,  40,  46,  /*   34 */
03657  46,  46,  46,  46,  46,  46,  81,  81,  /*   34 */
03658  81,  81,  81,  81,  81,  81,  81,  81,  /*   34 */
03659  60,  60,  40,  40,  40,  46,  46,  46,  /*   34 */
03660  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
03661  46,  60,  60,  80,  46,  40,  40,  40,  /*   35 */
03662  40,  40,  40,  40,  46,  40,  46,  40,  /*   35 */
03663  40,  40,  46,  40,  40,  40,  40,  40,  /*   35 */
03664  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
03665  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
03666  40,  46,  40,  40,  40,  40,  40,  40,  /*   35 */
03667  40,  46,  40,  40,  46,  40,  40,  40,  /*   35 */
03668  40,  40,  46,  46,  60,  40,  80,  80,  /*   35 */
03669  80,  60,  60,  60,  60,  60,  46,  60,  /*   36 */
03670  60,  80,  46,  80,  80,  60,  46,  46,  /*   36 */
03671  15,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
03672  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
03673  40,  46,  46,  46,  46,  46,  81,  81,  /*   36 */
03674  81,  81,  81,  81,  81,  81,  81,  81,  /*   36 */
03675  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
03676  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
03677  46,  60,  80,  80,  46,  40,  40,  40,  /*   37 */
03678  40,  40,  40,  40,  40,  46,  46,  40,  /*   37 */
03679  40,  46,  46,  40,  40,  40,  40,  40,  /*   37 */
03680  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
03681  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
03682  40,  46,  40,  40,  40,  40,  40,  40,  /*   37 */
03683  40,  46,  40,  40,  46,  46,  40,  40,  /*   37 */
03684  40,  40,  46,  46,  60,  40,  80,  60,  /*   37 */
03685  80,  60,  60,  60,  46,  46,  46,  80,  /*   38 */
03686  80,  46,  46,  80,  80,  60,  46,  46,  /*   38 */
03687  46,  46,  46,  46,  46,  46,  60,  80,  /*   38 */
03688  46,  46,  46,  46,  40,  40,  46,  40,  /*   38 */
03689  40,  40,  46,  46,  46,  46,  81,  81,  /*   38 */
03690  81,  81,  81,  81,  81,  81,  81,  81,  /*   38 */
03691  15,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
03692  46,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
03693  46,  46,  60,  80,  46,  40,  40,  40,  /*   39 */
03694  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
03695  40,  46,  40,  40,  40,  40,  46,  46,  /*   39 */
03696  46,  40,  40,  46,  40,  46,  40,  40,  /*   39 */
03697  46,  46,  46,  40,  40,  46,  46,  46,  /*   39 */
03698  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
03699  40,  40,  40,  40,  40,  40,  46,  40,  /*   39 */
03700  40,  40,  46,  46,  46,  46,  80,  80,  /*   39 */
03701  60,  80,  80,  46,  46,  46,  80,  80,  /*   40 */
03702  80,  46,  80,  80,  80,  60,  46,  46,  /*   40 */
03703  46,  46,  46,  46,  46,  46,  46,  80,  /*   40 */
03704  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
03705  46,  46,  46,  46,  46,  46,  46,  81,  /*   40 */
03706  81,  81,  81,  81,  81,  81,  81,  81,  /*   40 */
03707  84,  19,  19,  46,  46,  46,  46,  46,  /*   40 */
03708  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
03709  46,  80,  80,  80,  46,  40,  40,  40,  /*   41 */
03710  40,  40,  40,  40,  40,  46,  40,  40,  /*   41 */
03711  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
03712  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
03713  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
03714  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
03715  40,  40,  40,  40,  46,  40,  40,  40,  /*   41 */
03716  40,  40,  46,  46,  46,  46,  60,  60,  /*   41 */
03717  60,  80,  80,  80,  80,  46,  60,  60,  /*   42 */
03718  60,  46,  60,  60,  60,  60,  46,  46,  /*   42 */
03719  46,  46,  46,  46,  46,  60,  60,  46,  /*   42 */
03720  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
03721  40,  40,  46,  46,  46,  46,  81,  81,  /*   42 */
03722  81,  81,  81,  81,  81,  81,  81,  81,  /*   42 */
03723  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
03724  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
03725  46,  46,  80,  80,  46,  40,  40,  40,  /*   43 */
03726  40,  40,  40,  40,  40,  46,  40,  40,  /*   43 */
03727  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
03728  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
03729  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
03730  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
03731  40,  40,  40,  40,  46,  40,  40,  40,  /*   43 */
03732  40,  40,  46,  46,  46,  46,  80,  60,  /*   43 */
03733  80,  80,  80,  80,  80,  46,  60,  80,  /*   44 */
03734  80,  46,  80,  80,  60,  60,  46,  46,  /*   44 */
03735  46,  46,  46,  46,  46,  80,  80,  46,  /*   44 */
03736  46,  46,  46,  46,  46,  46,  40,  46,  /*   44 */
03737  40,  40,  46,  46,  46,  46,  81,  81,  /*   44 */
03738  81,  81,  81,  81,  81,  81,  81,  81,  /*   44 */
03739  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
03740  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
03741  46,  46,  80,  80,  46,  40,  40,  40,  /*   45 */
03742  40,  40,  40,  40,  40,  46,  40,  40,  /*   45 */
03743  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
03744  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
03745  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
03746  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
03747  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
03748  40,  40,  46,  46,  46,  46,  80,  80,  /*   45 */
03749  80,  60,  60,  60,  46,  46,  80,  80,  /*   46 */
03750  80,  46,  80,  80,  80,  60,  46,  46,  /*   46 */
03751  46,  46,  46,  46,  46,  46,  46,  80,  /*   46 */
03752  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
03753  40,  40,  46,  46,  46,  46,  81,  81,  /*   46 */
03754  81,  81,  81,  81,  81,  81,  81,  81,  /*   46 */
03755  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
03756  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
03757  46,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
03758  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
03759  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
03760  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
03761  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
03762  40,  40,  40,  40,  40,  40,  40,   3,  /*   47 */
03763  40,  60,  40,  40,  60,  60,  60,  60,  /*   47 */
03764  60,  60,  60,  46,  46,  46,  46,   4,  /*   47 */
03765  40,  40,  40,  40,  40,  40,  59,  60,  /*   48 */
03766  60,  60,  60,  60,  60,  60,  60,  15,  /*   48 */
03767   9,   9,   9,   9,   9,   9,   9,   9,  /*   48 */
03768   9,   9,   3,   3,  46,  46,  46,  46,  /*   48 */
03769  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
03770  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
03771  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
03772  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
03773  46,  40,  40,  46,  40,  46,  46,  40,  /*   49 */
03774  40,  46,  40,  46,  46,  40,  46,  46,  /*   49 */
03775  46,  46,  46,  46,  40,  40,  40,  40,  /*   49 */
03776  46,  40,  40,  40,  40,  40,  40,  40,  /*   49 */
03777  46,  40,  40,  40,  46,  40,  46,  40,  /*   49 */
03778  46,  46,  40,  40,  46,  40,  40,   3,  /*   49 */
03779  40,  60,  40,  40,  60,  60,  60,  60,  /*   49 */
03780  60,  60,  46,  60,  60,  40,  46,  46,  /*   49 */
03781  40,  40,  40,  40,  40,  46,  59,  46,  /*   50 */
03782  60,  60,  60,  60,  60,  60,  46,  46,  /*   50 */
03783   9,   9,   9,   9,   9,   9,   9,   9,  /*   50 */
03784   9,   9,  46,  46,  40,  40,  46,  46,  /*   50 */
03785  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
03786  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
03787  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
03788  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
03789  15,  15,  15,  15,   3,   3,   3,   3,  /*   51 */
03790   3,   3,   3,   3,   3,   3,   3,   3,  /*   51 */
03791   3,   3,   3,  15,  15,  15,  15,  15,  /*   51 */
03792  60,  60,  15,  15,  15,  15,  15,  15,  /*   51 */
03793  78,  78,  78,  78,  78,  78,  78,  78,  /*   51 */
03794  78,  78,  85,  85,  85,  85,  85,  85,  /*   51 */
03795  85,  85,  85,  85,  15,  60,  15,  60,  /*   51 */
03796  15,  60,   5,   6,   5,   6,  80,  80,  /*   51 */
03797  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
03798  46,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
03799  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
03800  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
03801  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
03802  40,  40,  46,  46,  46,  46,  46,  46,  /*   52 */
03803  46,  60,  60,  60,  60,  60,  60,  60,  /*   52 */
03804  60,  60,  60,  60,  60,  60,  60,  80,  /*   52 */
03805  60,  60,  60,  60,  60,   3,  60,  60,  /*   53 */
03806  60,  60,  60,  60,  46,  46,  46,  46,  /*   53 */
03807  60,  60,  60,  60,  60,  60,  46,  60,  /*   53 */
03808  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
03809  60,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
03810  60,  60,  60,  60,  60,  60,  46,  46,  /*   53 */
03811  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
03812  46,  60,  46,  46,  46,  46,  46,  46,  /*   53 */
03813  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
03814  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
03815  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
03816  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
03817  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
03818  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
03819  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
03820  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
03821  76,  76,  76,  76,  76,  76,  46,  46,  /*   55 */
03822  46,  46,  46,  46,  46,  46,  46,  46,  /*   55 */
03823  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
03824  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
03825  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
03826  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
03827  16,  16,  16,  16,  16,  16,  16,  46,  /*   55 */
03828  46,  46,  46,   3,  46,  46,  46,  46,  /*   55 */
03829  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03830  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03831  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03832  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03833  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03834  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03835  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03836  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
03837  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03838  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03839  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03840  40,  40,  46,  46,  46,  46,  46,  40,  /*   57 */
03841  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03842  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03843  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03844  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
03845  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03846  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03847  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03848  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03849  40,  40,  40,  46,  46,  46,  46,  46,  /*   58 */
03850  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03851  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03852  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
03853  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03854  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03855  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03856  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03857  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03858  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03859  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
03860  40,  40,  46,  46,  46,  46,  46,  46,  /*   59 */
03861  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03862  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03863  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03864  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03865  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03866  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03867  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03868  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
03869  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03870  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03871  23,  24,  23,  24,  23,  24,  16,  16,  /*   61 */
03872  16,  16,  16,  16,  46,  46,  46,  46,  /*   61 */
03873  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03874  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03875  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03876  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
03877  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03878  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03879  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03880  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03881  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03882  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03883  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
03884  23,  24,  46,  46,  46,  46,  46,  46,  /*   62 */
03885  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
03886  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
03887  86,  86,  86,  86,  86,  86,  46,  46,  /*   63 */
03888  87,  87,  87,  87,  87,  87,  46,  46,  /*   63 */
03889  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
03890  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
03891  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
03892  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
03893  86,  86,  86,  86,  86,  86,  46,  46,  /*   64 */
03894  87,  87,  87,  87,  87,  87,  46,  46,  /*   64 */
03895  16,  86,  16,  86,  16,  86,  16,  86,  /*   64 */
03896  46,  87,  46,  87,  46,  87,  46,  87,  /*   64 */
03897  86,  86,  86,  86,  86,  86,  86,  86,  /*   64 */
03898  87,  87,  87,  87,  87,  87,  87,  87,  /*   64 */
03899  88,  88,  89,  89,  89,  89,  90,  90,  /*   64 */
03900  91,  91,  92,  92,  93,  93,  46,  46,  /*   64 */
03901  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
03902  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
03903  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
03904  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
03905  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
03906  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
03907  86,  86,  16,  94,  16,  46,  16,  16,  /*   65 */
03908  87,  87,  95,  95,  96,  11,  38,  11,  /*   65 */
03909  11,  11,  16,  94,  16,  46,  16,  16,  /*   66 */
03910  97,  97,  97,  97,  96,  11,  11,  11,  /*   66 */
03911  86,  86,  16,  16,  46,  46,  16,  16,  /*   66 */
03912  87,  87,  98,  98,  46,  11,  11,  11,  /*   66 */
03913  86,  86,  16,  16,  16,  99,  16,  16,  /*   66 */
03914  87,  87, 100, 100, 101,  11,  11,  11,  /*   66 */
03915  46,  46,  16,  94,  16,  46,  16,  16,  /*   66 */
03916 102, 102, 103, 103,  96,  11,  11,  46,  /*   66 */
03917   2,   2,   2,   2,   2,   2,   2,   2,  /*   67 */
03918   2,   2,   2,   2, 104, 104, 104, 104,  /*   67 */
03919   8,   8,   8,   8,   8,   8,   3,   3,  /*   67 */
03920   5,   6,   5,   5,   5,   6,   5,   5,  /*   67 */
03921   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
03922 105, 106, 104, 104, 104, 104, 104,  46,  /*   67 */
03923   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
03924   3,   5,   6,   3,   3,   3,   3,  12,  /*   67 */
03925  12,   3,   3,   3,   7,   5,   6,  46,  /*   68 */
03926  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
03927  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
03928  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
03929  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
03930  46,  46, 104, 104, 104, 104, 104, 104,  /*   68 */
03931  17,  46,  46,  46,  17,  17,  17,  17,  /*   68 */
03932  17,  17,   7,   7,   7,   5,   6,  16,  /*   68 */
03933 107, 107, 107, 107, 107, 107, 107, 107,  /*   69 */
03934 107, 107,   7,   7,   7,   5,   6,  46,  /*   69 */
03935  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
03936  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
03937   4,   4,   4,   4,   4,   4,   4,   4,  /*   69 */
03938   4,   4,   4,   4,  46,  46,  46,  46,  /*   69 */
03939  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
03940  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
03941  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
03942  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
03943  60,  60,  60,  60,  60,  60,  60,  60,  /*   70 */
03944  60,  60,  60,  60,  60,  79,  79,  79,  /*   70 */
03945  79,  60,  46,  46,  46,  46,  46,  46,  /*   70 */
03946  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
03947  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
03948  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
03949  15,  15,  38,  15,  15,  15,  15,  38,  /*   71 */
03950  15,  15,  16,  38,  38,  38,  16,  16,  /*   71 */
03951  38,  38,  38,  16,  15,  38,  15,  15,  /*   71 */
03952  38,  38,  38,  38,  38,  38,  15,  15,  /*   71 */
03953  15,  15,  15,  15,  38,  15,  38,  15,  /*   71 */
03954  38,  15,  38,  38,  38,  38,  16,  16,  /*   71 */
03955  38,  38,  15,  38,  16,  40,  40,  40,  /*   71 */
03956  40,  46,  46,  46,  46,  46,  46,  46,  /*   71 */
03957  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
03958  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
03959  46,  46,  46,  19,  19,  19,  19,  19,  /*   72 */
03960  19,  19,  19,  19,  19,  19,  19, 108,  /*   72 */
03961 109, 109, 109, 109, 109, 109, 109, 109,  /*   72 */
03962 109, 109, 109, 109, 110, 110, 110, 110,  /*   72 */
03963 111, 111, 111, 111, 111, 111, 111, 111,  /*   72 */
03964 111, 111, 111, 111, 112, 112, 112, 112,  /*   72 */
03965 113, 113, 113,  46,  46,  46,  46,  46,  /*   73 */
03966  46,  46,  46,  46,  46,  46,  46,  46,  /*   73 */
03967   7,   7,   7,   7,   7,  15,  15,  15,  /*   73 */
03968  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
03969  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
03970  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
03971  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
03972  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
03973  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
03974  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
03975  15,  15,   7,  15,   7,  15,  15,  15,  /*   74 */
03976  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
03977  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
03978  15,  15,  15,  46,  46,  46,  46,  46,  /*   74 */
03979  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
03980  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
03981   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03982   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03983   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03984   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03985   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03986   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03987   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03988   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
03989   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03990   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03991   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03992   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03993   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03994   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
03995   7,   7,  46,  46,  46,  46,  46,  46,  /*   76 */
03996  46,  46,  46,  46,  46,  46,  46,  46,  /*   76 */
03997  15,  46,  15,  15,  15,  15,  15,  15,  /*   77 */
03998   7,   7,   7,   7,  15,  15,  15,  15,  /*   77 */
03999  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
04000  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
04001   7,   7,  15,  15,  15,  15,  15,  15,  /*   77 */
04002  15,   5,   6,  15,  15,  15,  15,  15,  /*   77 */
04003  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
04004  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
04005  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04006  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04007  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04008  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04009  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04010  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04011  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
04012  15,  15,  15,  46,  46,  46,  46,  46,  /*   78 */
04013  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
04014  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
04015  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
04016  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
04017  15,  15,  15,  15,  15,  46,  46,  46,  /*   79 */
04018  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
04019  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
04020  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
04021  15,  15,  15,  15,  15,  15,  15,  15,  /*   80 */
04022  15,  15,  15,  46,  46,  46,  46,  46,  /*   80 */
04023  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
04024  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
04025 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
04026 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
04027 114, 114, 114, 114,  82,  82,  82,  82,  /*   80 */
04028  82,  82,  82,  82,  82,  82,  82,  82,  /*   80 */
04029  82,  82,  82,  82,  82,  82,  82,  82,  /*   81 */
04030 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
04031 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
04032 115, 115, 115, 115,  15,  15,  15,  15,  /*   81 */
04033  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
04034  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
04035  15,  15,  15,  15,  15,  15, 116, 116,  /*   81 */
04036 116, 116, 116, 116, 116, 116, 116, 116,  /*   81 */
04037 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
04038 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
04039 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
04040 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
04041 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
04042 117, 117, 118,  46,  46,  46,  46,  46,  /*   82 */
04043  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
04044  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
04045  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04046  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04047  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04048  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04049  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04050  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04051  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04052  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
04053  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04054  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04055  15,  15,  15,  15,  15,  15,  46,  46,  /*   84 */
04056  46,  46,  46,  46,  46,  46,  46,  46,  /*   84 */
04057  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04058  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04059  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04060  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
04061  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04062  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04063  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04064  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04065  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04066  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
04067  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
04068  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
04069  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04070  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04071  15,  15,  15,  15,  46,  46,  46,  46,  /*   86 */
04072  46,  46,  15,  15,  15,  15,  15,  15,  /*   86 */
04073  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04074  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04075  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04076  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
04077  46,  15,  15,  15,  15,  46,  15,  15,  /*   87 */
04078  15,  15,  46,  46,  15,  15,  15,  15,  /*   87 */
04079  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04080  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04081  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04082  46,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04083  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04084  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
04085  15,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
04086  15,  15,  15,  15,  46,  15,  46,  15,  /*   88 */
04087  15,  15,  15,  46,  46,  46,  15,  46,  /*   88 */
04088  15,  15,  15,  15,  15,  15,  15,  46,  /*   88 */
04089  46,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
04090  46,  46,  46,  46,  46,  46,  46,  46,  /*   88 */
04091  46,  46,  46,  46,  46,  46, 119, 119,  /*   88 */
04092 119, 119, 119, 119, 119, 119, 119, 119,  /*   88 */
04093 114, 114, 114, 114, 114, 114, 114, 114,  /*   89 */
04094 114, 114,  83,  83,  83,  83,  83,  83,  /*   89 */
04095  83,  83,  83,  83,  15,  46,  46,  46,  /*   89 */
04096  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
04097  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
04098  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
04099  46,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
04100  15,  15,  15,  15,  15,  15,  15,  46,  /*   89 */
04101   2,   3,   3,   3,  15,  59,   3, 120,  /*   90 */
04102   5,   6,   5,   6,   5,   6,   5,   6,  /*   90 */
04103   5,   6,  15,  15,   5,   6,   5,   6,  /*   90 */
04104   5,   6,   5,   6,   8,   5,   6,   5,  /*   90 */
04105  15, 121, 121, 121, 121, 121, 121, 121,  /*   90 */
04106 121, 121,  60,  60,  60,  60,  60,  60,  /*   90 */
04107   8,  59,  59,  59,  59,  59,  15,  15,  /*   90 */
04108  46,  46,  46,  46,  46,  46,  46,  15,  /*   90 */
04109  46,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04110  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04111  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04112  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04113  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04114  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04115  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04116  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
04117  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04118  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04119  40,  40,  40,  40,  40,  46,  46,  46,  /*   92 */
04120  46,  60,  60,  59,  59,  59,  59,  46,  /*   92 */
04121  46,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04122  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04123  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04124  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
04125  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04126  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04127  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04128  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04129  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04130  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04131  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
04132  40,  40,  40,   3,  59,  59,  59,  46,  /*   93 */
04133  46,  46,  46,  46,  46,  40,  40,  40,  /*   94 */
04134  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04135  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04136  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04137  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04138  40,  40,  40,  40,  40,  46,  46,  46,  /*   94 */
04139  46,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04140  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
04141  40,  40,  40,  40,  40,  40,  40,  40,  /*   95 */
04142  40,  40,  40,  40,  40,  40,  40,  46,  /*   95 */
04143  15,  15,  85,  85,  85,  85,  15,  15,  /*   95 */
04144  15,  15,  15,  15,  15,  15,  15,  15,  /*   95 */
04145  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
04146  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
04147  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
04148  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
04149  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
04150  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
04151  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
04152  15,  15,  15,  15,  15,  46,  46,  46,  /*   96 */
04153  85,  85,  85,  85,  85,  85,  85,  85,  /*   96 */
04154  85,  85,  15,  15,  15,  15,  15,  15,  /*   96 */
04155  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
04156  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
04157  15,  15,  15,  15,  46,  46,  46,  46,  /*   97 */
04158  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
04159  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
04160  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
04161  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
04162  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
04163  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
04164  15,  15,  15,  15,  46,  46,  46,  15,  /*   97 */
04165 114, 114, 114, 114, 114, 114, 114, 114,  /*   98 */
04166 114, 114,  15,  15,  15,  15,  15,  15,  /*   98 */
04167  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
04168  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
04169  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
04170  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
04171  15,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
04172  46,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
04173  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04174  15,  15,  15,  15,  46,  46,  46,  46,  /*   99 */
04175  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04176  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04177  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04178  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04179  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
04180  15,  15,  15,  15,  15,  15,  15,  46,  /*   99 */
04181  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04182  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04183  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04184  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04185  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04186  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
04187  15,  15,  15,  15,  15,  15,  15,  46,  /*  100 */
04188  46,  46,  46,  15,  15,  15,  15,  15,  /*  100 */
04189  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04190  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04191  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04192  15,  15,  15,  15,  15,  15,  46,  46,  /*  101 */
04193  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04194  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04195  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
04196  15,  15,  15,  15,  15,  15,  15,  46,  /*  101 */
04197  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
04198  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
04199  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
04200  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
04201  40,  40,  40,  40,  40,  40,  46,  46,  /*  102 */
04202  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
04203  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
04204  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
04205  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
04206  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
04207  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
04208  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
04209  40,  40,  40,  40,  46,  46,  46,  46,  /*  103 */
04210  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
04211  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
04212  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
04213 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04214 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04215 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04216 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04217 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04218 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04219 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04220 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
04221 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04222 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04223 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04224 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04225 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04226 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04227 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04228 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
04229  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
04230  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
04231  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
04232  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
04233  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
04234  40,  40,  40,  40,  40,  40,  46,  46,  /*  106 */
04235  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
04236  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
04237  16,  16,  16,  16,  16,  16,  16,  46,  /*  107 */
04238  46,  46,  46,  46,  46,  46,  46,  46,  /*  107 */
04239  46,  46,  46,  16,  16,  16,  16,  16,  /*  107 */
04240  46,  46,  46,  46,  46,  46,  60,  40,  /*  107 */
04241  40,  40,  40,  40,  40,  40,  40,  40,  /*  107 */
04242  40,   7,  40,  40,  40,  40,  40,  40,  /*  107 */
04243  40,  40,  40,  40,  40,  40,  40,  46,  /*  107 */
04244  40,  40,  40,  40,  40,  46,  40,  46,  /*  107 */
04245  40,  40,  46,  40,  40,  46,  40,  40,  /*  108 */
04246  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04247  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04248  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04249  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04250  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04251  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04252  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
04253  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04254  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04255  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04256  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04257  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04258  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
04259  40,  40,  46,  46,  46,  46,  46,  46,  /*  109 */
04260  46,  46,  46,  46,  46,  46,  46,  46,  /*  109 */
04261  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
04262  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
04263  46,  46,  46,  40,  40,  40,  40,  40,  /*  110 */
04264  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
04265  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
04266  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
04267  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
04268  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
04269  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04270  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04271  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04272  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04273  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04274  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04275  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
04276  40,  40,  40,  40,  40,  40,   5,   6,  /*  111 */
04277  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
04278  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
04279  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04280  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04281  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04282  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04283  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04284  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
04285  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04286  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04287  46,  46,  40,  40,  40,  40,  40,  40,  /*  113 */
04288  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04289  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04290  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04291  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04292  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
04293  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
04294  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
04295  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
04296  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
04297  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
04298  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
04299  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
04300  40,  40,  40,  40,  46,  46,  46,  46,  /*  114 */
04301  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
04302  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
04303  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
04304  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
04305  60,  60,  60,  60,  46,  46,  46,  46,  /*  115 */
04306  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
04307   3,   8,   8,  12,  12,   5,   6,   5,  /*  115 */
04308   6,   5,   6,   5,   6,   5,   6,   5,  /*  115 */
04309   6,   5,   6,   5,   6,  46,  46,  46,  /*  116 */
04310  46,   3,   3,   3,   3,  12,  12,  12,  /*  116 */
04311   3,   3,   3,  46,   3,   3,   3,   3,  /*  116 */
04312   8,   5,   6,   5,   6,   5,   6,   3,  /*  116 */
04313   3,   3,   7,   8,   7,   7,   7,  46,  /*  116 */
04314   3,   4,   3,   3,  46,  46,  46,  46,  /*  116 */
04315  40,  40,  40,  46,  40,  46,  40,  40,  /*  116 */
04316  40,  40,  40,  40,  40,  40,  40,  40,  /*  116 */
04317  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04318  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04319  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04320  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04321  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04322  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04323  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
04324  40,  40,  40,  40,  40,  46,  46, 104,  /*  117 */
04325  46,   3,   3,   3,   4,   3,   3,   3,  /*  118 */
04326   5,   6,   3,   7,   3,   8,   3,   3,  /*  118 */
04327   9,   9,   9,   9,   9,   9,   9,   9,  /*  118 */
04328   9,   9,   3,   3,   7,   7,   7,   3,  /*  118 */
04329   3,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
04330  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
04331  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
04332  10,  10,  10,   5,   3,   6,  11,  12,  /*  118 */
04333  11,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
04334  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
04335  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
04336  13,  13,  13,   5,   7,   6,   7,  46,  /*  119 */
04337  46,   3,   5,   6,   3,   3,  40,  40,  /*  119 */
04338  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
04339  59,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
04340  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
04341  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04342  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04343  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04344  40,  40,  40,  40,  40,  40,  59,  59,  /*  120 */
04345  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04346  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04347  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
04348  40,  40,  40,  40,  40,  40,  40,  46,  /*  120 */
04349  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
04350  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
04351  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
04352  46,  46,  40,  40,  40,  46,  46,  46,  /*  121 */
04353   4,   4,   7,  11,  15,   4,   4,  46,  /*  121 */
04354   7,   7,   7,   7,   7,  15,  15,  46,  /*  121 */
04355  46,  46,  46,  46,  46,  46,  46,  46,  /*  121 */
04356  46,  46,  46,  46,  46,  15,  46,  46   /*  121 */
04357 };
04358 
04359 /* The A table has 124 entries for a total of 496 bytes. */
04360 
04361 const uint32 js_A[] = {
04362 0x0001000F,  /*    0   Cc, ignorable */
04363 0x0004000F,  /*    1   Cc, whitespace */
04364 0x0004000C,  /*    2   Zs, whitespace */
04365 0x00000018,  /*    3   Po */
04366 0x0006001A,  /*    4   Sc, currency */
04367 0x00000015,  /*    5   Ps */
04368 0x00000016,  /*    6   Pe */
04369 0x00000019,  /*    7   Sm */
04370 0x00000014,  /*    8   Pd */
04371 0x00036089,  /*    9   Nd, identifier part, decimal 16 */
04372 0x0827FF81,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
04373 0x0000001B,  /*   11   Sk */
04374 0x00050017,  /*   12   Pc, underscore */
04375 0x0817FF82,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
04376 0x0000000C,  /*   14   Zs */
04377 0x0000001C,  /*   15   So */
04378 0x00070182,  /*   16   Ll, identifier start */
04379 0x0000600B,  /*   17   No, decimal 16 */
04380 0x0000500B,  /*   18   No, decimal 8 */
04381 0x0000800B,  /*   19   No, strange */
04382 0x08270181,  /*   20   Lu, hasLower (add 32), identifier start */
04383 0x08170182,  /*   21   Ll, hasUpper (subtract 32), identifier start */
04384 0xE1D70182,  /*   22   Ll, hasUpper (subtract -121), identifier start */
04385 0x00670181,  /*   23   Lu, hasLower (add 1), identifier start */
04386 0x00570182,  /*   24   Ll, hasUpper (subtract 1), identifier start */
04387 0xCE670181,  /*   25   Lu, hasLower (add -199), identifier start */
04388 0x3A170182,  /*   26   Ll, hasUpper (subtract 232), identifier start */
04389 0xE1E70181,  /*   27   Lu, hasLower (add -121), identifier start */
04390 0x4B170182,  /*   28   Ll, hasUpper (subtract 300), identifier start */
04391 0x34A70181,  /*   29   Lu, hasLower (add 210), identifier start */
04392 0x33A70181,  /*   30   Lu, hasLower (add 206), identifier start */
04393 0x33670181,  /*   31   Lu, hasLower (add 205), identifier start */
04394 0x32A70181,  /*   32   Lu, hasLower (add 202), identifier start */
04395 0x32E70181,  /*   33   Lu, hasLower (add 203), identifier start */
04396 0x33E70181,  /*   34   Lu, hasLower (add 207), identifier start */
04397 0x34E70181,  /*   35   Lu, hasLower (add 211), identifier start */
04398 0x34670181,  /*   36   Lu, hasLower (add 209), identifier start */
04399 0x35670181,  /*   37   Lu, hasLower (add 213), identifier start */
04400 0x00070181,  /*   38   Lu, identifier start */
04401 0x36A70181,  /*   39   Lu, hasLower (add 218), identifier start */
04402 0x00070185,  /*   40   Lo, identifier start */
04403 0x36670181,  /*   41   Lu, hasLower (add 217), identifier start */
04404 0x36E70181,  /*   42   Lu, hasLower (add 219), identifier start */
04405 0x00AF0181,  /*   43   Lu, hasLower (add 2), hasTitle, identifier start */
04406 0x007F0183,  /*   44   Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
04407 0x009F0182,  /*   45   Ll, hasUpper (subtract 2), hasTitle, identifier start */
04408 0x00000000,  /*   46   unassigned */
04409 0x34970182,  /*   47   Ll, hasUpper (subtract 210), identifier start */
04410 0x33970182,  /*   48   Ll, hasUpper (subtract 206), identifier start */
04411 0x33570182,  /*   49   Ll, hasUpper (subtract 205), identifier start */
04412 0x32970182,  /*   50   Ll, hasUpper (subtract 202), identifier start */
04413 0x32D70182,  /*   51   Ll, hasUpper (subtract 203), identifier start */
04414 0x33D70182,  /*   52   Ll, hasUpper (subtract 207), identifier start */
04415 0x34570182,  /*   53   Ll, hasUpper (subtract 209), identifier start */
04416 0x34D70182,  /*   54   Ll, hasUpper (subtract 211), identifier start */
04417 0x35570182,  /*   55   Ll, hasUpper (subtract 213), identifier start */
04418 0x36970182,  /*   56   Ll, hasUpper (subtract 218), identifier start */
04419 0x36570182,  /*   57   Ll, hasUpper (subtract 217), identifier start */
04420 0x36D70182,  /*   58   Ll, hasUpper (subtract 219), identifier start */
04421 0x00070084,  /*   59   Lm, identifier start */
04422 0x00030086,  /*   60   Mn, identifier part */
04423 0x09A70181,  /*   61   Lu, hasLower (add 38), identifier start */
04424 0x09670181,  /*   62   Lu, hasLower (add 37), identifier start */
04425 0x10270181,  /*   63   Lu, hasLower (add 64), identifier start */
04426 0x0FE70181,  /*   64   Lu, hasLower (add 63), identifier start */
04427 0x09970182,  /*   65   Ll, hasUpper (subtract 38), identifier start */
04428 0x09570182,  /*   66   Ll, hasUpper (subtract 37), identifier start */
04429 0x10170182,  /*   67   Ll, hasUpper (subtract 64), identifier start */
04430 0x0FD70182,  /*   68   Ll, hasUpper (subtract 63), identifier start */
04431 0x0F970182,  /*   69   Ll, hasUpper (subtract 62), identifier start */
04432 0x0E570182,  /*   70   Ll, hasUpper (subtract 57), identifier start */
04433 0x0BD70182,  /*   71   Ll, hasUpper (subtract 47), identifier start */
04434 0x0D970182,  /*   72   Ll, hasUpper (subtract 54), identifier start */
04435 0x15970182,  /*   73   Ll, hasUpper (subtract 86), identifier start */
04436 0x14170182,  /*   74   Ll, hasUpper (subtract 80), identifier start */
04437 0x14270181,  /*   75   Lu, hasLower (add 80), identifier start */
04438 0x0C270181,  /*   76   Lu, hasLower (add 48), identifier start */
04439 0x0C170182,  /*   77   Ll, hasUpper (subtract 48), identifier start */
04440 0x00034089,  /*   78   Nd, identifier part, decimal 0 */
04441 0x00000087,  /*   79   Me */
04442 0x00030088,  /*   80   Mc, identifier part */
04443 0x00037489,  /*   81   Nd, identifier part, decimal 26 */
04444 0x00005A0B,  /*   82   No, decimal 13 */
04445 0x00006E0B,  /*   83   No, decimal 23 */
04446 0x0000740B,  /*   84   No, decimal 26 */
04447 0x0000000B,  /*   85   No */
04448 0xFE170182,  /*   86   Ll, hasUpper (subtract -8), identifier start */
04449 0xFE270181,  /*   87   Lu, hasLower (add -8), identifier start */
04450 0xED970182,  /*   88   Ll, hasUpper (subtract -74), identifier start */
04451 0xEA970182,  /*   89   Ll, hasUpper (subtract -86), identifier start */
04452 0xE7170182,  /*   90   Ll, hasUpper (subtract -100), identifier start */
04453 0xE0170182,  /*   91   Ll, hasUpper (subtract -128), identifier start */
04454 0xE4170182,  /*   92   Ll, hasUpper (subtract -112), identifier start */
04455 0xE0970182,  /*   93   Ll, hasUpper (subtract -126), identifier start */
04456 0xFDD70182,  /*   94   Ll, hasUpper (subtract -9), identifier start */
04457 0xEDA70181,  /*   95   Lu, hasLower (add -74), identifier start */
04458 0xFDE70181,  /*   96   Lu, hasLower (add -9), identifier start */
04459 0xEAA70181,  /*   97   Lu, hasLower (add -86), identifier start */
04460 0xE7270181,  /*   98   Lu, hasLower (add -100), identifier start */
04461 0xFE570182,  /*   99   Ll, hasUpper (subtract -7), identifier start */
04462 0xE4270181,  /*  100   Lu, hasLower (add -112), identifier start */
04463 0xFE670181,  /*  101   Lu, hasLower (add -7), identifier start */
04464 0xE0270181,  /*  102   Lu, hasLower (add -128), identifier start */
04465 0xE0A70181,  /*  103   Lu, hasLower (add -126), identifier start */
04466 0x00010010,  /*  104   Cf, ignorable */
04467 0x0004000D,  /*  105   Zl, whitespace */
04468 0x0004000E,  /*  106   Zp, whitespace */
04469 0x0000400B,  /*  107   No, decimal 0 */
04470 0x0000440B,  /*  108   No, decimal 2 */
04471 0x0427438A,  /*  109   Nl, hasLower (add 16), identifier start, decimal 1 */
04472 0x0427818A,  /*  110   Nl, hasLower (add 16), identifier start, strange */
04473 0x0417638A,  /*  111   Nl, hasUpper (subtract 16), identifier start, decimal 17 */
04474 0x0417818A,  /*  112   Nl, hasUpper (subtract 16), identifier start, strange */
04475 0x0007818A,  /*  113   Nl, identifier start, strange */
04476 0x0000420B,  /*  114   No, decimal 1 */
04477 0x0000720B,  /*  115   No, decimal 25 */
04478 0x06A0001C,  /*  116   So, hasLower (add 26) */
04479 0x0690001C,  /*  117   So, hasUpper (subtract 26) */
04480 0x00006C0B,  /*  118   No, decimal 22 */
04481 0x0000560B,  /*  119   No, decimal 11 */
04482 0x0007738A,  /*  120   Nl, identifier start, decimal 25 */
04483 0x0007418A,  /*  121   Nl, identifier start, decimal 0 */
04484 0x00000013,  /*  122   Cs */
04485 0x00000012   /*  123   Co */
04486 };
04487 
04488 const jschar js_uriReservedPlusPound_ucstr[] =
04489     {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
04490 const jschar js_uriUnescaped_ucstr[] =
04491     {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
04492      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
04493      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
04494      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
04495      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
04496      '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
04497 
04498 #define URI_CHUNK 64U
04499 
04500 /* Concatenate jschars onto an unshared/newborn JSString. */
04501 static JSBool
04502 AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
04503 {
04504     size_t total;
04505 
04506     JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
04507     total = str->length + length + 1;
04508     if (!str->chars ||
04509         JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
04510         total = JS_ROUNDUP(total, URI_CHUNK);
04511         str->chars = JS_realloc(cx, str->chars, total * sizeof(jschar));
04512         if (!str->chars)
04513             return JS_FALSE;
04514     }
04515     js_strncpy(str->chars + str->length, chars, length);
04516     str->length += length;
04517     str->chars[str->length] = 0;
04518     return JS_TRUE;
04519 }
04520 
04521 /*
04522  * ECMA 3, 15.1.3 URI Handling Function Properties
04523  *
04524  * The following are implementations of the algorithms
04525  * given in the ECMA specification for the hidden functions
04526  * 'Encode' and 'Decode'.
04527  */
04528 static JSBool
04529 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
04530        const jschar *unescapedSet2, jsval *rval)
04531 {
04532     size_t length, j, k, L;
04533     jschar *chars, c, c2;
04534     uint32 v;
04535     uint8 utf8buf[6];
04536     jschar hexBuf[4];
04537     static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
04538     JSString *R;
04539 
04540     length = JSSTRING_LENGTH(str);
04541     if (length == 0) {
04542         *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
04543         return JS_TRUE;
04544     }
04545 
04546     R = js_NewString(cx, NULL, 0, 0);
04547     if (!R)
04548         return JS_FALSE;
04549 
04550     hexBuf[0] = '%';
04551     hexBuf[3] = 0;
04552     chars = JSSTRING_CHARS(str);
04553     for (k = 0; k < length; k++) {
04554         c = chars[k];
04555         if (js_strchr(unescapedSet, c) ||
04556             (unescapedSet2 && js_strchr(unescapedSet2, c))) {
04557             if (!AddCharsToURI(cx, R, &c, 1))
04558                 return JS_FALSE;
04559         } else {
04560             if ((c >= 0xDC00) && (c <= 0xDFFF)) {
04561                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
04562                                  JSMSG_BAD_URI, NULL);
04563                 return JS_FALSE;
04564             }
04565             if (c < 0xD800 || c > 0xDBFF) {
04566                 v = c;
04567             } else {
04568                 k++;
04569                 if (k == length) {
04570                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
04571                                      JSMSG_BAD_URI, NULL);
04572                     return JS_FALSE;
04573                 }
04574                 c2 = chars[k];
04575                 if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
04576                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
04577                                      JSMSG_BAD_URI, NULL);
04578                     return JS_FALSE;
04579                 }
04580                 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
04581             }
04582             L = js_OneUcs4ToUtf8Char(utf8buf, v);
04583             for (j = 0; j < L; j++) {
04584                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
04585                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
04586                 if (!AddCharsToURI(cx, R, hexBuf, 3))
04587                     return JS_FALSE;
04588             }
04589         }
04590     }
04591 
04592     /*
04593      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
04594      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
04595      * more jschars than it needs.
04596      */
04597     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
04598     if (chars)
04599         R->chars = chars;
04600     *rval = STRING_TO_JSVAL(R);
04601     return JS_TRUE;
04602 }
04603 
04604 static JSBool
04605 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
04606 {
04607     size_t length, start, k;
04608     jschar *chars, c, H;
04609     uint32 v;
04610     jsuint B;
04611     uint8 octets[6];
04612     JSString *R;
04613     intN j, n;
04614 
04615     length = JSSTRING_LENGTH(str);
04616     if (length == 0) {
04617         *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
04618         return JS_TRUE;
04619     }
04620 
04621     R = js_NewString(cx, NULL, 0, 0);
04622     if (!R)
04623         return JS_FALSE;
04624 
04625     chars = JSSTRING_CHARS(str);
04626     for (k = 0; k < length; k++) {
04627         c = chars[k];
04628         if (c == '%') {
04629             start = k;
04630             if ((k + 2) >= length)
04631                 goto bad;
04632             if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
04633                 goto bad;
04634             B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
04635             k += 2;
04636             if (!(B & 0x80)) {
04637                 c = (jschar)B;
04638             } else {
04639                 n = 1;
04640                 while (B & (0x80 >> n))
04641                     n++;
04642                 if (n == 1 || n > 6)
04643                     goto bad;
04644                 octets[0] = (uint8)B;
04645                 if (k + 3 * (n - 1) >= length)
04646                     goto bad;
04647                 for (j = 1; j < n; j++) {
04648                     k++;
04649                     if (chars[k] != '%')
04650                         goto bad;
04651                     if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
04652                         goto bad;
04653                     B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
04654                     if ((B & 0xC0) != 0x80)
04655                         goto bad;
04656                     k += 2;
04657                     octets[j] = (char)B;
04658                 }
04659                 v = Utf8ToOneUcs4Char(octets, n);
04660                 if (v >= 0x10000) {
04661                     v -= 0x10000;
04662                     if (v > 0xFFFFF)
04663                         goto bad;
04664                     c = (jschar)((v & 0x3FF) + 0xDC00);
04665                     H = (jschar)((v >> 10) + 0xD800);
04666                     if (!AddCharsToURI(cx, R, &H, 1))
04667                         return JS_FALSE;
04668                 } else {
04669                     c = (jschar)v;
04670                 }
04671             }
04672             if (js_strchr(reservedSet, c)) {
04673                 if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
04674                     return JS_FALSE;
04675             } else {
04676                 if (!AddCharsToURI(cx, R, &c, 1))
04677                     return JS_FALSE;
04678             }
04679         } else {
04680             if (!AddCharsToURI(cx, R, &c, 1))
04681                 return JS_FALSE;
04682         }
04683     }
04684 
04685     /*
04686      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
04687      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
04688      * more jschars than it needs.
04689      */
04690     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
04691     if (chars)
04692         R->chars = chars;
04693     *rval = STRING_TO_JSVAL(R);
04694     return JS_TRUE;
04695 
04696 bad:
04697     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
04698     return JS_FALSE;
04699 }
04700 
04701 static JSBool
04702 str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
04703               jsval *rval)
04704 {
04705     JSString *str;
04706 
04707     str = js_ValueToString(cx, argv[0]);
04708     if (!str)
04709         return JS_FALSE;
04710     argv[0] = STRING_TO_JSVAL(str);
04711     return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval);
04712 }
04713 
04714 static JSBool
04715 str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
04716                         jsval *rval)
04717 {
04718     JSString *str;
04719 
04720     str = js_ValueToString(cx, argv[0]);
04721     if (!str)
04722         return JS_FALSE;
04723     argv[0] = STRING_TO_JSVAL(str);
04724     return Decode(cx, str, js_empty_ucstr, rval);
04725 }
04726 
04727 static JSBool
04728 str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
04729               jsval *rval)
04730 {
04731     JSString *str;
04732 
04733     str = js_ValueToString(cx, argv[0]);
04734     if (!str)
04735         return JS_FALSE;
04736     argv[0] = STRING_TO_JSVAL(str);
04737     return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
04738                   rval);
04739 }
04740 
04741 static JSBool
04742 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
04743                         jsval *rval)
04744 {
04745     JSString *str;
04746 
04747     str = js_ValueToString(cx, argv[0]);
04748     if (!str)
04749         return JS_FALSE;
04750     argv[0] = STRING_TO_JSVAL(str);
04751     return Encode(cx, str, js_uriUnescaped_ucstr, NULL, rval);
04752 }
04753 
04754 /*
04755  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
04756  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
04757  */
04758 int
04759 js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
04760 {
04761     int utf8Length = 1;
04762 
04763     JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
04764     if (ucs4Char < 0x80) {
04765         *utf8Buffer = (uint8)ucs4Char;
04766     } else {
04767         int i;
04768         uint32 a = ucs4Char >> 11;
04769         utf8Length = 2;
04770         while (a) {
04771             a >>= 5;
04772             utf8Length++;
04773         }
04774         i = utf8Length;
04775         while (--i) {
04776             utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
04777             ucs4Char >>= 6;
04778         }
04779         *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
04780     }
04781     return utf8Length;
04782 }
04783 
04784 /*
04785  * Convert a utf8 character sequence into a UCS-4 character and return that
04786  * character.  It is assumed that the caller already checked that the sequence
04787  * is valid.
04788  */
04789 static uint32
04790 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
04791 {
04792     uint32 ucs4Char;
04793     uint32 minucs4Char;
04794     /* from Unicode 3.1, non-shortest form is illegal */
04795     static const uint32 minucs4Table[] = {
04796         0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
04797     };
04798 
04799     JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
04800     if (utf8Length == 1) {
04801         ucs4Char = *utf8Buffer;
04802         JS_ASSERT(!(ucs4Char & 0x80));
04803     } else {
04804         JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
04805                   (0x100 - (1 << (8-utf8Length))));
04806         ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
04807         minucs4Char = minucs4Table[utf8Length-2];
04808         while (--utf8Length) {
04809             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
04810             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
04811         }
04812         if (ucs4Char < minucs4Char ||
04813             ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
04814             ucs4Char = 0xFFFD;
04815         }
04816     }
04817     return ucs4Char;
04818 }