]> rtime.felk.cvut.cz Git - hornmich/skoda-qr-demo.git/blob - QRScanner/mobile/jni/thirdparty/mujs/jsstring.c
Add MuPDF native source codes
[hornmich/skoda-qr-demo.git] / QRScanner / mobile / jni / thirdparty / mujs / jsstring.c
1 #include "jsi.h"
2 #include "jsvalue.h"
3 #include "jsbuiltin.h"
4 #include "utf.h"
5 #include "regex.h"
6
7 int js_runeat(js_State *J, const char *s, int i)
8 {
9         Rune rune = 0;
10         while (i-- >= 0) {
11                 rune = *(unsigned char*)s;
12                 if (rune < Runeself) {
13                         if (rune == 0)
14                                 return 0;
15                         ++s;
16                 } else
17                         s += chartorune(&rune, s);
18         }
19         return rune;
20 }
21
22 const char *js_utfidxtoptr(const char *s, int i)
23 {
24         Rune rune;
25         while (i-- > 0) {
26                 rune = *(unsigned char*)s;
27                 if (rune < Runeself) {
28                         if (rune == 0)
29                                 return NULL;
30                         ++s;
31                 } else
32                         s += chartorune(&rune, s);
33         }
34         return s;
35 }
36
37 int js_utfptrtoidx(const char *s, const char *p)
38 {
39         Rune rune;
40         int i = 0;
41         while (s < p) {
42                 if (*(unsigned char *)s < Runeself)
43                         ++s;
44                 else
45                         s += chartorune(&rune, s);
46                 ++i;
47         }
48         return i;
49 }
50
51 static void jsB_new_String(js_State *J)
52 {
53         js_newstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : "");
54 }
55
56 static void jsB_String(js_State *J)
57 {
58         js_pushstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : "");
59 }
60
61 static void Sp_toString(js_State *J)
62 {
63         js_Object *self = js_toobject(J, 0);
64         if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
65         js_pushliteral(J, self->u.s.string);
66 }
67
68 static void Sp_valueOf(js_State *J)
69 {
70         js_Object *self = js_toobject(J, 0);
71         if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
72         js_pushliteral(J, self->u.s.string);
73 }
74
75 static void Sp_charAt(js_State *J)
76 {
77         char buf[UTFmax + 1];
78         const char *s = js_tostring(J, 0);
79         int pos = js_tointeger(J, 1);
80         Rune rune = js_runeat(J, s, pos);
81         if (rune > 0) {
82                 buf[runetochar(buf, &rune)] = 0;
83                 js_pushstring(J, buf);
84         } else {
85                 js_pushliteral(J, "");
86         }
87 }
88
89 static void Sp_charCodeAt(js_State *J)
90 {
91         const char *s = js_tostring(J, 0);
92         int pos = js_tointeger(J, 1);
93         Rune rune = js_runeat(J, s, pos);
94         if (rune > 0)
95                 js_pushnumber(J, rune);
96         else
97                 js_pushnumber(J, NAN);
98 }
99
100 static void Sp_concat(js_State *J)
101 {
102         unsigned int i, top = js_gettop(J);
103         unsigned int n;
104         char * volatile out;
105         const char *s;
106
107         if (top == 1)
108                 return;
109
110         s = js_tostring(J, 0);
111         n = strlen(s);
112         out = js_malloc(J, n + 1);
113         strcpy(out, s);
114
115         if (js_try(J)) {
116                 js_free(J, out);
117                 js_throw(J);
118         }
119
120         for (i = 1; i < top; ++i) {
121                 s = js_tostring(J, i);
122                 n += strlen(s);
123                 out = realloc(out, n + 1);
124                 strcat(out, s);
125         }
126
127         js_pushstring(J, out);
128         js_endtry(J);
129         js_free(J, out);
130 }
131
132 static void Sp_indexOf(js_State *J)
133 {
134         const char *haystack = js_tostring(J, 0);
135         const char *needle = js_tostring(J, 1);
136         int pos = js_tointeger(J, 2);
137         int len = strlen(needle);
138         int k = 0;
139         Rune rune;
140         while (*haystack) {
141                 if (k >= pos && !strncmp(haystack, needle, len)) {
142                         js_pushnumber(J, k);
143                         return;
144                 }
145                 haystack += chartorune(&rune, haystack);
146                 ++k;
147         }
148         js_pushnumber(J, -1);
149 }
150
151 static void Sp_lastIndexOf(js_State *J)
152 {
153         const char *haystack = js_tostring(J, 0);
154         const char *needle = js_tostring(J, 1);
155         int pos = js_isdefined(J, 2) ? js_tointeger(J, 2) : strlen(haystack);
156         int len = strlen(needle);
157         int k = 0, last = -1;
158         Rune rune;
159         while (*haystack && k <= pos) {
160                 if (!strncmp(haystack, needle, len))
161                         last = k;
162                 haystack += chartorune(&rune, haystack);
163                 ++k;
164         }
165         js_pushnumber(J, last);
166 }
167
168 static void Sp_localeCompare(js_State *J)
169 {
170         const char *a = js_tostring(J, 0);
171         const char *b = js_tostring(J, 1);
172         js_pushnumber(J, strcmp(a, b));
173 }
174
175 static void Sp_slice(js_State *J)
176 {
177         const char *str = js_tostring(J, 0);
178         const char *ss, *ee;
179         int len = utflen(str);
180         int s = js_tointeger(J, 1);
181         int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
182
183         s = s < 0 ? s + len : s;
184         e = e < 0 ? e + len : e;
185
186         s = s < 0 ? 0 : s > len ? len : s;
187         e = e < 0 ? 0 : e > len ? len : e;
188
189         if (s < e) {
190                 ss = js_utfidxtoptr(str, s);
191                 ee = js_utfidxtoptr(ss, e - s);
192         } else {
193                 ss = js_utfidxtoptr(str, e);
194                 ee = js_utfidxtoptr(ss, s - e);
195         }
196
197         js_pushlstring(J, ss, ee - ss);
198 }
199
200 static void Sp_substring(js_State *J)
201 {
202         const char *str = js_tostring(J, 0);
203         const char *ss, *ee;
204         int len = utflen(str);
205         int s = js_tointeger(J, 1);
206         int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
207
208         s = s < 0 ? 0 : s > len ? len : s;
209         e = e < 0 ? 0 : e > len ? len : e;
210
211         if (s < e) {
212                 ss = js_utfidxtoptr(str, s);
213                 ee = js_utfidxtoptr(ss, e - s);
214         } else {
215                 ss = js_utfidxtoptr(str, e);
216                 ee = js_utfidxtoptr(ss, s - e);
217         }
218
219         js_pushlstring(J, ss, ee - ss);
220 }
221
222 static void Sp_toLowerCase(js_State *J)
223 {
224         const char *src = js_tostring(J, 0);
225         char *dst = js_malloc(J, UTFmax * strlen(src) + 1);
226         const char *s = src;
227         char *d = dst;
228         Rune rune;
229         while (*s) {
230                 s += chartorune(&rune, s);
231                 rune = tolowerrune(rune);
232                 d += runetochar(d, &rune);
233         }
234         *d = 0;
235         if (js_try(J)) {
236                 js_free(J, dst);
237                 js_throw(J);
238         }
239         js_pushstring(J, dst);
240         js_endtry(J);
241         js_free(J, dst);
242 }
243
244 static void Sp_toUpperCase(js_State *J)
245 {
246         const char *src = js_tostring(J, 0);
247         char *dst = js_malloc(J, UTFmax * strlen(src) + 1);
248         const char *s = src;
249         char *d = dst;
250         Rune rune;
251         while (*s) {
252                 s += chartorune(&rune, s);
253                 rune = toupperrune(rune);
254                 d += runetochar(d, &rune);
255         }
256         *d = 0;
257         if (js_try(J)) {
258                 js_free(J, dst);
259                 js_throw(J);
260         }
261         js_pushstring(J, dst);
262         js_endtry(J);
263         js_free(J, dst);
264 }
265
266 static int istrim(int c)
267 {
268         return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF ||
269                 c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
270 }
271
272 static void Sp_trim(js_State *J)
273 {
274         const char *s, *e;
275         s = js_tostring(J, 0);
276         while (istrim(*s))
277                 ++s;
278         e = s + strlen(s);
279         while (e > s && istrim(e[-1]))
280                 --e;
281         js_pushlstring(J, s, e - s);
282 }
283
284 static void S_fromCharCode(js_State *J)
285 {
286         unsigned int i, top = js_gettop(J);
287         Rune c;
288         char *s, *p;
289
290         s = p = js_malloc(J, (top-1) * UTFmax + 1);
291
292         if (js_try(J)) {
293                 js_free(J, s);
294                 js_throw(J);
295         }
296
297         for (i = 1; i < top; ++i) {
298                 c = js_touint16(J, i);
299                 p += runetochar(p, &c);
300         }
301         *p = 0;
302         js_pushstring(J, s);
303
304         js_endtry(J);
305         js_free(J, s);
306 }
307
308 static void Sp_match(js_State *J)
309 {
310         js_Regexp *re;
311         const char *text;
312         unsigned int len;
313         const char *a, *b, *c, *e;
314         Resub m;
315
316         text = js_tostring(J, 0);
317
318         if (js_isregexp(J, 1))
319                 js_copy(J, 1);
320         else if (js_isundefined(J, 1))
321                 js_newregexp(J, "", 0);
322         else
323                 js_newregexp(J, js_tostring(J, 1), 0);
324
325         re = js_toregexp(J, -1);
326         if (!(re->flags & JS_REGEXP_G)) {
327                 js_RegExp_prototype_exec(J, re, text);
328                 return;
329         }
330
331         re->last = 0;
332
333         js_newarray(J);
334
335         len = 0;
336         a = text;
337         e = text + strlen(text);
338         while (a <= e) {
339                 if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
340                         break;
341
342                 b = m.sub[0].sp;
343                 c = m.sub[0].ep;
344
345                 js_pushlstring(J, b, c - b);
346                 js_setindex(J, -2, len++);
347
348                 a = c;
349                 if (c - b == 0)
350                         ++a;
351         }
352 }
353
354 static void Sp_search(js_State *J)
355 {
356         js_Regexp *re;
357         const char *text;
358         Resub m;
359
360         text = js_tostring(J, 0);
361
362         if (js_isregexp(J, 1))
363                 js_copy(J, 1);
364         else if (js_isundefined(J, 1))
365                 js_newregexp(J, "", 0);
366         else
367                 js_newregexp(J, js_tostring(J, 1), 0);
368
369         re = js_toregexp(J, -1);
370
371         if (!js_regexec(re->prog, text, &m, 0))
372                 js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp));
373         else
374                 js_pushnumber(J, -1);
375 }
376
377 static void Sp_replace_regexp(js_State *J)
378 {
379         js_Regexp *re;
380         const char *source, *s, *r;
381         js_Buffer *sb = NULL;
382         unsigned int n, x;
383         Resub m;
384
385         source = js_tostring(J, 0);
386         re = js_toregexp(J, 1);
387
388         if (js_regexec(re->prog, source, &m, 0)) {
389                 js_copy(J, 0);
390                 return;
391         }
392
393         re->last = 0;
394
395 loop:
396         s = m.sub[0].sp;
397         n = m.sub[0].ep - m.sub[0].sp;
398
399         if (js_iscallable(J, 2)) {
400                 js_copy(J, 2);
401                 js_pushundefinedthis(J);
402                 for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */
403                         js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp);
404                 js_pushnumber(J, s - source); /* arg x+2: offset within search string */
405                 js_copy(J, 0); /* arg x+3: search string */
406                 js_call(J, 2 + x);
407                 r = js_tostring(J, -1);
408                 js_putm(J, &sb, source, s);
409                 js_puts(J, &sb, r);
410                 js_pop(J, 1);
411         } else {
412                 r = js_tostring(J, 2);
413                 js_putm(J, &sb, source, s);
414                 while (*r) {
415                         if (*r == '$') {
416                                 switch (*(++r)) {
417                                 case '$': js_putc(J, &sb, '$'); break;
418                                 case '`': js_putm(J, &sb, source, s); break;
419                                 case '\'': js_puts(J, &sb, s + n); break;
420                                 case '&':
421                                         js_putm(J, &sb, s, s + n);
422                                         break;
423                                 case '0': case '1': case '2': case '3': case '4':
424                                 case '5': case '6': case '7': case '8': case '9':
425                                         x = *r - '0';
426                                         if (r[1] >= '0' && r[1] <= '9')
427                                                 x = x * 10 + *(++r) - '0';
428                                         if (x > 0 && x < m.nsub) {
429                                                 js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep);
430                                         } else {
431                                                 js_putc(J, &sb, '$');
432                                                 if (x > 10) {
433                                                         js_putc(J, &sb, '0' + x / 10);
434                                                         js_putc(J, &sb, '0' + x % 10);
435                                                 } else {
436                                                         js_putc(J, &sb, '0' + x);
437                                                 }
438                                         }
439                                         break;
440                                 default:
441                                         js_putc(J, &sb, '$');
442                                         js_putc(J, &sb, *r);
443                                         break;
444                                 }
445                                 ++r;
446                         } else {
447                                 js_putc(J, &sb, *r++);
448                         }
449                 }
450         }
451
452         if (re->flags & JS_REGEXP_G) {
453                 source = m.sub[0].ep;
454                 if (n == 0) {
455                         if (*source)
456                                 js_putc(J, &sb, *source++);
457                         else
458                                 goto end;
459                 }
460                 if (!js_regexec(re->prog, source, &m, REG_NOTBOL))
461                         goto loop;
462         }
463
464 end:
465         js_puts(J, &sb, s + n);
466         js_putc(J, &sb, 0);
467
468         if (js_try(J)) {
469                 js_free(J, sb);
470                 js_throw(J);
471         }
472         js_pushstring(J, sb ? sb->s : "");
473         js_endtry(J);
474         js_free(J, sb);
475 }
476
477 static void Sp_replace_string(js_State *J)
478 {
479         const char *source, *needle, *s, *r;
480         js_Buffer *sb = NULL;
481         int n;
482
483         source = js_tostring(J, 0);
484         needle = js_tostring(J, 1);
485
486         s = strstr(source, needle);
487         if (!s) {
488                 js_copy(J, 0);
489                 return;
490         }
491         n = strlen(needle);
492
493         if (js_iscallable(J, 2)) {
494                 js_copy(J, 2);
495                 js_pushundefinedthis(J);
496                 js_pushlstring(J, s, n); /* arg 1: substring that matched */
497                 js_pushnumber(J, s - source); /* arg 2: offset within search string */
498                 js_copy(J, 0); /* arg 3: search string */
499                 js_call(J, 3);
500                 r = js_tostring(J, -1);
501                 js_putm(J, &sb, source, s);
502                 js_puts(J, &sb, r);
503                 js_puts(J, &sb, s + n);
504                 js_putc(J, &sb, 0);
505                 js_pop(J, 1);
506         } else {
507                 r = js_tostring(J, 2);
508                 js_putm(J, &sb, source, s);
509                 while (*r) {
510                         if (*r == '$') {
511                                 switch (*(++r)) {
512                                 case '$': js_putc(J, &sb, '$'); break;
513                                 case '&': js_putm(J, &sb, s, s + n); break;
514                                 case '`': js_putm(J, &sb, source, s); break;
515                                 case '\'': js_puts(J, &sb, s + n); break;
516                                 default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break;
517                                 }
518                                 ++r;
519                         } else {
520                                 js_putc(J, &sb, *r++);
521                         }
522                 }
523                 js_puts(J, &sb, s + n);
524                 js_putc(J, &sb, 0);
525         }
526
527         if (js_try(J)) {
528                 js_free(J, sb);
529                 js_throw(J);
530         }
531         js_pushstring(J, sb ? sb->s : "");
532         js_endtry(J);
533         js_free(J, sb);
534 }
535
536 static void Sp_replace(js_State *J)
537 {
538         if (js_isregexp(J, 1))
539                 Sp_replace_regexp(J);
540         else
541                 Sp_replace_string(J);
542 }
543
544 static void Sp_split_regexp(js_State *J)
545 {
546         js_Regexp *re;
547         const char *text;
548         unsigned int limit, len, k;
549         const char *p, *a, *b, *c, *e;
550         Resub m;
551
552         text = js_tostring(J, 0);
553         re = js_toregexp(J, 1);
554         limit = js_isdefined(J, 2) ? js_touint32(J, 2) : 1 << 30;
555
556         js_newarray(J);
557         len = 0;
558
559         e = text + strlen(text);
560
561         /* splitting the empty string */
562         if (e == text) {
563                 if (js_regexec(re->prog, text, &m, 0)) {
564                         if (len == limit) return;
565                         js_pushliteral(J, "");
566                         js_setindex(J, -2, 0);
567                 }
568                 return;
569         }
570
571         p = a = text;
572         while (a < e) {
573                 if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
574                         break; /* no match */
575
576                 b = m.sub[0].sp;
577                 c = m.sub[0].ep;
578
579                 /* empty string at end of last match */
580                 if (b == p) {
581                         ++a;
582                         continue;
583                 }
584
585                 if (len == limit) return;
586                 js_pushlstring(J, p, b - p);
587                 js_setindex(J, -2, len++);
588
589                 for (k = 1; k < m.nsub; ++k) {
590                         if (len == limit) return;
591                         js_pushlstring(J, m.sub[k].sp, m.sub[k].ep - m.sub[k].sp);
592                         js_setindex(J, -2, len++);
593                 }
594
595                 a = p = c;
596         }
597
598         if (len == limit) return;
599         js_pushstring(J, p);
600         js_setindex(J, -2, len);
601 }
602
603 static void Sp_split_string(js_State *J)
604 {
605         const char *str = js_tostring(J, 0);
606         const char *sep = js_tostring(J, 1);
607         unsigned int limit = js_isdefined(J, 2) ? js_touint32(J, 2) : 1 << 30;
608         unsigned int i, n;
609
610         js_newarray(J);
611
612         n = strlen(sep);
613
614         /* empty string */
615         if (n == 0) {
616                 Rune rune;
617                 for (i = 0; *str && i < limit; ++i) {
618                         n = chartorune(&rune, str);
619                         js_pushlstring(J, str, n);
620                         js_setindex(J, -2, i);
621                         str += n;
622                 }
623                 return;
624         }
625
626         for (i = 0; str && i < limit; ++i) {
627                 const char *s = strstr(str, sep);
628                 if (s) {
629                         js_pushlstring(J, str, s-str);
630                         js_setindex(J, -2, i);
631                         str = s + n;
632                 } else {
633                         js_pushstring(J, str);
634                         js_setindex(J, -2, i);
635                         str = NULL;
636                 }
637         }
638 }
639
640 static void Sp_split(js_State *J)
641 {
642         if (js_isundefined(J, 1)) {
643                 js_newarray(J);
644                 js_copy(J, 0);
645                 js_setindex(J, -2, 0);
646         } else if (js_isregexp(J, 1)) {
647                 Sp_split_regexp(J);
648         } else {
649                 Sp_split_string(J);
650         }
651 }
652
653 void jsB_initstring(js_State *J)
654 {
655         J->String_prototype->u.s.string = "";
656         J->String_prototype->u.s.length = 0;
657
658         js_pushobject(J, J->String_prototype);
659         {
660                 jsB_propf(J, "toString", Sp_toString, 0);
661                 jsB_propf(J, "valueOf", Sp_valueOf, 0);
662                 jsB_propf(J, "charAt", Sp_charAt, 1);
663                 jsB_propf(J, "charCodeAt", Sp_charCodeAt, 1);
664                 jsB_propf(J, "concat", Sp_concat, 1);
665                 jsB_propf(J, "indexOf", Sp_indexOf, 1);
666                 jsB_propf(J, "lastIndexOf", Sp_lastIndexOf, 1);
667                 jsB_propf(J, "localeCompare", Sp_localeCompare, 1);
668                 jsB_propf(J, "match", Sp_match, 1);
669                 jsB_propf(J, "replace", Sp_replace, 2);
670                 jsB_propf(J, "search", Sp_search, 1);
671                 jsB_propf(J, "slice", Sp_slice, 2);
672                 jsB_propf(J, "split", Sp_split, 2);
673                 jsB_propf(J, "substring", Sp_substring, 2);
674                 jsB_propf(J, "toLowerCase", Sp_toLowerCase, 0);
675                 jsB_propf(J, "toLocaleLowerCase", Sp_toLowerCase, 0);
676                 jsB_propf(J, "toUpperCase", Sp_toUpperCase, 0);
677                 jsB_propf(J, "toLocaleUpperCase", Sp_toUpperCase, 0);
678
679                 /* ES5 */
680                 jsB_propf(J, "trim", Sp_trim, 0);
681         }
682         js_newcconstructor(J, jsB_String, jsB_new_String, "String", 1);
683         {
684                 jsB_propf(J, "fromCharCode", S_fromCharCode, 1);
685         }
686         js_defglobal(J, "String", JS_DONTENUM);
687 }