Bug 22803 - Make header conform to implementation
[swfdec.git] / swfdec / swfdec_as_string.c
blob7bbd314ceb602592e27e6e48f49806a3db3e5719
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_internal.h"
31 #include "swfdec_as_native_function.h"
32 #include "swfdec_as_strings.h"
33 #include "swfdec_debug.h"
35 G_DEFINE_TYPE (SwfdecAsString, swfdec_as_string, SWFDEC_TYPE_AS_RELAY)
37 static void
38 swfdec_as_string_do_mark (SwfdecGcObject *object)
40 SwfdecAsString *string = SWFDEC_AS_STRING (object);
42 swfdec_as_string_mark (string->string);
44 SWFDEC_GC_OBJECT_CLASS (swfdec_as_string_parent_class)->mark (object);
47 static void
48 swfdec_as_string_class_init (SwfdecAsStringClass *klass)
50 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
52 gc_class->mark = swfdec_as_string_do_mark;
55 static void
56 swfdec_as_string_init (SwfdecAsString *string)
58 string->string = SWFDEC_AS_STR_EMPTY;
61 /*** AS CODE ***/
63 #define SWFDEC_AS_STRING_CHECK(result,...) G_STMT_START {\
64 if (object) {\
65 SwfdecAsValue _tmp; \
66 SWFDEC_AS_VALUE_SET_COMPOSITE (&_tmp, object); \
67 *(result) = swfdec_as_value_to_string (cx, _tmp);\
68 } else {\
69 *(result) = SWFDEC_AS_STR_undefined; \
71 if (!swfdec_as_native_function_check (cx, object, 0, NULL, argc, argv, __VA_ARGS__)) \
72 return; \
73 }G_STMT_END
75 static const char *
76 swfdec_as_str_nth_char (const char *s, guint n)
78 while (*s && n--)
79 s = g_utf8_next_char (s);
80 return s;
83 SWFDEC_AS_NATIVE (251, 9, swfdec_as_string_lastIndexOf)
84 void
85 swfdec_as_string_lastIndexOf (SwfdecAsContext *cx, SwfdecAsObject *object,
86 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
88 const char *string;
89 gsize len;
90 const char *s;
92 SWFDEC_AS_STRING_CHECK (&string, "s", &s);
94 if (argc == 2) {
95 int offset = swfdec_as_value_to_integer (cx, argv[1]);
96 const char *tmp;
97 if (offset < 0) {
98 *ret = swfdec_as_value_from_integer (cx, -1);
99 return;
101 tmp = string;
102 offset++;
103 while (*tmp && offset-- != 0)
104 tmp = g_utf8_next_char (tmp);
105 len = tmp - string;
106 } else {
107 len = G_MAXSIZE;
109 s = g_strrstr_len (string, len, s);
110 if (s) {
111 *ret = swfdec_as_value_from_integer (cx, g_utf8_pointer_to_offset (string, s));
112 } else {
113 *ret = swfdec_as_value_from_integer (cx, -1);
117 SWFDEC_AS_NATIVE (251, 8, swfdec_as_string_indexOf)
118 void
119 swfdec_as_string_indexOf (SwfdecAsContext *cx, SwfdecAsObject *object,
120 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
122 const char *string;
123 int offset=0, len, i=-1;
124 const char *s, *t = NULL;
126 SWFDEC_AS_STRING_CHECK (&string, "s", &s);
128 if (argc == 2)
129 offset = swfdec_as_value_to_integer (cx, argv[1]);
130 if (offset < 0)
131 offset = 0;
132 len = g_utf8_strlen (string, -1);
133 if (offset < len) {
134 t = strstr (g_utf8_offset_to_pointer (string, offset), s);
136 if (t != NULL) {
137 i = g_utf8_pointer_to_offset (string, t);
140 *ret = swfdec_as_value_from_integer (cx, i);
143 SWFDEC_AS_NATIVE (251, 5, swfdec_as_string_charAt)
144 void
145 swfdec_as_string_charAt (SwfdecAsContext *cx, SwfdecAsObject *object,
146 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
148 const char *string;
149 int i;
150 const char *s, *t;
152 SWFDEC_AS_STRING_CHECK (&string, "i", &i);
154 if (i < 0) {
155 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
156 return;
158 s = swfdec_as_str_nth_char (string, i);
159 if (*s == 0) {
160 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
161 return;
163 t = g_utf8_next_char (s);
164 s = swfdec_as_context_give_string (cx, g_strndup (s, t - s));
165 SWFDEC_AS_VALUE_SET_STRING (ret, s);
168 SWFDEC_AS_NATIVE (251, 6, swfdec_as_string_charCodeAt)
169 void
170 swfdec_as_string_charCodeAt (SwfdecAsContext *cx, SwfdecAsObject *object,
171 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
173 const char *string;
174 int i;
175 const char *s;
176 gunichar c;
178 SWFDEC_AS_STRING_CHECK (&string, "i", &i);
180 if (i < 0) {
181 *ret = swfdec_as_value_from_number (cx, NAN);
182 return;
184 s = swfdec_as_str_nth_char (string, i);
185 if (*s == 0) {
186 if (cx->version > 5) {
187 *ret = swfdec_as_value_from_number (cx, NAN);
188 } else {
189 *ret = swfdec_as_value_from_integer (cx, 0);
191 return;
193 c = g_utf8_get_char (s);
194 *ret = swfdec_as_value_from_number (cx, c);
197 static void
198 swfdec_as_string_fromCharCode_5 (SwfdecAsContext *cx, SwfdecAsObject *object,
199 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
201 guint i, c;
202 guint8 append;
203 GError *error = NULL;
204 char *s;
205 GByteArray *array = g_byte_array_new ();
207 if (argc > 0) {
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 } else{
221 s = g_strdup ("");
224 if (s) {
225 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s));
226 } else {
227 SWFDEC_ERROR ("%s", error->message);
228 g_error_free (error);
230 g_byte_array_free (array, TRUE);
233 static void
234 swfdec_as_string_fromCharCode_6 (SwfdecAsContext *cx, SwfdecAsObject *object,
235 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
237 gunichar tmp[8];
238 gunichar *chars;
239 guint i;
240 char *s;
241 GError *error = NULL;
243 if (argc <= 8)
244 chars = tmp;
245 else
246 chars = g_new (gunichar, argc);
248 for (i = 0; i < argc; i++) {
249 chars[i] = ((guint) swfdec_as_value_to_integer (cx, argv[i])) % 65536;
252 s = g_ucs4_to_utf8 (chars, argc, NULL, NULL, &error);
253 if (s) {
254 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s));
255 g_free (s);
256 } else {
257 SWFDEC_ERROR ("%s", error->message);
258 g_error_free (error);
261 if (chars != tmp)
262 g_free (chars);
265 SWFDEC_AS_NATIVE (251, 14, swfdec_as_string_fromCharCode)
266 void
267 swfdec_as_string_fromCharCode (SwfdecAsContext *cx, SwfdecAsObject *object,
268 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
270 if (cx->version <= 5) {
271 swfdec_as_string_fromCharCode_5 (cx, object, argc, argv, ret);
272 } else {
273 swfdec_as_string_fromCharCode_6 (cx, object, argc, argv, ret);
277 SWFDEC_AS_NATIVE (251, 0, swfdec_as_string_construct)
278 void
279 swfdec_as_string_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
280 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
282 const char *s;
284 if (argc > 0) {
285 s = swfdec_as_value_to_string (cx, argv[0]);
286 } else {
287 s = SWFDEC_AS_STR_EMPTY;
290 if (swfdec_as_context_is_constructing (cx)) {
291 SwfdecAsString *string = g_object_new (SWFDEC_TYPE_AS_STRING, "context", cx, NULL);
292 SwfdecAsValue val;
294 string->string = s;
295 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (string));
297 val = swfdec_as_value_from_integer (cx, g_utf8_strlen (string->string, -1));
298 swfdec_as_object_set_variable_and_flags (object, SWFDEC_AS_STR_length,
299 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
301 SWFDEC_AS_VALUE_SET_OBJECT (ret, object);
302 } else {
303 SWFDEC_AS_VALUE_SET_STRING (ret, s);
307 SWFDEC_AS_NATIVE (251, 2, swfdec_as_string_toString)
308 void
309 swfdec_as_string_toString (SwfdecAsContext *cx, SwfdecAsObject *object,
310 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
312 SwfdecAsString *string;
314 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_STRING, &string, "");
316 SWFDEC_AS_VALUE_SET_STRING (ret, string->string);
319 SWFDEC_AS_NATIVE (251, 1, swfdec_as_string_valueOf)
320 void
321 swfdec_as_string_valueOf (SwfdecAsContext *cx, SwfdecAsObject *object,
322 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
324 const char *string;
326 SWFDEC_AS_STRING_CHECK (&string, "");
328 SWFDEC_AS_VALUE_SET_STRING (ret, string);
331 static void
332 swfdec_as_string_split_5 (SwfdecAsContext *cx, SwfdecAsObject *object,
333 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
335 SwfdecAsObject *arr;
336 SwfdecAsValue val;
337 const char *str, *end, *delim;
338 int count;
340 SWFDEC_AS_STRING_CHECK (&str, "");
342 arr = swfdec_as_array_new (cx);
343 SWFDEC_AS_VALUE_SET_OBJECT (ret, arr);
344 /* hi, i'm the special case */
345 if (argc < 1 || SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0])) {
346 delim = SWFDEC_AS_STR_COMMA;
347 } else {
348 delim = swfdec_as_value_to_string (cx, argv[0]);
350 if (delim == SWFDEC_AS_STR_EMPTY) {
351 SWFDEC_AS_VALUE_SET_STRING (&val, str);
352 swfdec_as_array_push (arr, &val);
353 return;
355 if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) {
356 swfdec_as_value_to_string (cx, argv[0]);
357 count = swfdec_as_value_to_integer (cx, argv[1]);
358 } else {
359 count = G_MAXINT;
361 if (count <= 0)
362 return;
363 if (str == SWFDEC_AS_STR_EMPTY || delim[1] != 0) {
364 SWFDEC_AS_VALUE_SET_STRING (&val, str);
365 swfdec_as_array_push (arr, &val);
366 return;
368 while (count > 0) {
369 end = strchr (str, delim[0]);
370 if (end == NULL) {
371 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str));
372 swfdec_as_array_push (arr, &val);
373 break;
375 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str)));
376 swfdec_as_array_push (arr, &val);
377 count--;
378 str = end + 1;
382 static void
383 swfdec_as_string_split_6 (SwfdecAsContext *cx, SwfdecAsObject *object,
384 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
386 SwfdecAsObject *arr;
387 SwfdecAsValue val;
388 const char *str, *end, *delim;
389 int count;
390 guint len;
392 SWFDEC_AS_STRING_CHECK (&str, "");
394 arr = swfdec_as_array_new (cx);
395 SWFDEC_AS_VALUE_SET_OBJECT (ret, arr);
396 /* hi, i'm the special case */
397 if (argc < 1 || SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0])) {
398 SWFDEC_AS_VALUE_SET_STRING (&val, str);
399 swfdec_as_array_push (arr, &val);
400 return;
402 delim = swfdec_as_value_to_string (cx, argv[0]);
403 if (str == SWFDEC_AS_STR_EMPTY) {
404 if (strlen (delim) > 0) {
405 SWFDEC_AS_VALUE_SET_STRING (&val, str);
406 swfdec_as_array_push (arr, &val);
408 return;
410 if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1]))
411 count = swfdec_as_value_to_integer (cx, argv[1]);
412 else
413 count = G_MAXINT;
414 if (count <= 0)
415 return;
416 len = strlen (delim);
417 while (count > 0) {
418 if (delim == SWFDEC_AS_STR_EMPTY) {
419 if (*str)
420 end = str + 1;
421 else
422 break;
423 } else {
424 end = strstr (str, delim);
425 if (end == NULL) {
426 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str));
427 swfdec_as_array_push (arr, &val);
428 break;
431 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str)));
432 swfdec_as_array_push (arr, &val);
433 count--;
434 str = end + len;
438 SWFDEC_AS_NATIVE (251, 12, swfdec_as_string_split)
439 void
440 swfdec_as_string_split (SwfdecAsContext *cx, SwfdecAsObject *object,
441 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
443 if (cx->version <= 5) {
444 swfdec_as_string_split_5 (cx, object, argc, argv, ret);
445 } else {
446 swfdec_as_string_split_6 (cx, object, argc, argv, ret);
450 SWFDEC_AS_NATIVE (251, 10, swfdec_as_string_slice)
451 void
452 swfdec_as_string_slice (SwfdecAsContext *cx, SwfdecAsObject *object,
453 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
455 int start, end, length;
456 const char *str;
458 SWFDEC_AS_STRING_CHECK (&str, "i", &start);
460 length = g_utf8_strlen (str, -1);
462 if (start < 0)
463 start += length;
464 start = CLAMP (start, 0, length);
466 if (argc > 1) {
467 end = swfdec_as_value_to_integer (cx, argv[1]);
468 if (end < 0)
469 end += length;
470 end = CLAMP (end, start, length);
471 } else {
472 end = length;
475 SWFDEC_AS_VALUE_SET_STRING (ret,
476 swfdec_as_str_sub (cx, str, start, end - start));
479 SWFDEC_AS_NATIVE (251, 7, swfdec_as_string_concat)
480 void
481 swfdec_as_string_concat (SwfdecAsContext *cx, SwfdecAsObject *object,
482 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
484 guint i;
485 GString *string;
486 const char *s;
488 SWFDEC_AS_STRING_CHECK (&s, "");
490 string = g_string_new (s);
492 for (i = 0; i < argc; i++) {
493 string = g_string_append (string, swfdec_as_value_to_string (cx, argv[i]));
496 SWFDEC_AS_VALUE_SET_STRING (ret,
497 swfdec_as_context_give_string (cx, g_string_free (string, FALSE)));
500 const char *
501 swfdec_as_str_sub (SwfdecAsContext *cx, const char *str, guint offset, guint len)
503 const char *end;
505 str = g_utf8_offset_to_pointer (str, offset);
506 end = g_utf8_offset_to_pointer (str, len);
507 str = swfdec_as_context_give_string (cx, g_strndup (str, end - str));
508 return str;
511 SWFDEC_AS_NATIVE (251, 13, swfdec_as_string_substr)
512 void
513 swfdec_as_string_substr (SwfdecAsContext *cx, SwfdecAsObject *object,
514 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
516 const char *string;
517 int from, to, len;
519 SWFDEC_AS_STRING_CHECK (&string, "i", &from);
521 len = g_utf8_strlen (string, -1);
523 if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) {
524 to = swfdec_as_value_to_integer (cx, argv[1]);
525 /* FIXME: wtf? */
526 if (to < 0) {
527 if (-to <= from)
528 to = 0;
529 else
530 to += len;
531 if (to < 0)
532 to = 0;
533 if (from < 0 && to >= -from)
534 to = 0;
536 } else {
537 to = G_MAXINT;
539 if (from < 0)
540 from += len;
541 from = CLAMP (from, 0, len);
542 to = CLAMP (to, 0, len - from);
543 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to));
546 SWFDEC_AS_NATIVE (251, 11, swfdec_as_string_substring)
547 void
548 swfdec_as_string_substring (SwfdecAsContext *cx, SwfdecAsObject *object,
549 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
551 const char *string;
552 int from, to, len;
554 SWFDEC_AS_STRING_CHECK (&string, "i", &from);
556 len = g_utf8_strlen (string, -1);
557 if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) {
558 to = swfdec_as_value_to_integer (cx, argv[1]);
559 } else {
560 to = len;
562 from = MAX (from, 0);
563 if (from >= len) {
564 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
565 return;
567 to = CLAMP (to, 0, len);
568 if (to < from) {
569 int tmp = to;
570 to = from;
571 from = tmp;
573 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to - from));
576 SWFDEC_AS_NATIVE (251, 4, swfdec_as_string_toLowerCase)
577 void
578 swfdec_as_string_toLowerCase (SwfdecAsContext *cx, SwfdecAsObject *object,
579 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
581 const char *string;
582 char *s;
584 SWFDEC_AS_STRING_CHECK (&string, "");
586 s = g_utf8_strdown (string, -1);
587 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s));
590 SWFDEC_AS_NATIVE (251, 3, swfdec_as_string_toUpperCase)
591 void
592 swfdec_as_string_toUpperCase (SwfdecAsContext *cx, SwfdecAsObject *object,
593 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
595 const char *string;
596 char *s;
598 SWFDEC_AS_STRING_CHECK (&string, "");
600 s = g_utf8_strup (string, -1);
601 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s));
604 // only available as ASnative
605 SWFDEC_AS_NATIVE (102, 1, swfdec_as_string_old_toLowerCase)
606 void
607 swfdec_as_string_old_toLowerCase (SwfdecAsContext *cx, SwfdecAsObject *object,
608 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
610 const char *string;
611 char *s;
613 SWFDEC_AS_STRING_CHECK (&string, "");
615 s = g_ascii_strdown (string, -1);
616 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s));
619 // only available as ASnative
620 SWFDEC_AS_NATIVE (102, 0, swfdec_as_string_old_toUpperCase)
621 void
622 swfdec_as_string_old_toUpperCase (SwfdecAsContext *cx, SwfdecAsObject *object,
623 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
625 const char *string;
626 char *s;
628 SWFDEC_AS_STRING_CHECK (&string, "");
630 s = g_ascii_strup (string, -1);
631 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s));
634 /* escape and unescape are implemented here so the mad string functions share the same place */
636 static char *
637 swfdec_as_string_unescape_5 (SwfdecAsContext *cx, const char *msg)
639 GByteArray *array;
640 char cur = 0; /* currently decoded character */
641 char *out, *in, *s;
642 guint decoding = 0; /* set if we're decoding a %XY string */
644 /* attention: c is a char* */
645 #define APPEND(chr) G_STMT_START{ \
646 g_byte_array_append (array, (guchar *) chr, 1); \
647 }G_STMT_END
648 in = s = g_convert (msg, -1, "LATIN1", "UTF-8", NULL, NULL, NULL);
649 if (s == NULL) {
650 SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", msg);
651 return NULL;
653 array = g_byte_array_new ();
654 while (*s != 0) {
655 if (decoding) {
656 decoding++;
657 if (*s >= '0' && *s <= '9') {
658 cur = cur * 16 + *s - '0';
659 } else if (*s >= 'A' && *s <= 'F') {
660 cur = cur * 16 + *s - 'A' + 10;
661 } else if (*s >= 'a' && *s <= 'f') {
662 cur = cur * 16 + *s - 'a' + 10;
663 } else {
664 cur = 0;
665 decoding = 0;
667 if (decoding == 3) {
668 APPEND (&cur);
669 cur = 0;
670 decoding = 0;
672 } else if (*s == '%') {
673 decoding = 1;
674 } else if (*s == '+') {
675 char tmp = ' ';
676 APPEND (&tmp);
677 } else {
678 APPEND (s);
680 s++;
682 g_free (in);
683 if (array->len == 0) {
684 g_byte_array_free (array, TRUE);
685 return NULL;
687 cur = 0;
688 g_byte_array_append (array, (guchar *) &cur, 1);
689 out = g_convert ((char *) array->data, -1, "UTF-8", "LATIN1", NULL, NULL, NULL);
690 g_byte_array_free (array, TRUE);
691 if (out) {
692 return out;
693 } else {
694 g_warning ("can't convert %s to UTF-8", msg);
695 g_free (out);
696 return g_strdup ("");
698 #undef APPEND
701 char *
702 swfdec_as_string_escape (SwfdecAsContext *cx, const char *s)
704 GByteArray *array;
705 char *in = NULL;
707 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx), NULL);
708 g_return_val_if_fail (s != NULL, NULL);
710 array = g_byte_array_new ();
711 if (cx->version <= 5) {
712 in = g_convert (s, -1, "LATIN1", "UTF-8", NULL, NULL, NULL);
713 if (in == NULL) {
714 SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", s);
715 return NULL;
716 } else {
717 s = in;
720 while (*s) {
721 if ((*s >= '0' && *s <= '9') ||
722 (*s >= 'A' && *s <= 'Z') ||
723 (*s >= 'a' && *s <= 'z')) {
724 g_byte_array_append (array, (guchar *) s, 1);
725 } else {
726 guchar add[3] = { '%', 0, 0 };
727 add[1] = (guchar) *s / 16;
728 add[2] = (guchar) *s % 16;
729 add[1] += add[1] < 10 ? '0' : ('A' - 10);
730 add[2] += add[2] < 10 ? '0' : ('A' - 10);
731 g_byte_array_append (array, add, 3);
733 s++;
735 g_byte_array_append (array, (guchar *) s, 1);
736 g_free (in);
737 return (char *) g_byte_array_free (array, FALSE);
740 SWFDEC_AS_NATIVE (100, 0, swfdec_as_string_escape_internal)
741 void
742 swfdec_as_string_escape_internal (SwfdecAsContext *cx, SwfdecAsObject *object,
743 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
745 const char *s;
746 char *result;
748 SWFDEC_AS_CHECK (0, NULL, "s", &s);
750 result = swfdec_as_string_escape (cx, s);
751 if (result != NULL) {
752 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result));
753 g_free (result);
754 } else {
755 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
759 static char *
760 swfdec_as_string_unescape_6 (SwfdecAsContext *cx, const char *s)
762 GByteArray *array;
763 const char *msg;
764 char cur = 0; /* currently decoded character */
765 guint decoding = 0; /* set if we're decoding a %XY string */
766 guint utf8left = 0; /* how many valid utf8 chars are still required */
767 const guchar invalid[3] = { 0xEF, 0xBF, 0xBD };
769 /* attention: c is a char* */
770 /* can't use break inside G_STMT_START */
771 #define APPEND(chr) G_STMT_START{ \
772 guchar c = *chr; \
773 if (utf8left) { \
774 if ((c & 0xC0) == 0x80) { \
775 g_byte_array_append (array, &c, 1); \
776 utf8left--; \
777 } else { \
778 guint __len = array->len - 1; \
779 while ((array->data[__len] & 0xC0) != 0xC0) \
780 __len--; \
781 g_byte_array_set_size (array, __len); \
782 g_byte_array_append (array, invalid, 3); \
783 utf8left = 0; \
785 } else { \
786 if (c < 0x80) { \
787 g_byte_array_append (array, &c, 1); \
788 } else if (c < 0xC0) { \
789 guchar __foo = 0xC2; \
790 g_byte_array_append (array, &__foo, 1); \
791 g_byte_array_append (array, &c, 1); \
792 } else if (c > 0xF7) { \
793 goto out; \
794 } else { \
795 g_byte_array_append (array, &c, 1); \
796 utf8left = (c < 0xE0) ? 1 : ((c < 0xF0) ? 2 : 3); \
799 }G_STMT_END
800 array = g_byte_array_new ();
801 msg = s;
802 while (*s != 0) {
803 if (decoding) {
804 decoding++;
805 if (*s >= '0' && *s <= '9') {
806 cur = cur * 16 + *s - '0';
807 } else if (*s >= 'A' && *s <= 'F') {
808 cur = cur * 16 + *s - 'A' + 10;
809 } else if (*s >= 'a' && *s <= 'f') {
810 cur = cur * 16 + *s - 'a' + 10;
811 } else {
812 cur = 0;
813 decoding = 0;
814 if ((guchar) *s > 0x7F) {
815 APPEND (s);
818 if (decoding == 3) {
819 APPEND (&cur);
820 cur = 0;
821 decoding = 0;
823 } else if (*s == '%') {
824 decoding = 1;
825 } else if (*s == '+') {
826 char tmp = ' ';
827 APPEND (&tmp);
828 } else {
829 APPEND (s);
831 s++;
833 out:
834 cur = 0;
835 /* loop for break statement in APPEND macro */
836 if (utf8left) {
837 guint __len = array->len - 1;
838 while ((array->data[__len] & 0xC0) != 0xC0)
839 __len--;
840 g_byte_array_set_size (array, __len);
842 g_byte_array_append (array, (guchar *) &cur, 1);
843 if (g_utf8_validate ((char *) array->data, -1, NULL)) {
844 return (char *) g_byte_array_free (array, FALSE);
845 } else {
846 g_warning ("%s unescaped is invalid UTF-8", msg);
847 g_byte_array_free (array, TRUE);
848 return g_strdup ("");
850 #undef APPEND
853 char *
854 swfdec_as_string_unescape (SwfdecAsContext *context, const char *string)
856 if (context->version < 6) {
857 return swfdec_as_string_unescape_5 (context, string);
858 } else {
859 return swfdec_as_string_unescape_6 (context, string);
863 SWFDEC_AS_NATIVE (100, 1, swfdec_as_string_unescape_internal)
864 void
865 swfdec_as_string_unescape_internal (SwfdecAsContext *cx, SwfdecAsObject *object,
866 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
868 const char *s;
869 char *result;
871 SWFDEC_AS_CHECK (0, NULL, "s", &s);
873 result = swfdec_as_string_unescape (cx, s);
874 if (result != NULL) {
875 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result));
876 g_free (result);
877 } else {
878 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
882 // only available as ASnative
883 SWFDEC_AS_NATIVE (3, 0, swfdec_as_string_old_constructor)
884 void
885 swfdec_as_string_old_constructor (SwfdecAsContext *cx, SwfdecAsObject *object,
886 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
888 SWFDEC_STUB ("old 'String' function (only available as ASnative)");