add swfdec_as_string_escape() function
[swfdec.git] / libswfdec / swfdec_as_string.c
blob59883696acbd5b56c910098ff45c027024f1f282
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <math.h>
25 #include <string.h>
27 #include "swfdec_as_string.h"
28 #include "swfdec_as_array.h"
29 #include "swfdec_as_context.h"
30 #include "swfdec_as_native_function.h"
31 #include "swfdec_as_strings.h"
32 #include "swfdec_debug.h"
33 #include "swfdec_player_internal.h"
35 G_DEFINE_TYPE (SwfdecAsString, swfdec_as_string, SWFDEC_TYPE_AS_OBJECT)
37 static void
38 swfdec_as_string_do_mark (SwfdecAsObject *object)
40 SwfdecAsString *string = SWFDEC_AS_STRING (object);
42 swfdec_as_string_mark (string->string);
44 SWFDEC_AS_OBJECT_CLASS (swfdec_as_string_parent_class)->mark (object);
47 static char *
48 swfdec_as_string_debug (SwfdecAsObject *object)
50 SwfdecAsString *string = SWFDEC_AS_STRING (object);
52 return g_strdup (string->string);
55 static void
56 swfdec_as_string_class_init (SwfdecAsStringClass *klass)
58 SwfdecAsObjectClass *asobject_class = SWFDEC_AS_OBJECT_CLASS (klass);
60 asobject_class->mark = swfdec_as_string_do_mark;
61 asobject_class->debug = swfdec_as_string_debug;
64 static void
65 swfdec_as_string_init (SwfdecAsString *string)
67 string->string = SWFDEC_AS_STR_EMPTY;
70 /*** AS CODE ***/
72 static const char *
73 swfdec_as_string_object_to_string (SwfdecAsContext *context,
74 SwfdecAsObject *object)
76 SwfdecAsValue val;
78 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object), NULL);
80 SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
82 return swfdec_as_value_to_string (context, &val);
85 static inline const char *
86 swfdec_as_str_nth_char (const char *s, guint n)
88 while (*s && n--)
89 s = g_utf8_next_char (s);
90 return s;
93 SWFDEC_AS_NATIVE (251, 9, swfdec_as_string_lastIndexOf)
94 void
95 swfdec_as_string_lastIndexOf (SwfdecAsContext *cx, SwfdecAsObject *object,
96 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
98 const char *string = swfdec_as_string_object_to_string (cx, object);
99 gsize len;
100 const char *s;
102 s = swfdec_as_value_to_string (object->context, &argv[0]);
103 if (argc == 2) {
104 int offset = swfdec_as_value_to_integer (object->context, &argv[1]);
105 if (offset < 0) {
106 SWFDEC_AS_VALUE_SET_INT (ret, -1);
107 return;
109 len = g_utf8_offset_to_pointer (string, offset + 1) - string;
110 } else {
111 len = G_MAXSIZE;
113 s = g_strrstr_len (string, len, s);
114 if (s) {
115 SWFDEC_AS_VALUE_SET_INT (ret, g_utf8_pointer_to_offset (string, s));
116 } else {
117 SWFDEC_AS_VALUE_SET_INT (ret, -1);
121 SWFDEC_AS_NATIVE (251, 8, swfdec_as_string_indexOf)
122 void
123 swfdec_as_string_indexOf (SwfdecAsContext *cx, SwfdecAsObject *object,
124 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
126 const char *string = swfdec_as_string_object_to_string (cx, object);
127 int offset=0, len, i=-1;
128 const char *s, *t = NULL;
130 s = swfdec_as_value_to_string (object->context, &argv[0]);
131 if (argc == 2)
132 offset = swfdec_as_value_to_integer (object->context, &argv[1]);
133 if (offset < 0)
134 offset = 0;
135 len = g_utf8_strlen (string, -1);
136 if (offset < len) {
137 t = strstr (g_utf8_offset_to_pointer (string, offset), s);
139 if (t != NULL) {
140 i = g_utf8_pointer_to_offset (string, t);
143 SWFDEC_AS_VALUE_SET_INT (ret, i);
146 SWFDEC_AS_NATIVE (251, 5, swfdec_as_string_charAt)
147 void
148 swfdec_as_string_charAt (SwfdecAsContext *cx, SwfdecAsObject *object,
149 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
151 const char *string = swfdec_as_string_object_to_string (cx, object);
152 int i;
153 const char *s, *t;
155 i = swfdec_as_value_to_integer (object->context, &argv[0]);
156 if (i < 0) {
157 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
158 return;
160 s = swfdec_as_str_nth_char (string, i);
161 if (*s == 0) {
162 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
163 return;
165 t = g_utf8_next_char (s);
166 s = swfdec_as_context_give_string (cx, g_strndup (s, t - s));
167 SWFDEC_AS_VALUE_SET_STRING (ret, s);
170 SWFDEC_AS_NATIVE (251, 6, swfdec_as_string_charCodeAt)
171 void
172 swfdec_as_string_charCodeAt (SwfdecAsContext *cx, SwfdecAsObject *object,
173 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
175 const char *string = swfdec_as_string_object_to_string (cx, object);
176 int i;
177 const char *s;
178 gunichar c;
180 i = swfdec_as_value_to_integer (cx, &argv[0]);
181 if (i < 0) {
182 SWFDEC_AS_VALUE_SET_NUMBER (ret, NAN);
183 return;
185 s = swfdec_as_str_nth_char (string, i);
186 if (*s == 0) {
187 if (cx->version > 5) {
188 SWFDEC_AS_VALUE_SET_NUMBER (ret, NAN);
189 } else {
190 SWFDEC_AS_VALUE_SET_INT (ret, 0);
192 return;
194 c = g_utf8_get_char (s);
195 SWFDEC_AS_VALUE_SET_NUMBER (ret, c);
198 static void
199 swfdec_as_string_fromCharCode_5 (SwfdecAsContext *cx, SwfdecAsObject *object,
200 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
202 guint i, c;
203 guint8 append;
204 GError *error = NULL;
205 char *s;
206 GByteArray *array = g_byte_array_new ();
208 for (i = 0; i < argc; i++) {
209 c = ((guint) swfdec_as_value_to_integer (cx, &argv[i])) % 65536;
210 if (c > 255) {
211 append = c / 256;
212 g_byte_array_append (array, &append, 1);
214 append = c;
215 g_byte_array_append (array, &append, 1);
218 /* FIXME: are these the correct charset names? */
219 s = g_convert ((char *) array->data, array->len, "UTF-8", "LATIN1", NULL, NULL, &error);
220 if (s) {
221 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s));
222 g_free (s);
223 } else {
224 SWFDEC_ERROR ("%s", error->message);
225 g_error_free (error);
227 g_byte_array_free (array, TRUE);
230 static void
231 swfdec_as_string_fromCharCode (SwfdecAsContext *cx, SwfdecAsObject *object,
232 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
234 gunichar tmp[8];
235 gunichar *chars;
236 guint i;
237 char *s;
238 GError *error = NULL;
240 if (argc <= 8)
241 chars = tmp;
242 else
243 chars = g_new (gunichar, argc);
245 for (i = 0; i < argc; i++) {
246 chars[i] = ((guint) swfdec_as_value_to_integer (cx, &argv[i])) % 65536;
249 s = g_ucs4_to_utf8 (chars, argc, NULL, NULL, &error);
250 if (s) {
251 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s));
252 g_free (s);
253 } else {
254 SWFDEC_ERROR ("%s", error->message);
255 g_error_free (error);
258 if (chars != tmp)
259 g_free (chars);
262 static void
263 swfdec_as_string_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
264 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
266 const char *s;
268 if (argc > 0) {
269 s = swfdec_as_value_to_string (cx, &argv[0]);
270 } else {
271 s = SWFDEC_AS_STR_EMPTY;
274 if (swfdec_as_context_is_constructing (cx)) {
275 SwfdecAsString *string = SWFDEC_AS_STRING (object);
276 SwfdecAsValue val;
278 string->string = s;
279 SWFDEC_AS_VALUE_SET_INT (&val, g_utf8_strlen (string->string, -1));
280 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_length, &val);
281 SWFDEC_AS_VALUE_SET_OBJECT (ret, object);
282 } else {
283 SWFDEC_AS_VALUE_SET_STRING (ret, s);
287 SWFDEC_AS_NATIVE (251, 2, swfdec_as_string_toString)
288 void
289 swfdec_as_string_toString (SwfdecAsContext *cx, SwfdecAsObject *object,
290 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
292 SwfdecAsString *string = SWFDEC_AS_STRING (object);
294 SWFDEC_AS_VALUE_SET_STRING (ret, string->string);
297 SWFDEC_AS_NATIVE (251, 1, swfdec_as_string_valueOf)
298 void
299 swfdec_as_string_valueOf (SwfdecAsContext *cx, SwfdecAsObject *object,
300 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
302 SwfdecAsString *string = SWFDEC_AS_STRING (object);
304 SWFDEC_AS_VALUE_SET_STRING (ret, string->string);
307 #if 0
308 charAt(index:Number) : String
309 charCodeAt(index:Number) : Number
310 concat(value:Object) : String
311 indexOf(value:String, [startIndex:Number]) : Number
312 slice(start:Number, end:Number) : String
313 split(delimiter:String, [limit:Number]) : Array
314 #endif
316 static void
317 swfdec_as_string_split_5 (SwfdecAsContext *cx, SwfdecAsObject *object,
318 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
320 SwfdecAsArray *arr;
321 SwfdecAsValue val;
322 const char *str, *end, *delim;
323 int count;
325 str = swfdec_as_string_object_to_string (cx, object);
326 arr = SWFDEC_AS_ARRAY (swfdec_as_array_new (cx));
327 if (arr == NULL)
328 return;
329 SWFDEC_AS_VALUE_SET_OBJECT (ret, SWFDEC_AS_OBJECT (arr));
330 /* hi, i'm the special case */
331 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0])) {
332 delim = SWFDEC_AS_STR_COMMA;
333 } else {
334 delim = swfdec_as_value_to_string (cx, &argv[0]);
336 if (delim == SWFDEC_AS_STR_EMPTY) {
337 SWFDEC_AS_VALUE_SET_STRING (&val, str);
338 swfdec_as_array_push (arr, &val);
339 return;
341 if (argc > 1) {
342 swfdec_as_value_to_string (cx, &argv[0]);
343 count = swfdec_as_value_to_integer (cx, &argv[1]);
344 } else {
345 count = G_MAXINT;
347 if (count <= 0)
348 return;
349 if (str == SWFDEC_AS_STR_EMPTY || delim[1] != 0) {
350 SWFDEC_AS_VALUE_SET_STRING (&val, str);
351 swfdec_as_array_push (arr, &val);
352 return;
354 while (*str && count > 0) {
355 end = strchr (str, delim[0]);
356 if (end == NULL) {
357 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str));
358 swfdec_as_array_push (arr, &val);
359 break;
361 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str)));
362 swfdec_as_array_push (arr, &val);
363 if (count)
364 count--;
365 str = end + 1;
369 static void
370 swfdec_as_string_split_6 (SwfdecAsContext *cx, SwfdecAsObject *object,
371 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
373 SwfdecAsArray *arr;
374 SwfdecAsValue val;
375 const char *str, *end, *delim;
376 int count;
377 guint len;
379 str = swfdec_as_string_object_to_string (cx, object);
380 arr = SWFDEC_AS_ARRAY (swfdec_as_array_new (cx));
381 if (arr == NULL)
382 return;
383 SWFDEC_AS_VALUE_SET_OBJECT (ret, SWFDEC_AS_OBJECT (arr));
384 /* hi, i'm the special case */
385 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0])) {
386 SWFDEC_AS_VALUE_SET_STRING (&val, str);
387 swfdec_as_array_push (arr, &val);
388 return;
390 delim = swfdec_as_value_to_string (cx, &argv[0]);
391 if (str == SWFDEC_AS_STR_EMPTY) {
392 SWFDEC_AS_VALUE_SET_STRING (&val, str);
393 swfdec_as_array_push (arr, &val);
394 return;
396 if (argc > 1)
397 count = swfdec_as_value_to_integer (cx, &argv[1]);
398 else
399 count = G_MAXINT;
400 if (count <= 0)
401 return;
402 len = strlen (delim);
403 while (count > 0) {
404 if (delim == SWFDEC_AS_STR_EMPTY) {
405 if (*str)
406 end = str + 1;
407 else
408 break;
409 } else {
410 end = strstr (str, delim);
411 if (end == NULL) {
412 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str));
413 swfdec_as_array_push (arr, &val);
414 break;
417 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str)));
418 swfdec_as_array_push (arr, &val);
419 if (count)
420 count--;
421 str = end + len;
425 SWFDEC_AS_NATIVE (251, 12, swfdec_as_string_split)
426 void
427 swfdec_as_string_split (SwfdecAsContext *cx, SwfdecAsObject *object,
428 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
430 if (cx->version == 5) {
431 swfdec_as_string_split_5 (cx, object, argc, argv, ret);
432 } else {
433 swfdec_as_string_split_6 (cx, object, argc, argv, ret);
437 static const char *
438 swfdec_as_str_sub (SwfdecAsContext *cx, const char *str, guint offset, guint len)
440 const char *end;
442 str = g_utf8_offset_to_pointer (str, offset);
443 end = g_utf8_offset_to_pointer (str, len);
444 str = swfdec_as_context_give_string (cx, g_strndup (str, end - str));
445 return str;
448 SWFDEC_AS_NATIVE (251, 13, swfdec_as_string_substr)
449 void
450 swfdec_as_string_substr (SwfdecAsContext *cx, SwfdecAsObject *object,
451 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
453 const char *string = swfdec_as_string_object_to_string (cx, object);
454 int from, to, len;
456 from = swfdec_as_value_to_integer (cx, &argv[0]);
457 len = g_utf8_strlen (string, -1);
459 if (argc > 1) {
460 to = swfdec_as_value_to_integer (cx, &argv[1]);
461 /* FIXME: wtf? */
462 if (to < 0) {
463 if (-to <= from)
464 to = 0;
465 else
466 to += len;
467 if (to < 0)
468 to = 0;
469 if (from < 0 && to >= -from)
470 to = 0;
472 } else {
473 to = G_MAXINT;
475 if (from < 0)
476 from += len;
477 from = CLAMP (from, 0, len);
478 to = CLAMP (to, 0, len - from);
479 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to));
482 SWFDEC_AS_NATIVE (251, 11, swfdec_as_string_substring)
483 void
484 swfdec_as_string_substring (SwfdecAsContext *cx, SwfdecAsObject *object,
485 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
487 const char *string = swfdec_as_string_object_to_string (cx, object);
488 int from, to, len;
490 len = g_utf8_strlen (string, -1);
491 from = swfdec_as_value_to_integer (cx, &argv[0]);
492 if (argc > 1) {
493 to = swfdec_as_value_to_integer (cx, &argv[1]);
494 } else {
495 to = len;
497 from = MAX (from, 0);
498 if (from >= len) {
499 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
500 return;
502 to = CLAMP (to, 0, len);
503 if (to < from) {
504 int tmp = to;
505 to = from;
506 from = tmp;
508 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to - from));
511 SWFDEC_AS_NATIVE (251, 4, swfdec_as_string_toLowerCase)
512 void
513 swfdec_as_string_toLowerCase (SwfdecAsContext *cx, SwfdecAsObject *object,
514 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
516 const char *string = swfdec_as_string_object_to_string (cx, object);
517 char *s;
519 s = g_utf8_strdown (string, -1);
520 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s));
521 g_free (s);
524 SWFDEC_AS_NATIVE (251, 3, swfdec_as_string_toUpperCase)
525 void
526 swfdec_as_string_toUpperCase (SwfdecAsContext *cx, SwfdecAsObject *object,
527 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
529 const char *string = swfdec_as_string_object_to_string (cx, object);
530 char *s;
532 s = g_utf8_strup (string, -1);
533 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s));
534 g_free (s);
537 /* escape and unescape are implemented here so the mad string functions share the same place */
539 static char *
540 swfdec_as_string_unescape_5 (SwfdecAsContext *cx, const char *msg)
542 GByteArray *array;
543 char cur = 0; /* currently decoded character */
544 char *out, *in, *s;
545 guint decoding = 0; /* set if we're decoding a %XY string */
547 /* attention: c is a char* */
548 #define APPEND(chr) G_STMT_START{ \
549 g_byte_array_append (array, (guchar *) chr, 1); \
550 }G_STMT_END
551 array = g_byte_array_new ();
552 in = s = g_convert (msg, -1, "LATIN1", "UTF-8", NULL, NULL, NULL);
553 if (s == NULL) {
554 SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", msg);
555 return NULL;
557 while (*s != 0) {
558 if (decoding) {
559 decoding++;
560 if (*s >= '0' && *s <= '9') {
561 cur = cur * 16 + *s - '0';
562 } else if (*s >= 'A' && *s <= 'F') {
563 cur = cur * 16 + *s - 'A' + 10;
564 } else if (*s >= 'a' && *s <= 'f') {
565 cur = cur * 16 + *s - 'a' + 10;
566 } else {
567 cur = 0;
568 decoding = 0;
570 if (decoding == 3) {
571 APPEND (&cur);
572 cur = 0;
573 decoding = 0;
575 } else if (*s == '%') {
576 decoding = 1;
577 } else if (*s == '+') {
578 char tmp = ' ';
579 APPEND (&tmp);
580 } else {
581 APPEND (s);
583 s++;
585 g_free (in);
586 if (array->len == 0)
587 return NULL;
588 cur = 0;
589 g_byte_array_append (array, (guchar *) &cur, 1);
590 out = g_convert ((char *) array->data, -1, "UTF-8", "LATIN1", NULL, NULL, NULL);
591 g_byte_array_free (array, TRUE);
592 if (out) {
593 return out;
594 } else {
595 g_warning ("can't convert %s to UTF-8", msg);
596 g_free (out);
597 return g_strdup ("");
599 #undef APPEND
602 char *
603 swfdec_as_string_escape (SwfdecAsContext *cx, const char *s)
605 GByteArray *array;
606 char *in = NULL;
608 array = g_byte_array_new ();
609 if (cx->version <= 5) {
610 in = g_convert (s, -1, "LATIN1", "UTF-8", NULL, NULL, NULL);
611 if (s == NULL) {
612 SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", s);
613 return NULL;
614 } else {
615 s = in;
618 while (*s) {
619 if ((*s >= '0' && *s <= '9') ||
620 (*s >= 'A' && *s <= 'Z') ||
621 (*s >= 'a' && *s <= 'z')) {
622 g_byte_array_append (array, (guchar *) s, 1);
623 } else {
624 guchar add[3] = { '%', 0, 0 };
625 add[1] = (guchar) *s / 16;
626 add[2] = (guchar) *s % 16;
627 add[1] += add[1] < 10 ? '0' : ('A' - 10);
628 add[2] += add[2] < 10 ? '0' : ('A' - 10);
629 g_byte_array_append (array, add, 3);
631 s++;
633 g_byte_array_append (array, (guchar *) s, 1);
634 g_free (in);
635 return (char *) g_byte_array_free (array, FALSE);
638 static void
639 swfdec_as_string_escape_internal (SwfdecAsContext *cx, SwfdecAsObject *object,
640 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
642 char *result;
644 result =
645 swfdec_as_string_escape (cx, swfdec_as_value_to_string (cx, &argv[0]));
646 if (result != NULL) {
647 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result));
648 g_free (result);
649 } else {
650 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
654 static char *
655 swfdec_as_string_unescape_6 (SwfdecAsContext *cx, const char *s)
657 GByteArray *array;
658 const char *msg;
659 char cur = 0; /* currently decoded character */
660 guint decoding = 0; /* set if we're decoding a %XY string */
661 guint utf8left = 0; /* how many valid utf8 chars are still required */
662 const guchar invalid[3] = { 0xEF, 0xBF, 0xBD };
664 /* attention: c is a char* */
665 #define APPEND(chr) G_STMT_START{ \
666 guchar c = *chr; \
667 if (utf8left) { \
668 if ((c & 0xC0) == 0x80) { \
669 g_byte_array_append (array, &c, 1); \
670 utf8left--; \
671 } else { \
672 guint __len = array->len - 1; \
673 while ((array->data[__len] & 0xC0) != 0xC0) \
674 __len--; \
675 g_byte_array_set_size (array, __len); \
676 g_byte_array_append (array, invalid, 3); \
677 utf8left = 0; \
679 } else { \
680 if (c < 0x80) { \
681 g_byte_array_append (array, &c, 1); \
682 } else if (c < 0xC0) { \
683 guchar __foo = 0xC2; \
684 g_byte_array_append (array, &__foo, 1); \
685 g_byte_array_append (array, &c, 1); \
686 } else if (c > 0xF7) { \
687 break; \
688 } else { \
689 g_byte_array_append (array, &c, 1); \
690 utf8left = (c < 0xE0) ? 1 : ((c < 0xF0) ? 2 : 3); \
693 }G_STMT_END
694 array = g_byte_array_new ();
695 msg = s;
696 while (*s != 0) {
697 if (decoding) {
698 decoding++;
699 if (*s >= '0' && *s <= '9') {
700 cur = cur * 16 + *s - '0';
701 } else if (*s >= 'A' && *s <= 'F') {
702 cur = cur * 16 + *s - 'A' + 10;
703 } else if (*s >= 'a' && *s <= 'f') {
704 cur = cur * 16 + *s - 'a' + 10;
705 } else {
706 cur = 0;
707 decoding = 0;
708 if ((guchar) *s > 0x7F) {
709 APPEND (s);
712 if (decoding == 3) {
713 APPEND (&cur);
714 cur = 0;
715 decoding = 0;
717 } else if (*s == '%') {
718 decoding = 1;
719 } else if (*s == '+') {
720 char tmp = ' ';
721 APPEND (&tmp);
722 } else {
723 APPEND (s);
725 s++;
727 cur = 0;
728 /* loop for break statement in APPEND macro */
729 if (utf8left) {
730 guint __len = array->len - 1;
731 while ((array->data[__len] & 0xC0) != 0xC0)
732 __len--;
733 g_byte_array_set_size (array, __len);
735 g_byte_array_append (array, (guchar *) &cur, 1);
736 if (g_utf8_validate ((char *) array->data, -1, NULL)) {
737 return (char *) g_byte_array_free (array, FALSE);
738 } else {
739 g_warning ("%s unescaped is invalid UTF-8", msg);
740 g_byte_array_free (array, TRUE);
741 return g_strdup ("");
743 #undef APPEND
746 char *
747 swfdec_as_string_unescape (SwfdecAsContext *context, const char *string)
749 if (context->version < 6) {
750 return swfdec_as_string_unescape_5 (context, string);
751 } else {
752 return swfdec_as_string_unescape_6 (context, string);
756 static void
757 swfdec_as_string_unescape_internal (SwfdecAsContext *cx, SwfdecAsObject *object,
758 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
760 char *result;
762 result =
763 swfdec_as_string_unescape (cx, swfdec_as_value_to_string (cx, &argv[0]));
764 if (result != NULL) {
765 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result));
766 g_free (result);
767 } else {
768 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
772 void
773 swfdec_as_string_init_context (SwfdecAsContext *context, guint version)
775 SwfdecAsObject *string, *proto;
776 SwfdecAsValue val;
778 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
780 proto = swfdec_as_object_new_empty (context);
781 if (proto == NULL)
782 return;
783 string = SWFDEC_AS_OBJECT (swfdec_as_object_add_constructor (context->global,
784 SWFDEC_AS_STR_String, 0, SWFDEC_TYPE_AS_STRING,
785 swfdec_as_string_construct, 0, proto));
786 if (!string)
787 return;
788 /* set the right properties on the String object */
789 if (version <= 5) {
790 swfdec_as_object_add_function (string, SWFDEC_AS_STR_fromCharCode, 0, swfdec_as_string_fromCharCode_5, 0);
791 } else {
792 swfdec_as_object_add_function (string, SWFDEC_AS_STR_fromCharCode, 0, swfdec_as_string_fromCharCode, 0);
795 /* set the right properties on the String.prototype object */
796 SWFDEC_AS_VALUE_SET_OBJECT (&val, string);
797 swfdec_as_object_set_variable_and_flags (proto, SWFDEC_AS_STR_constructor,
798 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
799 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_charAt, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_charAt, 1);
800 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_indexOf, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_indexOf, 1);
801 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_lastIndexOf, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_lastIndexOf, 1);
802 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_charCodeAt, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_charCodeAt, 1);
803 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_substr, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_substr, 1);
804 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_substring, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_substring, 1);
805 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_toLowerCase, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_toLowerCase, 0);
806 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_toString, SWFDEC_TYPE_AS_STRING, swfdec_as_string_toString, 0);
807 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_toUpperCase, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_toUpperCase, 0);
808 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_valueOf, SWFDEC_TYPE_AS_STRING, swfdec_as_string_valueOf, 0);
809 swfdec_as_object_add_function (proto, SWFDEC_AS_STR_split, SWFDEC_TYPE_AS_OBJECT, swfdec_as_string_split, 1);
810 SWFDEC_AS_VALUE_SET_OBJECT (&val, context->Object_prototype);
811 swfdec_as_object_set_variable_and_flags (proto, SWFDEC_AS_STR___proto__, &val,
812 SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
814 /* add properties to global object */
815 swfdec_as_object_add_function (context->global, SWFDEC_AS_STR_escape, 0, swfdec_as_string_escape_internal, 1);
816 swfdec_as_object_add_function (context->global, SWFDEC_AS_STR_unescape, 0, swfdec_as_string_unescape_internal, 1);