/* Swfdec * Copyright (C) 2007 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "swfdec_as_string.h" #include "swfdec_as_array.h" #include "swfdec_as_context.h" #include "swfdec_as_internal.h" #include "swfdec_as_native_function.h" #include "swfdec_as_strings.h" #include "swfdec_debug.h" G_DEFINE_TYPE (SwfdecAsString, swfdec_as_string, SWFDEC_TYPE_AS_RELAY) static void swfdec_as_string_do_mark (SwfdecGcObject *object) { SwfdecAsString *string = SWFDEC_AS_STRING (object); swfdec_as_string_mark (string->string); SWFDEC_GC_OBJECT_CLASS (swfdec_as_string_parent_class)->mark (object); } static void swfdec_as_string_class_init (SwfdecAsStringClass *klass) { SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass); gc_class->mark = swfdec_as_string_do_mark; } static void swfdec_as_string_init (SwfdecAsString *string) { string->string = SWFDEC_AS_STR_EMPTY; } /*** AS CODE ***/ #define SWFDEC_AS_STRING_CHECK(result,...) G_STMT_START {\ if (object) {\ SwfdecAsValue _tmp; \ SWFDEC_AS_VALUE_SET_COMPOSITE (&_tmp, object); \ *(result) = swfdec_as_value_to_string (cx, _tmp);\ } else {\ *(result) = SWFDEC_AS_STR_undefined; \ }\ if (!swfdec_as_native_function_check (cx, object, 0, NULL, argc, argv, __VA_ARGS__)) \ return; \ }G_STMT_END static const char * swfdec_as_str_nth_char (const char *s, guint n) { while (*s && n--) s = g_utf8_next_char (s); return s; } SWFDEC_AS_NATIVE (251, 9, swfdec_as_string_lastIndexOf) void swfdec_as_string_lastIndexOf (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; gsize len; const char *s; SWFDEC_AS_STRING_CHECK (&string, "s", &s); if (argc == 2) { int offset = swfdec_as_value_to_integer (cx, argv[1]); const char *tmp; if (offset < 0) { *ret = swfdec_as_value_from_integer (cx, -1); return; } tmp = string; offset++; while (*tmp && offset-- != 0) tmp = g_utf8_next_char (tmp); len = tmp - string; } else { len = G_MAXSIZE; } s = g_strrstr_len (string, len, s); if (s) { *ret = swfdec_as_value_from_integer (cx, g_utf8_pointer_to_offset (string, s)); } else { *ret = swfdec_as_value_from_integer (cx, -1); } } SWFDEC_AS_NATIVE (251, 8, swfdec_as_string_indexOf) void swfdec_as_string_indexOf (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; int offset=0, len, i=-1; const char *s, *t = NULL; SWFDEC_AS_STRING_CHECK (&string, "s", &s); if (argc == 2) offset = swfdec_as_value_to_integer (cx, argv[1]); if (offset < 0) offset = 0; len = g_utf8_strlen (string, -1); if (offset < len) { t = strstr (g_utf8_offset_to_pointer (string, offset), s); } if (t != NULL) { i = g_utf8_pointer_to_offset (string, t); } *ret = swfdec_as_value_from_integer (cx, i); } SWFDEC_AS_NATIVE (251, 5, swfdec_as_string_charAt) void swfdec_as_string_charAt (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; int i; const char *s, *t; SWFDEC_AS_STRING_CHECK (&string, "i", &i); if (i < 0) { SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY); return; } s = swfdec_as_str_nth_char (string, i); if (*s == 0) { SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY); return; } t = g_utf8_next_char (s); s = swfdec_as_context_give_string (cx, g_strndup (s, t - s)); SWFDEC_AS_VALUE_SET_STRING (ret, s); } SWFDEC_AS_NATIVE (251, 6, swfdec_as_string_charCodeAt) void swfdec_as_string_charCodeAt (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; int i; const char *s; gunichar c; SWFDEC_AS_STRING_CHECK (&string, "i", &i); if (i < 0) { *ret = swfdec_as_value_from_number (cx, NAN); return; } s = swfdec_as_str_nth_char (string, i); if (*s == 0) { if (cx->version > 5) { *ret = swfdec_as_value_from_number (cx, NAN); } else { *ret = swfdec_as_value_from_integer (cx, 0); } return; } c = g_utf8_get_char (s); *ret = swfdec_as_value_from_number (cx, c); } static void swfdec_as_string_fromCharCode_5 (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { guint i, c; guint8 append; GError *error = NULL; char *s; GByteArray *array = g_byte_array_new (); if (argc > 0) { for (i = 0; i < argc; i++) { c = ((guint) swfdec_as_value_to_integer (cx, argv[i])) % 65536; if (c > 255) { append = c / 256; g_byte_array_append (array, &append, 1); } append = c; g_byte_array_append (array, &append, 1); } /* FIXME: are these the correct charset names? */ s = g_convert ((char *) array->data, array->len, "UTF-8", "LATIN1", NULL, NULL, &error); } else{ s = g_strdup (""); } if (s) { SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s)); } else { SWFDEC_ERROR ("%s", error->message); g_error_free (error); } g_byte_array_free (array, TRUE); } static void swfdec_as_string_fromCharCode_6 (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { gunichar tmp[8]; gunichar *chars; guint i; char *s; GError *error = NULL; if (argc <= 8) chars = tmp; else chars = g_new (gunichar, argc); for (i = 0; i < argc; i++) { chars[i] = ((guint) swfdec_as_value_to_integer (cx, argv[i])) % 65536; } s = g_ucs4_to_utf8 (chars, argc, NULL, NULL, &error); if (s) { SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, s)); g_free (s); } else { SWFDEC_ERROR ("%s", error->message); g_error_free (error); } if (chars != tmp) g_free (chars); } SWFDEC_AS_NATIVE (251, 14, swfdec_as_string_fromCharCode) void swfdec_as_string_fromCharCode (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { if (cx->version <= 5) { swfdec_as_string_fromCharCode_5 (cx, object, argc, argv, ret); } else { swfdec_as_string_fromCharCode_6 (cx, object, argc, argv, ret); } } SWFDEC_AS_NATIVE (251, 0, swfdec_as_string_construct) void swfdec_as_string_construct (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *s; if (argc > 0) { s = swfdec_as_value_to_string (cx, argv[0]); } else { s = SWFDEC_AS_STR_EMPTY; } if (swfdec_as_context_is_constructing (cx)) { SwfdecAsString *string = g_object_new (SWFDEC_TYPE_AS_STRING, "context", cx, NULL); SwfdecAsValue val; string->string = s; swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (string)); val = swfdec_as_value_from_integer (cx, g_utf8_strlen (string->string, -1)); swfdec_as_object_set_variable_and_flags (object, SWFDEC_AS_STR_length, &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT); SWFDEC_AS_VALUE_SET_OBJECT (ret, object); } else { SWFDEC_AS_VALUE_SET_STRING (ret, s); } } SWFDEC_AS_NATIVE (251, 2, swfdec_as_string_toString) void swfdec_as_string_toString (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { SwfdecAsString *string; SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_STRING, &string, ""); SWFDEC_AS_VALUE_SET_STRING (ret, string->string); } SWFDEC_AS_NATIVE (251, 1, swfdec_as_string_valueOf) void swfdec_as_string_valueOf (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; SWFDEC_AS_STRING_CHECK (&string, ""); SWFDEC_AS_VALUE_SET_STRING (ret, string); } static void swfdec_as_string_split_5 (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { SwfdecAsObject *arr; SwfdecAsValue val; const char *str, *end, *delim; int count; SWFDEC_AS_STRING_CHECK (&str, ""); arr = swfdec_as_array_new (cx); SWFDEC_AS_VALUE_SET_OBJECT (ret, arr); /* hi, i'm the special case */ if (argc < 1 || SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0])) { delim = SWFDEC_AS_STR_COMMA; } else { delim = swfdec_as_value_to_string (cx, argv[0]); } if (delim == SWFDEC_AS_STR_EMPTY) { SWFDEC_AS_VALUE_SET_STRING (&val, str); swfdec_as_array_push (arr, &val); return; } if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) { swfdec_as_value_to_string (cx, argv[0]); count = swfdec_as_value_to_integer (cx, argv[1]); } else { count = G_MAXINT; } if (count <= 0) return; if (str == SWFDEC_AS_STR_EMPTY || delim[1] != 0) { SWFDEC_AS_VALUE_SET_STRING (&val, str); swfdec_as_array_push (arr, &val); return; } while (count > 0) { end = strchr (str, delim[0]); if (end == NULL) { SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str)); swfdec_as_array_push (arr, &val); break; } SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str))); swfdec_as_array_push (arr, &val); count--; str = end + 1; } } static void swfdec_as_string_split_6 (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { SwfdecAsObject *arr; SwfdecAsValue val; const char *str, *end, *delim; int count; guint len; SWFDEC_AS_STRING_CHECK (&str, ""); arr = swfdec_as_array_new (cx); SWFDEC_AS_VALUE_SET_OBJECT (ret, arr); /* hi, i'm the special case */ if (argc < 1 || SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0])) { SWFDEC_AS_VALUE_SET_STRING (&val, str); swfdec_as_array_push (arr, &val); return; } delim = swfdec_as_value_to_string (cx, argv[0]); if (str == SWFDEC_AS_STR_EMPTY) { if (strlen (delim) > 0) { SWFDEC_AS_VALUE_SET_STRING (&val, str); swfdec_as_array_push (arr, &val); } return; } if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) count = swfdec_as_value_to_integer (cx, argv[1]); else count = G_MAXINT; if (count <= 0) return; len = strlen (delim); while (count > 0) { if (delim == SWFDEC_AS_STR_EMPTY) { if (*str) end = str + 1; else break; } else { end = strstr (str, delim); if (end == NULL) { SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, str)); swfdec_as_array_push (arr, &val); break; } } SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, g_strndup (str, end - str))); swfdec_as_array_push (arr, &val); count--; str = end + len; } } SWFDEC_AS_NATIVE (251, 12, swfdec_as_string_split) void swfdec_as_string_split (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { if (cx->version <= 5) { swfdec_as_string_split_5 (cx, object, argc, argv, ret); } else { swfdec_as_string_split_6 (cx, object, argc, argv, ret); } } SWFDEC_AS_NATIVE (251, 10, swfdec_as_string_slice) void swfdec_as_string_slice (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { int start, end, length; const char *str; SWFDEC_AS_STRING_CHECK (&str, "i", &start); length = g_utf8_strlen (str, -1); if (start < 0) start += length; start = CLAMP (start, 0, length); if (argc > 1) { end = swfdec_as_value_to_integer (cx, argv[1]); if (end < 0) end += length; end = CLAMP (end, start, length); } else { end = length; } SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, str, start, end - start)); } SWFDEC_AS_NATIVE (251, 7, swfdec_as_string_concat) void swfdec_as_string_concat (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { guint i; GString *string; const char *s; SWFDEC_AS_STRING_CHECK (&s, ""); string = g_string_new (s); for (i = 0; i < argc; i++) { string = g_string_append (string, swfdec_as_value_to_string (cx, argv[i])); } SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, g_string_free (string, FALSE))); } const char * swfdec_as_str_sub (SwfdecAsContext *cx, const char *str, guint offset, guint len) { const char *end; str = g_utf8_offset_to_pointer (str, offset); end = g_utf8_offset_to_pointer (str, len); str = swfdec_as_context_give_string (cx, g_strndup (str, end - str)); return str; } SWFDEC_AS_NATIVE (251, 13, swfdec_as_string_substr) void swfdec_as_string_substr (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; int from, to, len; SWFDEC_AS_STRING_CHECK (&string, "i", &from); len = g_utf8_strlen (string, -1); if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) { to = swfdec_as_value_to_integer (cx, argv[1]); /* FIXME: wtf? */ if (to < 0) { if (-to <= from) to = 0; else to += len; if (to < 0) to = 0; if (from < 0 && to >= -from) to = 0; } } else { to = G_MAXINT; } if (from < 0) from += len; from = CLAMP (from, 0, len); to = CLAMP (to, 0, len - from); SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to)); } SWFDEC_AS_NATIVE (251, 11, swfdec_as_string_substring) void swfdec_as_string_substring (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; int from, to, len; SWFDEC_AS_STRING_CHECK (&string, "i", &from); len = g_utf8_strlen (string, -1); if (argc > 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1])) { to = swfdec_as_value_to_integer (cx, argv[1]); } else { to = len; } from = MAX (from, 0); if (from >= len) { SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY); return; } to = CLAMP (to, 0, len); if (to < from) { int tmp = to; to = from; from = tmp; } SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_str_sub (cx, string, from, to - from)); } SWFDEC_AS_NATIVE (251, 4, swfdec_as_string_toLowerCase) void swfdec_as_string_toLowerCase (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; char *s; SWFDEC_AS_STRING_CHECK (&string, ""); s = g_utf8_strdown (string, -1); SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s)); } SWFDEC_AS_NATIVE (251, 3, swfdec_as_string_toUpperCase) void swfdec_as_string_toUpperCase (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; char *s; SWFDEC_AS_STRING_CHECK (&string, ""); s = g_utf8_strup (string, -1); SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s)); } // only available as ASnative SWFDEC_AS_NATIVE (102, 1, swfdec_as_string_old_toLowerCase) void swfdec_as_string_old_toLowerCase (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; char *s; SWFDEC_AS_STRING_CHECK (&string, ""); s = g_ascii_strdown (string, -1); SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s)); } // only available as ASnative SWFDEC_AS_NATIVE (102, 0, swfdec_as_string_old_toUpperCase) void swfdec_as_string_old_toUpperCase (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *string; char *s; SWFDEC_AS_STRING_CHECK (&string, ""); s = g_ascii_strup (string, -1); SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, s)); } /* escape and unescape are implemented here so the mad string functions share the same place */ static char * swfdec_as_string_unescape_5 (SwfdecAsContext *cx, const char *msg) { GByteArray *array; char cur = 0; /* currently decoded character */ char *out, *in, *s; guint decoding = 0; /* set if we're decoding a %XY string */ /* attention: c is a char* */ #define APPEND(chr) G_STMT_START{ \ g_byte_array_append (array, (guchar *) chr, 1); \ }G_STMT_END in = s = g_convert (msg, -1, "LATIN1", "UTF-8", NULL, NULL, NULL); if (s == NULL) { SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", msg); return NULL; } array = g_byte_array_new (); while (*s != 0) { if (decoding) { decoding++; if (*s >= '0' && *s <= '9') { cur = cur * 16 + *s - '0'; } else if (*s >= 'A' && *s <= 'F') { cur = cur * 16 + *s - 'A' + 10; } else if (*s >= 'a' && *s <= 'f') { cur = cur * 16 + *s - 'a' + 10; } else { cur = 0; decoding = 0; } if (decoding == 3) { APPEND (&cur); cur = 0; decoding = 0; } } else if (*s == '%') { decoding = 1; } else if (*s == '+') { char tmp = ' '; APPEND (&tmp); } else { APPEND (s); } s++; } g_free (in); if (array->len == 0) { g_byte_array_free (array, TRUE); return NULL; } cur = 0; g_byte_array_append (array, (guchar *) &cur, 1); out = g_convert ((char *) array->data, -1, "UTF-8", "LATIN1", NULL, NULL, NULL); g_byte_array_free (array, TRUE); if (out) { return out; } else { g_warning ("can't convert %s to UTF-8", msg); g_free (out); return g_strdup (""); } #undef APPEND } char * swfdec_as_string_escape (SwfdecAsContext *cx, const char *s) { GByteArray *array; char *in = NULL; g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx), NULL); g_return_val_if_fail (s != NULL, NULL); array = g_byte_array_new (); if (cx->version <= 5) { in = g_convert (s, -1, "LATIN1", "UTF-8", NULL, NULL, NULL); if (in == NULL) { SWFDEC_FIXME ("%s can not be converted to utf8 - is this Flash 5 or what?", s); return NULL; } else { s = in; } } while (*s) { if ((*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')) { g_byte_array_append (array, (guchar *) s, 1); } else { guchar add[3] = { '%', 0, 0 }; add[1] = (guchar) *s / 16; add[2] = (guchar) *s % 16; add[1] += add[1] < 10 ? '0' : ('A' - 10); add[2] += add[2] < 10 ? '0' : ('A' - 10); g_byte_array_append (array, add, 3); } s++; } g_byte_array_append (array, (guchar *) s, 1); g_free (in); return (char *) g_byte_array_free (array, FALSE); } SWFDEC_AS_NATIVE (100, 0, swfdec_as_string_escape_internal) void swfdec_as_string_escape_internal (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *s; char *result; SWFDEC_AS_CHECK (0, NULL, "s", &s); result = swfdec_as_string_escape (cx, s); if (result != NULL) { SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result)); g_free (result); } else { SWFDEC_AS_VALUE_SET_UNDEFINED (ret); } } static char * swfdec_as_string_unescape_6 (SwfdecAsContext *cx, const char *s) { GByteArray *array; const char *msg; char cur = 0; /* currently decoded character */ guint decoding = 0; /* set if we're decoding a %XY string */ guint utf8left = 0; /* how many valid utf8 chars are still required */ const guchar invalid[3] = { 0xEF, 0xBF, 0xBD }; /* attention: c is a char* */ /* can't use break inside G_STMT_START */ #define APPEND(chr) G_STMT_START{ \ guchar c = *chr; \ if (utf8left) { \ if ((c & 0xC0) == 0x80) { \ g_byte_array_append (array, &c, 1); \ utf8left--; \ } else { \ guint __len = array->len - 1; \ while ((array->data[__len] & 0xC0) != 0xC0) \ __len--; \ g_byte_array_set_size (array, __len); \ g_byte_array_append (array, invalid, 3); \ utf8left = 0; \ } \ } else { \ if (c < 0x80) { \ g_byte_array_append (array, &c, 1); \ } else if (c < 0xC0) { \ guchar __foo = 0xC2; \ g_byte_array_append (array, &__foo, 1); \ g_byte_array_append (array, &c, 1); \ } else if (c > 0xF7) { \ goto out; \ } else { \ g_byte_array_append (array, &c, 1); \ utf8left = (c < 0xE0) ? 1 : ((c < 0xF0) ? 2 : 3); \ } \ } \ }G_STMT_END array = g_byte_array_new (); msg = s; while (*s != 0) { if (decoding) { decoding++; if (*s >= '0' && *s <= '9') { cur = cur * 16 + *s - '0'; } else if (*s >= 'A' && *s <= 'F') { cur = cur * 16 + *s - 'A' + 10; } else if (*s >= 'a' && *s <= 'f') { cur = cur * 16 + *s - 'a' + 10; } else { cur = 0; decoding = 0; if ((guchar) *s > 0x7F) { APPEND (s); } } if (decoding == 3) { APPEND (&cur); cur = 0; decoding = 0; } } else if (*s == '%') { decoding = 1; } else if (*s == '+') { char tmp = ' '; APPEND (&tmp); } else { APPEND (s); } s++; } out: cur = 0; /* loop for break statement in APPEND macro */ if (utf8left) { guint __len = array->len - 1; while ((array->data[__len] & 0xC0) != 0xC0) __len--; g_byte_array_set_size (array, __len); } g_byte_array_append (array, (guchar *) &cur, 1); if (g_utf8_validate ((char *) array->data, -1, NULL)) { return (char *) g_byte_array_free (array, FALSE); } else { g_warning ("%s unescaped is invalid UTF-8", msg); g_byte_array_free (array, TRUE); return g_strdup (""); } #undef APPEND } char * swfdec_as_string_unescape (SwfdecAsContext *context, const char *string) { if (context->version < 6) { return swfdec_as_string_unescape_5 (context, string); } else { return swfdec_as_string_unescape_6 (context, string); } } SWFDEC_AS_NATIVE (100, 1, swfdec_as_string_unescape_internal) void swfdec_as_string_unescape_internal (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { const char *s; char *result; SWFDEC_AS_CHECK (0, NULL, "s", &s); result = swfdec_as_string_unescape (cx, s); if (result != NULL) { SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_get_string (cx, result)); g_free (result); } else { SWFDEC_AS_VALUE_SET_UNDEFINED (ret); } } // only available as ASnative SWFDEC_AS_NATIVE (3, 0, swfdec_as_string_old_constructor) void swfdec_as_string_old_constructor (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret) { SWFDEC_STUB ("old 'String' function (only available as ASnative)"); }