1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39 
40 /*
41  * JS string type implementation.
42  *
43  * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
44  * native methods store strings (possibly newborn) converted from their 'this'
45  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
46  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
47  * of rooting things that might lose their newborn root due to subsequent GC
48  * allocations in the same native method.
49  */
50 #include "jsstddef.h"
51 #include <stdlib.h>
52 #include <string.h>
53 #include "jstypes.h"
54 #include "jsutil.h" /* Added by JSIFY */
55 #include "jshash.h" /* Added by JSIFY */
56 #include "jsprf.h"
57 #include "jsapi.h"
58 #include "jsarray.h"
59 #include "jsatom.h"
60 #include "jsbool.h"
61 #include "jscntxt.h"
62 #include "jsconfig.h"
63 #include "jsgc.h"
64 #include "jsinterp.h"
65 #include "jslock.h"
66 #include "jsnum.h"
67 #include "jsobj.h"
68 #include "jsopcode.h"
69 #include "jsregexp.h"
70 #include "jsstr.h"
71 
72 #if JS_HAS_REPLACE_LAMBDA
73 #include "jsinterp.h"
74 #endif
75 
76 #define JSSTRDEP_RECURSION_LIMIT        100
77 
78 size_t
js_MinimizeDependentStrings(JSString * str,int level,JSString ** basep)79 js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
80 {
81     JSString *base;
82     size_t start, length;
83 
84     JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
85     base = JSSTRDEP_BASE(str);
86     start = JSSTRDEP_START(str);
87     if (JSSTRING_IS_DEPENDENT(base)) {
88         if (level < JSSTRDEP_RECURSION_LIMIT) {
89             start += js_MinimizeDependentStrings(base, level + 1, &base);
90         } else {
91             do {
92                 start += JSSTRDEP_START(base);
93                 base = JSSTRDEP_BASE(base);
94             } while (JSSTRING_IS_DEPENDENT(base));
95         }
96         if (start == 0) {
97             JS_ASSERT(JSSTRING_IS_PREFIX(str));
98             JSPREFIX_SET_BASE(str, base);
99         } else if (start <= JSSTRDEP_START_MASK) {
100             length = JSSTRDEP_LENGTH(str);
101             JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
102             JSSTRDEP_SET_BASE(str, base);
103         }
104     }
105     *basep = base;
106     return start;
107 }
108 
109 jschar *
js_GetDependentStringChars(JSString * str)110 js_GetDependentStringChars(JSString *str)
111 {
112     size_t start;
113     JSString *base;
114 
115     start = js_MinimizeDependentStrings(str, 0, &base);
116     JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
117     JS_ASSERT(start < base->length);
118     return base->chars + start;
119 }
120 
121 jschar *
js_GetStringChars(JSString * str)122 js_GetStringChars(JSString *str)
123 {
124     if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(NULL, str))
125         return NULL;
126 
127     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
128     return str->chars;
129 }
130 
131 JSString *
js_ConcatStrings(JSContext * cx,JSString * left,JSString * right)132 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
133 {
134     size_t rn, ln, lrdist, n;
135     jschar *rs, *ls, *s;
136     JSDependentString *ldep;    /* non-null if left should become dependent */
137     JSString *str;
138 
139     if (JSSTRING_IS_DEPENDENT(right)) {
140         rn = JSSTRDEP_LENGTH(right);
141         rs = JSSTRDEP_CHARS(right);
142     } else {
143         rn = right->length;
144         rs = right->chars;
145     }
146     if (rn == 0)
147         return left;
148 
149     if (JSSTRING_IS_DEPENDENT(left) ||
150         !(*js_GetGCThingFlags(left) & GCF_MUTABLE)) {
151         /* We must copy if left does not own a buffer to realloc. */
152         ln = JSSTRING_LENGTH(left);
153         if (ln == 0)
154             return right;
155         ls = JSSTRING_CHARS(left);
156         s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
157         if (!s)
158             return NULL;
159         js_strncpy(s, ls, ln);
160         ldep = NULL;
161     } else {
162         /* We can realloc left's space and make it depend on our result. */
163         ln = left->length;
164         if (ln == 0)
165             return right;
166         ls = left->chars;
167         s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
168         if (!s)
169             return NULL;
170 
171         /* Take care: right could depend on left! */
172         lrdist = (size_t)(rs - ls);
173         if (lrdist < ln)
174             rs = s + lrdist;
175         left->chars = ls = s;
176         ldep = JSSTRDEP(left);
177     }
178 
179     js_strncpy(s + ln, rs, rn);
180     n = ln + rn;
181     s[n] = 0;
182     str = js_NewString(cx, s, n, GCF_MUTABLE);
183     if (!str) {
184         /* Out of memory: clean up any space we (re-)allocated. */
185         if (!ldep) {
186             JS_free(cx, s);
187         } else {
188             s = JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
189             if (s)
190                 left->chars = s;
191         }
192     } else {
193         /* Morph left into a dependent prefix if we realloc'd its buffer. */
194         if (ldep) {
195             JSPREFIX_SET_LENGTH(ldep, ln);
196             JSPREFIX_SET_BASE(ldep, str);
197 #ifdef DEBUG
198           {
199             JSRuntime *rt = cx->runtime;
200             JS_RUNTIME_METER(rt, liveDependentStrings);
201             JS_RUNTIME_METER(rt, totalDependentStrings);
202             JS_LOCK_RUNTIME_VOID(rt,
203                 (rt->strdepLengthSum += (double)ln,
204                  rt->strdepLengthSquaredSum += (double)ln * (double)ln));
205           }
206 #endif
207         }
208     }
209 
210     return str;
211 }
212 
213 /*
214  * May be called with null cx by js_GetStringChars, above; and by the jslock.c
215  * MAKE_STRING_IMMUTABLE file-local macro.
216  */
217 const jschar *
js_UndependString(JSContext * cx,JSString * str)218 js_UndependString(JSContext *cx, JSString *str)
219 {
220     size_t n, size;
221     jschar *s;
222 
223     if (JSSTRING_IS_DEPENDENT(str)) {
224         n = JSSTRDEP_LENGTH(str);
225         size = (n + 1) * sizeof(jschar);
226         s = (jschar *) (cx ? JS_malloc(cx, size) : malloc(size));
227         if (!s)
228             return NULL;
229 
230         js_strncpy(s, JSSTRDEP_CHARS(str), n);
231         s[n] = 0;
232         str->length = n;
233         str->chars = s;
234 
235 #ifdef DEBUG
236         if (cx) {
237             JSRuntime *rt = cx->runtime;
238             JS_RUNTIME_UNMETER(rt, liveDependentStrings);
239             JS_RUNTIME_UNMETER(rt, totalDependentStrings);
240             JS_LOCK_RUNTIME_VOID(rt,
241                 (rt->strdepLengthSum -= (double)n,
242                  rt->strdepLengthSquaredSum -= (double)n * (double)n));
243         }
244 #endif
245     }
246 
247     return str->chars;
248 }
249 
250 /*
251  * Forward declarations for URI encode/decode and helper routines
252  */
253 static JSBool
254 str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
255               jsval *rval);
256 
257 static JSBool
258 str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
259                         jsval *rval);
260 
261 static JSBool
262 str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
263               jsval *rval);
264 
265 static JSBool
266 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
267                         jsval *rval);
268 
269 static int
270 OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
271 
272 static uint32
273 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
274 
275 /*
276  * Contributions from the String class to the set of methods defined for the
277  * global object.  escape and unescape used to be defined in the Mocha library,
278  * but as ECMA decided to spec them, they've been moved to the core engine
279  * and made ECMA-compliant.  (Incomplete escapes are interpreted as literal
280  * characters by unescape.)
281  */
282 
283 /*
284  * Stuff to emulate the old libmocha escape, which took a second argument
285  * giving the type of escape to perform.  Retained for compatibility, and
286  * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
287  */
288 
289 #define URL_XALPHAS     ((uint8) 1)
290 #define URL_XPALPHAS    ((uint8) 2)
291 #define URL_PATH        ((uint8) 4)
292 
293 static const uint8 urlCharType[256] =
294 /*      Bit 0           xalpha          -- the alphas
295  *      Bit 1           xpalpha         -- as xalpha but
296  *                             converts spaces to plus and plus to %20
297  *      Bit 2 ...       path            -- as xalphas but doesn't escape '/'
298  */
299     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
300     {    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 0x */
301          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 1x */
302          0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,       /* 2x   !"#$%&'()*+,-./  */
303          7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,       /* 3x  0123456789:;<=>?  */
304          7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 4x  @ABCDEFGHIJKLMNO  */
305          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,       /* 5X  PQRSTUVWXYZ[\]^_  */
306          0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 6x  `abcdefghijklmno  */
307          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,       /* 7X  pqrstuvwxyz{\}~  DEL */
308          0, };
309 
310 /* This matches the ECMA escape set when mask is 7 (default.) */
311 
312 #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
313 
314 /* See ECMA-262 15.1.2.4. */
315 JSBool
js_str_escape(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)316 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
317 {
318     JSString *str;
319     size_t i, ni, length, newlength;
320     const jschar *chars;
321     jschar *newchars;
322     jschar ch;
323     jsint mask;
324     jsdouble d;
325     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
326                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
327 
328     mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
329     if (argc > 1) {
330         if (!js_ValueToNumber(cx, argv[1], &d))
331             return JS_FALSE;
332         if (!JSDOUBLE_IS_FINITE(d) ||
333             (mask = (jsint)d) != d ||
334             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
335         {
336             char numBuf[12];
337             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
338             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
339                                  JSMSG_BAD_STRING_MASK, numBuf);
340             return JS_FALSE;
341         }
342     }
343 
344     str = js_ValueToString(cx, argv[0]);
345     if (!str)
346         return JS_FALSE;
347     argv[0] = STRING_TO_JSVAL(str);
348 
349     chars = JSSTRING_CHARS(str);
350     length = newlength = JSSTRING_LENGTH(str);
351 
352     /* Take a first pass and see how big the result string will need to be. */
353     for (i = 0; i < length; i++) {
354         if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
355             continue;
356         if (ch < 256) {
357             if (mask == URL_XPALPHAS && ch == ' ')
358                 continue;   /* The character will be encoded as '+' */
359             newlength += 2; /* The character will be encoded as %XX */
360         } else {
361             newlength += 5; /* The character will be encoded as %uXXXX */
362         }
363     }
364 
365     newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
366     if (!newchars)
367         return JS_FALSE;
368     for (i = 0, ni = 0; i < length; i++) {
369         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
370             newchars[ni++] = ch;
371         } else if (ch < 256) {
372             if (mask == URL_XPALPHAS && ch == ' ') {
373                 newchars[ni++] = '+'; /* convert spaces to pluses */
374             } else {
375                 newchars[ni++] = '%';
376                 newchars[ni++] = digits[ch >> 4];
377                 newchars[ni++] = digits[ch & 0xF];
378             }
379         } else {
380             newchars[ni++] = '%';
381             newchars[ni++] = 'u';
382             newchars[ni++] = digits[ch >> 12];
383             newchars[ni++] = digits[(ch & 0xF00) >> 8];
384             newchars[ni++] = digits[(ch & 0xF0) >> 4];
385             newchars[ni++] = digits[ch & 0xF];
386         }
387     }
388     JS_ASSERT(ni == newlength);
389     newchars[newlength] = 0;
390 
391     str = js_NewString(cx, newchars, newlength, 0);
392     if (!str) {
393         JS_free(cx, newchars);
394         return JS_FALSE;
395     }
396     *rval = STRING_TO_JSVAL(str);
397     return JS_TRUE;
398 }
399 #undef IS_OK
400 
401 /* See ECMA-262 15.1.2.5 */
402 static JSBool
str_unescape(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)403 str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
404 {
405     JSString *str;
406     size_t i, ni, length;
407     const jschar *chars;
408     jschar *newchars;
409     jschar ch;
410 
411     str = js_ValueToString(cx, argv[0]);
412     if (!str)
413         return JS_FALSE;
414     argv[0] = STRING_TO_JSVAL(str);
415 
416     chars = JSSTRING_CHARS(str);
417     length = JSSTRING_LENGTH(str);
418 
419     /* Don't bother allocating less space for the new string. */
420     newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
421     if (!newchars)
422         return JS_FALSE;
423     ni = i = 0;
424     while (i < length) {
425         ch = chars[i++];
426         if (ch == '%') {
427             if (i + 1 < length &&
428                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
429             {
430                 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
431                 i += 2;
432             } else if (i + 4 < length && chars[i] == 'u' &&
433                        JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
434                        JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
435             {
436                 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
437                         + JS7_UNHEX(chars[i + 2])) << 4)
438                       + JS7_UNHEX(chars[i + 3])) << 4)
439                     + JS7_UNHEX(chars[i + 4]);
440                 i += 5;
441             }
442         }
443         newchars[ni++] = ch;
444     }
445     newchars[ni] = 0;
446 
447     str = js_NewString(cx, newchars, ni, 0);
448     if (!str) {
449         JS_free(cx, newchars);
450         return JS_FALSE;
451     }
452     *rval = STRING_TO_JSVAL(str);
453     return JS_TRUE;
454 }
455 
456 #if JS_HAS_UNEVAL
457 static JSBool
str_uneval(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)458 str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
459 {
460     JSString *str;
461 
462     str = js_ValueToSource(cx, argv[0]);
463     if (!str)
464         return JS_FALSE;
465     *rval = STRING_TO_JSVAL(str);
466     return JS_TRUE;
467 }
468 #endif
469 
470 const char js_escape_str[] = "escape";
471 const char js_unescape_str[] = "unescape";
472 #if JS_HAS_UNEVAL
473 const char js_uneval_str[] = "uneval";
474 #endif
475 const char js_decodeURI_str[] = "decodeURI";
476 const char js_encodeURI_str[] = "encodeURI";
477 const char js_decodeURIComponent_str[] = "decodeURIComponent";
478 const char js_encodeURIComponent_str[] = "encodeURIComponent";
479 
480 static JSFunctionSpec string_functions[] = {
481     {js_escape_str,             js_str_escape,              1,0,0},
482     {js_unescape_str,           str_unescape,               1,0,0},
483 #if JS_HAS_UNEVAL
484     {js_uneval_str,             str_uneval,                 1,0,0},
485 #endif
486     {js_decodeURI_str,          str_decodeURI,              1,0,0},
487     {js_encodeURI_str,          str_encodeURI,              1,0,0},
488     {js_decodeURIComponent_str, str_decodeURI_Component,    1,0,0},
489     {js_encodeURIComponent_str, str_encodeURI_Component,    1,0,0},
490 
491     {0,0,0,0,0}
492 };
493 
494 jschar      js_empty_ucstr[]  = {0};
495 JSSubString js_EmptySubString = {0, js_empty_ucstr};
496 
497 enum string_tinyid {
498     STRING_LENGTH = -1
499 };
500 
501 static JSPropertySpec string_props[] = {
502     {js_length_str,     STRING_LENGTH,
503                         JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0},
504     {0,0,0,0,0}
505 };
506 
507 static JSBool
str_getProperty(JSContext * cx,JSObject * obj,jsval id,jsval * vp)508 str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
509 {
510     JSString *str;
511     jsint slot;
512 
513     if (!JSVAL_IS_INT(id))
514         return JS_TRUE;
515     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
516     if (!str)
517         return JS_FALSE;
518     slot = JSVAL_TO_INT(id);
519     if (slot == STRING_LENGTH)
520         *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
521     return JS_TRUE;
522 }
523 
524 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
525 
526 static JSBool
str_enumerate(JSContext * cx,JSObject * obj)527 str_enumerate(JSContext *cx, JSObject *obj)
528 {
529     JSString *str, *str1;
530     size_t i, length;
531 
532     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
533     if (!str)
534         return JS_FALSE;
535     length = JSSTRING_LENGTH(str);
536     for (i = 0; i < length; i++) {
537         str1 = js_NewDependentString(cx, str, i, 1, 0);
538         if (!str1)
539             return JS_FALSE;
540         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(i),
541                                  STRING_TO_JSVAL(str1), NULL, NULL,
542                                  STRING_ELEMENT_ATTRS, NULL)) {
543             return JS_FALSE;
544         }
545     }
546     return JS_TRUE;
547 }
548 
549 static JSBool
str_resolve(JSContext * cx,JSObject * obj,jsval id)550 str_resolve(JSContext *cx, JSObject *obj, jsval id)
551 {
552     JSString *str, *str1;
553     jsint slot;
554 
555     if (!JSVAL_IS_INT(id))
556         return JS_TRUE;
557 
558     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
559     if (!str)
560         return JS_FALSE;
561     slot = JSVAL_TO_INT(id);
562     if ((size_t)slot < JSSTRING_LENGTH(str)) {
563         str1 = js_NewDependentString(cx, str, (size_t)slot, 1, 0);
564         if (!str1)
565             return JS_FALSE;
566         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(slot),
567                                  STRING_TO_JSVAL(str1), NULL, NULL,
568                                  STRING_ELEMENT_ATTRS, NULL)) {
569             return JS_FALSE;
570         }
571     }
572     return JS_TRUE;
573 }
574 
575 static JSClass string_class = {
576     js_String_str,
577     JSCLASS_HAS_PRIVATE,
578     JS_PropertyStub,  JS_PropertyStub,  str_getProperty,  JS_PropertyStub,
579     str_enumerate,    str_resolve,      JS_ConvertStub,   JS_FinalizeStub,
580     JSCLASS_NO_OPTIONAL_MEMBERS
581 };
582 
583 #if JS_HAS_TOSOURCE
584 
585 /*
586  * String.prototype.quote is generic (as are most string methods), unlike
587  * toSource, toString, and valueOf.
588  */
589 static JSBool
str_quote(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)590 str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
591 {
592     JSString *str;
593 
594     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
595     if (!str)
596         return JS_FALSE;
597     str = js_QuoteString(cx, str, '"');
598     if (!str)
599         return JS_FALSE;
600     *rval = STRING_TO_JSVAL(str);
601     return JS_TRUE;
602 }
603 
604 static JSBool
str_toSource(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)605 str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
606 {
607     jsval v;
608     JSString *str;
609     size_t i, j, k, n;
610     char buf[16];
611     jschar *s, *t;
612 
613     if (!JS_InstanceOf(cx, obj, &string_class, argv))
614         return JS_FALSE;
615     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
616     if (!JSVAL_IS_STRING(v))
617         return js_obj_toSource(cx, obj, argc, argv, rval);
618     str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
619     if (!str)
620         return JS_FALSE;
621     j = JS_snprintf(buf, sizeof buf, "(new %s(", string_class.name);
622     s = JSSTRING_CHARS(str);
623     k = JSSTRING_LENGTH(str);
624     n = j + k + 2;
625     t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
626     if (!t)
627         return JS_FALSE;
628     for (i = 0; i < j; i++)
629         t[i] = buf[i];
630     for (j = 0; j < k; i++, j++)
631         t[i] = s[j];
632     t[i++] = ')';
633     t[i++] = ')';
634     t[i] = 0;
635     str = js_NewString(cx, t, n, 0);
636     if (!str) {
637         JS_free(cx, t);
638         return JS_FALSE;
639     }
640     *rval = STRING_TO_JSVAL(str);
641     return JS_TRUE;
642 }
643 
644 #endif /* JS_HAS_TOSOURCE */
645 
646 static JSBool
str_toString(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)647 str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
648 {
649     jsval v;
650 
651     if (!JS_InstanceOf(cx, obj, &string_class, argv))
652         return JS_FALSE;
653     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
654     if (!JSVAL_IS_STRING(v))
655         return js_obj_toString(cx, obj, argc, argv, rval);
656     *rval = v;
657     return JS_TRUE;
658 }
659 
660 static JSBool
str_valueOf(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)661 str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
662 {
663     if (!JS_InstanceOf(cx, obj, &string_class, argv))
664         return JS_FALSE;
665     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
666     return JS_TRUE;
667 }
668 
669 /*
670  * Java-like string native methods.
671  */
672 static JSBool
str_substring(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)673 str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
674               jsval *rval)
675 {
676     JSString *str;
677     jsdouble d;
678     jsdouble length, begin, end;
679 
680     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
681     if (!str)
682         return JS_FALSE;
683     argv[-1] = STRING_TO_JSVAL(str);
684 
685     if (argc != 0) {
686         if (!js_ValueToNumber(cx, argv[0], &d))
687             return JS_FALSE;
688         length = JSSTRING_LENGTH(str);
689         begin = js_DoubleToInteger(d);
690         if (begin < 0)
691             begin = 0;
692         else if (begin > length)
693             begin = length;
694 
695         if (argc == 1) {
696             end = length;
697         } else {
698             if (!js_ValueToNumber(cx, argv[1], &d))
699                 return JS_FALSE;
700             end = js_DoubleToInteger(d);
701             if (end < 0)
702                 end = 0;
703             else if (end > length)
704                 end = length;
705             if (end < begin) {
706                 if (cx->version != JSVERSION_1_2) {
707                     /* XXX emulate old JDK1.0 java.lang.String.substring. */
708                     jsdouble tmp = begin;
709                     begin = end;
710                     end = tmp;
711                 } else {
712                     end = begin;
713                 }
714             }
715         }
716 
717         str = js_NewDependentString(cx, str, (size_t)begin,
718                                     (size_t)(end - begin), 0);
719         if (!str)
720             return JS_FALSE;
721     }
722     *rval = STRING_TO_JSVAL(str);
723     return JS_TRUE;
724 }
725 
726 static JSBool
str_toLowerCase(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)727 str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
728                 jsval *rval)
729 {
730     JSString *str;
731     size_t i, n;
732     jschar *s, *news;
733 
734     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
735     if (!str)
736         return JS_FALSE;
737     n = JSSTRING_LENGTH(str);
738     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
739     if (!news)
740         return JS_FALSE;
741     s = JSSTRING_CHARS(str);
742     for (i = 0; i < n; i++)
743         news[i] = JS_TOLOWER(s[i]);
744     news[n] = 0;
745     str = js_NewString(cx, news, n, 0);
746     if (!str) {
747         JS_free(cx, news);
748         return JS_FALSE;
749     }
750     *rval = STRING_TO_JSVAL(str);
751     return JS_TRUE;
752 }
753 
754 static JSBool
str_toLocaleLowerCase(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)755 str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
756                 jsval *rval)
757 {
758     JSString *str;
759 
760     /*
761      * Forcefully ignore the first (or any) argument and return toLowerCase(),
762      * ECMA has reserved that argument, presumably for defining the locale.
763      */
764     if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
765         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
766         if (!str)
767             return JS_FALSE;
768         return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
769     }
770     return str_toLowerCase(cx, obj, 0, argv, rval);
771 }
772 
773 static JSBool
str_toUpperCase(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)774 str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
775                 jsval *rval)
776 {
777     JSString *str;
778     size_t i, n;
779     jschar *s, *news;
780 
781     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
782     if (!str)
783         return JS_FALSE;
784     n = JSSTRING_LENGTH(str);
785     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
786     if (!news)
787         return JS_FALSE;
788     s = JSSTRING_CHARS(str);
789     for (i = 0; i < n; i++)
790         news[i] = JS_TOUPPER(s[i]);
791     news[n] = 0;
792     str = js_NewString(cx, news, n, 0);
793     if (!str) {
794         JS_free(cx, news);
795         return JS_FALSE;
796     }
797     *rval = STRING_TO_JSVAL(str);
798     return JS_TRUE;
799 }
800 
801 static JSBool
str_toLocaleUpperCase(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)802 str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
803                 jsval *rval)
804 {
805     JSString *str;
806 
807     /*
808      * Forcefully ignore the first (or any) argument and return toUpperCase(),
809      * ECMA has reserved that argument, presumbaly for defining the locale.
810      */
811     if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
812         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
813         if (!str)
814             return JS_FALSE;
815         return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
816     }
817     return str_toUpperCase(cx, obj, 0, argv, rval);
818 }
819 
820 static JSBool
str_localeCompare(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)821 str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
822                   jsval *rval)
823 {
824     JSString *str, *thatStr;
825 
826     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
827     if (!str)
828         return JS_FALSE;
829     argv[-1] = STRING_TO_JSVAL(str);
830 
831     if (argc == 0) {
832         *rval = JSVAL_ZERO;
833     } else {
834         thatStr = js_ValueToString(cx, argv[0]);
835         if (!thatStr)
836             return JS_FALSE;
837         if (cx->localeCallbacks && cx->localeCallbacks->localeCompare)
838             return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
839         *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
840     }
841     return JS_TRUE;
842 }
843 
844 static JSBool
str_charAt(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)845 str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
846 {
847     JSString *str;
848     jsdouble d;
849     size_t index;
850 
851     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
852     if (!str)
853         return JS_FALSE;
854     argv[-1] = STRING_TO_JSVAL(str);
855 
856     if (argc == 0) {
857         d = 0.0;
858     } else {
859         if (!js_ValueToNumber(cx, argv[0], &d))
860             return JS_FALSE;
861         d = js_DoubleToInteger(d);
862     }
863 
864     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
865         *rval = JS_GetEmptyStringValue(cx);
866     } else {
867         index = (size_t)d;
868         str = js_NewDependentString(cx, str, index, 1, 0);
869         if (!str)
870             return JS_FALSE;
871         *rval = STRING_TO_JSVAL(str);
872     }
873     return JS_TRUE;
874 }
875 
876 static JSBool
str_charCodeAt(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)877 str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
878                jsval *rval)
879 {
880     JSString *str;
881     jsdouble d;
882     size_t index;
883 
884     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
885     if (!str)
886         return JS_FALSE;
887     argv[-1] = STRING_TO_JSVAL(str);
888 
889     if (argc == 0) {
890         d = 0.0;
891     } else {
892         if (!js_ValueToNumber(cx, argv[0], &d))
893             return JS_FALSE;
894         d = js_DoubleToInteger(d);
895     }
896 
897     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
898         *rval = JS_GetNaNValue(cx);
899     } else {
900         index = (size_t)d;
901         *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]);
902     }
903     return JS_TRUE;
904 }
905 
906 jsint
js_BoyerMooreHorspool(const jschar * text,jsint textlen,const jschar * pat,jsint patlen,jsint start)907 js_BoyerMooreHorspool(const jschar *text, jsint textlen,
908                       const jschar *pat, jsint patlen,
909                       jsint start)
910 {
911     jsint i, j, k, m;
912     uint8 skip[BMH_CHARSET_SIZE];
913     jschar c;
914 
915     JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
916     for (i = 0; i < BMH_CHARSET_SIZE; i++)
917         skip[i] = (uint8)patlen;
918     m = patlen - 1;
919     for (i = 0; i < m; i++) {
920         c = pat[i];
921         if (c >= BMH_CHARSET_SIZE)
922             return BMH_BAD_PATTERN;
923         skip[c] = (uint8)(m - i);
924     }
925     for (k = start + m;
926          k < textlen;
927          k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
928         for (i = k, j = m; ; i--, j--) {
929             if (j < 0)
930                 return i + 1;
931             if (text[i] != pat[j])
932                 break;
933         }
934     }
935     return -1;
936 }
937 
938 static JSBool
str_indexOf(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)939 str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
940 {
941     JSString *str, *str2;
942     jsint i, j, index, textlen, patlen;
943     const jschar *text, *pat;
944     jsdouble d;
945 
946     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
947     if (!str)
948         return JS_FALSE;
949     argv[-1] = STRING_TO_JSVAL(str);
950     text = JSSTRING_CHARS(str);
951     textlen = (jsint) JSSTRING_LENGTH(str);
952 
953     str2 = js_ValueToString(cx, argv[0]);
954     if (!str2)
955         return JS_FALSE;
956     argv[0] = STRING_TO_JSVAL(str2);
957     pat = JSSTRING_CHARS(str2);
958     patlen = (jsint) JSSTRING_LENGTH(str2);
959 
960     if (argc > 1) {
961         if (!js_ValueToNumber(cx, argv[1], &d))
962             return JS_FALSE;
963         d = js_DoubleToInteger(d);
964         if (d < 0)
965             i = 0;
966         else if (d > textlen)
967             i = textlen;
968         else
969             i = (jsint)d;
970     } else {
971         i = 0;
972     }
973     if (patlen == 0) {
974         *rval = INT_TO_JSVAL(i);
975         return JS_TRUE;
976     }
977 
978     /* XXX tune the BMH threshold (512) */
979     if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) {
980         index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
981         if (index != BMH_BAD_PATTERN)
982             goto out;
983     }
984 
985     index = -1;
986     j = 0;
987     while (i + j < textlen) {
988         if (text[i + j] == pat[j]) {
989             if (++j == patlen) {
990                 index = i;
991                 break;
992             }
993         } else {
994             i++;
995             j = 0;
996         }
997     }
998 
999 out:
1000     *rval = INT_TO_JSVAL(index);
1001     return JS_TRUE;
1002 }
1003 
1004 static JSBool
str_lastIndexOf(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1005 str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1006                   jsval *rval)
1007 {
1008     JSString *str, *str2;
1009     const jschar *text, *pat;
1010     jsint i, j, textlen, patlen;
1011     jsdouble d;
1012 
1013     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1014     if (!str)
1015         return JS_FALSE;
1016     argv[-1] = STRING_TO_JSVAL(str);
1017     text = JSSTRING_CHARS(str);
1018     textlen = (jsint) JSSTRING_LENGTH(str);
1019 
1020     str2 = js_ValueToString(cx, argv[0]);
1021     if (!str2)
1022         return JS_FALSE;
1023     argv[0] = STRING_TO_JSVAL(str2);
1024     pat = JSSTRING_CHARS(str2);
1025     patlen = (jsint) JSSTRING_LENGTH(str2);
1026 
1027     if (argc > 1) {
1028         if (!js_ValueToNumber(cx, argv[1], &d))
1029             return JS_FALSE;
1030         if (JSDOUBLE_IS_NaN(d)) {
1031             i = textlen;
1032         } else {
1033             d = js_DoubleToInteger(d);
1034             if (d < 0)
1035                 i = 0;
1036             else if (d > textlen - patlen)
1037                 i = textlen - patlen;
1038             else
1039                 i = (jsint)d;
1040         }
1041     } else {
1042         i = textlen;
1043     }
1044 
1045     if (patlen == 0) {
1046         *rval = INT_TO_JSVAL(i);
1047         return JS_TRUE;
1048     }
1049 
1050     j = 0;
1051     while (i >= 0) {
1052         /* Don't assume that text is NUL-terminated: it could be dependent. */
1053         if (i + j < textlen && text[i + j] == pat[j]) {
1054             if (++j == patlen)
1055                 break;
1056         } else {
1057             i--;
1058             j = 0;
1059         }
1060     }
1061     *rval = INT_TO_JSVAL(i);
1062     return JS_TRUE;
1063 }
1064 
1065 /*
1066  * Perl-inspired string functions.
1067  */
1068 #if JS_HAS_REGEXPS
1069 typedef struct GlobData {
1070     uintN       flags;          /* inout: mode and flag bits, see below */
1071     uintN       optarg;         /* in: index of optional flags argument */
1072     JSString    *str;           /* out: 'this' parameter object as string */
1073     JSRegExp    *regexp;        /* out: regexp parameter object private data */
1074 } GlobData;
1075 
1076 /*
1077  * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
1078  */
1079 #define MODE_MATCH      0x00    /* in: return match array on success */
1080 #define MODE_REPLACE    0x01    /* in: match and replace */
1081 #define MODE_SEARCH     0x02    /* in: search only, return match index or -1 */
1082 #define GET_MODE(f)     ((f) & 0x03)
1083 #define FORCE_FLAT      0x04    /* in: force flat (non-regexp) string match */
1084 #define KEEP_REGEXP     0x08    /* inout: keep GlobData.regexp alive for caller
1085                                           of match_or_replace; if set on input
1086                                           but clear on output, regexp ownership
1087                                           does not pass to caller */
1088 #define GLOBAL_REGEXP   0x10    /* out: regexp had the 'g' flag */
1089 
1090 static JSBool
match_or_replace(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,JSBool (* glob)(JSContext * cx,jsint count,GlobData * data),GlobData * data,jsval * rval)1091 match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1092                  JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
1093                  GlobData *data, jsval *rval)
1094 {
1095     JSString *str, *src, *opt;
1096     JSObject *reobj;
1097     JSRegExp *re;
1098     size_t index, length;
1099     JSBool ok, test;
1100     jsint count;
1101 
1102     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1103     if (!str)
1104         return JS_FALSE;
1105     argv[-1] = STRING_TO_JSVAL(str);
1106     data->str = str;
1107 
1108     if (JSVAL_IS_REGEXP(cx, argv[0])) {
1109         reobj = JSVAL_TO_OBJECT(argv[0]);
1110         re = (JSRegExp *) JS_GetPrivate(cx, reobj);
1111     } else {
1112         src = js_ValueToString(cx, argv[0]);
1113         if (!src)
1114             return JS_FALSE;
1115         if (data->optarg < argc) {
1116             argv[0] = STRING_TO_JSVAL(src);
1117             opt = js_ValueToString(cx, argv[data->optarg]);
1118             if (!opt)
1119                 return JS_FALSE;
1120         } else {
1121             opt = NULL;
1122         }
1123         re = js_NewRegExpOpt(cx, NULL, src, opt,
1124                              (data->flags & FORCE_FLAT) != 0);
1125         if (!re)
1126             return JS_FALSE;
1127         reobj = NULL;
1128     }
1129     data->regexp = re;
1130 
1131     if (re->flags & JSREG_GLOB)
1132         data->flags |= GLOBAL_REGEXP;
1133     index = 0;
1134     if (GET_MODE(data->flags) == MODE_SEARCH) {
1135         ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
1136         if (ok) {
1137             *rval = (*rval == JSVAL_TRUE)
1138                     ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
1139                     : INT_TO_JSVAL(-1);
1140         }
1141     } else if (data->flags & GLOBAL_REGEXP) {
1142         if (reobj) {
1143             /* Set the lastIndex property's reserved slot to 0. */
1144             ok = js_SetLastIndex(cx, reobj, 0);
1145             if (!ok)
1146                 return JS_FALSE;
1147         } else {
1148             ok = JS_TRUE;
1149         }
1150         length = JSSTRING_LENGTH(str);
1151         for (count = 0; index <= length; count++) {
1152             ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
1153             if (!ok || *rval != JSVAL_TRUE)
1154                 break;
1155             ok = glob(cx, count, data);
1156             if (!ok)
1157                 break;
1158             if (cx->regExpStatics.lastMatch.length == 0) {
1159                 if (index == length)
1160                     break;
1161                 index++;
1162             }
1163         }
1164     } else {
1165         if (GET_MODE(data->flags) == MODE_REPLACE) {
1166             test = JS_TRUE;
1167         } else {
1168             /*
1169              * MODE_MATCH implies str_match is being called from a script or a
1170              * scripted function.  If the caller cares only about testing null
1171              * vs. non-null return value, optimize away the array object that
1172              * would normally be returned in *rval.
1173              */
1174             JS_ASSERT(*cx->fp->down->pc == JSOP_CALL ||
1175                       *cx->fp->down->pc == JSOP_NEW);
1176             JS_ASSERT(js_CodeSpec[*cx->fp->down->pc].length == 3);
1177             switch (cx->fp->down->pc[3]) {
1178               case JSOP_POP:
1179               case JSOP_IFEQ:
1180               case JSOP_IFNE:
1181               case JSOP_IFEQX:
1182               case JSOP_IFNEX:
1183                 test = JS_TRUE;
1184                 break;
1185               default:
1186                 test = JS_FALSE;
1187                 break;
1188             }
1189         }
1190         ok = js_ExecuteRegExp(cx, re, str, &index, test, rval);
1191     }
1192 
1193     if (reobj) {
1194         /* Tell our caller that it doesn't need to destroy data->regexp. */
1195         data->flags &= ~KEEP_REGEXP;
1196     } else if (!(data->flags & KEEP_REGEXP)) {
1197         /* Caller didn't want to keep data->regexp, so null and destroy it.  */
1198         data->regexp = NULL;
1199         js_DestroyRegExp(cx, re);
1200     }
1201     return ok;
1202 }
1203 
1204 typedef struct MatchData {
1205     GlobData    base;
1206     jsval       *arrayval;      /* NB: local root pointer */
1207 } MatchData;
1208 
1209 static JSBool
match_glob(JSContext * cx,jsint count,GlobData * data)1210 match_glob(JSContext *cx, jsint count, GlobData *data)
1211 {
1212     MatchData *mdata;
1213     JSObject *arrayobj;
1214     JSSubString *matchsub;
1215     JSString *matchstr;
1216     jsval v;
1217 
1218     mdata = (MatchData *)data;
1219     arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
1220     if (!arrayobj) {
1221         arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
1222         if (!arrayobj)
1223             return JS_FALSE;
1224         *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
1225     }
1226     matchsub = &cx->regExpStatics.lastMatch;
1227     matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length, 0);
1228     if (!matchstr)
1229         return JS_FALSE;
1230     v = STRING_TO_JSVAL(matchstr);
1231     return js_SetProperty(cx, arrayobj, INT_TO_JSVAL(count), &v);
1232 }
1233 
1234 static JSBool
str_match(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1235 str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1236 {
1237     MatchData mdata;
1238     JSBool ok;
1239 
1240     mdata.base.flags = MODE_MATCH;
1241     mdata.base.optarg = 1;
1242     mdata.arrayval = &argv[2];
1243     *mdata.arrayval = JSVAL_NULL;
1244     ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
1245     if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
1246         *rval = *mdata.arrayval;
1247     return ok;
1248 }
1249 
1250 static JSBool
str_search(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1251 str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1252 {
1253     GlobData data;
1254 
1255     data.flags = MODE_SEARCH;
1256     data.optarg = 1;
1257     return match_or_replace(cx, obj, argc, argv, NULL, &data, rval);
1258 }
1259 
1260 typedef struct ReplaceData {
1261     GlobData    base;           /* base struct state */
1262     JSObject    *lambda;        /* replacement function object or null */
1263     JSString    *repstr;        /* replacement string */
1264     jschar      *dollar;        /* null or pointer to first $ in repstr */
1265     jschar      *dollarEnd;     /* limit pointer for js_strchr_limit */
1266     jschar      *chars;         /* result chars, null initially */
1267     size_t      length;         /* result length, 0 initially */
1268     jsint       index;          /* index in result of next replacement */
1269     jsint       leftIndex;      /* left context index in base.str->chars */
1270     JSSubString dollarStr;      /* for "$$" interpret_dollar result */
1271 } ReplaceData;
1272 
1273 static JSSubString *
interpret_dollar(JSContext * cx,jschar * dp,ReplaceData * rdata,size_t * skip)1274 interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
1275 {
1276     JSRegExpStatics *res;
1277     jschar dc, *cp;
1278     uintN num, tmp;
1279     JSString *str;
1280 
1281     JS_ASSERT(*dp == '$');
1282 
1283     /*
1284      * Allow a real backslash (literal "\\" before "$1") to escape "$1", e.g.
1285      * Do this only for versions strictly less than ECMAv3.
1286      */
1287     if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
1288         if (dp > JSSTRING_CHARS(rdata->repstr) && dp[-1] == '\\')
1289             return NULL;
1290     }
1291 
1292     /* Interpret all Perl match-induced dollar variables. */
1293     res = &cx->regExpStatics;
1294     dc = dp[1];
1295     if (JS7_ISDEC(dc)) {
1296         if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
1297             if (dc == '0')
1298                 return NULL;
1299 
1300             /* Check for overflow to avoid gobbling arbitrary decimal digits. */
1301             num = 0;
1302             cp = dp;
1303             while ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
1304                 tmp = 10 * num + JS7_UNDEC(dc);
1305                 if (tmp < num)
1306                     break;
1307                 num = tmp;
1308             }
1309         } else { /* ECMA 3, 1-9 or 01-99 */
1310             num = JS7_UNDEC(dc);
1311             if (num > res->parenCount)
1312                 return NULL;
1313             cp = dp + 2;
1314             dc = *cp;
1315             if ((dc != 0) && JS7_ISDEC(dc)) {
1316                 tmp = 10 * num + JS7_UNDEC(dc);
1317                 if (tmp <= res->parenCount) {
1318                     cp++;
1319                     num = tmp;
1320                 }
1321             }
1322             if (num == 0)
1323                 return NULL;
1324         }
1325         /* Adjust num from 1 $n-origin to 0 array-index-origin. */
1326         num--;
1327         *skip = cp - dp;
1328         return REGEXP_PAREN_SUBSTRING(res, num);
1329     }
1330 
1331     *skip = 2;
1332     switch (dc) {
1333       case '$':
1334         rdata->dollarStr.chars = dp;
1335         rdata->dollarStr.length = 1;
1336         return &rdata->dollarStr;
1337       case '&':
1338         return &res->lastMatch;
1339       case '+':
1340         return &res->lastParen;
1341       case '`':
1342         if (cx->version == JSVERSION_1_2) {
1343             /*
1344              * JS1.2 imitated the Perl4 bug where left context at each step
1345              * in an iterative use of a global regexp started from last match,
1346              * not from the start of the target string.  But Perl4 does start
1347              * $` at the beginning of the target string when it is used in a
1348              * substitution, so we emulate that special case here.
1349              */
1350             str = rdata->base.str;
1351             res->leftContext.chars = JSSTRING_CHARS(str);
1352             res->leftContext.length = res->lastMatch.chars
1353                                     - JSSTRING_CHARS(str);
1354         }
1355         return &res->leftContext;
1356       case '\'':
1357         return &res->rightContext;
1358     }
1359     return NULL;
1360 }
1361 
1362 static JSBool
find_replen(JSContext * cx,ReplaceData * rdata,size_t * sizep)1363 find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
1364 {
1365     JSString *repstr;
1366     size_t replen, skip;
1367     jschar *dp, *ep;
1368     JSSubString *sub;
1369 #if JS_HAS_REPLACE_LAMBDA
1370     JSObject *lambda;
1371 
1372     lambda = rdata->lambda;
1373     if (lambda) {
1374         uintN argc, i, j, m, n, p;
1375         jsval *sp, *oldsp, rval;
1376         void *mark;
1377         JSStackFrame *fp;
1378         JSBool ok;
1379 
1380         /*
1381          * Save the rightContext from the current regexp, since it
1382          * gets stuck at the end of the replacement string and may
1383          * be clobbered by a RegExp usage in the lambda function.
1384          */
1385         JSSubString saveRightContext = cx->regExpStatics.rightContext;
1386 
1387         /*
1388          * In the lambda case, not only do we find the replacement string's
1389          * length, we compute repstr and return it via rdata for use within
1390          * do_replace.  The lambda is called with arguments ($&, $1, $2, ...,
1391          * index, input), i.e., all the properties of a regexp match array.
1392          * For $&, etc., we must create string jsvals from cx->regExpStatics.
1393          * We grab up stack space to keep the newborn strings GC-rooted.
1394          */
1395         p = rdata->base.regexp->parenCount;
1396         argc = 1 + p + 2;
1397         sp = js_AllocStack(cx, 2 + argc, &mark);
1398         if (!sp)
1399             return JS_FALSE;
1400 
1401         /* Push lambda and its 'this' parameter. */
1402         *sp++ = OBJECT_TO_JSVAL(lambda);
1403         *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
1404 
1405 #define PUSH_REGEXP_STATIC(sub)                                               \
1406     JS_BEGIN_MACRO                                                            \
1407         JSString *str = js_NewStringCopyN(cx,                                 \
1408                                           cx->regExpStatics.sub.chars,        \
1409                                           cx->regExpStatics.sub.length,       \
1410                                           0);                                 \
1411         if (!str) {                                                           \
1412             ok = JS_FALSE;                                                    \
1413             goto lambda_out;                                                  \
1414         }                                                                     \
1415         *sp++ = STRING_TO_JSVAL(str);                                         \
1416     JS_END_MACRO
1417 
1418         /* Push $&, $1, $2, ... */
1419         PUSH_REGEXP_STATIC(lastMatch);
1420         i = 0;
1421         m = cx->regExpStatics.parenCount;
1422         n = JS_MIN(m, 9);
1423         for (j = 0; i < n; i++, j++)
1424             PUSH_REGEXP_STATIC(parens[j]);
1425         for (j = 0; i < m; i++, j++)
1426             PUSH_REGEXP_STATIC(moreParens[j]);
1427 
1428 #undef PUSH_REGEXP_STATIC
1429 
1430         /* Make sure to push undefined for any unmatched parens. */
1431         for (; i < p; i++)
1432             *sp++ = JSVAL_VOID;
1433 
1434         /* Push match index and input string. */
1435         *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
1436         *sp++ = STRING_TO_JSVAL(rdata->base.str);
1437 
1438         /* Lift current frame to include the args and do the call. */
1439         fp = cx->fp;
1440         oldsp = fp->sp;
1441         fp->sp = sp;
1442         ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
1443         rval = fp->sp[-1];
1444         fp->sp = oldsp;
1445 
1446         if (ok) {
1447             /*
1448              * NB: we count on the newborn string root to hold any string
1449              * created by this js_ValueToString that would otherwise be GC-
1450              * able, until we use rdata->repstr in do_replace.
1451              */
1452             repstr = js_ValueToString(cx, rval);
1453             if (!repstr) {
1454                 ok = JS_FALSE;
1455             } else {
1456                 rdata->repstr = repstr;
1457                 *sizep = JSSTRING_LENGTH(repstr);
1458             }
1459         }
1460 
1461       lambda_out:
1462         js_FreeStack(cx, mark);
1463         cx->regExpStatics.rightContext = saveRightContext;
1464         return ok;
1465     }
1466 #endif /* JS_HAS_REPLACE_LAMBDA */
1467 
1468     repstr = rdata->repstr;
1469     replen = JSSTRING_LENGTH(repstr);
1470     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1471          dp = js_strchr_limit(dp, '$', ep)) {
1472         sub = interpret_dollar(cx, dp, rdata, &skip);
1473         if (sub) {
1474             replen += sub->length - skip;
1475             dp += skip;
1476         }
1477         else
1478             dp++;
1479     }
1480     *sizep = replen;
1481     return JS_TRUE;
1482 }
1483 
1484 static void
do_replace(JSContext * cx,ReplaceData * rdata,jschar * chars)1485 do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
1486 {
1487     JSString *repstr;
1488     jschar *bp, *cp, *dp, *ep;
1489     size_t len, skip;
1490     JSSubString *sub;
1491 
1492     repstr = rdata->repstr;
1493     bp = cp = JSSTRING_CHARS(repstr);
1494     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1495          dp = js_strchr_limit(dp, '$', ep)) {
1496         len = dp - cp;
1497         js_strncpy(chars, cp, len);
1498         chars += len;
1499         cp = dp;
1500         sub = interpret_dollar(cx, dp, rdata, &skip);
1501         if (sub) {
1502             len = sub->length;
1503             js_strncpy(chars, sub->chars, len);
1504             chars += len;
1505             cp += skip;
1506             dp += skip;
1507         } else {
1508             dp++;
1509         }
1510     }
1511     js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
1512 }
1513 
1514 static JSBool
replace_glob(JSContext * cx,jsint count,GlobData * data)1515 replace_glob(JSContext *cx, jsint count, GlobData *data)
1516 {
1517     ReplaceData *rdata;
1518     JSString *str;
1519     size_t leftoff, leftlen, replen, growth;
1520     const jschar *left;
1521     jschar *chars;
1522 
1523     rdata = (ReplaceData *)data;
1524     str = data->str;
1525     leftoff = rdata->leftIndex;
1526     left = JSSTRING_CHARS(str) + leftoff;
1527     leftlen = cx->regExpStatics.lastMatch.chars - left;
1528     rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
1529     rdata->leftIndex += cx->regExpStatics.lastMatch.length;
1530     if (!find_replen(cx, rdata, &replen))
1531         return JS_FALSE;
1532     growth = leftlen + replen;
1533     chars = (jschar *)
1534         (rdata->chars
1535          ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1)
1536                                         * sizeof(jschar))
1537          : JS_malloc(cx, (growth + 1) * sizeof(jschar)));
1538     if (!chars) {
1539         JS_free(cx, rdata->chars);
1540         rdata->chars = NULL;
1541         return JS_FALSE;
1542     }
1543     rdata->chars = chars;
1544     rdata->length += growth;
1545     chars += rdata->index;
1546     rdata->index += growth;
1547     js_strncpy(chars, left, leftlen);
1548     chars += leftlen;
1549     do_replace(cx, rdata, chars);
1550     return JS_TRUE;
1551 }
1552 
1553 static JSBool
str_replace(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1554 str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1555 {
1556     JSObject *lambda;
1557     JSString *repstr, *str;
1558     ReplaceData rdata;
1559     JSBool ok;
1560     jschar *chars;
1561     size_t leftlen, rightlen, length;
1562 
1563 #if JS_HAS_REPLACE_LAMBDA
1564     if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {
1565         lambda = JSVAL_TO_OBJECT(argv[1]);
1566         repstr = NULL;
1567     } else
1568 #endif
1569     {
1570         if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))
1571             return JS_FALSE;
1572         repstr = JSVAL_TO_STRING(argv[1]);
1573         lambda = NULL;
1574     }
1575 
1576     /*
1577      * For ECMA Edition 3, the first argument is to be converted to a string
1578      * to match in a "flat" sense (without regular expression metachars having
1579      * special meanings) UNLESS the first arg is a RegExp object.
1580      */
1581     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP;
1582     if (cx->version == JSVERSION_DEFAULT || cx->version > JSVERSION_1_4)
1583         rdata.base.flags |= FORCE_FLAT;
1584     rdata.base.optarg = 2;
1585 
1586     rdata.lambda = lambda;
1587     rdata.repstr = repstr;
1588     if (repstr) {
1589         rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
1590         rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
1591                                        rdata.dollarEnd);
1592     } else {
1593         rdata.dollar = rdata.dollarEnd = NULL;
1594     }
1595     rdata.chars = NULL;
1596     rdata.length = 0;
1597     rdata.index = 0;
1598     rdata.leftIndex = 0;
1599 
1600     ok = match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval);
1601     if (!ok)
1602         return JS_FALSE;
1603 
1604     if (!rdata.chars) {
1605         if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) {
1606             /* Didn't match even once. */
1607             *rval = STRING_TO_JSVAL(rdata.base.str);
1608             goto out;
1609         }
1610         leftlen = cx->regExpStatics.leftContext.length;
1611         ok = find_replen(cx, &rdata, &length);
1612         if (!ok)
1613             goto out;
1614         length += leftlen;
1615         chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
1616         if (!chars) {
1617             ok = JS_FALSE;
1618             goto out;
1619         }
1620         js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
1621         do_replace(cx, &rdata, chars + leftlen);
1622         rdata.chars = chars;
1623         rdata.length = length;
1624     }
1625 
1626     rightlen = cx->regExpStatics.rightContext.length;
1627     length = rdata.length + rightlen;
1628     chars = (jschar *)
1629         JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
1630     if (!chars) {
1631         JS_free(cx, rdata.chars);
1632         ok = JS_FALSE;
1633         goto out;
1634     }
1635     js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
1636                rightlen);
1637     chars[length] = 0;
1638 
1639     str = js_NewString(cx, chars, length, 0);
1640     if (!str) {
1641         JS_free(cx, chars);
1642         ok = JS_FALSE;
1643         goto out;
1644     }
1645     *rval = STRING_TO_JSVAL(str);
1646 
1647 out:
1648     /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
1649     if (rdata.base.flags & KEEP_REGEXP)
1650         js_DestroyRegExp(cx, rdata.base.regexp);
1651     return ok;
1652 }
1653 #endif /* JS_HAS_REGEXPS */
1654 
1655 /*
1656  * Subroutine used by str_split to find the next split point in str, starting
1657  * at offset *ip and looking either for the separator substring given by sep,
1658  * or for the next re match.  In the re case, return the matched separator in
1659  * *sep, and the possibly updated offset in *ip.
1660  *
1661  * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
1662  * separator occurrence if found, or str->length if no separator is found.
1663  */
1664 static jsint
find_split(JSContext * cx,JSString * str,JSRegExp * re,jsint * ip,JSSubString * sep)1665 find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
1666            JSSubString *sep)
1667 {
1668     jsint i, j, k;
1669     jschar *chars;
1670     size_t length;
1671 
1672     /*
1673      * Stop if past end of string.  If at end of string, we will compare the
1674      * null char stored there (by js_NewString*) to sep->chars[j] in the while
1675      * loop at the end of this function, so that
1676      *
1677      *  "ab,".split(',') => ["ab", ""]
1678      *
1679      * and the resulting array converts back to the string "ab," for symmetry.
1680      * However, we ape Perl and do this only if there is a sufficiently large
1681      * limit argument (see str_split).
1682      */
1683     i = *ip;
1684     if ((size_t)i > JSSTRING_LENGTH(str))
1685         return -1;
1686 
1687     /*
1688      * Perl4 special case for str.split(' '), only if the user has selected
1689      * JavaScript1.2 explicitly.  Split on whitespace, and skip leading w/s.
1690      * Strange but true, apparently modeled after awk.
1691      *
1692      * NB: we set sep->length to the length of the w/s run, so we must test
1693      * sep->chars[1] == 0 to make sure sep is just one space.
1694      */
1695     chars = JSSTRING_CHARS(str);
1696     length = JSSTRING_LENGTH(str);
1697     if (cx->version == JSVERSION_1_2 &&
1698         !re && *sep->chars == ' ' && sep->chars[1] == 0) {
1699 
1700         /* Skip leading whitespace if at front of str. */
1701         if (i == 0) {
1702             while (JS_ISSPACE(chars[i]))
1703                 i++;
1704             *ip = i;
1705         }
1706 
1707         /* Don't delimit whitespace at end of string. */
1708         if ((size_t)i == length)
1709             return -1;
1710 
1711         /* Skip over the non-whitespace chars. */
1712         while ((size_t)i < length && !JS_ISSPACE(chars[i]))
1713             i++;
1714 
1715         /* Now skip the next run of whitespace. */
1716         j = i;
1717         while ((size_t)j < length && JS_ISSPACE(chars[j]))
1718             j++;
1719 
1720         /* Update sep->length to count delimiter chars. */
1721         sep->length = (size_t)(j - i);
1722         return i;
1723     }
1724 
1725 #if JS_HAS_REGEXPS
1726     /*
1727      * Match a regular expression against the separator at or above index i.
1728      * Call js_ExecuteRegExp with true for the test argument.  On successful
1729      * match, get the separator from cx->regExpStatics.lastMatch.
1730      */
1731     if (re) {
1732         size_t index;
1733         jsval rval;
1734 
1735       again:
1736         /* JS1.2 deviated from Perl by never matching at end of string. */
1737         index = (size_t)i;
1738         if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
1739             return -2;
1740         if (rval != JSVAL_TRUE) {
1741             /* Mismatch: ensure our caller advances i past end of string. */
1742             sep->length = 1;
1743             return length;
1744         }
1745         i = (jsint)index;
1746         *sep = cx->regExpStatics.lastMatch;
1747         if (sep->length == 0) {
1748             /*
1749              * Empty string match: never split on an empty match at the start
1750              * of a find_split cycle.  Same rule as for an empty global match
1751              * in match_or_replace.
1752              */
1753             if (i == *ip) {
1754                 /*
1755                  * "Bump-along" to avoid sticking at an empty match, but don't
1756                  * bump past end of string -- our caller must do that by adding
1757                  * sep->length to our return value.
1758                  */
1759                 if ((size_t)i == length) {
1760                     if (cx->version == JSVERSION_1_2) {
1761                         sep->length = 1;
1762                         return i;
1763                     }
1764                     return -1;
1765                 }
1766                 i++;
1767                 goto again;
1768             }
1769         }
1770         JS_ASSERT((size_t)i >= sep->length);
1771         return i - sep->length;
1772     }
1773 #endif /* JS_HAS_REGEXPS */
1774 
1775     /*
1776      * Deviate from ECMA by never splitting an empty string by any separator
1777      * string into a non-empty array (an array of length 1 that contains the
1778      * empty string).
1779      */
1780     if (!JSVERSION_IS_ECMA(cx->version) && length == 0)
1781         return -1;
1782 
1783     /*
1784      * Special case: if sep is the empty string, split str into one character
1785      * substrings.  Let our caller worry about whether to split once at end of
1786      * string into an empty substring.
1787      *
1788      * For 1.2 compatibility, at the end of the string, we return the length as
1789      * the result, and set the separator length to 1 -- this allows the caller
1790      * to include an additional null string at the end of the substring list.
1791      */
1792     if (sep->length == 0) {
1793         if (cx->version == JSVERSION_1_2) {
1794             if ((size_t)i == length) {
1795                 sep->length = 1;
1796                 return i;
1797             }
1798             return i + 1;
1799         }
1800         return ((size_t)i == length) ? -1 : i + 1;
1801     }
1802 
1803     /*
1804      * Now that we know sep is non-empty, search starting at i in str for an
1805      * occurrence of all of sep's chars.  If we find them, return the index of
1806      * the first separator char.  Otherwise, return length.
1807      */
1808     j = 0;
1809     while ((size_t)(k = i + j) < length) {
1810         if (chars[k] == sep->chars[j]) {
1811             if ((size_t)++j == sep->length)
1812                 return i;
1813         } else {
1814             i++;
1815             j = 0;
1816         }
1817     }
1818     return k;
1819 }
1820 
1821 static JSBool
str_split(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1822 str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1823 {
1824     JSString *str, *sub;
1825     JSObject *arrayobj;
1826     jsval v;
1827     JSBool ok, limited;
1828     JSRegExp *re;
1829     JSSubString *sep, tmp;
1830     jsdouble d;
1831     jsint i, j;
1832     uint32 len, limit;
1833 
1834     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1835     if (!str)
1836         return JS_FALSE;
1837     argv[-1] = STRING_TO_JSVAL(str);
1838 
1839     arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
1840     if (!arrayobj)
1841         return JS_FALSE;
1842     *rval = OBJECT_TO_JSVAL(arrayobj);
1843 
1844     if (argc == 0) {
1845         v = STRING_TO_JSVAL(str);
1846         ok = JS_SetElement(cx, arrayobj, 0, &v);
1847     } else {
1848 #if JS_HAS_REGEXPS
1849         if (JSVAL_IS_REGEXP(cx, argv[0])) {
1850             re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
1851             sep = &tmp;
1852 
1853             /* Set a magic value so we can detect a successful re match. */
1854             sep->chars = NULL;
1855         } else
1856 #endif
1857         {
1858             JSString *str2 = js_ValueToString(cx, argv[0]);
1859             if (!str2)
1860                 return JS_FALSE;
1861             argv[0] = STRING_TO_JSVAL(str2);
1862 
1863             /*
1864              * Point sep at a local copy of str2's header because find_split
1865              * will modify sep->length.
1866              */
1867             tmp.length = JSSTRING_LENGTH(str2);
1868             tmp.chars = JSSTRING_CHARS(str2);
1869             sep = &tmp;
1870             re = NULL;
1871         }
1872 
1873         /* Use the second argument as the split limit, if given. */
1874         limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]);
1875         limit = 0; /* Avoid warning. */
1876         if (limited) {
1877             if (!js_ValueToNumber(cx, argv[1], &d))
1878                 return JS_FALSE;
1879 
1880             /* Clamp limit between 0 and 1 + string length. */
1881             if (!js_DoubleToECMAUint32(cx, d, &limit))
1882                 return JS_FALSE;
1883             if (limit > JSSTRING_LENGTH(str))
1884                 limit = 1 + JSSTRING_LENGTH(str);
1885         }
1886 
1887         len = i = 0;
1888         while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
1889             if (limited && len >= limit)
1890                 break;
1891             sub = js_NewDependentString(cx, str, i, (size_t)(j - i), 0);
1892             if (!sub)
1893                 return JS_FALSE;
1894             v = STRING_TO_JSVAL(sub);
1895             if (!JS_SetElement(cx, arrayobj, len, &v))
1896                 return JS_FALSE;
1897             len++;
1898 #if JS_HAS_REGEXPS
1899             /*
1900              * Imitate perl's feature of including parenthesized substrings
1901              * that matched part of the delimiter in the new array, after the
1902              * split substring that was delimited.
1903              */
1904             if (re && sep->chars) {
1905                 uintN num;
1906                 JSSubString *parsub;
1907 
1908                 for (num = 0; num < cx->regExpStatics.parenCount; num++) {
1909                     if (limited && len >= limit)
1910                         break;
1911                     parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
1912                     sub = js_NewStringCopyN(cx, parsub->chars, parsub->length,
1913                                             0);
1914                     if (!sub)
1915                         return JS_FALSE;
1916                     v = STRING_TO_JSVAL(sub);
1917                     if (!JS_SetElement(cx, arrayobj, len, &v))
1918                         return JS_FALSE;
1919                     len++;
1920                 }
1921                 sep->chars = NULL;
1922             }
1923 #endif
1924             i = j + sep->length;
1925             if (!JSVERSION_IS_ECMA(cx->version)) {
1926                 /*
1927                  * Deviate from ECMA to imitate Perl, which omits a final
1928                  * split unless a limit argument is given and big enough.
1929                  */
1930                 if (!limited && (size_t)i == JSSTRING_LENGTH(str))
1931                     break;
1932             }
1933         }
1934         ok = (j != -2);
1935     }
1936     return ok;
1937 }
1938 
1939 #if JS_HAS_PERL_SUBSTR
1940 static JSBool
str_substr(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1941 str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1942 {
1943     JSString *str;
1944     jsdouble d;
1945     jsdouble length, begin, end;
1946 
1947     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1948     if (!str)
1949         return JS_FALSE;
1950 
1951     if (argc != 0) {
1952         if (!js_ValueToNumber(cx, argv[0], &d))
1953             return JS_FALSE;
1954         length = JSSTRING_LENGTH(str);
1955         begin = js_DoubleToInteger(d);
1956         if (begin < 0) {
1957             begin += length;
1958             if (begin < 0)
1959                 begin = 0;
1960         } else if (begin > length) {
1961             begin = length;
1962         }
1963 
1964         if (argc == 1) {
1965             end = length;
1966         } else {
1967             if (!js_ValueToNumber(cx, argv[1], &d))
1968                 return JS_FALSE;
1969             end = js_DoubleToInteger(d);
1970             if (end < 0)
1971                 end = 0;
1972             end += begin;
1973             if (end > length)
1974                 end = length;
1975         }
1976 
1977         str = js_NewDependentString(cx, str, (size_t)begin,
1978                                     (size_t)(end - begin), 0);
1979         if (!str)
1980             return JS_FALSE;
1981     }
1982     *rval = STRING_TO_JSVAL(str);
1983     return JS_TRUE;
1984 }
1985 #endif /* JS_HAS_PERL_SUBSTR */
1986 
1987 #if JS_HAS_SEQUENCE_OPS
1988 /*
1989  * Python-esque sequence operations.
1990  */
1991 static JSBool
str_concat(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)1992 str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1993 {
1994     JSString *str, *str2;
1995     uintN i;
1996 
1997     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1998     if (!str)
1999         return JS_FALSE;
2000     argv[-1] = STRING_TO_JSVAL(str);
2001 
2002     for (i = 0; i < argc; i++) {
2003         str2 = js_ValueToString(cx, argv[i]);
2004         if (!str2)
2005             return JS_FALSE;
2006         argv[i] = STRING_TO_JSVAL(str2);
2007 
2008         str = js_ConcatStrings(cx, str, str2);
2009         if (!str)
2010             return JS_FALSE;
2011     }
2012 
2013     *rval = STRING_TO_JSVAL(str);
2014     return JS_TRUE;
2015 }
2016 
2017 static JSBool
str_slice(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2018 str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2019 {
2020     JSString *str;
2021     jsdouble d;
2022     jsdouble length, begin, end;
2023 
2024     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
2025     if (!str)
2026         return JS_FALSE;
2027     argv[-1] = STRING_TO_JSVAL(str);
2028 
2029     if (argc != 0) {
2030         if (!js_ValueToNumber(cx, argv[0], &d))
2031             return JS_FALSE;
2032         length = JSSTRING_LENGTH(str);
2033         begin = js_DoubleToInteger(d);
2034         if (begin < 0) {
2035             begin += length;
2036             if (begin < 0)
2037                 begin = 0;
2038         } else if (begin > length) {
2039             begin = length;
2040         }
2041 
2042         if (argc == 1) {
2043             end = length;
2044         } else {
2045             if (!js_ValueToNumber(cx, argv[1], &d))
2046                 return JS_FALSE;
2047             end = js_DoubleToInteger(d);
2048             if (end < 0) {
2049                 end += length;
2050                 if (end < 0)
2051                     end = 0;
2052             } else if (end > length) {
2053                 end = length;
2054             }
2055             if (end < begin)
2056                 end = begin;
2057         }
2058 
2059         str = js_NewDependentString(cx, str, (size_t)begin,
2060                                     (size_t)(end - begin), 0);
2061         if (!str)
2062             return JS_FALSE;
2063     }
2064     *rval = STRING_TO_JSVAL(str);
2065     return JS_TRUE;
2066 }
2067 #endif /* JS_HAS_SEQUENCE_OPS */
2068 
2069 #if JS_HAS_STR_HTML_HELPERS
2070 /*
2071  * HTML composition aids.
2072  */
2073 static JSBool
tagify(JSContext * cx,JSObject * obj,jsval * argv,const char * begin,const jschar * param,const char * end,jsval * rval)2074 tagify(JSContext *cx, JSObject *obj, jsval *argv,
2075        const char *begin, const jschar *param, const char *end,
2076        jsval *rval)
2077 {
2078     JSString *str;
2079     jschar *tagbuf;
2080     size_t beglen, endlen, parlen, taglen;
2081     size_t i, j;
2082 
2083     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
2084     if (!str)
2085         return JS_FALSE;
2086     argv[-1] = STRING_TO_JSVAL(str);
2087 
2088     if (!end)
2089         end = begin;
2090 
2091     beglen = strlen(begin);
2092     taglen = 1 + beglen + 1;                            /* '<begin' + '>' */
2093     parlen = 0; /* Avoid warning. */
2094     if (param) {
2095         parlen = js_strlen(param);
2096         taglen += 2 + parlen + 1;                       /* '="param"' */
2097     }
2098     endlen = strlen(end);
2099     taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1;    /* 'str</end>' */
2100 
2101     tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
2102     if (!tagbuf)
2103         return JS_FALSE;
2104 
2105     j = 0;
2106     tagbuf[j++] = '<';
2107     for (i = 0; i < beglen; i++)
2108         tagbuf[j++] = (jschar)begin[i];
2109     if (param) {
2110         tagbuf[j++] = '=';
2111         tagbuf[j++] = '"';
2112         js_strncpy(&tagbuf[j], param, parlen);
2113         j += parlen;
2114         tagbuf[j++] = '"';
2115     }
2116     tagbuf[j++] = '>';
2117     js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
2118     j += JSSTRING_LENGTH(str);
2119     tagbuf[j++] = '<';
2120     tagbuf[j++] = '/';
2121     for (i = 0; i < endlen; i++)
2122         tagbuf[j++] = (jschar)end[i];
2123     tagbuf[j++] = '>';
2124     JS_ASSERT(j == taglen);
2125     tagbuf[j] = 0;
2126 
2127     str = js_NewString(cx, tagbuf, taglen, 0);
2128     if (!str) {
2129         free((char *)tagbuf);
2130         return JS_FALSE;
2131     }
2132     *rval = STRING_TO_JSVAL(str);
2133     return JS_TRUE;
2134 }
2135 
2136 static JSBool
tagify_value(JSContext * cx,JSObject * obj,jsval * argv,const char * begin,const char * end,jsval * rval)2137 tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
2138              const char *begin, const char *end,
2139              jsval *rval)
2140 {
2141     JSString *param;
2142 
2143     param = js_ValueToString(cx, argv[0]);
2144     if (!param)
2145         return JS_FALSE;
2146     argv[0] = STRING_TO_JSVAL(param);
2147     return tagify(cx, obj, argv, begin, JSSTRING_CHARS(param), end, rval);
2148 }
2149 
2150 static JSBool
str_bold(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2151 str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2152 {
2153     return tagify(cx, obj, argv, "b", NULL, NULL, rval);
2154 }
2155 
2156 static JSBool
str_italics(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2157 str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2158 {
2159     return tagify(cx, obj, argv, "i", NULL, NULL, rval);
2160 }
2161 
2162 static JSBool
str_fixed(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2163 str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2164 {
2165     return tagify(cx, obj, argv, "tt", NULL, NULL, rval);
2166 }
2167 
2168 static JSBool
str_fontsize(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2169 str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2170 {
2171     return tagify_value(cx, obj, argv, "font size", "font", rval);
2172 }
2173 
2174 static JSBool
str_fontcolor(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2175 str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2176               jsval *rval)
2177 {
2178     return tagify_value(cx, obj, argv, "font color", "font", rval);
2179 }
2180 
2181 static JSBool
str_link(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2182 str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2183 {
2184     return tagify_value(cx, obj, argv, "a href", "a", rval);
2185 }
2186 
2187 static JSBool
str_anchor(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2188 str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2189 {
2190     return tagify_value(cx, obj, argv, "a name", "a", rval);
2191 }
2192 
2193 static JSBool
str_strike(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2194 str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2195 {
2196     return tagify(cx, obj, argv, "strike", NULL, NULL, rval);
2197 }
2198 
2199 static JSBool
str_small(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2200 str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2201 {
2202     return tagify(cx, obj, argv, "small", NULL, NULL, rval);
2203 }
2204 
2205 static JSBool
str_big(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2206 str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2207 {
2208     return tagify(cx, obj, argv, "big", NULL, NULL, rval);
2209 }
2210 
2211 static JSBool
str_blink(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2212 str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2213 {
2214     return tagify(cx, obj, argv, "blink", NULL, NULL, rval);
2215 }
2216 
2217 static JSBool
str_sup(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2218 str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2219 {
2220     return tagify(cx, obj, argv, "sup", NULL, NULL, rval);
2221 }
2222 
2223 static JSBool
str_sub(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2224 str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2225 {
2226     return tagify(cx, obj, argv, "sub", NULL, NULL, rval);
2227 }
2228 #endif /* JS_HAS_STR_HTML_HELPERS */
2229 
2230 static JSFunctionSpec string_methods[] = {
2231 #if JS_HAS_TOSOURCE
2232     {"quote",               str_quote,              0,0,0},
2233     {js_toSource_str,       str_toSource,           0,0,0},
2234 #endif
2235 
2236     /* Java-like methods. */
2237     {js_toString_str,       str_toString,           0,0,0},
2238     {js_valueOf_str,        str_valueOf,            0,0,0},
2239     {"substring",           str_substring,          2,0,0},
2240     {"toLowerCase",         str_toLowerCase,        0,0,0},
2241     {"toUpperCase",         str_toUpperCase,        0,0,0},
2242     {"charAt",              str_charAt,             1,0,0},
2243     {"charCodeAt",          str_charCodeAt,         1,0,0},
2244     {"indexOf",             str_indexOf,            1,0,0},
2245     {"lastIndexOf",         str_lastIndexOf,        1,0,0},
2246     {"toLocaleLowerCase",   str_toLocaleLowerCase,  0,0,0},
2247     {"toLocaleUpperCase",   str_toLocaleUpperCase,  0,0,0},
2248     {"localeCompare",       str_localeCompare,      1,0,0},
2249 
2250     /* Perl-ish methods (search is actually Python-esque). */
2251 #if JS_HAS_REGEXPS
2252     {"match",               str_match,              1,0,2},
2253     {"search",              str_search,             1,0,0},
2254     {"replace",             str_replace,            2,0,0},
2255     {"split",               str_split,              2,0,0},
2256 #endif
2257 #if JS_HAS_PERL_SUBSTR
2258     {"substr",              str_substr,             2,0,0},
2259 #endif
2260 
2261     /* Python-esque sequence methods. */
2262 #if JS_HAS_SEQUENCE_OPS
2263     {"concat",              str_concat,             0,0,0},
2264     {"slice",               str_slice,              0,0,0},
2265 #endif
2266 
2267     /* HTML string methods. */
2268 #if JS_HAS_STR_HTML_HELPERS
2269     {"bold",                str_bold,               0,0,0},
2270     {"italics",             str_italics,            0,0,0},
2271     {"fixed",               str_fixed,              0,0,0},
2272     {"fontsize",            str_fontsize,           1,0,0},
2273     {"fontcolor",           str_fontcolor,          1,0,0},
2274     {"link",                str_link,               1,0,0},
2275     {"anchor",              str_anchor,             1,0,0},
2276     {"strike",              str_strike,             0,0,0},
2277     {"small",               str_small,              0,0,0},
2278     {"big",                 str_big,                0,0,0},
2279     {"blink",               str_blink,              0,0,0},
2280     {"sup",                 str_sup,                0,0,0},
2281     {"sub",                 str_sub,                0,0,0},
2282 #endif
2283 
2284     {0,0,0,0,0}
2285 };
2286 
2287 static JSBool
String(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2288 String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2289 {
2290     JSString *str;
2291 
2292     if (argc > 0) {
2293         str = js_ValueToString(cx, argv[0]);
2294         if (!str)
2295             return JS_FALSE;
2296     } else {
2297         str = cx->runtime->emptyString;
2298     }
2299     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
2300         *rval = STRING_TO_JSVAL(str);
2301         return JS_TRUE;
2302     }
2303     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
2304     return JS_TRUE;
2305 }
2306 
2307 static JSBool
str_fromCharCode(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)2308 str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2309                  jsval *rval)
2310 {
2311     jschar *chars;
2312     uintN i;
2313     uint16 code;
2314     JSString *str;
2315 
2316     chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
2317     if (!chars)
2318         return JS_FALSE;
2319     for (i = 0; i < argc; i++) {
2320         if (!js_ValueToUint16(cx, argv[i], &code)) {
2321             JS_free(cx, chars);
2322             return JS_FALSE;
2323         }
2324         chars[i] = (jschar)code;
2325     }
2326     chars[i] = 0;
2327     str = js_NewString(cx, chars, argc, 0);
2328     if (!str) {
2329         JS_free(cx, chars);
2330         return JS_FALSE;
2331     }
2332     *rval = STRING_TO_JSVAL(str);
2333     return JS_TRUE;
2334 }
2335 
2336 static JSFunctionSpec string_static_methods[] = {
2337     {"fromCharCode",    str_fromCharCode,       1,0,0},
2338     {0,0,0,0,0}
2339 };
2340 
2341 static JSHashTable *deflated_string_cache;
2342 #ifdef DEBUG
2343 static uint32 deflated_string_cache_bytes;
2344 #endif
2345 #ifdef JS_THREADSAFE
2346 static JSLock *deflated_string_cache_lock;
2347 #endif
2348 
2349 JSBool
js_InitStringGlobals(void)2350 js_InitStringGlobals(void)
2351 {
2352 #ifdef JS_THREADSAFE
2353     /* Must come through here once in primordial thread to init safely! */
2354     if (!deflated_string_cache_lock) {
2355         deflated_string_cache_lock = JS_NEW_LOCK();
2356         if (!deflated_string_cache_lock)
2357             return JS_FALSE;
2358     }
2359 #endif
2360     return JS_TRUE;
2361 }
2362 
2363 void
js_FreeStringGlobals()2364 js_FreeStringGlobals()
2365 {
2366     if (deflated_string_cache) {
2367         JS_HashTableDestroy(deflated_string_cache);
2368         deflated_string_cache = NULL;
2369     }
2370 #ifdef JS_THREADSAFE
2371     if (deflated_string_cache_lock) {
2372         JS_DESTROY_LOCK(deflated_string_cache_lock);
2373         deflated_string_cache_lock = NULL;
2374     }
2375 #endif
2376 }
2377 
2378 JSBool
js_InitRuntimeStringState(JSContext * cx)2379 js_InitRuntimeStringState(JSContext *cx)
2380 {
2381     JSRuntime *rt;
2382     JSString *empty;
2383 
2384     rt = cx->runtime;
2385     JS_ASSERT(!rt->emptyString);
2386 
2387     /* Make a permanently locked empty string. */
2388     empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
2389     if (!empty)
2390         return JS_FALSE;
2391 
2392     /* Atomize it for scripts that use '' + x to convert x to string. */
2393     if (!js_AtomizeString(cx, empty, ATOM_PINNED))
2394         return JS_FALSE;
2395 
2396     rt->emptyString = empty;
2397     return JS_TRUE;
2398 }
2399 
2400 void
js_FinishRuntimeStringState(JSContext * cx)2401 js_FinishRuntimeStringState(JSContext *cx)
2402 {
2403     JSRuntime *rt = cx->runtime;
2404 
2405     js_UnlockGCThingRT(rt, rt->emptyString);
2406     rt->emptyString = NULL;
2407 }
2408 
2409 JSObject *
js_InitStringClass(JSContext * cx,JSObject * obj)2410 js_InitStringClass(JSContext *cx, JSObject *obj)
2411 {
2412     JSObject *proto;
2413 
2414     /* Define the escape, unescape functions in the global object. */
2415     if (!JS_DefineFunctions(cx, obj, string_functions))
2416         return NULL;
2417 
2418     proto = JS_InitClass(cx, obj, NULL, &string_class, String, 1,
2419                          string_props, string_methods,
2420                          NULL, string_static_methods);
2421     if (!proto)
2422         return NULL;
2423     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE,
2424                  STRING_TO_JSVAL(cx->runtime->emptyString));
2425     return proto;
2426 }
2427 
2428 JSString *
js_NewString(JSContext * cx,jschar * chars,size_t length,uintN gcflag)2429 js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
2430 {
2431     JSString *str;
2432 
2433     if (length > JSSTRING_LENGTH_MASK) {
2434         JS_ReportOutOfMemory(cx);
2435         return NULL;
2436     }
2437 
2438     str = (JSString *) js_AllocGCThing(cx, gcflag | GCX_STRING);
2439     if (!str)
2440         return NULL;
2441     str->length = length;
2442     str->chars = chars;
2443 #ifdef DEBUG
2444   {
2445     JSRuntime *rt = cx->runtime;
2446     JS_RUNTIME_METER(rt, liveStrings);
2447     JS_RUNTIME_METER(rt, totalStrings);
2448     JS_LOCK_RUNTIME_VOID(rt,
2449         (rt->lengthSum += (double)length,
2450          rt->lengthSquaredSum += (double)length * (double)length));
2451   }
2452 #endif
2453     return str;
2454 }
2455 
2456 JSString *
js_NewDependentString(JSContext * cx,JSString * base,size_t start,size_t length,uintN gcflag)2457 js_NewDependentString(JSContext *cx, JSString *base, size_t start,
2458                       size_t length, uintN gcflag)
2459 {
2460     JSDependentString *ds;
2461 
2462     if (length == 0)
2463         return cx->runtime->emptyString;
2464 
2465     if (start > JSSTRDEP_START_MASK ||
2466         (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
2467         return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length,
2468                                  gcflag);
2469     }
2470 
2471     ds = (JSDependentString *) js_AllocGCThing(cx, gcflag | GCX_MUTABLE_STRING);
2472     if (!ds)
2473         return NULL;
2474     if (start == 0) {
2475         JSPREFIX_SET_LENGTH(ds, length);
2476         JSPREFIX_SET_BASE(ds, base);
2477     } else {
2478         JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
2479         JSSTRDEP_SET_BASE(ds, base);
2480     }
2481 #ifdef DEBUG
2482   {
2483     JSRuntime *rt = cx->runtime;
2484     JS_RUNTIME_METER(rt, liveDependentStrings);
2485     JS_RUNTIME_METER(rt, totalDependentStrings);
2486     JS_RUNTIME_METER(rt, liveStrings);
2487     JS_RUNTIME_METER(rt, totalStrings);
2488     JS_LOCK_RUNTIME_VOID(rt,
2489         (rt->strdepLengthSum += (double)length,
2490          rt->strdepLengthSquaredSum += (double)length * (double)length));
2491     JS_LOCK_RUNTIME_VOID(rt,
2492         (rt->lengthSum += (double)length,
2493          rt->lengthSquaredSum += (double)length * (double)length));
2494   }
2495 #endif
2496     return (JSString *)ds;
2497 }
2498 
2499 #ifdef DEBUG
2500 #include <math.h>
2501 
printJSStringStats(JSRuntime * rt)2502 void printJSStringStats(JSRuntime *rt) {
2503     double mean = 0., var = 0., sigma = 0.;
2504     jsrefcount count = rt->totalStrings;
2505     if (count > 0 && rt->lengthSum >= 0) {
2506         mean = rt->lengthSum / count;
2507         var = count * rt->lengthSquaredSum - rt->lengthSum * rt->lengthSum;
2508         if (var < 0.0 || count <= 1)
2509             var = 0.0;
2510         else
2511             var /= count * (count - 1);
2512 
2513         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
2514         sigma = (var != 0.) ? sqrt(var) : 0.;
2515     }
2516     fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
2517             (unsigned long)count, mean, sigma);
2518 
2519     mean = var = sigma = 0.;
2520     count = rt->totalDependentStrings;
2521     if (count > 0 && rt->strdepLengthSum >= 0) {
2522         mean = rt->strdepLengthSum / count;
2523         var = count * rt->strdepLengthSquaredSum
2524             - rt->strdepLengthSum * rt->strdepLengthSum;
2525         if (var < 0.0 || count <= 1)
2526             var = 0.0;
2527         else
2528             var /= count * (count - 1);
2529 
2530         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
2531         sigma = (var != 0.) ? sqrt(var) : 0.;
2532     }
2533     fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
2534             (unsigned long)count, mean, sigma);
2535 }
2536 #endif
2537 
2538 JSString *
js_NewStringCopyN(JSContext * cx,const jschar * s,size_t n,uintN gcflag)2539 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag)
2540 {
2541     jschar *news;
2542     JSString *str;
2543 
2544     news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar));
2545     if (!news)
2546         return NULL;
2547     js_strncpy(news, s, n);
2548     news[n] = 0;
2549     str = js_NewString(cx, news, n, gcflag);
2550     if (!str)
2551         JS_free(cx, news);
2552     return str;
2553 }
2554 
2555 JSString *
js_NewStringCopyZ(JSContext * cx,const jschar * s,uintN gcflag)2556 js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
2557 {
2558     size_t n, m;
2559     jschar *news;
2560     JSString *str;
2561 
2562     n = js_strlen(s);
2563     m = (n + 1) * sizeof(jschar);
2564     news = (jschar *) JS_malloc(cx, m);
2565     if (!news)
2566         return NULL;
2567     memcpy(news, s, m);
2568     str = js_NewString(cx, news, n, gcflag);
2569     if (!str)
2570         JS_free(cx, news);
2571     return str;
2572 }
2573 
2574 JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_string_pointer(const void * key)2575 js_hash_string_pointer(const void *key)
2576 {
2577     return (JSHashNumber)key >> JSVAL_TAGBITS;
2578 }
2579 
2580 void
js_PurgeDeflatedStringCache(JSString * str)2581 js_PurgeDeflatedStringCache(JSString *str)
2582 {
2583     JSHashNumber hash;
2584     JSHashEntry *he, **hep;
2585 
2586     if (!deflated_string_cache)
2587         return;
2588 
2589     hash = js_hash_string_pointer(str);
2590     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2591     hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
2592     he = *hep;
2593     if (he) {
2594 #ifdef DEBUG
2595         deflated_string_cache_bytes -= JSSTRING_LENGTH(str);
2596 #endif
2597         free(he->value);
2598         JS_HashTableRawRemove(deflated_string_cache, hep, he);
2599     }
2600     JS_RELEASE_LOCK(deflated_string_cache_lock);
2601 }
2602 
2603 void
js_FinalizeString(JSContext * cx,JSString * str)2604 js_FinalizeString(JSContext *cx, JSString *str)
2605 {
2606     js_FinalizeStringRT(cx->runtime, str);
2607 }
2608 
2609 void
js_FinalizeStringRT(JSRuntime * rt,JSString * str)2610 js_FinalizeStringRT(JSRuntime *rt, JSString *str)
2611 {
2612     JSBool valid;
2613 
2614     JS_RUNTIME_UNMETER(rt, liveStrings);
2615     if (JSSTRING_IS_DEPENDENT(str)) {
2616         /* If JSSTRFLAG_DEPENDENT is set, this string must be valid. */
2617         JS_ASSERT(JSSTRDEP_BASE(str));
2618         JS_RUNTIME_UNMETER(rt, liveDependentStrings);
2619         valid = JS_TRUE;
2620     } else {
2621         /* A stillborn string has null chars, so is not valid. */
2622         valid = (str->chars != NULL);
2623         if (valid)
2624             free(str->chars);
2625     }
2626     if (valid) {
2627         js_PurgeDeflatedStringCache(str);
2628         str->chars = NULL;
2629     }
2630     str->length = 0;
2631 }
2632 
2633 JSObject *
js_StringToObject(JSContext * cx,JSString * str)2634 js_StringToObject(JSContext *cx, JSString *str)
2635 {
2636     JSObject *obj;
2637 
2638     obj = js_NewObject(cx, &string_class, NULL, NULL);
2639     if (!obj)
2640         return NULL;
2641     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
2642     return obj;
2643 }
2644 
2645 JSString *
js_ValueToString(JSContext * cx,jsval v)2646 js_ValueToString(JSContext *cx, jsval v)
2647 {
2648     JSObject *obj;
2649     JSString *str;
2650 
2651     if (JSVAL_IS_OBJECT(v)) {
2652         obj = JSVAL_TO_OBJECT(v);
2653         if (!obj)
2654             return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
2655         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
2656             return NULL;
2657     }
2658     if (JSVAL_IS_STRING(v)) {
2659         str = JSVAL_TO_STRING(v);
2660     } else if (JSVAL_IS_INT(v)) {
2661         str = js_NumberToString(cx, JSVAL_TO_INT(v));
2662     } else if (JSVAL_IS_DOUBLE(v)) {
2663         str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
2664     } else if (JSVAL_IS_BOOLEAN(v)) {
2665         str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
2666     } else {
2667         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
2668     }
2669     return str;
2670 }
2671 
2672 JSString *
js_ValueToSource(JSContext * cx,jsval v)2673 js_ValueToSource(JSContext *cx, jsval v)
2674 {
2675     if (JSVAL_IS_STRING(v))
2676         return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
2677     if (JSVAL_IS_PRIMITIVE(v)) {
2678         /* Special case to preserve negative zero, _contra_ toString. */
2679         if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
2680             /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
2681             static const jschar js_negzero_ucNstr[] = {'-', '0'};
2682 
2683             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2, 0);
2684         }
2685     } else {
2686         if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
2687                           cx->runtime->atomState.toSourceAtom,
2688                           0, NULL, &v)) {
2689             return NULL;
2690         }
2691     }
2692     return js_ValueToString(cx, v);
2693 }
2694 
2695 JSHashNumber
js_HashString(JSString * str)2696 js_HashString(JSString *str)
2697 {
2698     JSHashNumber h;
2699     const jschar *s;
2700     size_t n;
2701 
2702     h = 0;
2703     for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
2704         h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
2705     return h;
2706 }
2707 
2708 intN
js_CompareStrings(JSString * str1,JSString * str2)2709 js_CompareStrings(JSString *str1, JSString *str2)
2710 {
2711     size_t l1, l2, n, i;
2712     const jschar *s1, *s2;
2713     intN cmp;
2714 
2715     l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
2716     s1 = JSSTRING_CHARS(str1),  s2 = JSSTRING_CHARS(str2);
2717     n = JS_MIN(l1, l2);
2718     for (i = 0; i < n; i++) {
2719         cmp = s1[i] - s2[i];
2720         if (cmp != 0)
2721             return cmp;
2722     }
2723     return (intN)(l1 - l2);
2724 }
2725 
2726 size_t
js_strlen(const jschar * s)2727 js_strlen(const jschar *s)
2728 {
2729     const jschar *t;
2730 
2731     for (t = s; *t != 0; t++)
2732         continue;
2733     return (size_t)(t - s);
2734 }
2735 
2736 jschar *
js_strchr(const jschar * s,jschar c)2737 js_strchr(const jschar *s, jschar c)
2738 {
2739     while (*s != 0) {
2740         if (*s == c)
2741             return (jschar *)s;
2742         s++;
2743     }
2744     return NULL;
2745 }
2746 
2747 jschar *
js_strchr_limit(const jschar * s,jschar c,const jschar * limit)2748 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
2749 {
2750     while (s < limit) {
2751         if (*s == c)
2752             return (jschar *)s;
2753         s++;
2754     }
2755     return NULL;
2756 }
2757 
2758 const jschar *
js_SkipWhiteSpace(const jschar * s)2759 js_SkipWhiteSpace(const jschar *s)
2760 {
2761     /* JS_ISSPACE is false on a null. */
2762     while (JS_ISSPACE(*s))
2763         s++;
2764     return s;
2765 }
2766 
2767 #define INFLATE_STRING_BODY                                                   \
2768     for (i = 0; i < length; i++)                                              \
2769         chars[i] = (unsigned char) bytes[i];                                  \
2770     chars[i] = 0;
2771 
2772 void
js_InflateStringToBuffer(jschar * chars,const char * bytes,size_t length)2773 js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length)
2774 {
2775     size_t i;
2776 
2777     INFLATE_STRING_BODY
2778 }
2779 
2780 jschar *
js_InflateString(JSContext * cx,const char * bytes,size_t length)2781 js_InflateString(JSContext *cx, const char *bytes, size_t length)
2782 {
2783     jschar *chars;
2784     size_t i;
2785 
2786     chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
2787     if (!chars)
2788         return NULL;
2789 
2790     INFLATE_STRING_BODY
2791 
2792     return chars;
2793 }
2794 
2795 /*
2796  * May be called with null cx by js_GetStringBytes, see below.
2797  */
2798 char *
js_DeflateString(JSContext * cx,const jschar * chars,size_t length)2799 js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
2800 {
2801     size_t i, size;
2802     char *bytes;
2803 
2804     size = (length + 1) * sizeof(char);
2805     bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
2806     if (!bytes)
2807         return NULL;
2808     for (i = 0; i < length; i++)
2809         bytes[i] = (char) chars[i];
2810     bytes[i] = 0;
2811     return bytes;
2812 }
2813 
2814 static JSHashTable *
GetDeflatedStringCache(void)2815 GetDeflatedStringCache(void)
2816 {
2817     JSHashTable *cache;
2818 
2819     cache = deflated_string_cache;
2820     if (!cache) {
2821         cache = JS_NewHashTable(8, js_hash_string_pointer,
2822                                 JS_CompareValues, JS_CompareValues,
2823                                 NULL, NULL);
2824         deflated_string_cache = cache;
2825     }
2826     return cache;
2827 }
2828 
2829 JSBool
js_SetStringBytes(JSString * str,char * bytes,size_t length)2830 js_SetStringBytes(JSString *str, char *bytes, size_t length)
2831 {
2832     JSHashTable *cache;
2833     JSBool ok;
2834     JSHashNumber hash;
2835     JSHashEntry **hep;
2836 
2837     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2838 
2839     cache = GetDeflatedStringCache();
2840     if (!cache) {
2841         ok = JS_FALSE;
2842     } else {
2843         hash = js_hash_string_pointer(str);
2844         hep = JS_HashTableRawLookup(cache, hash, str);
2845         JS_ASSERT(*hep == NULL);
2846         ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
2847 #ifdef DEBUG
2848         if (ok)
2849             deflated_string_cache_bytes += length;
2850 #endif
2851     }
2852 
2853     JS_RELEASE_LOCK(deflated_string_cache_lock);
2854     return ok;
2855 }
2856 
2857 char *
js_GetStringBytes(JSString * str)2858 js_GetStringBytes(JSString *str)
2859 {
2860     JSHashTable *cache;
2861     char *bytes;
2862     JSHashNumber hash;
2863     JSHashEntry *he, **hep;
2864 
2865     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2866 
2867     cache = GetDeflatedStringCache();
2868     if (!cache) {
2869         bytes = NULL;
2870     } else {
2871         hash = js_hash_string_pointer(str);
2872         hep = JS_HashTableRawLookup(cache, hash, str);
2873         he = *hep;
2874         if (he) {
2875             bytes = (char *) he->value;
2876 
2877             /* Try to catch failure to JS_ShutDown between runtime epochs. */
2878             JS_ASSERT((*bytes == '\0' && JSSTRING_LENGTH(str) == 0) ||
2879                       *bytes == (char) JSSTRING_CHARS(str)[0]);
2880         } else {
2881             bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
2882                                      JSSTRING_LENGTH(str));
2883             if (bytes) {
2884                 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
2885 #ifdef DEBUG
2886                     deflated_string_cache_bytes += JSSTRING_LENGTH(str);
2887 #endif
2888                 } else {
2889                     free(bytes);
2890                     bytes = NULL;
2891                 }
2892             }
2893         }
2894     }
2895 
2896     JS_RELEASE_LOCK(deflated_string_cache_lock);
2897     return bytes;
2898 }
2899 
2900 /*
2901  * From java.lang.Character.java:
2902  *
2903  * The character properties are currently encoded into 32 bits in the
2904  * following manner:
2905  *
2906  * 10 bits      signed offset used for converting case
2907  *  1 bit       if 1, adding the signed offset converts the character to
2908  *              lowercase
2909  *  1 bit       if 1, subtracting the signed offset converts the character to
2910  *              uppercase
2911  *  1 bit       if 1, character has a titlecase equivalent (possibly itself)
2912  *  3 bits      0  may not be part of an identifier
2913  *              1  ignorable control; may continue a Unicode identifier or JS
2914  *                 identifier
2915  *              2  may continue a JS identifier but not a Unicode identifier
2916  *                 (unused)
2917  *              3  may continue a Unicode identifier or JS identifier
2918  *              4  is a JS whitespace character
2919  *              5  may start or continue a JS identifier;
2920  *                 may continue but not start a Unicode identifier (_)
2921  *              6  may start or continue a JS identifier but not a Unicode
2922  *                 identifier ($)
2923  *              7  may start or continue a Unicode identifier or JS identifier
2924  *              Thus:
2925  *                 5, 6, 7 may start a JS identifier
2926  *                 1, 2, 3, 5, 6, 7 may continue a JS identifier
2927  *                 7 may start a Unicode identifier
2928  *                 1, 3, 5, 7 may continue a Unicode identifier
2929  *                 1 is ignorable within an identifier
2930  *                 4 is JS whitespace
2931  *  2 bits      0  this character has no numeric property
2932  *              1  adding the digit offset to the character code and then
2933  *                 masking with 0x1F will produce the desired numeric value
2934  *              2  this character has a "strange" numeric value
2935  *              3  a JS supradecimal digit: adding the digit offset to the
2936  *                 character code, then masking with 0x1F, then adding 10
2937  *                 will produce the desired numeric value
2938  *  5 bits      digit offset
2939  *  4 bits      reserved for future use
2940  *  5 bits      character type
2941  */
2942 
2943 /* The X table has 1024 entries for a total of 1024 bytes. */
2944 
2945 const uint8 js_X[] = {
2946   0,   1,   2,   3,   4,   5,   6,   7,  /*  0x0000 */
2947   8,   9,  10,  11,  12,  13,  14,  15,  /*  0x0200 */
2948  16,  17,  18,  19,  20,  21,  22,  23,  /*  0x0400 */
2949  24,  25,  26,  27,  28,  28,  28,  28,  /*  0x0600 */
2950  28,  28,  28,  28,  29,  30,  31,  32,  /*  0x0800 */
2951  33,  34,  35,  36,  37,  38,  39,  40,  /*  0x0A00 */
2952  41,  42,  43,  44,  45,  46,  28,  28,  /*  0x0C00 */
2953  47,  48,  49,  50,  51,  52,  53,  28,  /*  0x0E00 */
2954  28,  28,  54,  55,  56,  57,  58,  59,  /*  0x1000 */
2955  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1200 */
2956  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1400 */
2957  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1600 */
2958  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1800 */
2959  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1A00 */
2960  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1C00 */
2961  60,  60,  61,  62,  63,  64,  65,  66,  /*  0x1E00 */
2962  67,  68,  69,  70,  71,  72,  73,  74,  /*  0x2000 */
2963  75,  75,  75,  76,  77,  78,  28,  28,  /*  0x2200 */
2964  79,  80,  81,  82,  83,  83,  84,  85,  /*  0x2400 */
2965  86,  85,  28,  28,  87,  88,  89,  28,  /*  0x2600 */
2966  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2800 */
2967  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2A00 */
2968  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2C00 */
2969  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2E00 */
2970  90,  91,  92,  93,  94,  56,  95,  28,  /*  0x3000 */
2971  96,  97,  98,  99,  83, 100,  83, 101,  /*  0x3200 */
2972  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3400 */
2973  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3600 */
2974  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3800 */
2975  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3A00 */
2976  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3C00 */
2977  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3E00 */
2978  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4000 */
2979  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4200 */
2980  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4400 */
2981  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4600 */
2982  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4800 */
2983  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4A00 */
2984  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4C00 */
2985  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x4E00 */
2986  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5000 */
2987  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5200 */
2988  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5400 */
2989  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5600 */
2990  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5800 */
2991  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5A00 */
2992  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5C00 */
2993  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5E00 */
2994  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6000 */
2995  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6200 */
2996  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6400 */
2997  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6600 */
2998  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6800 */
2999  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6A00 */
3000  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6C00 */
3001  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6E00 */
3002  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7000 */
3003  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7200 */
3004  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7400 */
3005  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7600 */
3006  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7800 */
3007  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7A00 */
3008  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7C00 */
3009  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7E00 */
3010  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8000 */
3011  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8200 */
3012  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8400 */
3013  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8600 */
3014  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8800 */
3015  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8A00 */
3016  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8C00 */
3017  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8E00 */
3018  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9000 */
3019  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9200 */
3020  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9400 */
3021  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9600 */
3022  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9800 */
3023  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9A00 */
3024  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9C00 */
3025  56,  56,  56,  56,  56,  56, 102,  28,  /*  0x9E00 */
3026  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA000 */
3027  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA200 */
3028  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA400 */
3029  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA600 */
3030  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA800 */
3031  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xAA00 */
3032  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAC00 */
3033  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAE00 */
3034  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB000 */
3035  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB200 */
3036  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB400 */
3037  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB600 */
3038  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB800 */
3039  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBA00 */
3040  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBC00 */
3041  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBE00 */
3042  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC000 */
3043  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC200 */
3044  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC400 */
3045  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC600 */
3046  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC800 */
3047  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCA00 */
3048  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCC00 */
3049  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCE00 */
3050  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD000 */
3051  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD200 */
3052  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD400 */
3053  56,  56,  56,  56,  56,  56, 103,  28,  /*  0xD600 */
3054 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xD800 */
3055 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDA00 */
3056 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDC00 */
3057 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDE00 */
3058 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE000 */
3059 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE200 */
3060 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE400 */
3061 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE600 */
3062 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE800 */
3063 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEA00 */
3064 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEC00 */
3065 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEE00 */
3066 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF000 */
3067 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF200 */
3068 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF400 */
3069 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF600 */
3070 105, 105, 105, 105,  56,  56,  56,  56,  /*  0xF800 */
3071 106,  28,  28,  28, 107, 108, 109, 110,  /*  0xFA00 */
3072  56,  56,  56,  56, 111, 112, 113, 114,  /*  0xFC00 */
3073 115, 116,  56, 117, 118, 119, 120, 121   /*  0xFE00 */
3074 };
3075 
3076 /* The Y table has 7808 entries for a total of 7808 bytes. */
3077 
3078 const uint8 js_Y[] = {
3079   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
3080   0,   1,   1,   1,   1,   1,   0,   0,  /*    0 */
3081   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
3082   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
3083   2,   3,   3,   3,   4,   3,   3,   3,  /*    0 */
3084   5,   6,   3,   7,   3,   8,   3,   3,  /*    0 */
3085   9,   9,   9,   9,   9,   9,   9,   9,  /*    0 */
3086   9,   9,   3,   3,   7,   7,   7,   3,  /*    0 */
3087   3,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
3088  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
3089  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
3090  10,  10,  10,   5,   3,   6,  11,  12,  /*    1 */
3091  11,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
3092  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
3093  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
3094  13,  13,  13,   5,   7,   6,   7,   0,  /*    1 */
3095   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
3096   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
3097   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
3098   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
3099   2,   3,   4,   4,   4,   4,  15,  15,  /*    2 */
3100  11,  15,  16,   5,   7,   8,  15,  11,  /*    2 */
3101  15,   7,  17,  17,  11,  16,  15,   3,  /*    2 */
3102  11,  18,  16,   6,  19,  19,  19,   3,  /*    2 */
3103  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
3104  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
3105  20,  20,  20,  20,  20,  20,  20,   7,  /*    3 */
3106  20,  20,  20,  20,  20,  20,  20,  16,  /*    3 */
3107  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
3108  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
3109  21,  21,  21,  21,  21,  21,  21,   7,  /*    3 */
3110  21,  21,  21,  21,  21,  21,  21,  22,  /*    3 */
3111  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3112  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3113  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3114  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3115  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3116  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
3117  25,  26,  23,  24,  23,  24,  23,  24,  /*    4 */
3118  16,  23,  24,  23,  24,  23,  24,  23,  /*    4 */
3119  24,  23,  24,  23,  24,  23,  24,  23,  /*    5 */
3120  24,  16,  23,  24,  23,  24,  23,  24,  /*    5 */
3121  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
3122  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
3123  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
3124  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
3125  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
3126  27,  23,  24,  23,  24,  23,  24,  28,  /*    5 */
3127  16,  29,  23,  24,  23,  24,  30,  23,  /*    6 */
3128  24,  31,  31,  23,  24,  16,  32,  32,  /*    6 */
3129  33,  23,  24,  31,  34,  16,  35,  36,  /*    6 */
3130  23,  24,  16,  16,  35,  37,  16,  38,  /*    6 */
3131  23,  24,  23,  24,  23,  24,  38,  23,  /*    6 */
3132  24,  39,  40,  16,  23,  24,  39,  23,  /*    6 */
3133  24,  41,  41,  23,  24,  23,  24,  42,  /*    6 */
3134  23,  24,  16,  40,  23,  24,  40,  40,  /*    6 */
3135  40,  40,  40,  40,  43,  44,  45,  43,  /*    7 */
3136  44,  45,  43,  44,  45,  23,  24,  23,  /*    7 */
3137  24,  23,  24,  23,  24,  23,  24,  23,  /*    7 */
3138  24,  23,  24,  23,  24,  16,  23,  24,  /*    7 */
3139  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
3140  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
3141  16,  43,  44,  45,  23,  24,  46,  46,  /*    7 */
3142  46,  46,  23,  24,  23,  24,  23,  24,  /*    7 */
3143  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
3144  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
3145  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
3146  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
3147  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
3148  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
3149  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
3150  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
3151  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
3152  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
3153  16,  16,  16,  47,  48,  16,  49,  49,  /*    9 */
3154  50,  50,  16,  51,  16,  16,  16,  16,  /*    9 */
3155  49,  16,  16,  52,  16,  16,  16,  16,  /*    9 */
3156  53,  54,  16,  16,  16,  16,  16,  54,  /*    9 */
3157  16,  16,  55,  16,  16,  16,  16,  16,  /*    9 */
3158  16,  16,  16,  16,  16,  16,  16,  16,  /*    9 */
3159  16,  16,  16,  56,  16,  16,  16,  16,  /*   10 */
3160  56,  16,  57,  57,  16,  16,  16,  16,  /*   10 */
3161  16,  16,  58,  16,  16,  16,  16,  16,  /*   10 */
3162  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
3163  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
3164  16,  46,  46,  46,  46,  46,  46,  46,  /*   10 */
3165  59,  59,  59,  59,  59,  59,  59,  59,  /*   10 */
3166  59,  11,  11,  59,  59,  59,  59,  59,  /*   10 */
3167  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
3168  11,  11,  11,  11,  11,  11,  11,  11,  /*   11 */
3169  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
3170  11,  11,  11,  11,  11,  11,  11,  46,  /*   11 */
3171  59,  59,  59,  59,  59,  11,  11,  11,  /*   11 */
3172  11,  11,  46,  46,  46,  46,  46,  46,  /*   11 */
3173  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
3174  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
3175  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3176  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3177  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3178  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3179  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3180  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3181  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3182  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
3183  60,  60,  60,  60,  60,  60,  46,  46,  /*   13 */
3184  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
3185  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
3186  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
3187  60,  60,  46,  46,  46,  46,  46,  46,  /*   13 */
3188  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
3189  46,  46,  46,  46,   3,   3,  46,  46,  /*   13 */
3190  46,  46,  59,  46,  46,  46,   3,  46,  /*   13 */
3191  46,  46,  46,  46,  11,  11,  61,   3,  /*   14 */
3192  62,  62,  62,  46,  63,  46,  64,  64,  /*   14 */
3193  16,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
3194  20,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
3195  20,  20,  46,  20,  20,  20,  20,  20,  /*   14 */
3196  20,  20,  20,  20,  65,  66,  66,  66,  /*   14 */
3197  16,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
3198  21,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
3199  21,  21,  16,  21,  21,  21,  21,  21,  /*   15 */
3200  21,  21,  21,  21,  67,  68,  68,  46,  /*   15 */
3201  69,  70,  38,  38,  38,  71,  72,  46,  /*   15 */
3202  46,  46,  38,  46,  38,  46,  38,  46,  /*   15 */
3203  38,  46,  23,  24,  23,  24,  23,  24,  /*   15 */
3204  23,  24,  23,  24,  23,  24,  23,  24,  /*   15 */
3205  73,  74,  16,  40,  46,  46,  46,  46,  /*   15 */
3206  46,  46,  46,  46,  46,  46,  46,  46,  /*   15 */
3207  46,  75,  75,  75,  75,  75,  75,  75,  /*   16 */
3208  75,  75,  75,  75,  75,  46,  75,  75,  /*   16 */
3209  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
3210  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
3211  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
3212  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
3213  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
3214  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
3215  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
3216  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
3217  46,  74,  74,  74,  74,  74,  74,  74,  /*   17 */
3218  74,  74,  74,  74,  74,  46,  74,  74,  /*   17 */
3219  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
3220  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
3221  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
3222  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
3223  23,  24,  15,  60,  60,  60,  60,  46,  /*   18 */
3224  46,  46,  46,  46,  46,  46,  46,  46,  /*   18 */
3225  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3226  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3227  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3228  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3229  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3230  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
3231  40,  23,  24,  23,  24,  46,  46,  23,  /*   19 */
3232  24,  46,  46,  23,  24,  46,  46,  46,  /*   19 */
3233  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
3234  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
3235  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
3236  23,  24,  23,  24,  46,  46,  23,  24,  /*   19 */
3237  23,  24,  23,  24,  23,  24,  46,  46,  /*   19 */
3238  23,  24,  46,  46,  46,  46,  46,  46,  /*   19 */
3239  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3240  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3241  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3242  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3243  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3244  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
3245  46,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
3246  76,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
3247  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
3248  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
3249  76,  76,  76,  76,  76,  76,  76,  46,  /*   21 */
3250  46,  59,   3,   3,   3,   3,   3,   3,  /*   21 */
3251  46,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
3252  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
3253  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
3254  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
3255  77,  77,  77,  77,  77,  77,  77,  16,  /*   22 */
3256  46,   3,  46,  46,  46,  46,  46,  46,  /*   22 */
3257  46,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
3258  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
3259  60,  60,  46,  60,  60,  60,  60,  60,  /*   22 */
3260  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
3261  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
3262  60,  60,  46,  60,  60,  60,   3,  60,  /*   22 */
3263   3,  60,  60,   3,  60,  46,  46,  46,  /*   23 */
3264  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
3265  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
3266  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
3267  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
3268  40,  40,  40,  46,  46,  46,  46,  46,  /*   23 */
3269  40,  40,  40,   3,   3,  46,  46,  46,  /*   23 */
3270  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
3271  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
3272  46,  46,  46,  46,   3,  46,  46,  46,  /*   24 */
3273  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
3274  46,  46,  46,   3,  46,  46,  46,   3,  /*   24 */
3275  46,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
3276  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
3277  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
3278  40,  40,  40,  46,  46,  46,  46,  46,  /*   24 */
3279  59,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
3280  40,  40,  40,  60,  60,  60,  60,  60,  /*   25 */
3281  60,  60,  60,  46,  46,  46,  46,  46,  /*   25 */
3282  46,  46,  46,  46,  46,  46,  46,  46,  /*   25 */
3283  78,  78,  78,  78,  78,  78,  78,  78,  /*   25 */
3284  78,  78,   3,   3,   3,   3,  46,  46,  /*   25 */
3285  60,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
3286  40,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
3287  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3288  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3289  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3290  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3291  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3292  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3293  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
3294  46,  46,  40,  40,  40,  40,  40,  46,  /*   26 */
3295  40,  40,  40,  40,  40,  40,  40,  40,  /*   27 */
3296  40,  40,  40,  40,  40,  40,  40,  46,  /*   27 */
3297  40,  40,  40,  40,   3,  40,  60,  60,  /*   27 */
3298  60,  60,  60,  60,  60,  79,  79,  60,  /*   27 */
3299  60,  60,  60,  60,  60,  59,  59,  60,  /*   27 */
3300  60,  15,  60,  60,  60,  60,  46,  46,  /*   27 */
3301   9,   9,   9,   9,   9,   9,   9,   9,  /*   27 */
3302   9,   9,  46,  46,  46,  46,  46,  46,  /*   27 */
3303  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3304  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3305  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3306  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3307  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3308  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3309  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3310  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
3311  46,  60,  60,  80,  46,  40,  40,  40,  /*   29 */
3312  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3313  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3314  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3315  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3316  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3317  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
3318  40,  40,  46,  46,  60,  40,  80,  80,  /*   29 */
3319  80,  60,  60,  60,  60,  60,  60,  60,  /*   30 */
3320  60,  80,  80,  80,  80,  60,  46,  46,  /*   30 */
3321  15,  60,  60,  60,  60,  46,  46,  46,  /*   30 */
3322  40,  40,  40,  40,  40,  40,  40,  40,  /*   30 */
3323  40,  40,  60,  60,   3,   3,  81,  81,  /*   30 */
3324  81,  81,  81,  81,  81,  81,  81,  81,  /*   30 */
3325   3,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
3326  46,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
3327  46,  60,  80,  80,  46,  40,  40,  40,  /*   31 */
3328  40,  40,  40,  40,  40,  46,  46,  40,  /*   31 */
3329  40,  46,  46,  40,  40,  40,  40,  40,  /*   31 */
3330  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
3331  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
3332  40,  46,  40,  40,  40,  40,  40,  40,  /*   31 */
3333  40,  46,  40,  46,  46,  46,  40,  40,  /*   31 */
3334  40,  40,  46,  46,  60,  46,  80,  80,  /*   31 */
3335  80,  60,  60,  60,  60,  46,  46,  80,  /*   32 */
3336  80,  46,  46,  80,  80,  60,  46,  46,  /*   32 */
3337  46,  46,  46,  46,  46,  46,  46,  80,  /*   32 */
3338  46,  46,  46,  46,  40,  40,  46,  40,  /*   32 */
3339  40,  40,  60,  60,  46,  46,  81,  81,  /*   32 */
3340  81,  81,  81,  81,  81,  81,  81,  81,  /*   32 */
3341  40,  40,   4,   4,  82,  82,  82,  82,  /*   32 */
3342  19,  83,  15,  46,  46,  46,  46,  46,  /*   32 */
3343  46,  46,  60,  46,  46,  40,  40,  40,  /*   33 */
3344  40,  40,  40,  46,  46,  46,  46,  40,  /*   33 */
3345  40,  46,  46,  40,  40,  40,  40,  40,  /*   33 */
3346  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
3347  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
3348  40,  46,  40,  40,  40,  40,  40,  40,  /*   33 */
3349  40,  46,  40,  40,  46,  40,  40,  46,  /*   33 */
3350  40,  40,  46,  46,  60,  46,  80,  80,  /*   33 */
3351  80,  60,  60,  46,  46,  46,  46,  60,  /*   34 */
3352  60,  46,  46,  60,  60,  60,  46,  46,  /*   34 */
3353  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
3354  46,  40,  40,  40,  40,  46,  40,  46,  /*   34 */
3355  46,  46,  46,  46,  46,  46,  81,  81,  /*   34 */
3356  81,  81,  81,  81,  81,  81,  81,  81,  /*   34 */
3357  60,  60,  40,  40,  40,  46,  46,  46,  /*   34 */
3358  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
3359  46,  60,  60,  80,  46,  40,  40,  40,  /*   35 */
3360  40,  40,  40,  40,  46,  40,  46,  40,  /*   35 */
3361  40,  40,  46,  40,  40,  40,  40,  40,  /*   35 */
3362  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
3363  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
3364  40,  46,  40,  40,  40,  40,  40,  40,  /*   35 */
3365  40,  46,  40,  40,  46,  40,  40,  40,  /*   35 */
3366  40,  40,  46,  46,  60,  40,  80,  80,  /*   35 */
3367  80,  60,  60,  60,  60,  60,  46,  60,  /*   36 */
3368  60,  80,  46,  80,  80,  60,  46,  46,  /*   36 */
3369  15,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
3370  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
3371  40,  46,  46,  46,  46,  46,  81,  81,  /*   36 */
3372  81,  81,  81,  81,  81,  81,  81,  81,  /*   36 */
3373  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
3374  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
3375  46,  60,  80,  80,  46,  40,  40,  40,  /*   37 */
3376  40,  40,  40,  40,  40,  46,  46,  40,  /*   37 */
3377  40,  46,  46,  40,  40,  40,  40,  40,  /*   37 */
3378  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
3379  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
3380  40,  46,  40,  40,  40,  40,  40,  40,  /*   37 */
3381  40,  46,  40,  40,  46,  46,  40,  40,  /*   37 */
3382  40,  40,  46,  46,  60,  40,  80,  60,  /*   37 */
3383  80,  60,  60,  60,  46,  46,  46,  80,  /*   38 */
3384  80,  46,  46,  80,  80,  60,  46,  46,  /*   38 */
3385  46,  46,  46,  46,  46,  46,  60,  80,  /*   38 */
3386  46,  46,  46,  46,  40,  40,  46,  40,  /*   38 */
3387  40,  40,  46,  46,  46,  46,  81,  81,  /*   38 */
3388  81,  81,  81,  81,  81,  81,  81,  81,  /*   38 */
3389  15,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
3390  46,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
3391  46,  46,  60,  80,  46,  40,  40,  40,  /*   39 */
3392  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
3393  40,  46,  40,  40,  40,  40,  46,  46,  /*   39 */
3394  46,  40,  40,  46,  40,  46,  40,  40,  /*   39 */
3395  46,  46,  46,  40,  40,  46,  46,  46,  /*   39 */
3396  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
3397  40,  40,  40,  40,  40,  40,  46,  40,  /*   39 */
3398  40,  40,  46,  46,  46,  46,  80,  80,  /*   39 */
3399  60,  80,  80,  46,  46,  46,  80,  80,  /*   40 */
3400  80,  46,  80,  80,  80,  60,  46,  46,  /*   40 */
3401  46,  46,  46,  46,  46,  46,  46,  80,  /*   40 */
3402  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
3403  46,  46,  46,  46,  46,  46,  46,  81,  /*   40 */
3404  81,  81,  81,  81,  81,  81,  81,  81,  /*   40 */
3405  84,  19,  19,  46,  46,  46,  46,  46,  /*   40 */
3406  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
3407  46,  80,  80,  80,  46,  40,  40,  40,  /*   41 */
3408  40,  40,  40,  40,  40,  46,  40,  40,  /*   41 */
3409  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
3410  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
3411  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
3412  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
3413  40,  40,  40,  40,  46,  40,  40,  40,  /*   41 */
3414  40,  40,  46,  46,  46,  46,  60,  60,  /*   41 */
3415  60,  80,  80,  80,  80,  46,  60,  60,  /*   42 */
3416  60,  46,  60,  60,  60,  60,  46,  46,  /*   42 */
3417  46,  46,  46,  46,  46,  60,  60,  46,  /*   42 */
3418  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
3419  40,  40,  46,  46,  46,  46,  81,  81,  /*   42 */
3420  81,  81,  81,  81,  81,  81,  81,  81,  /*   42 */
3421  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
3422  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
3423  46,  46,  80,  80,  46,  40,  40,  40,  /*   43 */
3424  40,  40,  40,  40,  40,  46,  40,  40,  /*   43 */
3425  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
3426  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
3427  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
3428  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
3429  40,  40,  40,  40,  46,  40,  40,  40,  /*   43 */
3430  40,  40,  46,  46,  46,  46,  80,  60,  /*   43 */
3431  80,  80,  80,  80,  80,  46,  60,  80,  /*   44 */
3432  80,  46,  80,  80,  60,  60,  46,  46,  /*   44 */
3433  46,  46,  46,  46,  46,  80,  80,  46,  /*   44 */
3434  46,  46,  46,  46,  46,  46,  40,  46,  /*   44 */
3435  40,  40,  46,  46,  46,  46,  81,  81,  /*   44 */
3436  81,  81,  81,  81,  81,  81,  81,  81,  /*   44 */
3437  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
3438  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
3439  46,  46,  80,  80,  46,  40,  40,  40,  /*   45 */
3440  40,  40,  40,  40,  40,  46,  40,  40,  /*   45 */
3441  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
3442  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
3443  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
3444  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
3445  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
3446  40,  40,  46,  46,  46,  46,  80,  80,  /*   45 */
3447  80,  60,  60,  60,  46,  46,  80,  80,  /*   46 */
3448  80,  46,  80,  80,  80,  60,  46,  46,  /*   46 */
3449  46,  46,  46,  46,  46,  46,  46,  80,  /*   46 */
3450  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
3451  40,  40,  46,  46,  46,  46,  81,  81,  /*   46 */
3452  81,  81,  81,  81,  81,  81,  81,  81,  /*   46 */
3453  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
3454  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
3455  46,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
3456  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
3457  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
3458  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
3459  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
3460  40,  40,  40,  40,  40,  40,  40,   3,  /*   47 */
3461  40,  60,  40,  40,  60,  60,  60,  60,  /*   47 */
3462  60,  60,  60,  46,  46,  46,  46,   4,  /*   47 */
3463  40,  40,  40,  40,  40,  40,  59,  60,  /*   48 */
3464  60,  60,  60,  60,  60,  60,  60,  15,  /*   48 */
3465   9,   9,   9,   9,   9,   9,   9,   9,  /*   48 */
3466   9,   9,   3,   3,  46,  46,  46,  46,  /*   48 */
3467  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
3468  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
3469  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
3470  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
3471  46,  40,  40,  46,  40,  46,  46,  40,  /*   49 */
3472  40,  46,  40,  46,  46,  40,  46,  46,  /*   49 */
3473  46,  46,  46,  46,  40,  40,  40,  40,  /*   49 */
3474  46,  40,  40,  40,  40,  40,  40,  40,  /*   49 */
3475  46,  40,  40,  40,  46,  40,  46,  40,  /*   49 */
3476  46,  46,  40,  40,  46,  40,  40,   3,  /*   49 */
3477  40,  60,  40,  40,  60,  60,  60,  60,  /*   49 */
3478  60,  60,  46,  60,  60,  40,  46,  46,  /*   49 */
3479  40,  40,  40,  40,  40,  46,  59,  46,  /*   50 */
3480  60,  60,  60,  60,  60,  60,  46,  46,  /*   50 */
3481   9,   9,   9,   9,   9,   9,   9,   9,  /*   50 */
3482   9,   9,  46,  46,  40,  40,  46,  46,  /*   50 */
3483  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
3484  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
3485  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
3486  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
3487  15,  15,  15,  15,   3,   3,   3,   3,  /*   51 */
3488   3,   3,   3,   3,   3,   3,   3,   3,  /*   51 */
3489   3,   3,   3,  15,  15,  15,  15,  15,  /*   51 */
3490  60,  60,  15,  15,  15,  15,  15,  15,  /*   51 */
3491  78,  78,  78,  78,  78,  78,  78,  78,  /*   51 */
3492  78,  78,  85,  85,  85,  85,  85,  85,  /*   51 */
3493  85,  85,  85,  85,  15,  60,  15,  60,  /*   51 */
3494  15,  60,   5,   6,   5,   6,  80,  80,  /*   51 */
3495  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
3496  46,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
3497  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
3498  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
3499  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
3500  40,  40,  46,  46,  46,  46,  46,  46,  /*   52 */
3501  46,  60,  60,  60,  60,  60,  60,  60,  /*   52 */
3502  60,  60,  60,  60,  60,  60,  60,  80,  /*   52 */
3503  60,  60,  60,  60,  60,   3,  60,  60,  /*   53 */
3504  60,  60,  60,  60,  46,  46,  46,  46,  /*   53 */
3505  60,  60,  60,  60,  60,  60,  46,  60,  /*   53 */
3506  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
3507  60,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
3508  60,  60,  60,  60,  60,  60,  46,  46,  /*   53 */
3509  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
3510  46,  60,  46,  46,  46,  46,  46,  46,  /*   53 */
3511  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
3512  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
3513  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
3514  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
3515  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
3516  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
3517  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
3518  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
3519  76,  76,  76,  76,  76,  76,  46,  46,  /*   55 */
3520  46,  46,  46,  46,  46,  46,  46,  46,  /*   55 */
3521  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
3522  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
3523  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
3524  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
3525  16,  16,  16,  16,  16,  16,  16,  46,  /*   55 */
3526  46,  46,  46,   3,  46,  46,  46,  46,  /*   55 */
3527  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3528  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3529  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3530  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3531  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3532  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3533  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3534  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
3535  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3536  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3537  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3538  40,  40,  46,  46,  46,  46,  46,  40,  /*   57 */
3539  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3540  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3541  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3542  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
3543  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3544  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3545  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3546  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3547  40,  40,  40,  46,  46,  46,  46,  46,  /*   58 */
3548  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3549  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3550  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
3551  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3552  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3553  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3554  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3555  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3556  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3557  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
3558  40,  40,  46,  46,  46,  46,  46,  46,  /*   59 */
3559  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3560  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3561  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3562  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3563  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3564  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3565  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3566  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
3567  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3568  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3569  23,  24,  23,  24,  23,  24,  16,  16,  /*   61 */
3570  16,  16,  16,  16,  46,  46,  46,  46,  /*   61 */
3571  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3572  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3573  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3574  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
3575  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3576  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3577  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3578  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3579  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3580  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3581  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
3582  23,  24,  46,  46,  46,  46,  46,  46,  /*   62 */
3583  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
3584  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
3585  86,  86,  86,  86,  86,  86,  46,  46,  /*   63 */
3586  87,  87,  87,  87,  87,  87,  46,  46,  /*   63 */
3587  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
3588  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
3589  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
3590  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
3591  86,  86,  86,  86,  86,  86,  46,  46,  /*   64 */
3592  87,  87,  87,  87,  87,  87,  46,  46,  /*   64 */
3593  16,  86,  16,  86,  16,  86,  16,  86,  /*   64 */
3594  46,  87,  46,  87,  46,  87,  46,  87,  /*   64 */
3595  86,  86,  86,  86,  86,  86,  86,  86,  /*   64 */
3596  87,  87,  87,  87,  87,  87,  87,  87,  /*   64 */
3597  88,  88,  89,  89,  89,  89,  90,  90,  /*   64 */
3598  91,  91,  92,  92,  93,  93,  46,  46,  /*   64 */
3599  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
3600  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
3601  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
3602  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
3603  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
3604  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
3605  86,  86,  16,  94,  16,  46,  16,  16,  /*   65 */
3606  87,  87,  95,  95,  96,  11,  38,  11,  /*   65 */
3607  11,  11,  16,  94,  16,  46,  16,  16,  /*   66 */
3608  97,  97,  97,  97,  96,  11,  11,  11,  /*   66 */
3609  86,  86,  16,  16,  46,  46,  16,  16,  /*   66 */
3610  87,  87,  98,  98,  46,  11,  11,  11,  /*   66 */
3611  86,  86,  16,  16,  16,  99,  16,  16,  /*   66 */
3612  87,  87, 100, 100, 101,  11,  11,  11,  /*   66 */
3613  46,  46,  16,  94,  16,  46,  16,  16,  /*   66 */
3614 102, 102, 103, 103,  96,  11,  11,  46,  /*   66 */
3615   2,   2,   2,   2,   2,   2,   2,   2,  /*   67 */
3616   2,   2,   2,   2, 104, 104, 104, 104,  /*   67 */
3617   8,   8,   8,   8,   8,   8,   3,   3,  /*   67 */
3618   5,   6,   5,   5,   5,   6,   5,   5,  /*   67 */
3619   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
3620 105, 106, 104, 104, 104, 104, 104,  46,  /*   67 */
3621   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
3622   3,   5,   6,   3,   3,   3,   3,  12,  /*   67 */
3623  12,   3,   3,   3,   7,   5,   6,  46,  /*   68 */
3624  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
3625  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
3626  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
3627  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
3628  46,  46, 104, 104, 104, 104, 104, 104,  /*   68 */
3629  17,  46,  46,  46,  17,  17,  17,  17,  /*   68 */
3630  17,  17,   7,   7,   7,   5,   6,  16,  /*   68 */
3631 107, 107, 107, 107, 107, 107, 107, 107,  /*   69 */
3632 107, 107,   7,   7,   7,   5,   6,  46,  /*   69 */
3633  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
3634  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
3635   4,   4,   4,   4,   4,   4,   4,   4,  /*   69 */
3636   4,   4,   4,   4,  46,  46,  46,  46,  /*   69 */
3637  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
3638  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
3639  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
3640  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
3641  60,  60,  60,  60,  60,  60,  60,  60,  /*   70 */
3642  60,  60,  60,  60,  60,  79,  79,  79,  /*   70 */
3643  79,  60,  46,  46,  46,  46,  46,  46,  /*   70 */
3644  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
3645  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
3646  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
3647  15,  15,  38,  15,  15,  15,  15,  38,  /*   71 */
3648  15,  15,  16,  38,  38,  38,  16,  16,  /*   71 */
3649  38,  38,  38,  16,  15,  38,  15,  15,  /*   71 */
3650  38,  38,  38,  38,  38,  38,  15,  15,  /*   71 */
3651  15,  15,  15,  15,  38,  15,  38,  15,  /*   71 */
3652  38,  15,  38,  38,  38,  38,  16,  16,  /*   71 */
3653  38,  38,  15,  38,  16,  40,  40,  40,  /*   71 */
3654  40,  46,  46,  46,  46,  46,  46,  46,  /*   71 */
3655  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
3656  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
3657  46,  46,  46,  19,  19,  19,  19,  19,  /*   72 */
3658  19,  19,  19,  19,  19,  19,  19, 108,  /*   72 */
3659 109, 109, 109, 109, 109, 109, 109, 109,  /*   72 */
3660 109, 109, 109, 109, 110, 110, 110, 110,  /*   72 */
3661 111, 111, 111, 111, 111, 111, 111, 111,  /*   72 */
3662 111, 111, 111, 111, 112, 112, 112, 112,  /*   72 */
3663 113, 113, 113,  46,  46,  46,  46,  46,  /*   73 */
3664  46,  46,  46,  46,  46,  46,  46,  46,  /*   73 */
3665   7,   7,   7,   7,   7,  15,  15,  15,  /*   73 */
3666  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
3667  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
3668  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
3669  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
3670  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
3671  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
3672  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
3673  15,  15,   7,  15,   7,  15,  15,  15,  /*   74 */
3674  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
3675  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
3676  15,  15,  15,  46,  46,  46,  46,  46,  /*   74 */
3677  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
3678  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
3679   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3680   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3681   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3682   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3683   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3684   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3685   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3686   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
3687   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3688   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3689   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3690   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3691   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3692   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
3693   7,   7,  46,  46,  46,  46,  46,  46,  /*   76 */
3694  46,  46,  46,  46,  46,  46,  46,  46,  /*   76 */
3695  15,  46,  15,  15,  15,  15,  15,  15,  /*   77 */
3696   7,   7,   7,   7,  15,  15,  15,  15,  /*   77 */
3697  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
3698  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
3699   7,   7,  15,  15,  15,  15,  15,  15,  /*   77 */
3700  15,   5,   6,  15,  15,  15,  15,  15,  /*   77 */
3701  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
3702  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
3703  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3704  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3705  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3706  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3707  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3708  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3709  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
3710  15,  15,  15,  46,  46,  46,  46,  46,  /*   78 */
3711  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
3712  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
3713  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
3714  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
3715  15,  15,  15,  15,  15,  46,  46,  46,  /*   79 */
3716  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
3717  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
3718  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
3719  15,  15,  15,  15,  15,  15,  15,  15,  /*   80 */
3720  15,  15,  15,  46,  46,  46,  46,  46,  /*   80 */
3721  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
3722  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
3723 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
3724 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
3725 114, 114, 114, 114,  82,  82,  82,  82,  /*   80 */
3726  82,  82,  82,  82,  82,  82,  82,  82,  /*   80 */
3727  82,  82,  82,  82,  82,  82,  82,  82,  /*   81 */
3728 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
3729 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
3730 115, 115, 115, 115,  15,  15,  15,  15,  /*   81 */
3731  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
3732  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
3733  15,  15,  15,  15,  15,  15, 116, 116,  /*   81 */
3734 116, 116, 116, 116, 116, 116, 116, 116,  /*   81 */
3735 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
3736 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
3737 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
3738 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
3739 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
3740 117, 117, 118,  46,  46,  46,  46,  46,  /*   82 */
3741  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
3742  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
3743  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3744  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3745  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3746  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3747  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3748  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3749  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3750  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
3751  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3752  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3753  15,  15,  15,  15,  15,  15,  46,  46,  /*   84 */
3754  46,  46,  46,  46,  46,  46,  46,  46,  /*   84 */
3755  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3756  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3757  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3758  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
3759  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3760  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3761  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3762  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3763  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3764  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
3765  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
3766  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
3767  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3768  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3769  15,  15,  15,  15,  46,  46,  46,  46,  /*   86 */
3770  46,  46,  15,  15,  15,  15,  15,  15,  /*   86 */
3771  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3772  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3773  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3774  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
3775  46,  15,  15,  15,  15,  46,  15,  15,  /*   87 */
3776  15,  15,  46,  46,  15,  15,  15,  15,  /*   87 */
3777  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3778  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3779  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3780  46,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3781  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3782  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
3783  15,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
3784  15,  15,  15,  15,  46,  15,  46,  15,  /*   88 */
3785  15,  15,  15,  46,  46,  46,  15,  46,  /*   88 */
3786  15,  15,  15,  15,  15,  15,  15,  46,  /*   88 */
3787  46,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
3788  46,  46,  46,  46,  46,  46,  46,  46,  /*   88 */
3789  46,  46,  46,  46,  46,  46, 119, 119,  /*   88 */
3790 119, 119, 119, 119, 119, 119, 119, 119,  /*   88 */
3791 114, 114, 114, 114, 114, 114, 114, 114,  /*   89 */
3792 114, 114,  83,  83,  83,  83,  83,  83,  /*   89 */
3793  83,  83,  83,  83,  15,  46,  46,  46,  /*   89 */
3794  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
3795  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
3796  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
3797  46,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
3798  15,  15,  15,  15,  15,  15,  15,  46,  /*   89 */
3799   2,   3,   3,   3,  15,  59,   3, 120,  /*   90 */
3800   5,   6,   5,   6,   5,   6,   5,   6,  /*   90 */
3801   5,   6,  15,  15,   5,   6,   5,   6,  /*   90 */
3802   5,   6,   5,   6,   8,   5,   6,   5,  /*   90 */
3803  15, 121, 121, 121, 121, 121, 121, 121,  /*   90 */
3804 121, 121,  60,  60,  60,  60,  60,  60,  /*   90 */
3805   8,  59,  59,  59,  59,  59,  15,  15,  /*   90 */
3806  46,  46,  46,  46,  46,  46,  46,  15,  /*   90 */
3807  46,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3808  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3809  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3810  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3811  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3812  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3813  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3814  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
3815  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3816  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3817  40,  40,  40,  40,  40,  46,  46,  46,  /*   92 */
3818  46,  60,  60,  59,  59,  59,  59,  46,  /*   92 */
3819  46,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3820  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3821  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3822  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
3823  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3824  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3825  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3826  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3827  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3828  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3829  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
3830  40,  40,  40,   3,  59,  59,  59,  46,  /*   93 */
3831  46,  46,  46,  46,  46,  40,  40,  40,  /*   94 */
3832  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3833  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3834  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3835  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3836  40,  40,  40,  40,  40,  46,  46,  46,  /*   94 */
3837  46,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3838  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
3839  40,  40,  40,  40,  40,  40,  40,  40,  /*   95 */
3840  40,  40,  40,  40,  40,  40,  40,  46,  /*   95 */
3841  15,  15,  85,  85,  85,  85,  15,  15,  /*   95 */
3842  15,  15,  15,  15,  15,  15,  15,  15,  /*   95 */
3843  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
3844  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
3845  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
3846  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
3847  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
3848  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
3849  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
3850  15,  15,  15,  15,  15,  46,  46,  46,  /*   96 */
3851  85,  85,  85,  85,  85,  85,  85,  85,  /*   96 */
3852  85,  85,  15,  15,  15,  15,  15,  15,  /*   96 */
3853  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
3854  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
3855  15,  15,  15,  15,  46,  46,  46,  46,  /*   97 */
3856  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
3857  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
3858  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
3859  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
3860  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
3861  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
3862  15,  15,  15,  15,  46,  46,  46,  15,  /*   97 */
3863 114, 114, 114, 114, 114, 114, 114, 114,  /*   98 */
3864 114, 114,  15,  15,  15,  15,  15,  15,  /*   98 */
3865  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
3866  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
3867  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
3868  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
3869  15,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
3870  46,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
3871  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3872  15,  15,  15,  15,  46,  46,  46,  46,  /*   99 */
3873  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3874  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3875  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3876  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3877  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
3878  15,  15,  15,  15,  15,  15,  15,  46,  /*   99 */
3879  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3880  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3881  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3882  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3883  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3884  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
3885  15,  15,  15,  15,  15,  15,  15,  46,  /*  100 */
3886  46,  46,  46,  15,  15,  15,  15,  15,  /*  100 */
3887  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3888  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3889  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3890  15,  15,  15,  15,  15,  15,  46,  46,  /*  101 */
3891  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3892  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3893  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
3894  15,  15,  15,  15,  15,  15,  15,  46,  /*  101 */
3895  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
3896  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
3897  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
3898  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
3899  40,  40,  40,  40,  40,  40,  46,  46,  /*  102 */
3900  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
3901  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
3902  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
3903  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
3904  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
3905  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
3906  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
3907  40,  40,  40,  40,  46,  46,  46,  46,  /*  103 */
3908  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
3909  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
3910  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
3911 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3912 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3913 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3914 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3915 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3916 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3917 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3918 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
3919 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3920 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3921 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3922 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3923 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3924 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3925 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3926 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
3927  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
3928  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
3929  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
3930  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
3931  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
3932  40,  40,  40,  40,  40,  40,  46,  46,  /*  106 */
3933  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
3934  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
3935  16,  16,  16,  16,  16,  16,  16,  46,  /*  107 */
3936  46,  46,  46,  46,  46,  46,  46,  46,  /*  107 */
3937  46,  46,  46,  16,  16,  16,  16,  16,  /*  107 */
3938  46,  46,  46,  46,  46,  46,  60,  40,  /*  107 */
3939  40,  40,  40,  40,  40,  40,  40,  40,  /*  107 */
3940  40,   7,  40,  40,  40,  40,  40,  40,  /*  107 */
3941  40,  40,  40,  40,  40,  40,  40,  46,  /*  107 */
3942  40,  40,  40,  40,  40,  46,  40,  46,  /*  107 */
3943  40,  40,  46,  40,  40,  46,  40,  40,  /*  108 */
3944  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3945  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3946  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3947  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3948  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3949  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3950  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
3951  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3952  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3953  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3954  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3955  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3956  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
3957  40,  40,  46,  46,  46,  46,  46,  46,  /*  109 */
3958  46,  46,  46,  46,  46,  46,  46,  46,  /*  109 */
3959  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
3960  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
3961  46,  46,  46,  40,  40,  40,  40,  40,  /*  110 */
3962  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
3963  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
3964  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
3965  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
3966  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
3967  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3968  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3969  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3970  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3971  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3972  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3973  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
3974  40,  40,  40,  40,  40,  40,   5,   6,  /*  111 */
3975  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
3976  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
3977  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3978  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3979  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3980  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3981  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3982  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
3983  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3984  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3985  46,  46,  40,  40,  40,  40,  40,  40,  /*  113 */
3986  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3987  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3988  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3989  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3990  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
3991  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
3992  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
3993  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
3994  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
3995  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
3996  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
3997  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
3998  40,  40,  40,  40,  46,  46,  46,  46,  /*  114 */
3999  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
4000  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
4001  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
4002  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
4003  60,  60,  60,  60,  46,  46,  46,  46,  /*  115 */
4004  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
4005   3,   8,   8,  12,  12,   5,   6,   5,  /*  115 */
4006   6,   5,   6,   5,   6,   5,   6,   5,  /*  115 */
4007   6,   5,   6,   5,   6,  46,  46,  46,  /*  116 */
4008  46,   3,   3,   3,   3,  12,  12,  12,  /*  116 */
4009   3,   3,   3,  46,   3,   3,   3,   3,  /*  116 */
4010   8,   5,   6,   5,   6,   5,   6,   3,  /*  116 */
4011   3,   3,   7,   8,   7,   7,   7,  46,  /*  116 */
4012   3,   4,   3,   3,  46,  46,  46,  46,  /*  116 */
4013  40,  40,  40,  46,  40,  46,  40,  40,  /*  116 */
4014  40,  40,  40,  40,  40,  40,  40,  40,  /*  116 */
4015  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4016  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4017  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4018  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4019  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4020  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4021  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
4022  40,  40,  40,  40,  40,  46,  46, 104,  /*  117 */
4023  46,   3,   3,   3,   4,   3,   3,   3,  /*  118 */
4024   5,   6,   3,   7,   3,   8,   3,   3,  /*  118 */
4025   9,   9,   9,   9,   9,   9,   9,   9,  /*  118 */
4026   9,   9,   3,   3,   7,   7,   7,   3,  /*  118 */
4027   3,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
4028  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
4029  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
4030  10,  10,  10,   5,   3,   6,  11,  12,  /*  118 */
4031  11,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
4032  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
4033  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
4034  13,  13,  13,   5,   7,   6,   7,  46,  /*  119 */
4035  46,   3,   5,   6,   3,   3,  40,  40,  /*  119 */
4036  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
4037  59,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
4038  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
4039  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4040  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4041  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4042  40,  40,  40,  40,  40,  40,  59,  59,  /*  120 */
4043  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4044  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4045  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
4046  40,  40,  40,  40,  40,  40,  40,  46,  /*  120 */
4047  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
4048  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
4049  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
4050  46,  46,  40,  40,  40,  46,  46,  46,  /*  121 */
4051   4,   4,   7,  11,  15,   4,   4,  46,  /*  121 */
4052   7,   7,   7,   7,   7,  15,  15,  46,  /*  121 */
4053  46,  46,  46,  46,  46,  46,  46,  46,  /*  121 */
4054  46,  46,  46,  46,  46,  15,  46,  46   /*  121 */
4055 };
4056 
4057 /* The A table has 124 entries for a total of 496 bytes. */
4058 
4059 const uint32 js_A[] = {
4060 0x0001000F,  /*    0   Cc, ignorable */
4061 0x0004000F,  /*    1   Cc, whitespace */
4062 0x0004000C,  /*    2   Zs, whitespace */
4063 0x00000018,  /*    3   Po */
4064 0x0006001A,  /*    4   Sc, currency */
4065 0x00000015,  /*    5   Ps */
4066 0x00000016,  /*    6   Pe */
4067 0x00000019,  /*    7   Sm */
4068 0x00000014,  /*    8   Pd */
4069 0x00036009,  /*    9   Nd, identifier part, decimal 16 */
4070 0x0827FE01,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
4071 0x0000001B,  /*   11   Sk */
4072 0x00050017,  /*   12   Pc, underscore */
4073 0x0817FE02,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
4074 0x0000000C,  /*   14   Zs */
4075 0x0000001C,  /*   15   So */
4076 0x00070002,  /*   16   Ll, identifier start */
4077 0x0000600B,  /*   17   No, decimal 16 */
4078 0x0000500B,  /*   18   No, decimal 8 */
4079 0x0000800B,  /*   19   No, strange */
4080 0x08270001,  /*   20   Lu, hasLower (add 32), identifier start */
4081 0x08170002,  /*   21   Ll, hasUpper (subtract 32), identifier start */
4082 0xE1D70002,  /*   22   Ll, hasUpper (subtract -121), identifier start */
4083 0x00670001,  /*   23   Lu, hasLower (add 1), identifier start */
4084 0x00570002,  /*   24   Ll, hasUpper (subtract 1), identifier start */
4085 0xCE670001,  /*   25   Lu, hasLower (add -199), identifier start */
4086 0x3A170002,  /*   26   Ll, hasUpper (subtract 232), identifier start */
4087 0xE1E70001,  /*   27   Lu, hasLower (add -121), identifier start */
4088 0x4B170002,  /*   28   Ll, hasUpper (subtract 300), identifier start */
4089 0x34A70001,  /*   29   Lu, hasLower (add 210), identifier start */
4090 0x33A70001,  /*   30   Lu, hasLower (add 206), identifier start */
4091 0x33670001,  /*   31   Lu, hasLower (add 205), identifier start */
4092 0x32A70001,  /*   32   Lu, hasLower (add 202), identifier start */
4093 0x32E70001,  /*   33   Lu, hasLower (add 203), identifier start */
4094 0x33E70001,  /*   34   Lu, hasLower (add 207), identifier start */
4095 0x34E70001,  /*   35   Lu, hasLower (add 211), identifier start */
4096 0x34670001,  /*   36   Lu, hasLower (add 209), identifier start */
4097 0x35670001,  /*   37   Lu, hasLower (add 213), identifier start */
4098 0x00070001,  /*   38   Lu, identifier start */
4099 0x36A70001,  /*   39   Lu, hasLower (add 218), identifier start */
4100 0x00070005,  /*   40   Lo, identifier start */
4101 0x36670001,  /*   41   Lu, hasLower (add 217), identifier start */
4102 0x36E70001,  /*   42   Lu, hasLower (add 219), identifier start */
4103 0x00AF0001,  /*   43   Lu, hasLower (add 2), hasTitle, identifier start */
4104 0x007F0003,  /*   44   Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
4105 0x009F0002,  /*   45   Ll, hasUpper (subtract 2), hasTitle, identifier start */
4106 0x00000000,  /*   46   unassigned */
4107 0x34970002,  /*   47   Ll, hasUpper (subtract 210), identifier start */
4108 0x33970002,  /*   48   Ll, hasUpper (subtract 206), identifier start */
4109 0x33570002,  /*   49   Ll, hasUpper (subtract 205), identifier start */
4110 0x32970002,  /*   50   Ll, hasUpper (subtract 202), identifier start */
4111 0x32D70002,  /*   51   Ll, hasUpper (subtract 203), identifier start */
4112 0x33D70002,  /*   52   Ll, hasUpper (subtract 207), identifier start */
4113 0x34570002,  /*   53   Ll, hasUpper (subtract 209), identifier start */
4114 0x34D70002,  /*   54   Ll, hasUpper (subtract 211), identifier start */
4115 0x35570002,  /*   55   Ll, hasUpper (subtract 213), identifier start */
4116 0x36970002,  /*   56   Ll, hasUpper (subtract 218), identifier start */
4117 0x36570002,  /*   57   Ll, hasUpper (subtract 217), identifier start */
4118 0x36D70002,  /*   58   Ll, hasUpper (subtract 219), identifier start */
4119 0x00070004,  /*   59   Lm, identifier start */
4120 0x00030006,  /*   60   Mn, identifier part */
4121 0x09A70001,  /*   61   Lu, hasLower (add 38), identifier start */
4122 0x09670001,  /*   62   Lu, hasLower (add 37), identifier start */
4123 0x10270001,  /*   63   Lu, hasLower (add 64), identifier start */
4124 0x0FE70001,  /*   64   Lu, hasLower (add 63), identifier start */
4125 0x09970002,  /*   65   Ll, hasUpper (subtract 38), identifier start */
4126 0x09570002,  /*   66   Ll, hasUpper (subtract 37), identifier start */
4127 0x10170002,  /*   67   Ll, hasUpper (subtract 64), identifier start */
4128 0x0FD70002,  /*   68   Ll, hasUpper (subtract 63), identifier start */
4129 0x0F970002,  /*   69   Ll, hasUpper (subtract 62), identifier start */
4130 0x0E570002,  /*   70   Ll, hasUpper (subtract 57), identifier start */
4131 0x0BD70002,  /*   71   Ll, hasUpper (subtract 47), identifier start */
4132 0x0D970002,  /*   72   Ll, hasUpper (subtract 54), identifier start */
4133 0x15970002,  /*   73   Ll, hasUpper (subtract 86), identifier start */
4134 0x14170002,  /*   74   Ll, hasUpper (subtract 80), identifier start */
4135 0x14270001,  /*   75   Lu, hasLower (add 80), identifier start */
4136 0x0C270001,  /*   76   Lu, hasLower (add 48), identifier start */
4137 0x0C170002,  /*   77   Ll, hasUpper (subtract 48), identifier start */
4138 0x00034009,  /*   78   Nd, identifier part, decimal 0 */
4139 0x00000007,  /*   79   Me */
4140 0x00030008,  /*   80   Mc, identifier part */
4141 0x00037409,  /*   81   Nd, identifier part, decimal 26 */
4142 0x00005A0B,  /*   82   No, decimal 13 */
4143 0x00006E0B,  /*   83   No, decimal 23 */
4144 0x0000740B,  /*   84   No, decimal 26 */
4145 0x0000000B,  /*   85   No */
4146 0xFE170002,  /*   86   Ll, hasUpper (subtract -8), identifier start */
4147 0xFE270001,  /*   87   Lu, hasLower (add -8), identifier start */
4148 0xED970002,  /*   88   Ll, hasUpper (subtract -74), identifier start */
4149 0xEA970002,  /*   89   Ll, hasUpper (subtract -86), identifier start */
4150 0xE7170002,  /*   90   Ll, hasUpper (subtract -100), identifier start */
4151 0xE0170002,  /*   91   Ll, hasUpper (subtract -128), identifier start */
4152 0xE4170002,  /*   92   Ll, hasUpper (subtract -112), identifier start */
4153 0xE0970002,  /*   93   Ll, hasUpper (subtract -126), identifier start */
4154 0xFDD70002,  /*   94   Ll, hasUpper (subtract -9), identifier start */
4155 0xEDA70001,  /*   95   Lu, hasLower (add -74), identifier start */
4156 0xFDE70001,  /*   96   Lu, hasLower (add -9), identifier start */
4157 0xEAA70001,  /*   97   Lu, hasLower (add -86), identifier start */
4158 0xE7270001,  /*   98   Lu, hasLower (add -100), identifier start */
4159 0xFE570002,  /*   99   Ll, hasUpper (subtract -7), identifier start */
4160 0xE4270001,  /*  100   Lu, hasLower (add -112), identifier start */
4161 0xFE670001,  /*  101   Lu, hasLower (add -7), identifier start */
4162 0xE0270001,  /*  102   Lu, hasLower (add -128), identifier start */
4163 0xE0A70001,  /*  103   Lu, hasLower (add -126), identifier start */
4164 0x00010010,  /*  104   Cf, ignorable */
4165 0x0004000D,  /*  105   Zl, whitespace */
4166 0x0004000E,  /*  106   Zp, whitespace */
4167 0x0000400B,  /*  107   No, decimal 0 */
4168 0x0000440B,  /*  108   No, decimal 2 */
4169 0x0427420A,  /*  109   Nl, hasLower (add 16), identifier start, decimal 1 */
4170 0x0427800A,  /*  110   Nl, hasLower (add 16), identifier start, strange */
4171 0x0417620A,  /*  111   Nl, hasUpper (subtract 16), identifier start, decimal 17 */
4172 0x0417800A,  /*  112   Nl, hasUpper (subtract 16), identifier start, strange */
4173 0x0007800A,  /*  113   Nl, identifier start, strange */
4174 0x0000420B,  /*  114   No, decimal 1 */
4175 0x0000720B,  /*  115   No, decimal 25 */
4176 0x06A0001C,  /*  116   So, hasLower (add 26) */
4177 0x0690001C,  /*  117   So, hasUpper (subtract 26) */
4178 0x00006C0B,  /*  118   No, decimal 22 */
4179 0x0000560B,  /*  119   No, decimal 11 */
4180 0x0007720A,  /*  120   Nl, identifier start, decimal 25 */
4181 0x0007400A,  /*  121   Nl, identifier start, decimal 0 */
4182 0x00000013,  /*  122   Cs */
4183 0x00000012   /*  123   Co */
4184 };
4185 
4186 const jschar js_uriReservedPlusPound_ucstr[] =
4187     {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
4188 const jschar js_uriUnescaped_ucstr[] =
4189     {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
4190      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
4191      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
4192      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
4193      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
4194      '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
4195 
4196 #define URI_CHUNK 64U
4197 
4198 /* Concatenate jschars onto an unshared/newborn JSString. */
4199 static JSBool
AddCharsToURI(JSContext * cx,JSString * str,const jschar * chars,size_t length)4200 AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
4201 {
4202     size_t total;
4203 
4204     JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
4205     total = str->length + length + 1;
4206     if (!str->chars ||
4207         JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
4208         total = JS_ROUNDUP(total, URI_CHUNK);
4209         str->chars = JS_realloc(cx, str->chars, total * sizeof(jschar));
4210         if (!str->chars)
4211             return JS_FALSE;
4212     }
4213     js_strncpy(str->chars + str->length, chars, length);
4214     str->length += length;
4215     str->chars[str->length] = 0;
4216     return JS_TRUE;
4217 }
4218 
4219 /*
4220  * ECMA 3, 15.1.3 URI Handling Function Properties
4221  *
4222  * The following are implementations of the algorithms
4223  * given in the ECMA specification for the hidden functions
4224  * 'Encode' and 'Decode'.
4225  */
4226 static JSBool
Encode(JSContext * cx,JSString * str,const jschar * unescapedSet,const jschar * unescapedSet2,jsval * rval)4227 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
4228        const jschar *unescapedSet2, jsval *rval)
4229 {
4230     size_t length, j, k, L;
4231     jschar *chars, C, C2;
4232     uint32 V;
4233     uint8 utf8buf[6];
4234     jschar hexBuf[4];
4235     static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
4236     JSString *R;
4237 
4238     R = js_NewString(cx, NULL, 0, 0);
4239     if (!R)
4240         return JS_FALSE;
4241 
4242     hexBuf[0] = '%';
4243     hexBuf[3] = 0;
4244     chars = JSSTRING_CHARS(str);
4245     length = JSSTRING_LENGTH(str);
4246     for (k = 0; k < length; k++) {
4247         C = chars[k];
4248         if (js_strchr(unescapedSet, C) ||
4249             (unescapedSet2 && js_strchr(unescapedSet2, C))) {
4250             if (!AddCharsToURI(cx, R, &C, 1))
4251                 return JS_FALSE;
4252         } else {
4253             if ((C >= 0xDC00) && (C <= 0xDFFF)) {
4254                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4255                                  JSMSG_BAD_URI, NULL);
4256                 return JS_FALSE;
4257             }
4258             if (C < 0xD800 || C > 0xDBFF) {
4259                 V = C;
4260             } else {
4261                 k++;
4262                 if (k == length) {
4263                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4264                                      JSMSG_BAD_URI, NULL);
4265                     return JS_FALSE;
4266                 }
4267                 C2 = chars[k];
4268                 if ((C2 < 0xDC00) || (C2 > 0xDFFF)) {
4269                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4270                                      JSMSG_BAD_URI, NULL);
4271                     return JS_FALSE;
4272                 }
4273                 V = ((C - 0xD800) << 10) + (C2 - 0xDC00) + 0x10000;
4274             }
4275             L = OneUcs4ToUtf8Char(utf8buf, V);
4276             for (j = 0; j < L; j++) {
4277                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
4278                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
4279                 if (!AddCharsToURI(cx, R, hexBuf, 3))
4280                     return JS_FALSE;
4281             }
4282         }
4283     }
4284 
4285     /*
4286      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
4287      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
4288      * more jschars than it needs.
4289      */
4290     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
4291     if (chars)
4292         R->chars = chars;
4293     *rval = STRING_TO_JSVAL(R);
4294     return JS_TRUE;
4295 }
4296 
4297 static JSBool
Decode(JSContext * cx,JSString * str,const jschar * reservedSet,jsval * rval)4298 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
4299 {
4300     size_t length, start, k;
4301     jschar *chars, C, H;
4302     uint32 V;
4303     jsuint B;
4304     uint8 octets[6];
4305     JSString *R;
4306     intN j, n;
4307 
4308     R = js_NewString(cx, NULL, 0, 0);
4309     if (!R)
4310         return JS_FALSE;
4311 
4312     chars = JSSTRING_CHARS(str);
4313     length = JSSTRING_LENGTH(str);
4314     for (k = 0; k < length; k++) {
4315         C = chars[k];
4316         if (C == '%') {
4317             start = k;
4318             if ((k + 2) >= length)
4319                 goto bad;
4320             if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
4321                 goto bad;
4322             B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
4323             k += 2;
4324             if (!(B & 0x80)) {
4325                 C = (jschar)B;
4326             } else {
4327                 n = 1;
4328                 while (B & (0x80 >> n))
4329                     n++;
4330                 if (n == 1 || n > 6)
4331                     goto bad;
4332                 octets[0] = (uint8)B;
4333                 if (k + 3 * (n - 1) >= length)
4334                     goto bad;
4335                 for (j = 1; j < n; j++) {
4336                     k++;
4337                     if (chars[k] != '%')
4338                         goto bad;
4339                     if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
4340                         goto bad;
4341                     B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
4342                     if ((B & 0xC0) != 0x80)
4343                         goto bad;
4344                     k += 2;
4345                     octets[j] = (char)B;
4346                 }
4347                 V = Utf8ToOneUcs4Char(octets, n);
4348                 if (V >= 0x10000) {
4349                     V -= 0x10000;
4350                     if (V > 0xFFFFF)
4351                         goto bad;
4352                     C = (jschar)((V & 0x3FF) + 0xDC00);
4353                     H = (jschar)((V >> 10) + 0xD800);
4354                     if (!AddCharsToURI(cx, R, &H, 1))
4355                         return JS_FALSE;
4356                 } else {
4357                     C = (jschar)V;
4358                 }
4359             }
4360             if (js_strchr(reservedSet, C)) {
4361                 if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
4362                     return JS_FALSE;
4363             } else {
4364                 if (!AddCharsToURI(cx, R, &C, 1))
4365                     return JS_FALSE;
4366             }
4367         } else {
4368             if (!AddCharsToURI(cx, R, &C, 1))
4369                 return JS_FALSE;
4370         }
4371     }
4372 
4373     /*
4374      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
4375      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
4376      * more jschars than it needs.
4377      */
4378     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
4379     if (chars)
4380         R->chars = chars;
4381     *rval = STRING_TO_JSVAL(R);
4382     return JS_TRUE;
4383 
4384 bad:
4385     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
4386     return JS_FALSE;
4387 }
4388 
4389 static JSBool
str_decodeURI(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)4390 str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4391               jsval *rval)
4392 {
4393     JSString *str;
4394 
4395     str = js_ValueToString(cx, argv[0]);
4396     if (!str)
4397         return JS_FALSE;
4398     return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval);
4399 }
4400 
4401 static JSBool
str_decodeURI_Component(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)4402 str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4403                         jsval *rval)
4404 {
4405     JSString *str;
4406 
4407     str = js_ValueToString(cx, argv[0]);
4408     if (!str)
4409         return JS_FALSE;
4410     return Decode(cx, str, js_empty_ucstr, rval);
4411 }
4412 
4413 static JSBool
str_encodeURI(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)4414 str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4415               jsval *rval)
4416 {
4417     JSString *str;
4418 
4419     str = js_ValueToString(cx, argv[0]);
4420     if (!str)
4421         return JS_FALSE;
4422     return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
4423                   rval);
4424 }
4425 
4426 static JSBool
str_encodeURI_Component(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)4427 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4428                         jsval *rval)
4429 {
4430     JSString *str;
4431 
4432     str = js_ValueToString(cx, argv[0]);
4433     if (!str)
4434         return JS_FALSE;
4435     return Encode(cx, str, js_uriUnescaped_ucstr, NULL, rval);
4436 }
4437 
4438 /*
4439  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
4440  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
4441  */
4442 static int
OneUcs4ToUtf8Char(uint8 * utf8Buffer,uint32 ucs4Char)4443 OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
4444 {
4445     int utf8Length = 1;
4446 
4447     JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
4448     if (ucs4Char < 0x80) {
4449         *utf8Buffer = (uint8)ucs4Char;
4450     } else {
4451         int i;
4452         uint32 a = ucs4Char >> 11;
4453         utf8Length = 2;
4454         while (a) {
4455             a >>= 5;
4456             utf8Length++;
4457         }
4458         i = utf8Length;
4459         while (--i) {
4460             utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
4461             ucs4Char >>= 6;
4462         }
4463         *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
4464     }
4465     return utf8Length;
4466 }
4467 
4468 /*
4469  * Convert a utf8 character sequence into a UCS-4 character and return that
4470  * character.  It is assumed that the caller already checked that the sequence
4471  * is valid.
4472  */
4473 static uint32
Utf8ToOneUcs4Char(const uint8 * utf8Buffer,int utf8Length)4474 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
4475 {
4476     uint32 ucs4Char;
4477     uint32 minucs4Char;
4478     /* from Unicode 3.1, non-shortest form is illegal */
4479     static const uint32 minucs4Table[] = {
4480         0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
4481     };
4482 
4483     JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
4484     if (utf8Length == 1) {
4485         ucs4Char = *utf8Buffer;
4486         JS_ASSERT(!(ucs4Char & 0x80));
4487     } else {
4488         JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
4489                   (0x100 - (1 << (8-utf8Length))));
4490         ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
4491         minucs4Char = minucs4Table[utf8Length-2];
4492         while (--utf8Length) {
4493             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
4494             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
4495         }
4496         if (ucs4Char < minucs4Char ||
4497             ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
4498             ucs4Char = 0xFFFD;
4499         }
4500     }
4501     return ucs4Char;
4502 }
4503