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
79 js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
80 690 {
81 690     JSString *base;
82 690     size_t start, length;
83
84 690     JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
85 690     base = JSSTRDEP_BASE(str);
86 690     start = JSSTRDEP_START(str);
87 690     if (JSSTRING_IS_DEPENDENT(base)) {
88 388         if (level < JSSTRDEP_RECURSION_LIMIT) {
89 388             start += js_MinimizeDependentStrings(base, level + 1, &base);
90         } else {
91 0             do {
92 0                 start += JSSTRDEP_START(base);
93 0                 base = JSSTRDEP_BASE(base);
94 0             } while (JSSTRING_IS_DEPENDENT(base));
95         }
96 388         if (start == 0) {
97 108             JS_ASSERT(JSSTRING_IS_PREFIX(str));
98 108             JSPREFIX_SET_BASE(str, base);
99 280         } else if (start <= JSSTRDEP_START_MASK) {
100 280             length = JSSTRDEP_LENGTH(str);
101 280             JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
102 280             JSSTRDEP_SET_BASE(str, base);
103         }
104     }
105 690     *basep = base;
106 690     return start;
107 }
108
109 jschar *
110 js_GetDependentStringChars(JSString *str)
111 302 {
112 302     size_t start;
113 302     JSString *base;
114
115 302     start = js_MinimizeDependentStrings(str, 0, &base);
116 302     JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
117 302     JS_ASSERT(start < base->length);
118 302     return base->chars + start;
119 }
120
121 jschar *
122 js_GetStringChars(JSString *str)
123 0 {
124 0     if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(NULL, str))
125 0         return NULL;
126
127 0     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
128 0     return str->chars;
129 }
130
131 JSString *
132 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
133 56698 {
134 56698     size_t rn, ln, lrdist, n;
135 56698     jschar *rs, *ls, *s;
136 56698     JSDependentString *ldep;    /* non-null if left should become dependent */
137 56698     JSString *str;
138
139 56698     if (JSSTRING_IS_DEPENDENT(right)) {
140 51         rn = JSSTRDEP_LENGTH(right);
141 51         rs = JSSTRDEP_CHARS(right);
142     } else {
143 56647         rn = right->length;
144 56647         rs = right->chars;
145     }
146 56698     if (rn == 0)
147 565         return left;
148
149 56133     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 37209         ln = JSSTRING_LENGTH(left);
153 37209         if (ln == 0)
154 198             return right;
155 37011         ls = JSSTRING_CHARS(left);
156 37011         s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
157 37011         if (!s)
158 0             return NULL;
159 37011         js_strncpy(s, ls, ln);
160 37011         ldep = NULL;
161     } else {
162         /* We can realloc left's space and make it depend on our result. */
163 18924         ln = left->length;
164 18924         if (ln == 0)
165 0             return right;
166 18924         ls = left->chars;
167 18924         s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
168 18924         if (!s)
169 0             return NULL;
170  
171         /* Take care: right could depend on left! */
172 18924         lrdist = (size_t)(rs - ls);
173 18924         if (lrdist < ln)
174 0             rs = s + lrdist;
175 18924         left->chars = ls = s;
176 18924         ldep = JSSTRDEP(left);
177     }
178
179 55935     js_strncpy(s + ln, rs, rn);
180 55935     n = ln + rn;
181 55935     s[n] = 0;
182 55935     str = js_NewString(cx, s, n, GCF_MUTABLE);
183 55935     if (!str) {
184         /* Out of memory: clean up any space we (re-)allocated. */
185 0         if (!ldep) {
186 0             JS_free(cx, s);
187         } else {
188 0             s = JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
189 0             if (s)
190 0                 left->chars = s;
191         }
192     } else {
193         /* Morph left into a dependent prefix if we realloc'd its buffer. */
194 55935         if (ldep) {
195 18924             JSPREFIX_SET_LENGTH(ldep, ln);
196 18924             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 55935     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 *
218 js_UndependString(JSContext *cx, JSString *str)
219 4207 {
220 4207     size_t n, size;
221 4207     jschar *s;
222
223 4207     if (JSSTRING_IS_DEPENDENT(str)) {
224 86         n = JSSTRDEP_LENGTH(str);
225 86         size = (n + 1) * sizeof(jschar);
226 86         s = (jschar *) (cx ? JS_malloc(cx, size) : malloc(size));
227 86         if (!s)
228 0             return NULL;
229
230 86         js_strncpy(s, JSSTRDEP_CHARS(str), n);
231 86         s[n] = 0;
232 86         str->length = n;
233 86         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 4207     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
316 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
317 0 {
318 0     JSString *str;
319 0     size_t i, ni, length, newlength;
320 0     const jschar *chars;
321 0     jschar *newchars;
322 0     jschar ch;
323 0     jsint mask;
324 0     jsdouble d;
325 0     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
326 0                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
327
328 0     mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
329 0     if (argc > 1) {
330 0         if (!js_ValueToNumber(cx, argv[1], &d))
331 0             return JS_FALSE;
332 0         if (!JSDOUBLE_IS_FINITE(d) ||
333             (mask = (jsint)d) != d ||
334             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
335         {
336 0             char numBuf[12];
337 0             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
338 0             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
339                                  JSMSG_BAD_STRING_MASK, numBuf);
340 0             return JS_FALSE;
341         }
342     }
343
344 0     str = js_ValueToString(cx, argv[0]);
345 0     if (!str)
346 0         return JS_FALSE;
347 0     argv[0] = STRING_TO_JSVAL(str);
348
349 0     chars = JSSTRING_CHARS(str);
350 0     length = newlength = JSSTRING_LENGTH(str);
351
352     /* Take a first pass and see how big the result string will need to be. */
353 0     for (i = 0; i < length; i++) {
354 0         if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
355 0             continue;
356 0         if (ch < 256) {
357 0             if (mask == URL_XPALPHAS && ch == ' ')
358 0                 continue;   /* The character will be encoded as '+' */
359 0             newlength += 2; /* The character will be encoded as %XX */
360         } else {
361 0             newlength += 5; /* The character will be encoded as %uXXXX */
362         }
363     }
364
365 0     newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
366 0     if (!newchars)
367 0         return JS_FALSE;
368 0     for (i = 0, ni = 0; i < length; i++) {
369 0         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
370 0             newchars[ni++] = ch;
371 0         } else if (ch < 256) {
372 0             if (mask == URL_XPALPHAS && ch == ' ') {
373 0                 newchars[ni++] = '+'; /* convert spaces to pluses */
374             } else {
375 0                 newchars[ni++] = '%';
376 0                 newchars[ni++] = digits[ch >> 4];
377 0                 newchars[ni++] = digits[ch & 0xF];
378             }
379         } else {
380 0             newchars[ni++] = '%';
381 0             newchars[ni++] = 'u';
382 0             newchars[ni++] = digits[ch >> 12];
383 0             newchars[ni++] = digits[(ch & 0xF00) >> 8];
384 0             newchars[ni++] = digits[(ch & 0xF0) >> 4];
385 0             newchars[ni++] = digits[ch & 0xF];
386         }
387     }
388 0     JS_ASSERT(ni == newlength);
389 0     newchars[newlength] = 0;
390
391 0     str = js_NewString(cx, newchars, newlength, 0);
392 0     if (!str) {
393 0         JS_free(cx, newchars);
394 0         return JS_FALSE;
395     }
396 0     *rval = STRING_TO_JSVAL(str);
397 0     return JS_TRUE;
398 }
399 #undef IS_OK
400
401 /* See ECMA-262 15.1.2.5 */
402 static JSBool
403 str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
404 0 {
405 0     JSString *str;
406 0     size_t i, ni, length;
407 0     const jschar *chars;
408 0     jschar *newchars;
409 0     jschar ch;
410
411 0     str = js_ValueToString(cx, argv[0]);
412 0     if (!str)
413 0         return JS_FALSE;
414 0     argv[0] = STRING_TO_JSVAL(str);
415
416 0     chars = JSSTRING_CHARS(str);
417 0     length = JSSTRING_LENGTH(str);
418
419     /* Don't bother allocating less space for the new string. */
420 0     newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
421 0     if (!newchars)
422 0         return JS_FALSE;
423 0     ni = i = 0;
424 0     while (i < length) {
425 0         ch = chars[i++];
426 0         if (ch == '%') {
427 0             if (i + 1 < length &&
428                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
429             {
430 0                 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
431 0                 i += 2;
432 0             } 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 0                 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 0                 i += 5;
441             }
442         }
443 0         newchars[ni++] = ch;
444     }
445 0     newchars[ni] = 0;
446
447 0     str = js_NewString(cx, newchars, ni, 0);
448 0     if (!str) {
449 0         JS_free(cx, newchars);
450 0         return JS_FALSE;
451     }
452 0     *rval = STRING_TO_JSVAL(str);
453 0     return JS_TRUE;
454 }
455
456 #if JS_HAS_UNEVAL
457 static JSBool
458 str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
459 0 {
460 0     JSString *str;
461
462 0     str = js_ValueToSource(cx, argv[0]);
463 0     if (!str)
464 0         return JS_FALSE;
465 0     *rval = STRING_TO_JSVAL(str);
466 0     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
508 str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
509 141879 {
510 141879     JSString *str;
511 141879     jsint slot;
512
513 141879     if (!JSVAL_IS_INT(id))
514 141537         return JS_TRUE;
515 342     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
516 342     if (!str)
517 0         return JS_FALSE;
518 342     slot = JSVAL_TO_INT(id);
519 342     if (slot == STRING_LENGTH)
520 84         *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
521 342     return JS_TRUE;
522 }
523
524 #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
525
526 static JSBool
527 str_enumerate(JSContext *cx, JSObject *obj)
528 0 {
529 0     JSString *str, *str1;
530 0     size_t i, length;
531
532 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
533 0     if (!str)
534 0         return JS_FALSE;
535 0     length = JSSTRING_LENGTH(str);
536 0     for (i = 0; i < length; i++) {
537 0         str1 = js_NewDependentString(cx, str, i, 1, 0);
538 0         if (!str1)
539 0             return JS_FALSE;
540 0         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(i),
541                                  STRING_TO_JSVAL(str1), NULL, NULL,
542                                  STRING_ELEMENT_ATTRS, NULL)) {
543 0             return JS_FALSE;
544         }
545     }
546 0     return JS_TRUE;
547 }
548
549 static JSBool
550 str_resolve(JSContext *cx, JSObject *obj, jsval id)
551 94672 {
552 94672     JSString *str, *str1;
553 94672     jsint slot;
554
555 94672     if (!JSVAL_IS_INT(id))
556 94414         return JS_TRUE;
557
558 258     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
559 258     if (!str)
560 0         return JS_FALSE;
561 258     slot = JSVAL_TO_INT(id);
562 258     if ((size_t)slot < JSSTRING_LENGTH(str)) {
563 258         str1 = js_NewDependentString(cx, str, (size_t)slot, 1, 0);
564 258         if (!str1)
565 0             return JS_FALSE;
566 258         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(slot),
567                                  STRING_TO_JSVAL(str1), NULL, NULL,
568                                  STRING_ELEMENT_ATTRS, NULL)) {
569 0             return JS_FALSE;
570         }
571     }
572 258     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
590 str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
591 0 {
592 0     JSString *str;
593
594 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
595 0     if (!str)
596 0         return JS_FALSE;
597 0     str = js_QuoteString(cx, str, '"');
598 0     if (!str)
599 0         return JS_FALSE;
600 0     *rval = STRING_TO_JSVAL(str);
601 0     return JS_TRUE;
602 }
603
604 static JSBool
605 str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
606 0 {
607 0     jsval v;
608 0     JSString *str;
609 0     size_t i, j, k, n;
610 0     char buf[16];
611 0     jschar *s, *t;
612
613 0     if (!JS_InstanceOf(cx, obj, &string_class, argv))
614 0         return JS_FALSE;
615 0     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
616 0     if (!JSVAL_IS_STRING(v))
617 0         return js_obj_toSource(cx, obj, argc, argv, rval);
618 0     str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
619 0     if (!str)
620 0         return JS_FALSE;
621 0     j = JS_snprintf(buf, sizeof buf, "(new %s(", string_class.name);
622 0     s = JSSTRING_CHARS(str);
623 0     k = JSSTRING_LENGTH(str);
624 0     n = j + k + 2;
625 0     t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
626 0     if (!t)
627 0         return JS_FALSE;
628 0     for (i = 0; i < j; i++)
629 0         t[i] = buf[i];
630 0     for (j = 0; j < k; i++, j++)
631 0         t[i] = s[j];
632 0     t[i++] = ')';
633 0     t[i++] = ')';
634 0     t[i] = 0;
635 0     str = js_NewString(cx, t, n, 0);
636 0     if (!str) {
637 0         JS_free(cx, t);
638 0         return JS_FALSE;
639     }
640 0     *rval = STRING_TO_JSVAL(str);
641 0     return JS_TRUE;
642 }
643
644 #endif /* JS_HAS_TOSOURCE */
645
646 static JSBool
647 str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
648 47465 {
649 47465     jsval v;
650
651 47465     if (!JS_InstanceOf(cx, obj, &string_class, argv))
652 0         return JS_FALSE;
653 47465     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
654 47465     if (!JSVAL_IS_STRING(v))
655 0         return js_obj_toString(cx, obj, argc, argv, rval);
656 47465     *rval = v;
657 47465     return JS_TRUE;
658 }
659
660 static JSBool
661 str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
662 0 {
663 0     if (!JS_InstanceOf(cx, obj, &string_class, argv))
664 0         return JS_FALSE;
665 0     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
666 0     return JS_TRUE;
667 }
668
669 /*
670  * Java-like string native methods.
671  */
672 static JSBool
673 str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
674               jsval *rval)
675 0 {
676 0     JSString *str;
677 0     jsdouble d;
678 0     jsdouble length, begin, end;
679
680 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
681 0     if (!str)
682 0         return JS_FALSE;
683 0     argv[-1] = STRING_TO_JSVAL(str);
684
685 0     if (argc != 0) {
686 0         if (!js_ValueToNumber(cx, argv[0], &d))
687 0             return JS_FALSE;
688 0         length = JSSTRING_LENGTH(str);
689 0         begin = js_DoubleToInteger(d);
690 0         if (begin < 0)
691 0             begin = 0;
692 0         else if (begin > length)
693 0             begin = length;
694
695 0         if (argc == 1) {
696 0             end = length;
697         } else {
698 0             if (!js_ValueToNumber(cx, argv[1], &d))
699 0                 return JS_FALSE;
700 0             end = js_DoubleToInteger(d);
701 0             if (end < 0)
702 0                 end = 0;
703 0             else if (end > length)
704 0                 end = length;
705 0             if (end < begin) {
706 0                 if (cx->version != JSVERSION_1_2) {
707                     /* XXX emulate old JDK1.0 java.lang.String.substring. */
708 0                     jsdouble tmp = begin;
709 0                     begin = end;
710 0                     end = tmp;
711                 } else {
712 0                     end = begin;
713                 }
714             }
715         }
716
717 0         str = js_NewDependentString(cx, str, (size_t)begin,
718                                     (size_t)(end - begin), 0);
719 0         if (!str)
720 0             return JS_FALSE;
721     }
722 0     *rval = STRING_TO_JSVAL(str);
723 0     return JS_TRUE;
724 }
725
726 static JSBool
727 str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
728                 jsval *rval)
729 0 {
730 0     JSString *str;
731 0     size_t i, n;
732 0     jschar *s, *news;
733
734 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
735 0     if (!str)
736 0         return JS_FALSE;
737 0     n = JSSTRING_LENGTH(str);
738 0     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
739 0     if (!news)
740 0         return JS_FALSE;
741 0     s = JSSTRING_CHARS(str);
742 0     for (i = 0; i < n; i++)
743 0         news[i] = JS_TOLOWER(s[i]);
744 0     news[n] = 0;
745 0     str = js_NewString(cx, news, n, 0);
746 0     if (!str) {
747 0         JS_free(cx, news);
748 0         return JS_FALSE;
749     }
750 0     *rval = STRING_TO_JSVAL(str);
751 0     return JS_TRUE;
752 }
753
754 static JSBool
755 str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
756                 jsval *rval)
757 0 {
758 0     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 0     if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
765 0         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
766 0         if (!str)
767 0             return JS_FALSE;
768 0         return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
769     }
770 0     return str_toLowerCase(cx, obj, 0, argv, rval);
771 }
772
773 static JSBool
774 str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
775                 jsval *rval)
776 4480 {
777 4480     JSString *str;
778 4480     size_t i, n;
779 4480     jschar *s, *news;
780
781 4480     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
782 4480     if (!str)
783 0         return JS_FALSE;
784 4480     n = JSSTRING_LENGTH(str);
785 4480     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
786 4480     if (!news)
787 0         return JS_FALSE;
788 4480     s = JSSTRING_CHARS(str);
789 122281     for (i = 0; i < n; i++)
790 117801         news[i] = JS_TOUPPER(s[i]);
791 4480     news[n] = 0;
792 4480     str = js_NewString(cx, news, n, 0);
793 4480     if (!str) {
794 0         JS_free(cx, news);
795 0         return JS_FALSE;
796     }
797 4480     *rval = STRING_TO_JSVAL(str);
798 4480     return JS_TRUE;
799 }
800
801 static JSBool
802 str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
803                 jsval *rval)
804 0 {
805 0     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 0     if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
812 0         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
813 0         if (!str)
814 0             return JS_FALSE;
815 0         return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
816     }
817 0     return str_toUpperCase(cx, obj, 0, argv, rval);
818 }
819
820 static JSBool
821 str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
822                   jsval *rval)
823 0 {
824 0     JSString *str, *thatStr;
825
826 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
827 0     if (!str)
828 0         return JS_FALSE;
829 0     argv[-1] = STRING_TO_JSVAL(str);
830
831 0     if (argc == 0) {
832 0         *rval = JSVAL_ZERO;
833     } else {
834 0         thatStr = js_ValueToString(cx, argv[0]);
835 0         if (!thatStr)
836 0             return JS_FALSE;
837 0         if (cx->localeCallbacks && cx->localeCallbacks->localeCompare)
838 0             return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
839 0         *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
840     }
841 0     return JS_TRUE;
842 }
843
844 static JSBool
845 str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
846 72 {
847 72     JSString *str;
848 72     jsdouble d;
849 72     size_t index;
850
851 72     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
852 72     if (!str)
853 0         return JS_FALSE;
854 72     argv[-1] = STRING_TO_JSVAL(str);
855
856 72     if (argc == 0) {
857 0         d = 0.0;
858     } else {
859 72         if (!js_ValueToNumber(cx, argv[0], &d))
860 0             return JS_FALSE;
861 72         d = js_DoubleToInteger(d);
862     }
863
864 72     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
865 0         *rval = JS_GetEmptyStringValue(cx);
866     } else {
867 72         index = (size_t)d;
868 72         str = js_NewDependentString(cx, str, index, 1, 0);
869 72         if (!str)
870 0             return JS_FALSE;
871 72         *rval = STRING_TO_JSVAL(str);
872     }
873 72     return JS_TRUE;
874 }
875
876 static JSBool
877 str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
878                jsval *rval)
879 0 {
880 0     JSString *str;
881 0     jsdouble d;
882 0     size_t index;
883
884 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
885 0     if (!str)
886 0         return JS_FALSE;
887 0     argv[-1] = STRING_TO_JSVAL(str);
888
889 0     if (argc == 0) {
890 0         d = 0.0;
891     } else {
892 0         if (!js_ValueToNumber(cx, argv[0], &d))
893 0             return JS_FALSE;
894 0         d = js_DoubleToInteger(d);
895     }
896
897 0     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
898 0         *rval = JS_GetNaNValue(cx);
899     } else {
900 0         index = (size_t)d;
901 0         *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]);
902     }
903 0     return JS_TRUE;
904 }
905
906 jsint
907 js_BoyerMooreHorspool(const jschar *text, jsint textlen,
908                       const jschar *pat, jsint patlen,
909                       jsint start)
910 0 {
911 0     jsint i, j, k, m;
912 0     uint8 skip[BMH_CHARSET_SIZE];
913 0     jschar c;
914
915 0     JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
916 0     for (i = 0; i < BMH_CHARSET_SIZE; i++)
917 0         skip[i] = (uint8)patlen;
918 0     m = patlen - 1;
919 0     for (i = 0; i < m; i++) {
920 0         c = pat[i];
921 0         if (c >= BMH_CHARSET_SIZE)
922 0             return BMH_BAD_PATTERN;
923 0         skip[c] = (uint8)(m - i);
924     }
925 0     for (k = start + m;
926          k < textlen;
927          k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
928 0         for (i = k, j = m; ; i--, j--) {
929 0             if (j < 0)
930 0                 return i + 1;
931 0             if (text[i] != pat[j])
932 0                 break;
933         }
934     }
935 0     return -1;
936 }
937
938 static JSBool
939 str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
940 404 {
941 404     JSString *str, *str2;
942 404     jsint i, j, index, textlen, patlen;
943 404     const jschar *text, *pat;
944 404     jsdouble d;
945
946 404     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
947 404     if (!str)
948 0         return JS_FALSE;
949 404     argv[-1] = STRING_TO_JSVAL(str);
950 404     text = JSSTRING_CHARS(str);
951 404     textlen = (jsint) JSSTRING_LENGTH(str);
952
953 404     str2 = js_ValueToString(cx, argv[0]);
954 404     if (!str2)
955 0         return JS_FALSE;
956 404     argv[0] = STRING_TO_JSVAL(str2);
957 404     pat = JSSTRING_CHARS(str2);
958 404     patlen = (jsint) JSSTRING_LENGTH(str2);
959
960 404     if (argc > 1) {
961 0         if (!js_ValueToNumber(cx, argv[1], &d))
962 0             return JS_FALSE;
963 0         d = js_DoubleToInteger(d);
964 0         if (d < 0)
965 0             i = 0;
966 0         else if (d > textlen)
967 0             i = textlen;
968         else
969 0             i = (jsint)d;
970     } else {
971 404         i = 0;
972     }
973 404     if (patlen == 0) {
974 0         *rval = INT_TO_JSVAL(i);
975 0         return JS_TRUE;
976     }
977
978     /* XXX tune the BMH threshold (512) */
979 404     if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) {
980 0         index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
981 0         if (index != BMH_BAD_PATTERN)
982 0             goto out;
983     }
984
985 404     index = -1;
986 404     j = 0;
987 12456     while (i + j < textlen) {
988 12326         if (text[i + j] == pat[j]) {
989 274             if (++j == patlen) {
990 274                 index = i;
991 274                 break;
992             }
993         } else {
994 12052             i++;
995 12052             j = 0;
996         }
997     }
998
999 out:
1000 404     *rval = INT_TO_JSVAL(index);
1001 404     return JS_TRUE;
1002 }
1003
1004 static JSBool
1005 str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1006                   jsval *rval)
1007 572 {
1008 572     JSString *str, *str2;
1009 572     const jschar *text, *pat;
1010 572     jsint i, j, textlen, patlen;
1011 572     jsdouble d;
1012
1013 572     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1014 572     if (!str)
1015 0         return JS_FALSE;
1016 572     argv[-1] = STRING_TO_JSVAL(str);
1017 572     text = JSSTRING_CHARS(str);
1018 572     textlen = (jsint) JSSTRING_LENGTH(str);
1019
1020 572     str2 = js_ValueToString(cx, argv[0]);
1021 572     if (!str2)
1022 0         return JS_FALSE;
1023 572     argv[0] = STRING_TO_JSVAL(str2);
1024 572     pat = JSSTRING_CHARS(str2);
1025 572     patlen = (jsint) JSSTRING_LENGTH(str2);
1026
1027 572     if (argc > 1) {
1028 0         if (!js_ValueToNumber(cx, argv[1], &d))
1029 0             return JS_FALSE;
1030 0         if (JSDOUBLE_IS_NaN(d)) {
1031 0             i = textlen;
1032         } else {
1033 0             d = js_DoubleToInteger(d);
1034 0             if (d < 0)
1035 0                 i = 0;
1036 0             else if (d > textlen - patlen)
1037 0                 i = textlen - patlen;
1038             else
1039 0                 i = (jsint)d;
1040         }
1041     } else {
1042 572         i = textlen;
1043     }
1044
1045 572     if (patlen == 0) {
1046 0         *rval = INT_TO_JSVAL(i);
1047 0         return JS_TRUE;
1048     }
1049
1050 572     j = 0;
1051 5666     while (i >= 0) {
1052         /* Don't assume that text is NUL-terminated: it could be dependent. */
1053 5666         if (i + j < textlen && text[i + j] == pat[j]) {
1054 572             if (++j == patlen)
1055 572                 break;
1056         } else {
1057 5094             i--;
1058 5094             j = 0;
1059         }
1060     }
1061 572     *rval = INT_TO_JSVAL(i);
1062 572     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
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 40711 {
1095 40711     JSString *str, *src, *opt;
1096 40711     JSObject *reobj;
1097 40711     JSRegExp *re;
1098 40711     size_t index, length;
1099 40711     JSBool ok, test;
1100 40711     jsint count;
1101
1102 40711     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1103 40711     if (!str)
1104 0         return JS_FALSE;
1105 40711     argv[-1] = STRING_TO_JSVAL(str);
1106 40711     data->str = str;
1107
1108 40711     if (JSVAL_IS_REGEXP(cx, argv[0])) {
1109 40711         reobj = JSVAL_TO_OBJECT(argv[0]);
1110 40711         re = (JSRegExp *) JS_GetPrivate(cx, reobj);
1111     } else {
1112 0         src = js_ValueToString(cx, argv[0]);
1113 0         if (!src)
1114 0             return JS_FALSE;
1115 0         if (data->optarg < argc) {
1116 0             argv[0] = STRING_TO_JSVAL(src);
1117 0             opt = js_ValueToString(cx, argv[data->optarg]);
1118 0             if (!opt)
1119 0                 return JS_FALSE;
1120         } else {
1121 0             opt = NULL;
1122         }
1123 0         re = js_NewRegExpOpt(cx, NULL, src, opt,
1124                              (data->flags & FORCE_FLAT) != 0);
1125 0         if (!re)
1126 0             return JS_FALSE;
1127 0         reobj = NULL;
1128     }
1129 40711     data->regexp = re;
1130
1131 40711     if (re->flags & JSREG_GLOB)
1132 0         data->flags |= GLOBAL_REGEXP;
1133 40711     index = 0;
1134 40711     if (GET_MODE(data->flags) == MODE_SEARCH) {
1135 40711         ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
1136 40711         if (ok) {
1137 40711             *rval = (*rval == JSVAL_TRUE)
1138                     ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
1139                     : INT_TO_JSVAL(-1);
1140         }
1141 0     } else if (data->flags & GLOBAL_REGEXP) {
1142 0         if (reobj) {
1143             /* Set the lastIndex property's reserved slot to 0. */
1144 0             ok = js_SetLastIndex(cx, reobj, 0);
1145 0             if (!ok)
1146 0                 return JS_FALSE;
1147         } else {
1148 0             ok = JS_TRUE;
1149         }
1150 0         length = JSSTRING_LENGTH(str);
1151 0         for (count = 0; index <= length; count++) {
1152 0             ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
1153 0             if (!ok || *rval != JSVAL_TRUE)
1154 0                 break;
1155 0             ok = glob(cx, count, data);
1156 0             if (!ok)
1157 0                 break;
1158 0             if (cx->regExpStatics.lastMatch.length == 0) {
1159 0                 if (index == length)
1160 0                     break;
1161 0                 index++;
1162             }
1163         }
1164     } else {
1165 0         if (GET_MODE(data->flags) == MODE_REPLACE) {
1166 0             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 0             JS_ASSERT(*cx->fp->down->pc == JSOP_CALL ||
1175                       *cx->fp->down->pc == JSOP_NEW);
1176 0             JS_ASSERT(js_CodeSpec[*cx->fp->down->pc].length == 3);
1177 0             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 0                 test = JS_TRUE;
1184 0                 break;
1185               default:
1186 0                 test = JS_FALSE;
1187 0                 break;
1188             }
1189         }
1190 0         ok = js_ExecuteRegExp(cx, re, str, &index, test, rval);
1191     }
1192
1193 40711     if (reobj) {
1194         /* Tell our caller that it doesn't need to destroy data->regexp. */
1195 40711         data->flags &= ~KEEP_REGEXP;
1196 0     } else if (!(data->flags & KEEP_REGEXP)) {
1197         /* Caller didn't want to keep data->regexp, so null and destroy it.  */
1198 0         data->regexp = NULL;
1199 0         js_DestroyRegExp(cx, re);
1200     }
1201 40711     return ok;
1202 }
1203
1204 typedef struct MatchData {
1205     GlobData    base;
1206     jsval       *arrayval;      /* NB: local root pointer */
1207 } MatchData;
1208
1209 static JSBool
1210 match_glob(JSContext *cx, jsint count, GlobData *data)
1211 0 {
1212 0     MatchData *mdata;
1213 0     JSObject *arrayobj;
1214 0     JSSubString *matchsub;
1215 0     JSString *matchstr;
1216 0     jsval v;
1217
1218 0     mdata = (MatchData *)data;
1219 0     arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
1220 0     if (!arrayobj) {
1221 0         arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
1222 0         if (!arrayobj)
1223 0             return JS_FALSE;
1224 0         *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
1225     }
1226 0     matchsub = &cx->regExpStatics.lastMatch;
1227 0     matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length, 0);
1228 0     if (!matchstr)
1229 0         return JS_FALSE;
1230 0     v = STRING_TO_JSVAL(matchstr);
1231 0     return js_SetProperty(cx, arrayobj, INT_TO_JSVAL(count), &v);
1232 }
1233
1234 static JSBool
1235 str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1236 0 {
1237 0     MatchData mdata;
1238 0     JSBool ok;
1239
1240 0     mdata.base.flags = MODE_MATCH;
1241 0     mdata.base.optarg = 1;
1242 0     mdata.arrayval = &argv[2];
1243 0     *mdata.arrayval = JSVAL_NULL;
1244 0     ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
1245 0     if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
1246 0         *rval = *mdata.arrayval;
1247 0     return ok;
1248 }
1249
1250 static JSBool
1251 str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1252 40711 {
1253 40711     GlobData data;
1254
1255 40711     data.flags = MODE_SEARCH;
1256 40711     data.optarg = 1;
1257 40711     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 *
1274 interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
1275 0 {
1276 0     JSRegExpStatics *res;
1277 0     jschar dc, *cp;
1278 0     uintN num, tmp;
1279 0     JSString *str;
1280
1281 0     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 0     if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
1288 0         if (dp > JSSTRING_CHARS(rdata->repstr) && dp[-1] == '\\')
1289 0             return NULL;
1290     }
1291
1292     /* Interpret all Perl match-induced dollar variables. */
1293 0     res = &cx->regExpStatics;
1294 0     dc = dp[1];
1295 0     if (JS7_ISDEC(dc)) {
1296 0         if (cx->version != JSVERSION_DEFAULT && cx->version <= JSVERSION_1_4) {
1297 0             if (dc == '0')
1298 0                 return NULL;
1299
1300             /* Check for overflow to avoid gobbling arbitrary decimal digits. */
1301 0             num = 0;
1302 0             cp = dp;
1303 0             while ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
1304 0                 tmp = 10 * num + JS7_UNDEC(dc);
1305 0                 if (tmp < num)
1306 0                     break;
1307 0                 num = tmp;
1308             }
1309         } else { /* ECMA 3, 1-9 or 01-99 */
1310 0             num = JS7_UNDEC(dc);
1311 0             if (num > res->parenCount)
1312 0                 return NULL;
1313 0             cp = dp + 2;
1314 0             dc = *cp;
1315 0             if ((dc != 0) && JS7_ISDEC(dc)) {
1316 0                 tmp = 10 * num + JS7_UNDEC(dc);
1317 0                 if (tmp <= res->parenCount) {
1318 0                     cp++;
1319 0                     num = tmp;
1320                 }
1321             }
1322 0             if (num == 0)
1323 0                 return NULL;
1324         }
1325         /* Adjust num from 1 $n-origin to 0 array-index-origin. */
1326 0         num--;
1327 0         *skip = cp - dp;
1328 0         return REGEXP_PAREN_SUBSTRING(res, num);
1329     }
1330
1331 0     *skip = 2;
1332 0     switch (dc) {
1333       case '$':
1334 0         rdata->dollarStr.chars = dp;
1335 0         rdata->dollarStr.length = 1;
1336 0         return &rdata->dollarStr;
1337       case '&':
1338 0         return &res->lastMatch;
1339       case '+':
1340 0         return &res->lastParen;
1341       case '`':
1342 0         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 0             str = rdata->base.str;
1351 0             res->leftContext.chars = JSSTRING_CHARS(str);
1352 0             res->leftContext.length = res->lastMatch.chars
1353                                     - JSSTRING_CHARS(str);
1354         }
1355 0         return &res->leftContext;
1356       case '\'':
1357 0         return &res->rightContext;
1358     }
1359 0     return NULL;
1360 }
1361
1362 static JSBool
1363 find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
1364 0 {
1365 0     JSString *repstr;
1366 0     size_t replen, skip;
1367 0     jschar *dp, *ep;
1368 0     JSSubString *sub;
1369 #if JS_HAS_REPLACE_LAMBDA
1370 0     JSObject *lambda;
1371
1372 0     lambda = rdata->lambda;
1373 0     if (lambda) {
1374 0         uintN argc, i, j, m, n, p;
1375 0         jsval *sp, *oldsp, rval;
1376 0         void *mark;
1377 0         JSStackFrame *fp;
1378 0         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 0         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 0         p = rdata->base.regexp->parenCount;
1396 0         argc = 1 + p + 2;
1397 0         sp = js_AllocStack(cx, 2 + argc, &mark);
1398 0         if (!sp)
1399 0             return JS_FALSE;
1400
1401         /* Push lambda and its 'this' parameter. */
1402 0         *sp++ = OBJECT_TO_JSVAL(lambda);
1403 0         *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 0         PUSH_REGEXP_STATIC(lastMatch);
1420 0         i = 0;
1421 0         m = cx->regExpStatics.parenCount;
1422 0         n = JS_MIN(m, 9);
1423 0         for (j = 0; i < n; i++, j++)
1424 0             PUSH_REGEXP_STATIC(parens[j]);
1425 0         for (j = 0; i < m; i++, j++)
1426 0             PUSH_REGEXP_STATIC(moreParens[j]);
1427
1428 #undef PUSH_REGEXP_STATIC
1429
1430         /* Make sure to push undefined for any unmatched parens. */
1431 0         for (; i < p; i++)
1432 0             *sp++ = JSVAL_VOID;
1433
1434         /* Push match index and input string. */
1435 0         *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
1436 0         *sp++ = STRING_TO_JSVAL(rdata->base.str);
1437
1438         /* Lift current frame to include the args and do the call. */
1439 0         fp = cx->fp;
1440 0         oldsp = fp->sp;
1441 0         fp->sp = sp;
1442 0         ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
1443 0         rval = fp->sp[-1];
1444 0         fp->sp = oldsp;
1445
1446 0         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 0             repstr = js_ValueToString(cx, rval);
1453 0             if (!repstr) {
1454 0                 ok = JS_FALSE;
1455             } else {
1456 0                 rdata->repstr = repstr;
1457 0                 *sizep = JSSTRING_LENGTH(repstr);
1458             }
1459         }
1460
1461       lambda_out:
1462 0         js_FreeStack(cx, mark);
1463 0         cx->regExpStatics.rightContext = saveRightContext;
1464 0         return ok;
1465     }
1466 #endif /* JS_HAS_REPLACE_LAMBDA */
1467
1468 0     repstr = rdata->repstr;
1469 0     replen = JSSTRING_LENGTH(repstr);
1470 0     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1471          dp = js_strchr_limit(dp, '$', ep)) {
1472 0         sub = interpret_dollar(cx, dp, rdata, &skip);
1473 0         if (sub) {
1474 0             replen += sub->length - skip;
1475 0             dp += skip;
1476         }
1477         else
1478 0             dp++;
1479     }
1480 0     *sizep = replen;
1481 0     return JS_TRUE;
1482 }
1483
1484 static void
1485 do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
1486 0 {
1487 0     JSString *repstr;
1488 0     jschar *bp, *cp, *dp, *ep;
1489 0     size_t len, skip;
1490 0     JSSubString *sub;
1491
1492 0     repstr = rdata->repstr;
1493 0     bp = cp = JSSTRING_CHARS(repstr);
1494 0     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
1495          dp = js_strchr_limit(dp, '$', ep)) {
1496 0         len = dp - cp;
1497 0         js_strncpy(chars, cp, len);
1498 0         chars += len;
1499 0         cp = dp;
1500 0         sub = interpret_dollar(cx, dp, rdata, &skip);
1501 0         if (sub) {
1502 0             len = sub->length;
1503 0             js_strncpy(chars, sub->chars, len);
1504 0             chars += len;
1505 0             cp += skip;
1506 0             dp += skip;
1507         } else {
1508 0             dp++;
1509         }
1510     }
1511 0     js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
1512 }
1513
1514 static JSBool
1515 replace_glob(JSContext *cx, jsint count, GlobData *data)
1516 0 {
1517 0     ReplaceData *rdata;
1518 0     JSString *str;
1519 0     size_t leftoff, leftlen, replen, growth;
1520 0     const jschar *left;
1521 0     jschar *chars;
1522
1523 0     rdata = (ReplaceData *)data;
1524 0     str = data->str;
1525 0     leftoff = rdata->leftIndex;
1526 0     left = JSSTRING_CHARS(str) + leftoff;
1527 0     leftlen = cx->regExpStatics.lastMatch.chars - left;
1528 0     rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
1529 0     rdata->leftIndex += cx->regExpStatics.lastMatch.length;
1530 0     if (!find_replen(cx, rdata, &replen))
1531 0         return JS_FALSE;
1532 0     growth = leftlen + replen;
1533 0     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 0     if (!chars) {
1539 0         JS_free(cx, rdata->chars);
1540 0         rdata->chars = NULL;
1541 0         return JS_FALSE;
1542     }
1543 0     rdata->chars = chars;
1544 0     rdata->length += growth;
1545 0     chars += rdata->index;
1546 0     rdata->index += growth;
1547 0     js_strncpy(chars, left, leftlen);
1548 0     chars += leftlen;
1549 0     do_replace(cx, rdata, chars);
1550 0     return JS_TRUE;
1551 }
1552
1553 static JSBool
1554 str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1555 0 {
1556 0     JSObject *lambda;
1557 0     JSString *repstr, *str;
1558 0     ReplaceData rdata;
1559 0     JSBool ok;
1560 0     jschar *chars;
1561 0     size_t leftlen, rightlen, length;
1562
1563 #if JS_HAS_REPLACE_LAMBDA
1564 0     if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {
1565 0         lambda = JSVAL_TO_OBJECT(argv[1]);
1566 0         repstr = NULL;
1567     } else
1568 #endif
1569     {
1570 0         if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))
1571 0             return JS_FALSE;
1572 0         repstr = JSVAL_TO_STRING(argv[1]);
1573 0         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 0     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP;
1582 0     if (cx->version == JSVERSION_DEFAULT || cx->version > JSVERSION_1_4)
1583 0         rdata.base.flags |= FORCE_FLAT;
1584 0     rdata.base.optarg = 2;
1585
1586 0     rdata.lambda = lambda;
1587 0     rdata.repstr = repstr;
1588 0     if (repstr) {
1589 0         rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
1590 0         rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
1591                                        rdata.dollarEnd);
1592     } else {
1593 0         rdata.dollar = rdata.dollarEnd = NULL;
1594     }
1595 0     rdata.chars = NULL;
1596 0     rdata.length = 0;
1597 0     rdata.index = 0;
1598 0     rdata.leftIndex = 0;
1599
1600 0     ok = match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval);
1601 0     if (!ok)
1602 0         return JS_FALSE;
1603
1604 0     if (!rdata.chars) {
1605 0         if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) {
1606             /* Didn't match even once. */
1607 0             *rval = STRING_TO_JSVAL(rdata.base.str);
1608 0             goto out;
1609         }
1610 0         leftlen = cx->regExpStatics.leftContext.length;
1611 0         ok = find_replen(cx, &rdata, &length);
1612 0         if (!ok)
1613 0             goto out;
1614 0         length += leftlen;
1615 0         chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
1616 0         if (!chars) {
1617 0             ok = JS_FALSE;
1618 0             goto out;
1619         }
1620 0         js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
1621 0         do_replace(cx, &rdata, chars + leftlen);
1622 0         rdata.chars = chars;
1623 0         rdata.length = length;
1624     }
1625
1626 0     rightlen = cx->regExpStatics.rightContext.length;
1627 0     length = rdata.length + rightlen;
1628 0     chars = (jschar *)
1629         JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
1630 0     if (!chars) {
1631 0         JS_free(cx, rdata.chars);
1632 0         ok = JS_FALSE;
1633 0         goto out;
1634     }
1635 0     js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
1636                rightlen);
1637 0     chars[length] = 0;
1638
1639 0     str = js_NewString(cx, chars, length, 0);
1640 0     if (!str) {
1641 0         JS_free(cx, chars);
1642 0         ok = JS_FALSE;
1643 0         goto out;
1644     }
1645 0     *rval = STRING_TO_JSVAL(str);
1646
1647 out:
1648     /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
1649 0     if (rdata.base.flags & KEEP_REGEXP)
1650 0         js_DestroyRegExp(cx, rdata.base.regexp);
1651 0     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
1665 find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
1666            JSSubString *sep)
1667 216 {
1668 216     jsint i, j, k;
1669 216     jschar *chars;
1670 216     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 216     i = *ip;
1684 216     if ((size_t)i > JSSTRING_LENGTH(str))
1685 54         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 162     chars = JSSTRING_CHARS(str);
1696 162     length = JSSTRING_LENGTH(str);
1697 162     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 0         if (i == 0) {
1702 0             while (JS_ISSPACE(chars[i]))
1703 0                 i++;
1704 0             *ip = i;
1705         }
1706
1707         /* Don't delimit whitespace at end of string. */
1708 0         if ((size_t)i == length)
1709 0             return -1;
1710
1711         /* Skip over the non-whitespace chars. */
1712 0         while ((size_t)i < length && !JS_ISSPACE(chars[i]))
1713 0             i++;
1714
1715         /* Now skip the next run of whitespace. */
1716 0         j = i;
1717 0         while ((size_t)j < length && JS_ISSPACE(chars[j]))
1718 0             j++;
1719
1720         /* Update sep->length to count delimiter chars. */
1721 0         sep->length = (size_t)(j - i);
1722 0         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 162     if (re) {
1732 0         size_t index;
1733 0         jsval rval;
1734
1735       again:
1736         /* JS1.2 deviated from Perl by never matching at end of string. */
1737 0         index = (size_t)i;
1738 0         if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
1739 0             return -2;
1740 0         if (rval != JSVAL_TRUE) {
1741             /* Mismatch: ensure our caller advances i past end of string. */
1742 0             sep->length = 1;
1743 0             return length;
1744         }
1745 0         i = (jsint)index;
1746 0         *sep = cx->regExpStatics.lastMatch;
1747 0         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 0             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 0                 if ((size_t)i == length) {
1760 0                     if (cx->version == JSVERSION_1_2) {
1761 0                         sep->length = 1;
1762 0                         return i;
1763                     }
1764 0                     return -1;
1765                 }
1766 0                 i++;
1767 0                 goto again;
1768             }
1769         }
1770 0         JS_ASSERT((size_t)i >= sep->length);
1771 0         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 162     if (!JSVERSION_IS_ECMA(cx->version) && length == 0)
1781 0         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 162     if (sep->length == 0) {
1793 0         if (cx->version == JSVERSION_1_2) {
1794 0             if ((size_t)i == length) {
1795 0                 sep->length = 1;
1796 0                 return i;
1797             }
1798 0             return i + 1;
1799         }
1800 0         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 162     j = 0;
1809 5400     while ((size_t)(k = i + j) < length) {
1810 5346         if (chars[k] == sep->chars[j]) {
1811 108             if ((size_t)++j == sep->length)
1812 108                 return i;
1813         } else {
1814 5238             i++;
1815 5238             j = 0;
1816         }
1817     }
1818 54     return k;
1819 }
1820
1821 static JSBool
1822 str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1823 54 {
1824 54     JSString *str, *sub;
1825 54     JSObject *arrayobj;
1826 54     jsval v;
1827 54     JSBool ok, limited;
1828 54     JSRegExp *re;
1829 54     JSSubString *sep, tmp;
1830 54     jsdouble d;
1831 54     jsint i, j;
1832 54     uint32 len, limit;
1833
1834 54     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1835 54     if (!str)
1836 0         return JS_FALSE;
1837 54     argv[-1] = STRING_TO_JSVAL(str);
1838
1839 54     arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
1840 54     if (!arrayobj)
1841 0         return JS_FALSE;
1842 54     *rval = OBJECT_TO_JSVAL(arrayobj);
1843
1844 54     if (argc == 0) {
1845 0         v = STRING_TO_JSVAL(str);
1846 0         ok = JS_SetElement(cx, arrayobj, 0, &v);
1847     } else {
1848 #if JS_HAS_REGEXPS
1849 54         if (JSVAL_IS_REGEXP(cx, argv[0])) {
1850 0             re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
1851 0             sep = &tmp;
1852
1853             /* Set a magic value so we can detect a successful re match. */
1854 0             sep->chars = NULL;
1855         } else
1856 #endif
1857         {
1858 54             JSString *str2 = js_ValueToString(cx, argv[0]);
1859 54             if (!str2)
1860 0                 return JS_FALSE;
1861 54             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 54             tmp.length = JSSTRING_LENGTH(str2);
1868 54             tmp.chars = JSSTRING_CHARS(str2);
1869 54             sep = &tmp;
1870 54             re = NULL;
1871         }
1872
1873         /* Use the second argument as the split limit, if given. */
1874 54         limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]);
1875 54         limit = 0; /* Avoid warning. */
1876 54         if (limited) {
1877 0             if (!js_ValueToNumber(cx, argv[1], &d))
1878 0                 return JS_FALSE;
1879
1880             /* Clamp limit between 0 and 1 + string length. */
1881 0             if (!js_DoubleToECMAUint32(cx, d, &limit))
1882 0                 return JS_FALSE;
1883 0             if (limit > JSSTRING_LENGTH(str))
1884 0                 limit = 1 + JSSTRING_LENGTH(str);
1885         }
1886
1887 54         len = i = 0;
1888 216         while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
1889 162             if (limited && len >= limit)
1890 0                 break;
1891 162             sub = js_NewDependentString(cx, str, i, (size_t)(j - i), 0);
1892 162             if (!sub)
1893 0                 return JS_FALSE;
1894 162             v = STRING_TO_JSVAL(sub);
1895 162             if (!JS_SetElement(cx, arrayobj, len, &v))
1896 0                 return JS_FALSE;
1897 162             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 162             if (re && sep->chars) {
1905 0                 uintN num;
1906 0                 JSSubString *parsub;
1907
1908 0                 for (num = 0; num < cx->regExpStatics.parenCount; num++) {
1909 0                     if (limited && len >= limit)
1910 0                         break;
1911 0                     parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
1912 0                     sub = js_NewStringCopyN(cx, parsub->chars, parsub->length,
1913                                             0);
1914 0                     if (!sub)
1915 0                         return JS_FALSE;
1916 0                     v = STRING_TO_JSVAL(sub);
1917 0                     if (!JS_SetElement(cx, arrayobj, len, &v))
1918 0                         return JS_FALSE;
1919 0                     len++;
1920                 }
1921 0                 sep->chars = NULL;
1922             }
1923 #endif
1924 162             i = j + sep->length;
1925 162             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 0                 if (!limited && (size_t)i == JSSTRING_LENGTH(str))
1931 54                     break;
1932             }
1933         }
1934 54         ok = (j != -2);
1935     }
1936 54     return ok;
1937 }
1938
1939 #if JS_HAS_PERL_SUBSTR
1940 static JSBool
1941 str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1942 24 {
1943 24     JSString *str;
1944 24     jsdouble d;
1945 24     jsdouble length, begin, end;
1946
1947 24     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1948 24     if (!str)
1949 0         return JS_FALSE;
1950
1951 24     if (argc != 0) {
1952 24         if (!js_ValueToNumber(cx, argv[0], &d))
1953 0             return JS_FALSE;
1954 24         length = JSSTRING_LENGTH(str);
1955 24         begin = js_DoubleToInteger(d);
1956 24         if (begin < 0) {
1957 0             begin += length;
1958 0             if (begin < 0)
1959 0                 begin = 0;
1960 24         } else if (begin > length) {
1961 0             begin = length;
1962         }
1963
1964 24         if (argc == 1) {
1965 12             end = length;
1966         } else {
1967 12             if (!js_ValueToNumber(cx, argv[1], &d))
1968 0                 return JS_FALSE;
1969 12             end = js_DoubleToInteger(d);
1970 12             if (end < 0)
1971 0                 end = 0;
1972 12             end += begin;
1973 12             if (end > length)
1974 0                 end = length;
1975         }
1976
1977 24         str = js_NewDependentString(cx, str, (size_t)begin,
1978                                     (size_t)(end - begin), 0);
1979 24         if (!str)
1980 0             return JS_FALSE;
1981     }
1982 24     *rval = STRING_TO_JSVAL(str);
1983 24     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
1992 str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1993 0 {
1994 0     JSString *str, *str2;
1995 0     uintN i;
1996
1997 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
1998 0     if (!str)
1999 0         return JS_FALSE;
2000 0     argv[-1] = STRING_TO_JSVAL(str);
2001
2002 0     for (i = 0; i < argc; i++) {
2003 0         str2 = js_ValueToString(cx, argv[i]);
2004 0         if (!str2)
2005 0             return JS_FALSE;
2006 0         argv[i] = STRING_TO_JSVAL(str2);
2007
2008 0         str = js_ConcatStrings(cx, str, str2);
2009 0         if (!str)
2010 0             return JS_FALSE;
2011     }
2012
2013 0     *rval = STRING_TO_JSVAL(str);
2014 0     return JS_TRUE;
2015 }
2016
2017 static JSBool
2018 str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2019 548 {
2020 548     JSString *str;
2021 548     jsdouble d;
2022 548     jsdouble length, begin, end;
2023
2024 548     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
2025 548     if (!str)
2026 0         return JS_FALSE;
2027 548     argv[-1] = STRING_TO_JSVAL(str);
2028
2029 548     if (argc != 0) {
2030 548         if (!js_ValueToNumber(cx, argv[0], &d))
2031 0             return JS_FALSE;
2032 548         length = JSSTRING_LENGTH(str);
2033 548         begin = js_DoubleToInteger(d);
2034 548         if (begin < 0) {
2035 0             begin += length;
2036 0             if (begin < 0)
2037 0                 begin = 0;
2038 548         } else if (begin > length) {
2039 0             begin = length;
2040         }
2041
2042 548         if (argc == 1) {
2043 274             end = length;
2044         } else {
2045 274             if (!js_ValueToNumber(cx, argv[1], &d))
2046 0                 return JS_FALSE;
2047 274             end = js_DoubleToInteger(d);
2048 274             if (end < 0) {
2049 0                 end += length;
2050 0                 if (end < 0)
2051 0                     end = 0;
2052 274             } else if (end > length) {
2053 0                 end = length;
2054             }
2055 274             if (end < begin)
2056 0                 end = begin;
2057         }
2058
2059 548         str = js_NewDependentString(cx, str, (size_t)begin,
2060                                     (size_t)(end - begin), 0);
2061 548         if (!str)
2062 0             return JS_FALSE;
2063     }
2064 548     *rval = STRING_TO_JSVAL(str);
2065 548     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
2074 tagify(JSContext *cx, JSObject *obj, jsval *argv,
2075        const char *begin, const jschar *param, const char *end,
2076        jsval *rval)
2077 0 {
2078 0     JSString *str;
2079 0     jschar *tagbuf;
2080 0     size_t beglen, endlen, parlen, taglen;
2081 0     size_t i, j;
2082
2083 0     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
2084 0     if (!str)
2085 0         return JS_FALSE;
2086 0     argv[-1] = STRING_TO_JSVAL(str);
2087
2088 0     if (!end)
2089 0         end = begin;
2090
2091 0     beglen = strlen(begin);
2092 0     taglen = 1 + beglen + 1;                            /* '<begin' + '>' */
2093 0     parlen = 0; /* Avoid warning. */
2094 0     if (param) {
2095 0         parlen = js_strlen(param);
2096 0         taglen += 2 + parlen + 1;                       /* '="param"' */
2097     }
2098 0     endlen = strlen(end);
2099 0     taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1;    /* 'str</end>' */
2100
2101 0     tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
2102 0     if (!tagbuf)
2103 0         return JS_FALSE;
2104
2105 0     j = 0;
2106 0     tagbuf[j++] = '<';
2107 0     for (i = 0; i < beglen; i++)
2108 0         tagbuf[j++] = (jschar)begin[i];
2109 0     if (param) {
2110 0         tagbuf[j++] = '=';
2111 0         tagbuf[j++] = '"';
2112 0         js_strncpy(&tagbuf[j], param, parlen);
2113 0         j += parlen;
2114 0         tagbuf[j++] = '"';
2115     }
2116 0     tagbuf[j++] = '>';
2117 0     js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
2118 0     j += JSSTRING_LENGTH(str);
2119 0     tagbuf[j++] = '<';
2120 0     tagbuf[j++] = '/';
2121 0     for (i = 0; i < endlen; i++)
2122 0         tagbuf[j++] = (jschar)end[i];
2123 0     tagbuf[j++] = '>';
2124 0     JS_ASSERT(j == taglen);
2125 0     tagbuf[j] = 0;
2126
2127 0     str = js_NewString(cx, tagbuf, taglen, 0);
2128 0     if (!str) {
2129 0         free((char *)tagbuf);
2130 0         return JS_FALSE;
2131     }
2132 0     *rval = STRING_TO_JSVAL(str);
2133 0     return JS_TRUE;
2134 }
2135
2136 static JSBool
2137 tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
2138              const char *begin, const char *end,
2139              jsval *rval)
2140 0 {
2141 0     JSString *param;
2142
2143 0     param = js_ValueToString(cx, argv[0]);
2144 0     if (!param)
2145 0         return JS_FALSE;
2146 0     argv[0] = STRING_TO_JSVAL(param);
2147 0     return tagify(cx, obj, argv, begin, JSSTRING_CHARS(param), end, rval);
2148 }
2149
2150 static JSBool
2151 str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2152 0 {
2153 0     return tagify(cx, obj, argv, "b", NULL, NULL, rval);
2154 }
2155
2156 static JSBool
2157 str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2158 0 {
2159 0     return tagify(cx, obj, argv, "i", NULL, NULL, rval);
2160 }
2161
2162 static JSBool
2163 str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2164 0 {
2165 0     return tagify(cx, obj, argv, "tt", NULL, NULL, rval);
2166 }
2167
2168 static JSBool
2169 str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2170 0 {
2171 0     return tagify_value(cx, obj, argv, "font size", "font", rval);
2172 }
2173
2174 static JSBool
2175 str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2176               jsval *rval)
2177 0 {
2178 0     return tagify_value(cx, obj, argv, "font color", "font", rval);
2179 }
2180
2181 static JSBool
2182 str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2183 0 {
2184 0     return tagify_value(cx, obj, argv, "a href", "a", rval);
2185 }
2186
2187 static JSBool
2188 str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2189 0 {
2190 0     return tagify_value(cx, obj, argv, "a name", "a", rval);
2191 }
2192
2193 static JSBool
2194 str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2195 0 {
2196 0     return tagify(cx, obj, argv, "strike", NULL, NULL, rval);
2197 }
2198
2199 static JSBool
2200 str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2201 0 {
2202 0     return tagify(cx, obj, argv, "small", NULL, NULL, rval);
2203 }
2204
2205 static JSBool
2206 str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2207 0 {
2208 0     return tagify(cx, obj, argv, "big", NULL, NULL, rval);
2209 }
2210
2211 static JSBool
2212 str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2213 0 {
2214 0     return tagify(cx, obj, argv, "blink", NULL, NULL, rval);
2215 }
2216
2217 static JSBool
2218 str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2219 0 {
2220 0     return tagify(cx, obj, argv, "sup", NULL, NULL, rval);
2221 }
2222
2223 static JSBool
2224 str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2225 0 {
2226 0     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
2288 String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2289 0 {
2290 0     JSString *str;
2291
2292 0     if (argc > 0) {
2293 0         str = js_ValueToString(cx, argv[0]);
2294 0         if (!str)
2295 0             return JS_FALSE;
2296     } else {
2297 0         str = cx->runtime->emptyString;
2298     }
2299 0     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
2300 0         *rval = STRING_TO_JSVAL(str);
2301 0         return JS_TRUE;
2302     }
2303 0     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
2304 0     return JS_TRUE;
2305 }
2306
2307 static JSBool
2308 str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2309                  jsval *rval)
2310 0 {
2311 0     jschar *chars;
2312 0     uintN i;
2313 0     uint16 code;
2314 0     JSString *str;
2315
2316 0     chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
2317 0     if (!chars)
2318 0         return JS_FALSE;
2319 0     for (i = 0; i < argc; i++) {
2320 0         if (!js_ValueToUint16(cx, argv[i], &code)) {
2321 0             JS_free(cx, chars);
2322 0             return JS_FALSE;
2323         }
2324 0         chars[i] = (jschar)code;
2325     }
2326 0     chars[i] = 0;
2327 0     str = js_NewString(cx, chars, argc, 0);
2328 0     if (!str) {
2329 0         JS_free(cx, chars);
2330 0         return JS_FALSE;
2331     }
2332 0     *rval = STRING_TO_JSVAL(str);
2333 0     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
2350 js_InitStringGlobals(void)
2351 17 {
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 17     return JS_TRUE;
2361 }
2362
2363 void
2364 js_FreeStringGlobals()
2365 0 {
2366 0     if (deflated_string_cache) {
2367 0         JS_HashTableDestroy(deflated_string_cache);
2368 0         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
2379 js_InitRuntimeStringState(JSContext *cx)
2380 17 {
2381 17     JSRuntime *rt;
2382 17     JSString *empty;
2383
2384 17     rt = cx->runtime;
2385 17     JS_ASSERT(!rt->emptyString);
2386
2387     /* Make a permanently locked empty string. */
2388 17     empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
2389 17     if (!empty)
2390 0         return JS_FALSE;
2391
2392     /* Atomize it for scripts that use '' + x to convert x to string. */
2393 17     if (!js_AtomizeString(cx, empty, ATOM_PINNED))
2394 0         return JS_FALSE;
2395
2396 17     rt->emptyString = empty;
2397 17     return JS_TRUE;
2398 }
2399
2400 void
2401 js_FinishRuntimeStringState(JSContext *cx)
2402 17 {
2403 17     JSRuntime *rt = cx->runtime;
2404
2405 17     js_UnlockGCThingRT(rt, rt->emptyString);
2406 17     rt->emptyString = NULL;
2407 }
2408
2409 JSObject *
2410 js_InitStringClass(JSContext *cx, JSObject *obj)
2411 17 {
2412 17     JSObject *proto;
2413
2414     /* Define the escape, unescape functions in the global object. */
2415 17     if (!JS_DefineFunctions(cx, obj, string_functions))
2416 0         return NULL;
2417
2418 17     proto = JS_InitClass(cx, obj, NULL, &string_class, String, 1,
2419                          string_props, string_methods,
2420                          NULL, string_static_methods);
2421 17     if (!proto)
2422 0         return NULL;
2423 17     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE,
2424                  STRING_TO_JSVAL(cx->runtime->emptyString));
2425 17     return proto;
2426 }
2427
2428 JSString *
2429 js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
2430 122919 {
2431 122919     JSString *str;
2432
2433 122919     if (length > JSSTRING_LENGTH_MASK) {
2434 0         JS_ReportOutOfMemory(cx);
2435 0         return NULL;
2436     }
2437
2438 122919     str = (JSString *) js_AllocGCThing(cx, gcflag | GCX_STRING);
2439 122919     if (!str)
2440 0         return NULL;
2441 122919     str->length = length;
2442 122919     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 122919     return str;
2454 }
2455
2456 JSString *
2457 js_NewDependentString(JSContext *cx, JSString *base, size_t start,
2458                       size_t length, uintN gcflag)
2459 1064 {
2460 1064     JSDependentString *ds;
2461
2462 1064     if (length == 0)
2463 54         return cx->runtime->emptyString;
2464
2465 1010     if (start > JSSTRDEP_START_MASK ||
2466         (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
2467 0         return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length,
2468                                  gcflag);
2469     }
2470
2471 1010     ds = (JSDependentString *) js_AllocGCThing(cx, gcflag | GCX_MUTABLE_STRING);
2472 1010     if (!ds)
2473 0         return NULL;
2474 1010     if (start == 0) {
2475 426         JSPREFIX_SET_LENGTH(ds, length);
2476 426         JSPREFIX_SET_BASE(ds, base);
2477     } else {
2478 584         JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
2479 584         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 1010     return (JSString *)ds;
2497 }
2498
2499 #ifdef DEBUG
2500 #include <math.h>
2501
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 *
2539 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag)
2540 34854 {
2541 34854     jschar *news;
2542 34854     JSString *str;
2543
2544 34854     news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar));
2545 34854     if (!news)
2546 0         return NULL;
2547 34854     js_strncpy(news, s, n);
2548 34854     news[n] = 0;
2549 34854     str = js_NewString(cx, news, n, gcflag);
2550 34854     if (!str)
2551 0         JS_free(cx, news);
2552 34854     return str;
2553 }
2554
2555 JSString *
2556 js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
2557 0 {
2558 0     size_t n, m;
2559 0     jschar *news;
2560 0     JSString *str;
2561
2562 0     n = js_strlen(s);
2563 0     m = (n + 1) * sizeof(jschar);
2564 0     news = (jschar *) JS_malloc(cx, m);
2565 0     if (!news)
2566 0         return NULL;
2567 0     memcpy(news, s, m);
2568 0     str = js_NewString(cx, news, n, gcflag);
2569 0     if (!str)
2570 0         JS_free(cx, news);
2571 0     return str;
2572 }
2573
2574 JS_STATIC_DLL_CALLBACK(JSHashNumber)
2575 js_hash_string_pointer(const void *key)
2576 498194 {
2577 498194     return (JSHashNumber)key >> JSVAL_TAGBITS;
2578 }
2579
2580 void
2581 js_PurgeDeflatedStringCache(JSString *str)
2582 123929 {
2583 123929     JSHashNumber hash;
2584 123929     JSHashEntry *he, **hep;
2585
2586 123929     if (!deflated_string_cache)
2587 0         return;
2588
2589 123929     hash = js_hash_string_pointer(str);
2590 123929     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2591 123929     hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
2592 123929     he = *hep;
2593 123929     if (he) {
2594 #ifdef DEBUG
2595         deflated_string_cache_bytes -= JSSTRING_LENGTH(str);
2596 #endif
2597 41113         free(he->value);
2598 41113         JS_HashTableRawRemove(deflated_string_cache, hep, he);
2599     }
2600 123929     JS_RELEASE_LOCK(deflated_string_cache_lock);
2601 }
2602
2603 void
2604 js_FinalizeString(JSContext *cx, JSString *str)
2605 116077 {
2606 116077     js_FinalizeStringRT(cx->runtime, str);
2607 }
2608
2609 void
2610 js_FinalizeStringRT(JSRuntime *rt, JSString *str)
2611 123929 {
2612 123929     JSBool valid;
2613
2614     JS_RUNTIME_UNMETER(rt, liveStrings);
2615 123929     if (JSSTRING_IS_DEPENDENT(str)) {
2616         /* If JSSTRFLAG_DEPENDENT is set, this string must be valid. */
2617 19848         JS_ASSERT(JSSTRDEP_BASE(str));
2618         JS_RUNTIME_UNMETER(rt, liveDependentStrings);
2619 19848         valid = JS_TRUE;
2620     } else {
2621         /* A stillborn string has null chars, so is not valid. */
2622 104081         valid = (str->chars != NULL);
2623 104081         if (valid)
2624 104081             free(str->chars);
2625     }
2626 123929     if (valid) {
2627 123929         js_PurgeDeflatedStringCache(str);
2628 123929         str->chars = NULL;
2629     }
2630 123929     str->length = 0;
2631 }
2632
2633 JSObject *
2634 js_StringToObject(JSContext *cx, JSString *str)
2635 47207 {
2636 47207     JSObject *obj;
2637
2638 47207     obj = js_NewObject(cx, &string_class, NULL, NULL);
2639 47207     if (!obj)
2640 0         return NULL;
2641 47207     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
2642 47207     return obj;
2643 }
2644
2645 JSString *
2646 js_ValueToString(JSContext *cx, jsval v)
2647 570693 {
2648 570693     JSObject *obj;
2649 570693     JSString *str;
2650
2651 570693     if (JSVAL_IS_OBJECT(v)) {
2652 47465         obj = JSVAL_TO_OBJECT(v);
2653 47465         if (!obj)
2654 0             return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
2655 47465         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
2656 0             return NULL;
2657     }
2658 570693     if (JSVAL_IS_STRING(v)) {
2659 568060         str = JSVAL_TO_STRING(v);
2660 2633     } else if (JSVAL_IS_INT(v)) {
2661 208         str = js_NumberToString(cx, JSVAL_TO_INT(v));
2662 2425     } else if (JSVAL_IS_DOUBLE(v)) {
2663 113         str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
2664 2312     } else if (JSVAL_IS_BOOLEAN(v)) {
2665 0         str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
2666     } else {
2667 2312         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
2668     }
2669 570693     return str;
2670 }
2671
2672 JSString *
2673 js_ValueToSource(JSContext *cx, jsval v)
2674 0 {
2675 0     if (JSVAL_IS_STRING(v))
2676 0         return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
2677 0     if (JSVAL_IS_PRIMITIVE(v)) {
2678         /* Special case to preserve negative zero, _contra_ toString. */
2679 0         if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
2680             /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
2681 0             static const jschar js_negzero_ucNstr[] = {'-', '0'};
2682
2683 0             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2, 0);
2684         }
2685     } else {
2686 0         if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
2687                           cx->runtime->atomState.toSourceAtom,
2688                           0, NULL, &v)) {
2689 0             return NULL;
2690         }
2691     }
2692 0     return js_ValueToString(cx, v);
2693 }
2694
2695 JSHashNumber
2696 js_HashString(JSString *str)
2697 2252120 {
2698 2252120     JSHashNumber h;
2699 2252120     const jschar *s;
2700 2252120     size_t n;
2701
2702 2252120     h = 0;
2703 37458653     for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
2704 35206533         h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
2705 2252120     return h;
2706 }
2707
2708 intN
2709 js_CompareStrings(JSString *str1, JSString *str2)
2710 2232452 {
2711 2232452     size_t l1, l2, n, i;
2712 2232452     const jschar *s1, *s2;
2713 2232452     intN cmp;
2714
2715 2232452     l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
2716 2232452     s1 = JSSTRING_CHARS(str1),  s2 = JSSTRING_CHARS(str2);
2717 2232452     n = JS_MIN(l1, l2);
2718 34977053     for (i = 0; i < n; i++) {
2719 32747392         cmp = s1[i] - s2[i];
2720 32747392         if (cmp != 0)
2721 2791             return cmp;
2722     }
2723 2229661     return (intN)(l1 - l2);
2724 }
2725
2726 size_t
2727 js_strlen(const jschar *s)
2728 16435 {
2729 16435     const jschar *t;
2730
2731 32870     for (t = s; *t != 0; t++)
2732 16435         continue;
2733 16435     return (size_t)(t - s);
2734 }
2735
2736 jschar *
2737 js_strchr(const jschar *s, jschar c)
2738 0 {
2739 0     while (*s != 0) {
2740 0         if (*s == c)
2741 0             return (jschar *)s;
2742 0         s++;
2743     }
2744 0     return NULL;
2745 }
2746
2747 jschar *
2748 js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
2749 0 {
2750 0     while (s < limit) {
2751 0         if (*s == c)
2752 0             return (jschar *)s;
2753 0         s++;
2754     }
2755 0     return NULL;
2756 }
2757
2758 const jschar *
2759 js_SkipWhiteSpace(const jschar *s)
2760 16693 {
2761     /* JS_ISSPACE is false on a null. */
2762 16693     while (JS_ISSPACE(*s))
2763 0         s++;
2764 16693     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
2773 js_InflateStringToBuffer(jschar *chars, const char *bytes, size_t length)
2774 1314340 {
2775 1314340     size_t i;
2776
2777 1314340     INFLATE_STRING_BODY
2778 }
2779
2780 jschar *
2781 js_InflateString(JSContext *cx, const char *bytes, size_t length)
2782 113391 {
2783 113391     jschar *chars;
2784 113391     size_t i;
2785
2786 113391     chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
2787 113391     if (!chars)
2788 0         return NULL;
2789
2790 113391     INFLATE_STRING_BODY
2791
2792 113391     return chars;
2793 }
2794
2795 /*
2796  * May be called with null cx by js_GetStringBytes, see below.
2797  */
2798 char *
2799 js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
2800 41113 {
2801 41113     size_t i, size;
2802 41113     char *bytes;
2803
2804 41113     size = (length + 1) * sizeof(char);
2805 41113     bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
2806 41113     if (!bytes)
2807 0         return NULL;
2808 2509741     for (i = 0; i < length; i++)
2809 2468628         bytes[i] = (char) chars[i];
2810 41113     bytes[i] = 0;
2811 41113     return bytes;
2812 }
2813
2814 static JSHashTable *
2815 GetDeflatedStringCache(void)
2816 374265 {
2817 374265     JSHashTable *cache;
2818
2819 374265     cache = deflated_string_cache;
2820 374265     if (!cache) {
2821 17         cache = JS_NewHashTable(8, js_hash_string_pointer,
2822                                 JS_CompareValues, JS_CompareValues,
2823                                 NULL, NULL);
2824 17         deflated_string_cache = cache;
2825     }
2826 374265     return cache;
2827 }
2828
2829 JSBool
2830 js_SetStringBytes(JSString *str, char *bytes, size_t length)
2831 0 {
2832 0     JSHashTable *cache;
2833 0     JSBool ok;
2834 0     JSHashNumber hash;
2835 0     JSHashEntry **hep;
2836
2837 0     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2838
2839 0     cache = GetDeflatedStringCache();
2840 0     if (!cache) {
2841 0         ok = JS_FALSE;
2842     } else {
2843 0         hash = js_hash_string_pointer(str);
2844 0         hep = JS_HashTableRawLookup(cache, hash, str);
2845 0         JS_ASSERT(*hep == NULL);
2846 0         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 0     JS_RELEASE_LOCK(deflated_string_cache_lock);
2854 0     return ok;
2855 }
2856
2857 char *
2858 js_GetStringBytes(JSString *str)
2859 374265 {
2860 374265     JSHashTable *cache;
2861 374265     char *bytes;
2862 374265     JSHashNumber hash;
2863 374265     JSHashEntry *he, **hep;
2864
2865 374265     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
2866
2867 374265     cache = GetDeflatedStringCache();
2868 374265     if (!cache) {
2869 0         bytes = NULL;
2870     } else {
2871 374265         hash = js_hash_string_pointer(str);
2872 374265         hep = JS_HashTableRawLookup(cache, hash, str);
2873 374265         he = *hep;
2874 374265         if (he) {
2875 333152             bytes = (char *) he->value;
2876
2877             /* Try to catch failure to JS_ShutDown between runtime epochs. */
2878 333152             JS_ASSERT((*bytes == '\0' && JSSTRING_LENGTH(str) == 0) ||
2879                       *bytes == (char) JSSTRING_CHARS(str)[0]);
2880         } else {
2881 41113             bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
2882                                      JSSTRING_LENGTH(str));
2883 41113             if (bytes) {
2884 41113                 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
2885 #ifdef DEBUG
2886                     deflated_string_cache_bytes += JSSTRING_LENGTH(str);
2887 #endif
2888                 } else {
2889 0                     free(bytes);
2890 0                     bytes = NULL;
2891                 }
2892             }
2893         }
2894     }
2895
2896 374265     JS_RELEASE_LOCK(deflated_string_cache_lock);
2897 374265     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
4200 AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
4201 0 {
4202 0     size_t total;
4203
4204 0     JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
4205 0     total = str->length + length + 1;
4206 0     if (!str->chars ||
4207         JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
4208 0         total = JS_ROUNDUP(total, URI_CHUNK);
4209 0         str->chars = JS_realloc(cx, str->chars, total * sizeof(jschar));
4210 0         if (!str->chars)
4211 0             return JS_FALSE;
4212     }
4213 0     js_strncpy(str->chars + str->length, chars, length);
4214 0     str->length += length;
4215 0     str->chars[str->length] = 0;
4216 0     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
4227 Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
4228        const jschar *unescapedSet2, jsval *rval)
4229 0 {
4230 0     size_t length, j, k, L;
4231 0     jschar *chars, C, C2;
4232 0     uint32 V;
4233 0     uint8 utf8buf[6];
4234 0     jschar hexBuf[4];
4235 0     static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
4236 0     JSString *R;
4237
4238 0     R = js_NewString(cx, NULL, 0, 0);
4239 0     if (!R)
4240 0         return JS_FALSE;
4241
4242 0     hexBuf[0] = '%';
4243 0     hexBuf[3] = 0;
4244 0     chars = JSSTRING_CHARS(str);
4245 0     length = JSSTRING_LENGTH(str);
4246 0     for (k = 0; k < length; k++) {
4247 0         C = chars[k];
4248 0         if (js_strchr(unescapedSet, C) ||
4249             (unescapedSet2 && js_strchr(unescapedSet2, C))) {
4250 0             if (!AddCharsToURI(cx, R, &C, 1))
4251 0                 return JS_FALSE;
4252         } else {
4253 0             if ((C >= 0xDC00) && (C <= 0xDFFF)) {
4254 0                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4255                                  JSMSG_BAD_URI, NULL);
4256 0                 return JS_FALSE;
4257             }
4258 0             if (C < 0xD800 || C > 0xDBFF) {
4259 0                 V = C;
4260             } else {
4261 0                 k++;
4262 0                 if (k == length) {
4263 0                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4264                                      JSMSG_BAD_URI, NULL);
4265 0                     return JS_FALSE;
4266                 }
4267 0                 C2 = chars[k];
4268 0                 if ((C2 < 0xDC00) || (C2 > 0xDFFF)) {
4269 0                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4270                                      JSMSG_BAD_URI, NULL);
4271 0                     return JS_FALSE;
4272                 }
4273 0                 V = ((C - 0xD800) << 10) + (C2 - 0xDC00) + 0x10000;
4274             }
4275 0             L = OneUcs4ToUtf8Char(utf8buf, V);
4276 0             for (j = 0; j < L; j++) {
4277 0                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
4278 0                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
4279 0                 if (!AddCharsToURI(cx, R, hexBuf, 3))
4280 0                     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 0     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
4291 0     if (chars)
4292 0         R->chars = chars;
4293 0     *rval = STRING_TO_JSVAL(R);
4294 0     return JS_TRUE;
4295 }
4296
4297 static JSBool
4298 Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
4299 0 {
4300 0     size_t length, start, k;
4301 0     jschar *chars, C, H;
4302 0     uint32 V;
4303 0     jsuint B;
4304 0     uint8 octets[6];
4305 0     JSString *R;
4306 0     intN j, n;
4307
4308 0     R = js_NewString(cx, NULL, 0, 0);
4309 0     if (!R)
4310 0         return JS_FALSE;
4311
4312 0     chars = JSSTRING_CHARS(str);
4313 0     length = JSSTRING_LENGTH(str);
4314 0     for (k = 0; k < length; k++) {
4315 0         C = chars[k];
4316 0         if (C == '%') {
4317 0             start = k;
4318 0             if ((k + 2) >= length)
4319 0                 goto bad;
4320 0             if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
4321 0                 goto bad;
4322 0             B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
4323 0             k += 2;
4324 0             if (!(B & 0x80)) {
4325 0                 C = (jschar)B;
4326             } else {
4327 0                 n = 1;
4328 0                 while (B & (0x80 >> n))
4329 0                     n++;
4330 0                 if (n == 1 || n > 6)
4331 0                     goto bad;
4332 0                 octets[0] = (uint8)B;
4333 0                 if (k + 3 * (n - 1) >= length)
4334 0                     goto bad;
4335 0                 for (j = 1; j < n; j++) {
4336 0                     k++;
4337 0                     if (chars[k] != '%')
4338 0                         goto bad;
4339 0                     if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
4340 0                         goto bad;
4341 0                     B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
4342 0                     if ((B & 0xC0) != 0x80)
4343 0                         goto bad;
4344 0                     k += 2;
4345 0                     octets[j] = (char)B;
4346                 }
4347 0                 V = Utf8ToOneUcs4Char(octets, n);
4348 0                 if (V >= 0x10000) {
4349 0                     V -= 0x10000;
4350 0                     if (V > 0xFFFFF)
4351 0                         goto bad;
4352 0                     C = (jschar)((V & 0x3FF) + 0xDC00);
4353 0                     H = (jschar)((V >> 10) + 0xD800);
4354 0                     if (!AddCharsToURI(cx, R, &H, 1))
4355 0                         return JS_FALSE;
4356                 } else {
4357 0                     C = (jschar)V;
4358                 }
4359             }
4360 0             if (js_strchr(reservedSet, C)) {
4361 0                 if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
4362 0                     return JS_FALSE;
4363             } else {
4364 0                 if (!AddCharsToURI(cx, R, &C, 1))
4365 0                     return JS_FALSE;
4366             }
4367         } else {
4368 0             if (!AddCharsToURI(cx, R, &C, 1))
4369 0                 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 0     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
4379 0     if (chars)
4380 0         R->chars = chars;
4381 0     *rval = STRING_TO_JSVAL(R);
4382 0     return JS_TRUE;
4383
4384 bad:
4385 0     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
4386 0     return JS_FALSE;
4387 }
4388
4389 static JSBool
4390 str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4391               jsval *rval)
4392 0 {
4393 0     JSString *str;
4394
4395 0     str = js_ValueToString(cx, argv[0]);
4396 0     if (!str)
4397 0         return JS_FALSE;
4398 0     return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval);
4399 }
4400
4401 static JSBool
4402 str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4403                         jsval *rval)
4404 0 {
4405 0     JSString *str;
4406
4407 0     str = js_ValueToString(cx, argv[0]);
4408 0     if (!str)
4409 0         return JS_FALSE;
4410 0     return Decode(cx, str, js_empty_ucstr, rval);
4411 }
4412
4413 static JSBool
4414 str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4415               jsval *rval)
4416 0 {
4417 0     JSString *str;
4418
4419 0     str = js_ValueToString(cx, argv[0]);
4420 0     if (!str)
4421 0         return JS_FALSE;
4422 0     return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
4423                   rval);
4424 }
4425
4426 static JSBool
4427 str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
4428                         jsval *rval)
4429 0 {
4430 0     JSString *str;
4431
4432 0     str = js_ValueToString(cx, argv[0]);
4433 0     if (!str)
4434 0         return JS_FALSE;
4435 0     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
4443 OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
4444 0 {
4445 0     int utf8Length = 1;
4446
4447 0     JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
4448 0     if (ucs4Char < 0x80) {
4449 0         *utf8Buffer = (uint8)ucs4Char;
4450     } else {
4451 0         int i;
4452 0         uint32 a = ucs4Char >> 11;
4453 0         utf8Length = 2;
4454 0         while (a) {
4455 0             a >>= 5;
4456 0             utf8Length++;
4457         }
4458 0         i = utf8Length;
4459 0         while (--i) {
4460 0             utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
4461 0             ucs4Char >>= 6;
4462         }
4463 0         *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
4464     }
4465 0     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
4474 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
4475 0 {
4476 0     uint32 ucs4Char;
4477 0     uint32 minucs4Char;
4478     /* from Unicode 3.1, non-shortest form is illegal */
4479     static const uint32 minucs4Table[] = {
4480         0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
4481 0     };
4482
4483 0     JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
4484 0     if (utf8Length == 1) {
4485 0         ucs4Char = *utf8Buffer;
4486 0         JS_ASSERT(!(ucs4Char & 0x80));
4487     } else {
4488 0         JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
4489                   (0x100 - (1 << (8-utf8Length))));
4490 0         ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
4491 0         minucs4Char = minucs4Table[utf8Length-2];
4492 0         while (--utf8Length) {
4493 0             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
4494 0             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
4495         }
4496 0         if (ucs4Char < minucs4Char || 
4497             ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
4498 0             ucs4Char = 0xFFFD;
4499         }
4500     }
4501 0     return ucs4Char;