/* 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 "swfdec_script.h" #include "swfdec_script_internal.h" #include "swfdec_as_context.h" #include "swfdec_as_interpret.h" #include "swfdec_debug.h" /** * SwfdecScript: * * This is the object used for code to be executed by Swfdec. Scripts are * independant from the #SwfdecAsContext they are executed in, so you can * execute the same script in multiple contexts. */ /* Define this to get SWFDEC_WARN'd about missing properties of objects. * This can be useful to find out about unimplemented native properties, * but usually just causes a lot of spam. */ //#define SWFDEC_WARN_MISSING_PROPERTIES /*** SUPPORT FUNCTIONS ***/ static gboolean swfdec_script_foreach_internal (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data) { guint action, len; const guint8 *data; gconstpointer bytecode; bytecode = bits->ptr; while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) { if (action & 0x80) { len = swfdec_bits_get_u16 (bits); data = bits->ptr; } else { len = 0; data = NULL; } if (swfdec_bits_skip_bytes (bits, len) != len) { SWFDEC_ERROR ("script too short"); return FALSE; } if (!func (bytecode, action, data, len, user_data)) return FALSE; bytecode = bits->ptr; } return TRUE; } static gboolean validate_action (gconstpointer bytecode, guint action, const guint8 *data, guint len, gpointer scriptp) { // TODO: get rid of this function return TRUE; } /*** PUBLIC API ***/ gboolean swfdec_script_foreach (SwfdecScript *script, SwfdecScriptForeachFunc func, gpointer user_data) { SwfdecBits bits; g_return_val_if_fail (script != NULL, FALSE); g_return_val_if_fail (func != NULL, FALSE); swfdec_bits_init (&bits, script->buffer); bits.ptr = script->main; return swfdec_script_foreach_internal (&bits, func, user_data); } /** * swfdec_script_new: * @buffer: the #SwfdecBuffer containing the script. This function will take * ownership of the passed in buffer. * @name: name of the script for debugging purposes * @version: Actionscript version to use in this script * * Creates a new script for the actionscript provided in @buffer. * * Returns: a new #SwfdecScript for executing the script in @buffer. **/ SwfdecScript * swfdec_script_new (SwfdecBuffer *buffer, const char *name, guint version) { SwfdecBits bits; SwfdecScript *script; g_return_val_if_fail (buffer != NULL, NULL); swfdec_bits_init (&bits, buffer); script = swfdec_script_new_from_bits (&bits, name, version); swfdec_buffer_unref (buffer); return script; } SwfdecScript * swfdec_script_new_from_bits (SwfdecBits *bits, const char *name, guint version) { SwfdecScript *script; SwfdecBuffer *buffer; SwfdecBits org; guint len; g_return_val_if_fail (bits != NULL, NULL); org = *bits; len = swfdec_bits_left (bits) / 8; script = g_new0 (SwfdecScript, 1); script->refcount = 1; script->name = g_strdup (name ? name : "Unnamed script"); script->version = version; /* by default, a function has 4 registers */ script->n_registers = 5; /* These flags are the default arguments used by scripts read from a file. * DefineFunction and friends override this */ script->flags = SWFDEC_SCRIPT_SUPPRESS_ARGS; if (!swfdec_script_foreach_internal (bits, validate_action, script)) { swfdec_script_unref (script); return NULL; } len -= swfdec_bits_left (bits) / 8; if (len == 0) { buffer = swfdec_buffer_new (0); } else { buffer = swfdec_bits_get_buffer (&org, len); } script->main = buffer->data; script->exit = buffer->data + buffer->length; script->buffer = swfdec_buffer_ref (swfdec_buffer_get_super (buffer)); swfdec_buffer_unref (buffer); return script; } /** * swfdec_script_ref: * @script: a script * * Increases the reference count of the given @script by one. * * Returns: The @script given as an argument **/ SwfdecScript * swfdec_script_ref (SwfdecScript *script) { g_return_val_if_fail (script != NULL, NULL); g_return_val_if_fail (script->refcount > 0, NULL); script->refcount++; return script; } /** * swfdec_script_unref: * @script: a script * * Decreases the reference count of the given @script by one. If the count * reaches zero, it will automatically be destroyed. **/ void swfdec_script_unref (SwfdecScript *script) { guint i; g_return_if_fail (script != NULL); g_return_if_fail (script->refcount > 0); script->refcount--; if (script->refcount > 0) return; if (script->buffer) swfdec_buffer_unref (script->buffer); if (script->constant_pool) swfdec_buffer_unref (script->constant_pool); g_free (script->name); for (i = 0; i < script->n_arguments; i++) { g_free (script->arguments[i].name); } g_free (script->arguments); g_free (script); } /** * swfdec_script_get_version: * @script: the script * * Queries the Flash version this script was compiled with. Different versions * result in slightly different behavior in the script interpreter. * * Returns: The Flash version this script conforms to **/ guint swfdec_script_get_version (SwfdecScript *script) { g_return_val_if_fail (script != NULL, 0); return script->version; } /*** UTILITY FUNCTIONS ***/ const char * swfdec_action_get_name (guint action) { g_return_val_if_fail (action < 256, NULL); return swfdec_as_actions[action].name; } guint swfdec_action_get_from_name (const char *name) { guint i; g_return_val_if_fail (name != NULL, 0); for (i = 0; i < 256; i++) { if (swfdec_as_actions[i].name && g_str_equal (name, swfdec_as_actions[i].name)) return i; } return 0; }