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