gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog server/Makefile.am server/actio...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog server/Makefile.am server/actio...
Date: Tue, 20 Jun 2006 11:12:36 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  06/06/20 11:12:36

Modified files:
        .              : ChangeLog 
        server         : Makefile.am action.cpp action.h 
                         as_environment.cpp impl.h textformat.cpp 
        server/swf     : ASHandlers.cpp 
Added files:
        server         : action_buffer.cpp action_buffer.h 
                         with_stack_entry.h 

Log message:
        moved action_buffer and with_stack_entry classes in their own files.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.415&r2=1.416
http://cvs.savannah.gnu.org/viewcvs/gnash/server/Makefile.am?cvsroot=gnash&r1=1.47&r2=1.48
http://cvs.savannah.gnu.org/viewcvs/gnash/server/action.cpp?cvsroot=gnash&r1=1.85&r2=1.86
http://cvs.savannah.gnu.org/viewcvs/gnash/server/action.h?cvsroot=gnash&r1=1.34&r2=1.35
http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_environment.cpp?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/server/impl.h?cvsroot=gnash&r1=1.27&r2=1.28
http://cvs.savannah.gnu.org/viewcvs/gnash/server/textformat.cpp?cvsroot=gnash&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/gnash/server/action_buffer.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/action_buffer.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/with_stack_entry.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/swf/ASHandlers.cpp?cvsroot=gnash&r1=1.9&r2=1.10

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.415
retrieving revision 1.416
diff -u -b -r1.415 -r1.416
--- ChangeLog   20 Jun 2006 02:05:22 -0000      1.415
+++ ChangeLog   20 Jun 2006 11:12:36 -0000      1.416
@@ -1,3 +1,12 @@
+2006-06-20 Sandro Santilli <address@hidden>
+
+       * server/Makefile.am, server/action.cpp, server/action.h,
+       server/action_buffer.cpp, server/action_buffer.h,
+       server/as_environment.cpp, server/impl.h, server/textformat.cpp,
+       server/with_stack_entry.h, server/swf/ASHandlers.cpp:
+       moved action_buffer and with_stack_entry classes in their own
+       files.
+
 2006-06-19 Michael Carlson <address@hidden>
 
        * server/string.cpp: Eliminate wasteful if/else and 

Index: server/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/Makefile.am,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -b -r1.47 -r1.48
--- server/Makefile.am  7 Jun 2006 03:03:21 -0000       1.47
+++ server/Makefile.am  20 Jun 2006 11:12:36 -0000      1.48
@@ -136,6 +136,7 @@
         xmlsocket.cpp \
         string.cpp \
         action.cpp \
+       action_buffer.cpp \
         button.cpp \
         dlist.cpp \
        edit_text_character.cpp \
@@ -166,6 +167,7 @@
 
 noinst_HEADERS = $(as_incls) \
        action.h \
+       action_buffer.h \
        array.h \
        as_value.h \
        as_environment.h \
@@ -227,6 +229,7 @@
        swf/TagLoadersTable.h \
        swf/tag_loaders.h \
        xmlsocket.h \
+       with_stack_entry.h \
        fn_call.h
 
 libgnashserver_la_LIBADD = \

Index: server/action.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/action.cpp,v
retrieving revision 1.85
retrieving revision 1.86
diff -u -b -r1.85 -r1.86
--- server/action.cpp   19 Jun 2006 14:39:48 -0000      1.85
+++ server/action.cpp   20 Jun 2006 11:12:36 -0000      1.86
@@ -62,6 +62,7 @@
 #include "sound.h"
 #include "array.h"
 #include "types.h"
+#include "with_stack_entry.h"
 
 #ifdef HAVE_LIBXML
 #include "xml.h"
@@ -152,9 +153,16 @@
 
 // Vitaly:     SWF::SWFHandlers::_handlers & SWF::SWFHandlers::_property_names
 //     are used at creation "SWFHandlers ash" and consequently they should be 
certain here
-std::map<action_type, ActionHandler> SWF::SWFHandlers::_handlers;
-std::vector<std::string> SWF::SWFHandlers::_property_names;
-SWFHandlers ash;
+//
+// Tue Jun 20 12:16:03 CEST 2006
+// strk: Moved  SWFHandlers stuff in server/swf/ASHandlers.cpp, where
+//       the SWFHandlers class is defined.
+//       Moved 'ash' definition to server/action_buffer.cpp, where
+//       it is used.
+//
+//std::map<action_type, ActionHandler> SWF::SWFHandlers::_handlers;
+//std::vector<std::string> SWF::SWFHandlers::_property_names;
+//SWFHandlers ash;
        
 //
 // action stuff
@@ -165,7 +173,6 @@
 // Statics.
 bool   s_inited = false;
 smart_ptr<as_object>   s_global;
-fscommand_callback     s_fscommand_handler = NULL;
 
 void register_component(const tu_stringi& name, as_c_function_ptr handler)
 {
@@ -245,29 +252,6 @@
 }
 #endif // EXTERN_MOVIE
 
-void   register_fscommand_callback(fscommand_callback handler)
-    // External interface.
-{
-    s_fscommand_handler = handler;
-}
-
-
-
-// Utility.  Try to convert str to a number.  If successful,
-// put the result in *result, and return true.  If not
-// successful, put 0 in *result, and return false.
-static bool string_to_number(double* result, const char* str)
-{
-    char* tail = 0;
-    *result = strtod(str, &tail);
-    if (tail == str || *tail != 0)
-       {
-           // Failed conversion to Number.
-           return false;
-       }
-    return true;
-}
-
 
 //
 // Function/method dispatch.
@@ -556,768 +540,6 @@
 }
 
 //
-// action_buffer
-//
-
-// Disassemble one instruction to the log.
-static void
-log_disasm(const unsigned char* instruction_data);
-
-action_buffer::action_buffer()
-    :
-    m_decl_dict_processed_at(-1)
-{
-}
-
-
-void
-action_buffer::read(stream* in)
-{
-    // Read action bytes.
-    for (;;) {
-       int     instruction_start = m_buffer.size();
-       
-       int     pc = m_buffer.size();
-       
-       int     action_id = in->read_u8();
-       m_buffer.push_back(action_id);
-       
-       if (action_id & 0x80) {
-           // Action contains extra data.  Read it.
-           int length = in->read_u16();
-           m_buffer.push_back(length & 0x0FF);
-           m_buffer.push_back((length >> 8) & 0x0FF);
-           for (int i = 0; i < length; i++) {
-               unsigned char b = in->read_u8();
-               m_buffer.push_back(b);
-           }
-       }
-
-       dbglogfile.setStamp(false);
-       log_action("PC index: %d:\t", pc);
-       if (dbglogfile.getActionDump()) {
-           log_disasm(&m_buffer[instruction_start]);
-       }
-       
-       if (action_id == 0) {
-           // end of action buffer.
-           break;
-       }
-    }
-}
-
-
-/*private*/
-// Interpret the decl_dict opcode.  Don't read stop_pc or
-// later.  A dictionary is some static strings embedded in the
-// action buffer; there should only be one dictionary per
-// action buffer.
-//
-// NOTE: Normally the dictionary is declared as the first
-// action in an action buffer, but I've seen what looks like
-// some form of copy protection that amounts to:
-//
-// <start of action buffer>
-//          push true
-//          branch_if_true label
-//          decl_dict   [0]   // this is never executed, but has lots of 
orphan data declared in the opcode
-// label:   // (embedded inside the previous opcode; looks like an invalid 
jump)
-//          ... "protected" code here, including the real decl_dict opcode ...
-//          <end of the dummy decl_dict [0] opcode>
-//
-// So we just interpret the first decl_dict we come to, and
-// cache the results.  If we ever hit a different decl_dict in
-// the same action_buffer, then we log an error and ignore it.
-void
-action_buffer::process_decl_dict(int start_pc, int stop_pc)
-{
-    assert(stop_pc <= (int) m_buffer.size());
-    
-    if (m_decl_dict_processed_at == start_pc) {
-       // We've already processed this decl_dict.
-       int     count = m_buffer[start_pc + 3] | (m_buffer[start_pc + 4] << 8);
-       assert((int) m_dictionary.size() == count);
-       UNUSED(count);
-       return;
-    }
-    
-    if (m_decl_dict_processed_at != -1)        {
-       log_error("process_decl_dict(%d, %d): decl_dict was already processed 
at %d\n",
-                 start_pc,
-                 stop_pc,
-                 m_decl_dict_processed_at);
-       return;
-    }
-    
-    m_decl_dict_processed_at = start_pc;
-    
-    // Actual processing.
-    int        i = start_pc;
-    int        length = m_buffer[i + 1] | (m_buffer[i + 2] << 8);
-    int        count = m_buffer[i + 3] | (m_buffer[i + 4] << 8);
-    i += 2;
-    
-    UNUSED(length);
-    
-    assert(start_pc + 3 + length == stop_pc);
-    
-    m_dictionary.resize(count);
-    
-    // Index the strings.
-    for (int ct = 0; ct < count; ct++) {
-       // Point into the current action buffer.
-       m_dictionary[ct] = (const char*) &m_buffer[3 + i];
-       
-       while (m_buffer[3 + i]) {
-           // safety check.
-           if (i >= stop_pc) {
-               log_error("action buffer dict length exceeded\n");
-               
-               // Jam something into the remaining (invalid) entries.
-               while (ct < count) {
-                   m_dictionary[ct] = "<invalid>";
-                   ct++;
-               }
-               return;
-           }
-           i++;
-       }
-       i++;
-    }
-}
-
-
-// Interpret the actions in this action buffer, and evaluate
-// them in the given environment.  Execute our whole buffer,
-// without any arguments passed in.
-void
-action_buffer::execute(as_environment* env)
-{
-    int        local_stack_top = env->get_local_frame_top();
-    env->add_frame_barrier();
-    
-    std::vector<with_stack_entry> empty_with_stack;
-    execute(env, 0, m_buffer.size(), NULL, empty_with_stack, false /* not 
function2 */);
-    
-    env->set_local_frame_top(local_stack_top);
-}
-
-#if 1
-/*private*/
-void
-action_buffer::doActionDefineFunction(as_environment* env,
-                                     std::vector<with_stack_entry>& 
with_stack, int pc, int* next_pc)
-{
-
-    // Create a new function_as_object
-    function_as_object* func = new function_as_object(this, env, *next_pc, 
with_stack);
-
-    int        i = pc;
-    i += 3;
-
-    // Extract name.
-    // @@ security: watch out for possible missing terminator here!
-    tu_string  name = (const char*) &m_buffer[i];
-    i += name.length() + 1;
-
-    // Get number of arguments.
-    int        nargs = m_buffer[i] | (m_buffer[i + 1] << 8);
-    i += 2;
-
-    // Get the names of the arguments.
-    for (int n = 0; n < nargs; n++) {
-       // @@ security: watch out for possible missing terminator here!
-       func->add_arg(0, (const char*) &m_buffer[i]);
-       i += func->m_args.back().m_name.length() + 1;
-    }
-    
-    // Get the length of the actual function code.
-    int        length = m_buffer[i] | (m_buffer[i + 1] << 8);
-    i += 2;
-    func->set_length(length);
-
-    // Skip the function body (don't interpret it now).
-    *next_pc += length;
-
-    // If we have a name, then save the function in this
-    // environment under that name.
-    as_value   function_value(func);
-    if (name.length() > 0) {
-       // @@ NOTE: should this be m_target->set_variable()???
-       env->set_member(name, function_value);
-    }
-    
-    // Also leave it on the stack.
-    env->push_val(function_value);
-}
-
-/*private*/
-void
-action_buffer::doActionDefineFunction2(as_environment* env,
-                                      std::vector<with_stack_entry>& 
with_stack, int pc, int* next_pc)
-{
-    function_as_object*        func = new function_as_object(this, env, 
*next_pc, with_stack);
-    func->set_is_function2();
-
-    int        i = pc;
-    i += 3;
-
-    // Extract name.
-    // @@ security: watch out for possible missing terminator here!
-    tu_string  name = (const char*) &m_buffer[i];
-    i += name.length() + 1;
-
-    // Get number of arguments.
-    int        nargs = m_buffer[i] | (m_buffer[i + 1] << 8);
-    i += 2;
-
-    // Get the count of local registers used by this function.
-    uint8      register_count = m_buffer[i];
-    i += 1;
-    func->set_local_register_count(register_count);
-
-    // Flags, for controlling register assignment of implicit args.
-    uint16     flags = m_buffer[i] | (m_buffer[i + 1] << 8);
-    i += 2;
-    func->set_function2_flags(flags);
-
-    // Get the register assignments and names of the arguments.
-    for (int n = 0; n < nargs; n++) {
-       int     arg_register = m_buffer[i];
-       i++;
-       
-       // @@ security: watch out for possible missing terminator here!
-       func->add_arg(arg_register, (const char*) &m_buffer[i]);
-           i += func->m_args.back().m_name.length() + 1;
-    }
-
-    // Get the length of the actual function code.
-    int        length = m_buffer[i] | (m_buffer[i + 1] << 8);
-    i += 2;
-    func->set_length(length);
-
-    // Skip the function body (don't interpret it now).
-    *next_pc += length;
-
-    // If we have a name, then save the function in this
-    // environment under that name.
-    as_value   function_value(func);
-    if (name.length() > 0) {
-       // @@ NOTE: should this be m_target->set_variable()???
-       env->set_member(name, function_value);
-    }
-    
-    // Also leave it on the stack.
-    env->push_val(function_value);
-}
-#endif
-
-// Interpret the specified subset of the actions in our
-// buffer.  Caller is responsible for cleaning up our local
-// stack frame (it may have passed its arguments in via the
-// local stack frame).
-// 
-// The is_function2 flag determines whether to use global or local registers.
-void
-action_buffer::execute(
-    as_environment* env,
-    int start_pc,
-    int exec_bytes,
-    as_value* retval,
-    const std::vector<with_stack_entry>& initial_with_stack,
-    bool is_function2)
-{
-    action_init();     // @@ stick this somewhere else; need some global 
static init function
-
-    assert(env);
-
-    std::vector<with_stack_entry>      with_stack(initial_with_stack);
-
-#if 0
-    // Check the time
-    if (periodic_events.expired()) {
-       periodic_events.poll_event_handlers(env);
-    }
-#endif
-               
-    movie*     original_target = env->get_target();
-    UNUSED(original_target);           // Avoid warnings.
-
-    int        stop_pc = start_pc + exec_bytes;
-
-    for (int pc = start_pc; pc < stop_pc; ) {
-       // Cleanup any expired "with" blocks.
-       while (with_stack.size() > 0
-              && pc >= with_stack.back().m_block_end_pc) {
-           // Drop this stack element
-           with_stack.resize(with_stack.size() - 1);
-       }
-       
-       // Get the opcode.
-       int     action_id = m_buffer[pc];
-       if ((action_id & 0x80) == 0) {
-           if (dbglogfile.getActionDump()) {
-               log_action("\nEX:\t");
-               log_disasm(&m_buffer[pc]);
-           }
-           
-           // IF_VERBOSE_ACTION(log_msg("Action ID is: 0x%x\n", action_id));
-           
-           ash.execute((action_type)action_id, *env);
-           pc++;       // advance to next action.
-       } else {
-           if (dbglogfile.getActionDump()) {
-               log_action("\nEX:\t");
-               log_disasm(&m_buffer[pc]);
-           }
-           
-           // Action containing extra data.
-           int length = m_buffer[pc + 1] | (m_buffer[pc + 2] << 8);
-           int next_pc = pc + length + 3;
-           
-           switch (action_id) {
-             default:
-                 break;
-                 
-             case SWF::ACTION_GOTOFRAME:       // goto frame
-             {
-                 int   frame = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
-                 // 0-based already?
-                 //// Convert from 1-based to 0-based
-                 //frame--;
-                 env->get_target()->goto_frame(frame);
-                 break;
-             }
-             
-             case SWF::ACTION_GETURL:  // get url
-             {
-                 // If this is an FSCommand, then call the callback
-                 // handler, if any.
-                 
-                 // Two strings as args.
-                 const char*   url = (const char*) &(m_buffer[pc + 3]);
-                 int   url_len = strlen(url);
-                 const char*   target = (const char*) &(m_buffer[pc + 3 + 
url_len + 1]);
-                 
-                 // If the url starts with an "http" or "https",
-                 // then we want to load it into a web browser.
-                 if (strncmp(url, "http", 4) == 0) {
-//                               if (windowid) {
-//                                   Atom mAtom = 486;
-//                                   Display *mDisplay = XOpenDisplay(NULL);
-//                                   XLockDisplay(mDisplay);
-//                                   XChangeProperty (mDisplay, windowid, 
mAtom,
-//                                                    XA_STRING, 8, 
PropModeReplace,
-//                                                    (unsigned char *)url,
-//                                                    url_len);
-                     
-//                                   XUnlockDisplay(mDisplay);
-//                                   XCloseDisplay(mDisplay);
-//                               } else {
-                     string command = "firefox -remote \"openurl(";
-                     command += url;
-                     command += ")\"";
-                     dbglogfile << "Launching URL... " << command << endl;
-//                               movie *target = env->get_target();
-//                               target->get_url(url);
-                     system(command.c_str());
-//                               }
-                     break;
-                 }
-                 
-                 // If the url starts with "FSCommand:", then this is
-                 // a message for the host app.
-                 if (strncmp(url, "FSCommand:", 10) == 0) {
-                     if (s_fscommand_handler) {
-                         // Call into the app.
-                         
(*s_fscommand_handler)(env->get_target()->get_root_interface(), url + 10, 
target);
-                     }
-                 } else {
-#ifdef EXTERN_MOVIE
-//                                   log_error("get url: target=%s, url=%s\n", 
target, url);
-                     
-                     tu_string tu_target = target;
-                     movie* target_movie = env->find_target(tu_target);
-                     if (target_movie != NULL) {
-                         movie *root_movie = 
env->get_target()->get_root_movie();
-                         attach_extern_movie(url, target_movie, root_movie);
-                     } else {
-                         log_error("get url: target %s not found\n", target);
-                     }
-#endif // EXTERN_MOVIE
-                 }
-                 
-                 break;
-             }
-             
-             case SWF::ACTION_SETREGISTER:     // store_register
-             {
-                 int   reg = m_buffer[pc + 3];
-                 // Save top of stack in specified register.
-                 if (is_function2) {
-                     *(env->local_register_ptr(reg)) = env->top(0);
-                     
-                         log_action("-------------- local register[%d] = 
'%s'\n",
-                         reg,
-                         env->top(0).to_string());
-                 } else if (reg >= 0 && reg < 4) {
-                     env->m_global_register[reg] = env->top(0);
-                     
-                         log_action("-------------- global register[%d] = 
'%s'\n",
-                                 reg,
-                                 env->top(0).to_string());
-                 } else {
-                     log_error("store_register[%d] -- register out of 
bounds!", reg);
-                 }
-                 
-                 break;
-             }
-             
-             case SWF::ACTION_CONSTANTPOOL:    // decl_dict: declare dictionary
-             {
-                 int   i = pc;
-                 //int count = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
-                 i += 2;
-                 
-                 process_decl_dict(pc, next_pc);
-                 
-                 break;
-             }
-             
-             case SWF::ACTION_WAITFORFRAME:    // wait for frame
-             {
-                 // If we haven't loaded a specified frame yet, then we're 
supposed to skip
-                 // some specified number of actions.
-                 //
-                 // Since we don't load incrementally, just ignore this opcode.
-                 break;
-             }
-             
-             case SWF::ACTION_SETTARGET:       // set target
-             {
-                 // Change the movie we're working on.
-                 const char* target_name = (const char*) &m_buffer[pc + 3];
-                 movie *new_target;
-                 
-                 // if the string is blank, we set target to the root movie
-                 // TODO - double check this is correct?
-                 if (target_name[0] == '\0')
-                     new_target = env->find_target((tu_string)"/");
-                 else
-                     new_target = env->find_target((tu_string)target_name);
-                 
-                 if (new_target == NULL) {
-                     log_action("ERROR: Couldn't find movie \"%s\" to set 
target to!"
-                                           " Not setting target at all...",
-                                           (const char *)target_name);
-                 }
-                 else
-                     env->set_target(new_target);
-                 
-                 break;
-             }
-             
-             case SWF::ACTION_GOTOLABEL:       // go to labeled frame, 
goto_frame_lbl
-             {
-                 char* frame_label = (char*) &m_buffer[pc + 3];
-                 movie *target = env->get_target();
-                 target->goto_labeled_frame(frame_label);
-                 break;
-             }
-             
-             case SWF::ACTION_WAITFORFRAMEEXPRESSION:  // wait for frame 
expression (?)
-             {
-                 // Pop the frame number to wait for; if it's not loaded skip 
the
-                 // specified number of actions.
-                 //
-                 // Since we don't support incremental loading, pop our arg and
-                 // don't do anything.
-                 env->drop(1);
-                 break;
-             }
-             
-             case SWF::ACTION_DEFINEFUNCTION2: // 0x8E
-                 doActionDefineFunction2(env, with_stack, pc, &next_pc);
-                 break;
-                 
-             case SWF::ACTION_WITH:    // with
-             {
-                 int   frame = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
-                 UNUSED(frame);
-                 log_action("-------------- with block start: stack size is 
%zd\n", with_stack.size());
-                 if (with_stack.size() < 8) {
-                     int       block_length = m_buffer[pc + 3] | (m_buffer[pc 
+ 4] << 8);
-                     int       block_end = next_pc + block_length;
-                     as_object*        with_obj = env->top(0).to_object();
-                     with_stack.push_back(with_stack_entry(with_obj, 
block_end));
-                 }
-                 env->drop(1);
-                 break;
-             }
-             case SWF::ACTION_PUSHDATA:        // push_data
-             {
-                 int i = pc;
-                 while (i - pc < length) {
-                     int       type = m_buffer[3 + i];
-                     i++;
-                     if (type == 0) {
-                         // string
-                         const char*   str = (const char*) &m_buffer[3 + i];
-                         i += strlen(str) + 1;
-                         env->push(str);
-                         
-                         log_action("-------------- pushed '%s'", str);
-                     } else if (type == 1) {
-                         // float (little-endian)
-                         union {
-                             float     f;
-                             uint32_t  i;
-                         } u;
-                         compiler_assert(sizeof(u) == sizeof(u.i));
-                         
-                         memcpy(&u.i, &m_buffer[3 + i], 4);
-                         u.i = swap_le32(u.i);
-                         i += 4;
-                         
-                         env->push(u.f);
-                         log_action("-------------- pushed '%g'", u.f);
-                     } else if (type == 2) {
-                         as_value nullvalue;
-                         nullvalue.set_null();
-                         env->push(nullvalue); 
-                         
-                         log_action("-------------- pushed NULL");
-                     } else if (type == 3) {
-                         env->push(as_value());
-                         
-                         log_action("-------------- pushed UNDEFINED");
-                     } else if (type == 4) {
-                         // contents of register
-                         int   reg = m_buffer[3 + i];
-                         UNUSED(reg);
-                         i++;
-                         if (is_function2) {
-                             env->push(*(env->local_register_ptr(reg)));
-                             log_action("-------------- pushed local 
register[%d] = '%s'\n",
-                                         reg,
-                                         env->top(0).to_string());
-                         } else if (reg < 0 || reg >= 4) {
-                             env->push(as_value());
-                             log_error("push register[%d] -- register out of 
bounds!\n", reg);
-                         } else {
-                             env->push(env->m_global_register[reg]);
-                             log_action("-------------- pushed global 
register[%d] = '%s'\n",
-                                         reg,
-                                         env->top(0).to_string());
-                         }
-                         
-                     } else if (type == 5) {
-                         bool  bool_val = m_buffer[3 + i] ? true : false;
-                         i++;
-//                                                     log_msg("bool(%d)\n", 
bool_val);
-                         env->push(bool_val);
-                         
-                         log_action("-------------- pushed %s",
-                                    (bool_val ? "true" : "false"));
-                     } else if (type == 6) {
-                         // double
-                         // wacky format: 45670123
-                         union {
-                             double    d;
-                             uint64    i;
-                             struct {
-                                 uint32_t      lo;
-                                 uint32_t      hi;
-                             } sub;
-                         } u;
-                         compiler_assert(sizeof(u) == sizeof(u.i));
-                         
-                         memcpy(&u.sub.hi, &m_buffer[3 + i], 4);
-                         memcpy(&u.sub.lo, &m_buffer[3 + i + 4], 4);
-                         u.i = swap_le64(u.i);
-                         i += 8;
-                         
-                         env->push(u.d);
-                         
-                         log_action("-------------- pushed double %g", u.d);
-                     } else if (type == 7) {
-                         // int32
-                         int32_t       val = m_buffer[3 + i]
-                             | (m_buffer[3 + i + 1] << 8)
-                             | (m_buffer[3 + i + 2] << 16)
-                             | (m_buffer[3 + i + 3] << 24);
-                         i += 4;
-                         
-                         env->push(val);
-                         
-                         log_action("-------------- pushed int32 %d",val);
-                     } else if (type == 8) {
-                         int   id = m_buffer[3 + i];
-                         i++;
-                         if (id < (int) m_dictionary.size()) {
-                             env->push(m_dictionary[id]);
-                             
-                             log_action("-------------- pushed '%s'",
-                                        m_dictionary[id]);
-                         } else {
-                             log_error("dict_lookup(%d) is out of bounds!\n", 
id);
-                             env->push(0);
-                             log_action("-------------- pushed 0");
-                         }
-                     } else if (type == 9) {
-                         int   id = m_buffer[3 + i] | (m_buffer[4 + i] << 8);
-                         i += 2;
-                         if (id < (int) m_dictionary.size()) {
-                             env->push(m_dictionary[id]);
-                             log_action("-------------- pushed '%s'\n", 
m_dictionary[id]);
-                         } else {
-                             log_error("dict_lookup(%d) is out of bounds!\n", 
id);
-                             env->push(0);
-                             
-                             log_action("-------------- pushed 0");
-                         }
-                     }
-                 }
-                 
-                 break;
-             }
-             case SWF::ACTION_BRANCHALWAYS:    // branch always (goto)
-             {
-                 int16_t       offset = m_buffer[pc + 3] | (m_buffer[pc + 4] 
<< 8);
-                 next_pc += offset;
-                 // @@ TODO range checks
-                 break;
-             }
-             case SWF::ACTION_GETURL2: // get url 2
-             {
-                 int   method = m_buffer[pc + 3];
-                 UNUSED(method);
-                 
-                 const char*   target = env->top(0).to_string();
-                 const char*   url = env->top(1).to_string();
-                 
-                 // If the url starts with "FSCommand:", then this is
-                 // a message for the host app.
-                 if (strncmp(url, "FSCommand:", 10) == 0) {
-                     if (s_fscommand_handler) {
-                         // Call into the app.
-                         
(*s_fscommand_handler)(env->get_target()->get_root_interface(), url + 10, 
target);
-                     }
-                 } else {
-#ifdef EXTERN_MOVIE
-//            log_error("get url2: target=%s, url=%s\n", target, url);
-                     
-                     movie* target_movie = env->find_target(env->top(0));
-                     if (target_movie != NULL) {
-                         movie*        root_movie = 
env->get_target()->get_root_movie();
-                         attach_extern_movie(url, target_movie, root_movie);
-                     } else {
-                         log_error("get url2: target %s not found\n", target);
-                     }
-#endif // EXTERN_MOVIE
-                 }
-                 env->drop(2);
-                 break;
-             }
-             
-             case SWF::ACTION_DEFINEFUNCTION: // declare function
-                 doActionDefineFunction(env, with_stack, pc, &next_pc);
-                 break;
-                 
-             case SWF::ACTION_BRANCHIFTRUE:    // branch if true
-             {
-                 int16_t       offset = m_buffer[pc + 3] | (m_buffer[pc + 4] 
<< 8);
-                 
-                 bool  test = env->top(0).to_bool();
-                 env->drop(1);
-                 if (test) {
-                     next_pc += offset;
-                     
-                     if (next_pc > stop_pc) {
-                         log_error("branch to offset %d -- this section only 
runs to %d\n",
-                                   next_pc,
-                                   stop_pc);
-                     }
-                 }
-                 break;
-             }
-             case SWF::ACTION_CALLFRAME:       // call frame
-             {
-                 // Note: no extra data in this instruction!
-                 assert(env->m_target);
-                 env->m_target->call_frame_actions(env->top(0));
-                 env->drop(1);
-                 
-                 break;
-             }
-             
-             case SWF::ACTION_GOTOEXPRESSION:  // goto frame expression, 
goto_frame_exp
-             {
-                 // From Alexi's SWF ref:
-                 //
-                 // Pop a value or a string and jump to the specified
-                 // frame. When a string is specified, it can include a
-                 // path to a sprite as in:
-                 // 
-                 //   /Test:55
-                 // 
-                 // When f_play is ON, the action is to play as soon as
-                 // that frame is reached. Otherwise, the
-                 // frame is shown in stop mode.
-                 
-                 unsigned char play_flag = m_buffer[pc + 3];
-                 movie::play_state     state = play_flag ? movie::PLAY : 
movie::STOP;
-                 
-                 movie* target = env->get_target();
-                 bool success = false;
-                 
-                 if (env->top(0).get_type() == as_value::UNDEFINED) {
-                     // No-op.
-                 } else if (env->top(0).get_type() == as_value::STRING) {
-                     // @@ TODO: parse possible sprite path...
-                     
-                     // Also, if the frame spec is actually a number (not a 
label), then
-                     // we need to do the conversion...
-                     
-                     const char* frame_label = env->top(0).to_string();
-                     if (target->goto_labeled_frame(frame_label)) {
-                         success = true;
-                     } else {
-                         // Couldn't find the label.  Try converting to a 
number.
-                         double num;
-                         if (string_to_number(&num, env->top(0).to_string())) {
-                             int frame_number = int(num);
-                             target->goto_frame(frame_number);
-                             success = true;
-                         }
-                         // else no-op.
-                     }
-                 } else if (env->top(0).get_type() == as_value::OBJECT) {
-                     // This is a no-op; see test_goto_frame.swf
-                 } else if (env->top(0).get_type() == as_value::NUMBER) {
-                     // Frame numbers appear to be 0-based!  @@ Verify.
-                     int frame_number = int(env->top(0).to_number());
-                     target->goto_frame(frame_number);
-                     success = true;
-                 }
-                 
-                 if (success) {
-                     target->set_play_state(state);
-                 }
-                 
-                 env->drop(1);  
-                 break;
-             }       
-           }
-           pc = next_pc;
-       }
-    }
-    
-    env->set_target(original_target);
-}
-
-
-//
 // event_id
 //
 
@@ -1414,226 +636,6 @@
 }
 
 
-//
-// Disassembler
-//
-
-// Disassemble one instruction to the log.
-void
-log_disasm(const unsigned char* instruction_data)
-{    
-    as_arg_t fmt = ARG_HEX;
-    action_type        action_id = (action_type)instruction_data[0];
-    unsigned char num[10];
-    memset(num, 0, 10);
-
-    dbglogfile.setStamp(false);
-    // Show instruction.
-    if (action_id > ash.lastType()) {
-       dbglogfile << "<unknown>[0x" << action_id  << "]" << endl;
-    } else {
-       dbglogfile << ash[action_id].getName().c_str() << endl;
-       fmt = ash[action_id].getArgFormat();
-    }
-
-    // Show instruction argument(s).
-    if (action_id & 0x80) {
-       assert(fmt != ARG_NONE);
-       int length = instruction_data[1] | (instruction_data[2] << 8);
-       if (fmt == ARG_HEX) {
-           for (int i = 0; i < length; i++) {
-               hexify(num, (const unsigned char *)&instruction_data[3 + i], 1);
-               dbglogfile << "0x" << num << " ";
-//             dbglogfile << instruction_data[3 + i] << " ";
-           }
-           dbglogfile << endl;
-       } else if (fmt == ARG_STR) {
-           string str;
-           for (int i = 0; i < length; i++) {
-               str = instruction_data[3 + i];
-           }
-           dbglogfile << "\"" << str.c_str() << "\"" << endl;
-       } else if (fmt == ARG_U8) {
-           int val = instruction_data[3];
-           dbglogfile << " " << val << endl;
-       } else if (fmt == ARG_U16) {
-           int val = instruction_data[3] | (instruction_data[4] << 8);
-           dbglogfile << " " << val << endl;
-       } else if (fmt == ARG_S16) {
-           int val = instruction_data[3] | (instruction_data[4] << 8);
-           if (val & 0x8000) val |= ~0x7FFF;   // sign-extend
-           dbglogfile << " " << val << endl;
-       } else if (fmt == ARG_PUSH_DATA) {
-           dbglogfile << endl;
-           int i = 0;
-           while (i < length) {
-               int     type = instruction_data[3 + i];
-               i++;
-               if (type == 0) {
-                   // string
-                   string str;
-                   while (instruction_data[3 + i]) {
-                       str += instruction_data[3 + i];
-                       i++;
-                   }
-                   i++;
-                   dbglogfile << "\t\"" << str.c_str() << "\"" << endl;
-               } else if (type == 1) {
-                   // float (little-endian)
-                   union {
-                       float   f;
-                       uint32_t        i;
-                   } u;
-                   compiler_assert(sizeof(u) == sizeof(u.i));
-                   
-                   memcpy(&u.i, instruction_data + 3 + i, 4);
-                   u.i = swap_le32(u.i);
-                   i += 4;
-                   
-                   dbglogfile << "(float) " << u.f << endl;
-               } else if (type == 2) {
-                   dbglogfile << "NULL" << endl;
-               } else if (type == 3) {
-                   dbglogfile << "undef" << endl;
-               } else if (type == 4) {
-                   // contents of register
-                   int reg = instruction_data[3 + i];
-                   i++;
-                   dbglogfile << "reg[" << reg << "]" << endl;
-               } else if (type == 5) {
-                   int bool_val = instruction_data[3 + i];
-                   i++;
-                   dbglogfile << "bool(" << bool_val << ")" << endl;
-               } else if (type == 6) {
-                   // double
-                   // wacky format: 45670123
-                   union {
-                       double  d;
-                       uint64  i;
-                       struct {
-                           uint32_t    lo;
-                           uint32_t    hi;
-                       } sub;
-                   } u;
-                   compiler_assert(sizeof(u) == sizeof(u.i));
-                   
-                   memcpy(&u.sub.hi, instruction_data + 3 + i, 4);
-                   memcpy(&u.sub.lo, instruction_data + 3 + i + 4, 4);
-                   u.i = swap_le64(u.i);
-                   i += 8;
-                   
-                   dbglogfile << "(double) " << u.d << endl;
-               } else if (type == 7) {
-                   // int32
-                   int32_t     val = instruction_data[3 + i]
-                       | (instruction_data[3 + i + 1] << 8)
-                       | (instruction_data[3 + i + 2] << 16)
-                       | (instruction_data[3 + i + 3] << 24);
-                   i += 4;
-                   dbglogfile << "(int) " << val << endl;
-               } else if (type == 8) {
-                   int id = instruction_data[3 + i];
-                   i++;
-                   dbglogfile << "dict_lookup[" << id << "]" << endl;
-               } else if (type == 9) {
-                   int id = instruction_data[3 + i] | (instruction_data[3 + i 
+ 1] << 8);
-                   i += 2;
-                   dbglogfile << "dict_lookup_lg[" << id << "]" << endl;
-               }
-           }
-       } else if (fmt == ARG_DECL_DICT) {
-           int i = 0;
-           int count = instruction_data[3 + i] | (instruction_data[3 + i + 1] 
<< 8);
-           i += 2;
-           
-           dbglogfile << " [" << count << "]" << endl;
-           
-           // Print strings.
-           for (int ct = 0; ct < count; ct++) {
-               dbglogfile << "\t" << endl;     // indent
-               
-               string str;
-               while (instruction_data[3 + i]) {
-                       // safety check.
-                   if (i >= length) {
-                       dbglogfile << "<disasm error -- length exceeded>" << 
endl;
-                       break;
-                   }
-                   str += instruction_data[3 + i];
-                   i++;
-               }
-               dbglogfile << "\"" << str.c_str() << "\"" << endl;
-               i++;
-           }
-       } else if (fmt == ARG_FUNCTION2) {
-           // Signature info for a function2 opcode.
-           int i = 0;
-           const char* function_name = (const char*) &instruction_data[3 + i];
-           i += strlen(function_name) + 1;
-           
-           int arg_count = instruction_data[3 + i] | (instruction_data[3 + i + 
1] << 8);
-           i += 2;
-           
-           int reg_count = instruction_data[3 + i];
-           i++;
-
-           dbglogfile << "\t\tname = '" << function_name << "'"
-                      << " arg_count = " << arg_count
-                      << " reg_count = " << reg_count << endl;
-           
-           uint16      flags = (instruction_data[3 + i]) | (instruction_data[3 
+ i + 1] << 8);
-           i += 2;
-           
-           // @@ What is the difference between "super" and "_parent"?
-           
-           bool        preload_global = (flags & 0x100) != 0;
-           bool        preload_parent = (flags & 0x80) != 0;
-           bool        preload_root   = (flags & 0x40) != 0;
-           bool        suppress_super = (flags & 0x20) != 0;
-           bool        preload_super  = (flags & 0x10) != 0;
-           bool        suppress_args  = (flags & 0x08) != 0;
-           bool        preload_args   = (flags & 0x04) != 0;
-           bool        suppress_this  = (flags & 0x02) != 0;
-           bool        preload_this   = (flags & 0x01) != 0;
-           
-           log_msg("\t\t        pg = %d\n"
-                   "\t\t        pp = %d\n"
-                   "\t\t        pr = %d\n"
-                   "\t\tss = %d, ps = %d\n"
-                   "\t\tsa = %d, pa = %d\n"
-                   "\t\tst = %d, pt = %d\n",
-                   int(preload_global),
-                   int(preload_parent),
-                   int(preload_root),
-                   int(suppress_super),
-                   int(preload_super),
-                   int(suppress_args),
-                   int(preload_args),
-                   int(suppress_this),
-                   int(preload_this));
-           
-           for (int argi = 0; argi < arg_count; argi++) {
-               int     arg_register = instruction_data[3 + i];
-               i++;
-               const char*     arg_name = (const char*) &instruction_data[3 + 
i];
-               i += strlen(arg_name) + 1;
-               
-               dbglogfile << "\t\targ[" << argi << "]"
-                          << " - reg[" << arg_register << "]"
-                          << " - '" << arg_name << "'" << endl;
-           }
-           
-           int function_length = instruction_data[3 + i] | (instruction_data[3 
+ i + 1] << 8);
-           i += 2;
-           
-           dbglogfile << "\t\tfunction length = " << function_length << endl;
-       }
-    } else {
-       dbglogfile << endl;
-    }
-    dbglogfile.setStamp(true);
-}
-
 
 };
 

Index: server/action.h
===================================================================
RCS file: /sources/gnash/gnash/server/action.h,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -b -r1.34 -r1.35
--- server/action.h     19 Jun 2006 14:39:48 -0000      1.34
+++ server/action.h     20 Jun 2006 11:12:36 -0000      1.35
@@ -150,117 +150,6 @@
                const tu_string&        get_function_name() const;
        };
 
-       //
-       // with_stack_entry
-       //
-
-       /// The "with" stack is for Pascal-like with-scoping.
-       struct with_stack_entry
-       {
-               smart_ptr<as_object>    m_object;
-               int     m_block_end_pc;
-               
-               with_stack_entry()
-                       :
-                       m_object(NULL),
-                       m_block_end_pc(0)
-               {
-               }
-
-               with_stack_entry(as_object* obj, int end)
-                       :
-                       m_object(obj),
-                       m_block_end_pc(end)
-               {
-               }
-       };
-
-
-       /// Base class for actions.
-       struct action_buffer
-       {
-               action_buffer();
-
-               /// Read action bytes from input stream
-               void    read(stream* in);
-
-               /// \brief
-               /// Interpret the actions in this action buffer, and evaluate
-               /// them in the given environment. 
-               //
-               /// Execute our whole buffer,
-               /// without any arguments passed in.
-               ///
-               void    execute(as_environment* env);
-
-               /// Interpret the specified subset of the actions in our buffer.
-               //
-               /// Caller is responsible for cleaning up our local
-               /// stack frame (it may have passed its arguments in via the
-               /// local stack frame).
-               void    execute(
-                       as_environment* env,
-                       int start_pc,
-                       int exec_bytes,
-                       as_value* retval,
-                       const std::vector<with_stack_entry>& initial_with_stack,
-                       bool is_function2);
-
-               bool    is_null()
-               {
-                       return m_buffer.size() < 1 || m_buffer[0] == 0;
-               }
-
-               int     get_length() const { return m_buffer.size(); }
-
-       private:
-               // Don't put these as values in std::vector<>!  They contain
-               // internal pointers and cannot be moved or copied.
-               // If you need to keep an array of them, keep pointers
-               // to new'd instances.
-               action_buffer(const action_buffer& a) { assert(0); }
-               void operator=(const action_buffer& a) { assert(0); }
-
-               void    process_decl_dict(int start_pc, int stop_pc);
-
-               // data:
-               std::vector<unsigned char>      m_buffer;
-               std::vector<const char*>        m_dictionary;
-               int     m_decl_dict_processed_at;
-
-               void doActionNew(as_environment* env, 
-                       std::vector<with_stack_entry>& with_stack);
-
-               void doActionInstanceOf(as_environment* env);
-
-               void doActionCast(as_environment* env);
-
-               void doActionCallMethod(as_environment* env);
-
-               void doActionCallFunction(as_environment* env,
-                       std::vector<with_stack_entry>& with_stack);
-
-               void doActionDefineFunction(as_environment* env,
-                       std::vector<with_stack_entry>& with_stack, int pc, int* 
next_pc);
-
-               void doActionDefineFunction2(as_environment* env,
-                       std::vector<with_stack_entry>& with_stack, int pc, int* 
next_pc);
-
-               void doActionGetMember(as_environment* env);
-
-               void doActionStrictEquals(as_environment* env);
-
-               void doActionEquals(as_environment* env);
-
-               void doActionDelete(as_environment* env,
-                       std::vector<with_stack_entry>& with_stack);
-
-               void doActionDelete2(as_environment* env,
-                       std::vector<with_stack_entry>& with_stack);
-
-       };
-
-
        struct as_property_interface
        {
                virtual ~as_property_interface() {}

Index: server/as_environment.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_environment.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- server/as_environment.cpp   7 Jun 2006 03:03:21 -0000       1.2
+++ server/as_environment.cpp   20 Jun 2006 11:12:36 -0000      1.3
@@ -42,6 +42,7 @@
 #include "movie.h"
 #include "as_value.h"
 #include "log.h"
+#include "with_stack_entry.h"
 
 #include <iostream>
 using namespace std;

Index: server/impl.h
===================================================================
RCS file: /sources/gnash/gnash/server/impl.h,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -b -r1.27 -r1.28
--- server/impl.h       25 May 2006 12:00:44 -0000      1.27
+++ server/impl.h       20 Jun 2006 11:12:36 -0000      1.28
@@ -44,7 +44,8 @@
 #endif
 
 #include "gnash.h"
-#include "action.h"
+//#include "action.h"
+#include "action_buffer.h"
 #include "types.h"
 #include "log.h"
 #include "container.h"

Index: server/textformat.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/textformat.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- server/textformat.cpp       20 May 2006 23:49:33 -0000      1.11
+++ server/textformat.cpp       20 Jun 2006 11:12:36 -0000      1.12
@@ -38,7 +38,8 @@
 
 #include "log.h"
 #include "textformat.h"
-#include "action.h" // for struct with_stack_entry
+//#include "action.h" // for struct with_stack_entry
+#include "with_stack_entry.h"
 #include "fn_call.h"
 
 namespace gnash {  

Index: server/swf/ASHandlers.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/swf/ASHandlers.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- server/swf/ASHandlers.cpp   16 Jun 2006 00:32:26 -0000      1.9
+++ server/swf/ASHandlers.cpp   20 Jun 2006 11:12:36 -0000      1.10
@@ -59,8 +59,8 @@
 /// SWF format parsing classes
 namespace SWF { // gnash::SWF
 
-//     std::map<action_type, ActionHandler> SWFHandlers::_handlers;
-//     std::vector<std::string> SWFHandlers::_property_names;
+std::map<action_type, ActionHandler> SWFHandlers::_handlers;
+std::vector<std::string> SWFHandlers::_property_names;
 
 ActionHandler::ActionHandler()
     : _debug(false), _stack_args(0), _arg_format(ARG_NONE)

Index: server/action_buffer.cpp
===================================================================
RCS file: server/action_buffer.cpp
diff -N server/action_buffer.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/action_buffer.cpp    20 Jun 2006 11:12:36 -0000      1.1
@@ -0,0 +1,1084 @@
+// 
+//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+//
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "action_buffer.h"
+#include "Function.h" // for function_as_object
+#include "log.h"
+#include "stream.h"
+
+#include "swf.h"
+#include "ASHandlers.h"
+#include "as_environment.h"
+
+#include <typeinfo> 
+
+#if !defined(_WIN32) && !defined(WIN32)
+# include <pthread.h> 
+#endif
+
+#include <string>
+#include <stdlib.h> // for strtod
+
+using namespace gnash;
+using namespace SWF;
+using std::string;
+using std::endl;
+
+
+namespace gnash {
+
+static SWFHandlers ash;
+
+// Utility.  Try to convert str to a number.  If successful,
+// put the result in *result, and return true.  If not
+// successful, put 0 in *result, and return false.
+static bool string_to_number(double* result, const char* str)
+{
+    char* tail = 0;
+    *result = strtod(str, &tail);
+    if (tail == str || *tail != 0)
+       {
+           // Failed conversion to Number.
+           return false;
+       }
+    return true;
+}
+
+fscommand_callback s_fscommand_handler = NULL;
+
+// External interface.
+void   register_fscommand_callback(fscommand_callback handler)
+{
+    s_fscommand_handler = handler;
+}
+
+
+
+// Disassemble one instruction to the log.
+static void
+log_disasm(const unsigned char* instruction_data);
+
+action_buffer::action_buffer()
+    :
+    m_decl_dict_processed_at(-1)
+{
+}
+
+
+void
+action_buffer::read(stream* in)
+{
+    // Read action bytes.
+    for (;;) {
+       int     instruction_start = m_buffer.size();
+       
+       int     pc = m_buffer.size();
+       
+       int     action_id = in->read_u8();
+       m_buffer.push_back(action_id);
+       
+       if (action_id & 0x80) {
+           // Action contains extra data.  Read it.
+           int length = in->read_u16();
+           m_buffer.push_back(length & 0x0FF);
+           m_buffer.push_back((length >> 8) & 0x0FF);
+           for (int i = 0; i < length; i++) {
+               unsigned char b = in->read_u8();
+               m_buffer.push_back(b);
+           }
+       }
+
+       dbglogfile.setStamp(false);
+       log_action("PC index: %d:\t", pc);
+       if (dbglogfile.getActionDump()) {
+           log_disasm(&m_buffer[instruction_start]);
+       }
+       
+       if (action_id == 0) {
+           // end of action buffer.
+           break;
+       }
+    }
+}
+
+
+/*private*/
+// Interpret the decl_dict opcode.  Don't read stop_pc or
+// later.  A dictionary is some static strings embedded in the
+// action buffer; there should only be one dictionary per
+// action buffer.
+//
+// NOTE: Normally the dictionary is declared as the first
+// action in an action buffer, but I've seen what looks like
+// some form of copy protection that amounts to:
+//
+// <start of action buffer>
+//          push true
+//          branch_if_true label
+//          decl_dict   [0]   // this is never executed, but has lots of 
orphan data declared in the opcode
+// label:   // (embedded inside the previous opcode; looks like an invalid 
jump)
+//          ... "protected" code here, including the real decl_dict opcode ...
+//          <end of the dummy decl_dict [0] opcode>
+//
+// So we just interpret the first decl_dict we come to, and
+// cache the results.  If we ever hit a different decl_dict in
+// the same action_buffer, then we log an error and ignore it.
+void
+action_buffer::process_decl_dict(int start_pc, int stop_pc)
+{
+    assert(stop_pc <= (int) m_buffer.size());
+    
+    if (m_decl_dict_processed_at == start_pc) {
+       // We've already processed this decl_dict.
+       int     count = m_buffer[start_pc + 3] | (m_buffer[start_pc + 4] << 8);
+       assert((int) m_dictionary.size() == count);
+       UNUSED(count);
+       return;
+    }
+    
+    if (m_decl_dict_processed_at != -1)        {
+       log_error("process_decl_dict(%d, %d): decl_dict was already processed 
at %d\n",
+                 start_pc,
+                 stop_pc,
+                 m_decl_dict_processed_at);
+       return;
+    }
+    
+    m_decl_dict_processed_at = start_pc;
+    
+    // Actual processing.
+    int        i = start_pc;
+    int        length = m_buffer[i + 1] | (m_buffer[i + 2] << 8);
+    int        count = m_buffer[i + 3] | (m_buffer[i + 4] << 8);
+    i += 2;
+    
+    UNUSED(length);
+    
+    assert(start_pc + 3 + length == stop_pc);
+    
+    m_dictionary.resize(count);
+    
+    // Index the strings.
+    for (int ct = 0; ct < count; ct++) {
+       // Point into the current action buffer.
+       m_dictionary[ct] = (const char*) &m_buffer[3 + i];
+       
+       while (m_buffer[3 + i]) {
+           // safety check.
+           if (i >= stop_pc) {
+               log_error("action buffer dict length exceeded\n");
+               
+               // Jam something into the remaining (invalid) entries.
+               while (ct < count) {
+                   m_dictionary[ct] = "<invalid>";
+                   ct++;
+               }
+               return;
+           }
+           i++;
+       }
+       i++;
+    }
+}
+
+
+// Interpret the actions in this action buffer, and evaluate
+// them in the given environment.  Execute our whole buffer,
+// without any arguments passed in.
+void
+action_buffer::execute(as_environment* env)
+{
+    int        local_stack_top = env->get_local_frame_top();
+    env->add_frame_barrier();
+    
+    std::vector<with_stack_entry> empty_with_stack;
+    execute(env, 0, m_buffer.size(), NULL, empty_with_stack, false /* not 
function2 */);
+    
+    env->set_local_frame_top(local_stack_top);
+}
+
+#if 1
+/*private*/
+void
+action_buffer::doActionDefineFunction(as_environment* env,
+               std::vector<with_stack_entry>& with_stack,
+               size_t pc,
+               size_t* next_pc)
+{
+
+    // Create a new function_as_object
+    function_as_object* func = new function_as_object(this, env, *next_pc, 
with_stack);
+
+    size_t     i = pc;
+    i += 3;
+
+    // Extract name.
+    // @@ security: watch out for possible missing terminator here!
+    tu_string  name = (const char*) &m_buffer[i];
+    i += name.length() + 1;
+
+    // Get number of arguments.
+    int        nargs = m_buffer[i] | (m_buffer[i + 1] << 8);
+    i += 2;
+
+    // Get the names of the arguments.
+    for (int n = 0; n < nargs; n++) {
+       // @@ security: watch out for possible missing terminator here!
+       func->add_arg(0, (const char*) &m_buffer[i]);
+       i += func->m_args.back().m_name.length() + 1;
+    }
+    
+    // Get the length of the actual function code.
+    int        length = m_buffer[i] | (m_buffer[i + 1] << 8);
+    i += 2;
+    func->set_length(length);
+
+    // Skip the function body (don't interpret it now).
+    *next_pc += length;
+
+    // If we have a name, then save the function in this
+    // environment under that name.
+    as_value   function_value(func);
+    if (name.length() > 0) {
+       // @@ NOTE: should this be m_target->set_variable()???
+       env->set_member(name, function_value);
+    }
+    
+    // Also leave it on the stack.
+    env->push_val(function_value);
+}
+
+/*private*/
+void
+action_buffer::doActionDefineFunction2(as_environment* env,
+               std::vector<with_stack_entry>& with_stack,
+               size_t pc,
+               size_t* next_pc)
+{
+    function_as_object*        func = new function_as_object(this, env, 
*next_pc, with_stack);
+    func->set_is_function2();
+
+    size_t i = pc;
+    i += 3;
+
+    // Extract name.
+    // @@ security: watch out for possible missing terminator here!
+    tu_string  name = (const char*) &m_buffer[i];
+    i += name.length() + 1;
+
+    // Get number of arguments.
+    int        nargs = m_buffer[i] | (m_buffer[i + 1] << 8);
+    i += 2;
+
+    // Get the count of local registers used by this function.
+    uint8      register_count = m_buffer[i];
+    i += 1;
+    func->set_local_register_count(register_count);
+
+    // Flags, for controlling register assignment of implicit args.
+    uint16     flags = m_buffer[i] | (m_buffer[i + 1] << 8);
+    i += 2;
+    func->set_function2_flags(flags);
+
+    // Get the register assignments and names of the arguments.
+    for (int n = 0; n < nargs; n++) {
+       int     arg_register = m_buffer[i];
+       i++;
+       
+       // @@ security: watch out for possible missing terminator here!
+       func->add_arg(arg_register, (const char*) &m_buffer[i]);
+           i += func->m_args.back().m_name.length() + 1;
+    }
+
+    // Get the length of the actual function code.
+    int        length = m_buffer[i] | (m_buffer[i + 1] << 8);
+    i += 2;
+    func->set_length(length);
+
+    // Skip the function body (don't interpret it now).
+    *next_pc += length;
+
+    // If we have a name, then save the function in this
+    // environment under that name.
+    as_value   function_value(func);
+    if (name.length() > 0) {
+       // @@ NOTE: should this be m_target->set_variable()???
+       env->set_member(name, function_value);
+    }
+    
+    // Also leave it on the stack.
+    env->push_val(function_value);
+}
+#endif
+
+// Interpret the specified subset of the actions in our
+// buffer.  Caller is responsible for cleaning up our local
+// stack frame (it may have passed its arguments in via the
+// local stack frame).
+// 
+// The is_function2 flag determines whether to use global or local registers.
+void
+action_buffer::execute(
+    as_environment* env,
+    size_t start_pc,
+    size_t exec_bytes,
+    as_value* /* retval */ , //should we drop this parameter ?
+    const std::vector<with_stack_entry>& initial_with_stack,
+    bool is_function2)
+{
+    action_init();     // @@ stick this somewhere else; need some global 
static init function
+
+    assert(env);
+
+    std::vector<with_stack_entry>      with_stack(initial_with_stack);
+
+#if 0
+    // Check the time
+    if (periodic_events.expired()) {
+       periodic_events.poll_event_handlers(env);
+    }
+#endif
+               
+    movie*     original_target = env->get_target();
+    UNUSED(original_target);           // Avoid warnings.
+
+    size_t stop_pc = start_pc + exec_bytes;
+
+    for (size_t pc = start_pc; pc < stop_pc; ) {
+       // Cleanup any expired "with" blocks.
+       while ( with_stack.size() > 0
+              && pc >= with_stack.back().end_pc() ) {
+           // Drop this stack element
+           with_stack.resize(with_stack.size() - 1);
+       }
+       
+       // Get the opcode.
+       int     action_id = m_buffer[pc];
+       if ((action_id & 0x80) == 0) {
+           if (dbglogfile.getActionDump()) {
+               log_action("\nEX:\t");
+               log_disasm(&m_buffer[pc]);
+           }
+           
+           // IF_VERBOSE_ACTION(log_msg("Action ID is: 0x%x\n", action_id));
+           
+           ash.execute((action_type)action_id, *env);
+           pc++;       // advance to next action.
+       } else {
+
+           if (dbglogfile.getActionDump()) {
+               log_action("\nEX:\t");
+               log_disasm(&m_buffer[pc]);
+           }
+           
+           // Action containing extra data.
+           size_t length = m_buffer[pc + 1] | (m_buffer[pc + 2] << 8);
+           size_t next_pc = pc + length + 3;
+           
+           switch (action_id) {
+             default:
+                 break;
+                 
+             case SWF::ACTION_GOTOFRAME:       // goto frame
+             {
+                 int   frame = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
+                 // 0-based already?
+                 //// Convert from 1-based to 0-based
+                 //frame--;
+                 env->get_target()->goto_frame(frame);
+                 break;
+             }
+             
+             case SWF::ACTION_GETURL:  // get url
+             {
+                 // If this is an FSCommand, then call the callback
+                 // handler, if any.
+                 
+                 // Two strings as args.
+                 const char*   url = (const char*) &(m_buffer[pc + 3]);
+                 size_t        url_len = strlen(url);
+                 const char*   target = (const char*) &(m_buffer[pc + 3 + 
url_len + 1]);
+                 
+                 // If the url starts with an "http" or "https",
+                 // then we want to load it into a web browser.
+                 if (strncmp(url, "http", 4) == 0) {
+//                               if (windowid) {
+//                                   Atom mAtom = 486;
+//                                   Display *mDisplay = XOpenDisplay(NULL);
+//                                   XLockDisplay(mDisplay);
+//                                   XChangeProperty (mDisplay, windowid, 
mAtom,
+//                                                    XA_STRING, 8, 
PropModeReplace,
+//                                                    (unsigned char *)url,
+//                                                    url_len);
+                     
+//                                   XUnlockDisplay(mDisplay);
+//                                   XCloseDisplay(mDisplay);
+//                               } else {
+                     string command = "firefox -remote \"openurl(";
+                     command += url;
+                     command += ")\"";
+                     dbglogfile << "Launching URL... " << command << endl;
+//                               movie *target = env->get_target();
+//                               target->get_url(url);
+                     system(command.c_str());
+//                               }
+                     break;
+                 }
+                 
+                 // If the url starts with "FSCommand:", then this is
+                 // a message for the host app.
+                 if (strncmp(url, "FSCommand:", 10) == 0) {
+                     if (s_fscommand_handler) {
+                         // Call into the app.
+                         
(*s_fscommand_handler)(env->get_target()->get_root_interface(), url + 10, 
target);
+                     }
+                 } else {
+#ifdef EXTERN_MOVIE
+//                                   log_error("get url: target=%s, url=%s\n", 
target, url);
+                     
+                     tu_string tu_target = target;
+                     movie* target_movie = env->find_target(tu_target);
+                     if (target_movie != NULL) {
+                         movie *root_movie = 
env->get_target()->get_root_movie();
+                         attach_extern_movie(url, target_movie, root_movie);
+                     } else {
+                         log_error("get url: target %s not found\n", target);
+                     }
+#endif // EXTERN_MOVIE
+                 }
+                 
+                 break;
+             }
+             
+             case SWF::ACTION_SETREGISTER:     // store_register
+             {
+                 int   reg = m_buffer[pc + 3];
+                 // Save top of stack in specified register.
+                 if (is_function2) {
+                     *(env->local_register_ptr(reg)) = env->top(0);
+                     
+                         log_action("-------------- local register[%d] = 
'%s'\n",
+                         reg,
+                         env->top(0).to_string());
+                 } else if (reg >= 0 && reg < 4) {
+                     env->m_global_register[reg] = env->top(0);
+                     
+                         log_action("-------------- global register[%d] = 
'%s'\n",
+                                 reg,
+                                 env->top(0).to_string());
+                 } else {
+                     log_error("store_register[%d] -- register out of 
bounds!", reg);
+                 }
+                 
+                 break;
+             }
+             
+             case SWF::ACTION_CONSTANTPOOL:    // decl_dict: declare dictionary
+             {
+                 //int i = pc;
+                 //int count = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
+                 //i += 2;
+                 
+                 process_decl_dict(pc, next_pc);
+                 
+                 break;
+             }
+             
+             case SWF::ACTION_WAITFORFRAME:    // wait for frame
+             {
+                 // If we haven't loaded a specified frame yet, then we're 
supposed to skip
+                 // some specified number of actions.
+                 //
+                 // Since we don't load incrementally, just ignore this opcode.
+                 break;
+             }
+             
+             case SWF::ACTION_SETTARGET:       // set target
+             {
+                 // Change the movie we're working on.
+                 const char* target_name = (const char*) &m_buffer[pc + 3];
+                 movie *new_target;
+                 
+                 // if the string is blank, we set target to the root movie
+                 // TODO - double check this is correct?
+                 if (target_name[0] == '\0')
+                     new_target = env->find_target((tu_string)"/");
+                 else
+                     new_target = env->find_target((tu_string)target_name);
+                 
+                 if (new_target == NULL) {
+                     log_action("ERROR: Couldn't find movie \"%s\" to set 
target to!"
+                                           " Not setting target at all...",
+                                           (const char *)target_name);
+                 }
+                 else
+                     env->set_target(new_target);
+                 
+                 break;
+             }
+             
+             case SWF::ACTION_GOTOLABEL:       // go to labeled frame, 
goto_frame_lbl
+             {
+                 char* frame_label = (char*) &m_buffer[pc + 3];
+                 movie *target = env->get_target();
+                 target->goto_labeled_frame(frame_label);
+                 break;
+             }
+             
+             case SWF::ACTION_WAITFORFRAMEEXPRESSION:  // wait for frame 
expression (?)
+             {
+                 // Pop the frame number to wait for; if it's not loaded skip 
the
+                 // specified number of actions.
+                 //
+                 // Since we don't support incremental loading, pop our arg and
+                 // don't do anything.
+                 env->drop(1);
+                 break;
+             }
+             
+             case SWF::ACTION_DEFINEFUNCTION2: // 0x8E
+                 doActionDefineFunction2(env, with_stack, pc, &next_pc);
+                 break;
+                 
+             case SWF::ACTION_WITH:    // with
+             {
+                 int   frame = m_buffer[pc + 3] | (m_buffer[pc + 4] << 8);
+                 UNUSED(frame);
+                 log_action("-------------- with block start: stack size is 
%zd\n", with_stack.size());
+                 if (with_stack.size() < 8) {
+                     int       block_length = m_buffer[pc + 3] | (m_buffer[pc 
+ 4] << 8);
+                     int       block_end = next_pc + block_length;
+                     as_object*        with_obj = env->top(0).to_object();
+                     with_stack.push_back(with_stack_entry(with_obj, 
block_end));
+                 }
+                 env->drop(1);
+                 break;
+             }
+             case SWF::ACTION_PUSHDATA:        // push_data
+             {
+                 size_t i = pc;
+                 while (i - pc < length) {
+                     int       type = m_buffer[3 + i];
+                     i++;
+                     if (type == 0) {
+                         // string
+                         const char*   str = (const char*) &m_buffer[3 + i];
+                         i += strlen(str) + 1;
+                         env->push(str);
+                         
+                         log_action("-------------- pushed '%s'", str);
+                     } else if (type == 1) {
+                         // float (little-endian)
+                         union {
+                             float     f;
+                             uint32_t  i;
+                         } u;
+                         compiler_assert(sizeof(u) == sizeof(u.i));
+                         
+                         memcpy(&u.i, &m_buffer[3 + i], 4);
+                         u.i = swap_le32(u.i);
+                         i += 4;
+                         
+                         env->push(u.f);
+                         log_action("-------------- pushed '%g'", u.f);
+                     } else if (type == 2) {
+                         as_value nullvalue;
+                         nullvalue.set_null();
+                         env->push(nullvalue); 
+                         
+                         log_action("-------------- pushed NULL");
+                     } else if (type == 3) {
+                         env->push(as_value());
+                         
+                         log_action("-------------- pushed UNDEFINED");
+                     } else if (type == 4) {
+                         // contents of register
+                         int   reg = m_buffer[3 + i];
+                         UNUSED(reg);
+                         i++;
+                         if (is_function2) {
+                             env->push(*(env->local_register_ptr(reg)));
+                             log_action("-------------- pushed local 
register[%d] = '%s'\n",
+                                         reg,
+                                         env->top(0).to_string());
+                         } else if (reg < 0 || reg >= 4) {
+                             env->push(as_value());
+                             log_error("push register[%d] -- register out of 
bounds!\n", reg);
+                         } else {
+                             env->push(env->m_global_register[reg]);
+                             log_action("-------------- pushed global 
register[%d] = '%s'\n",
+                                         reg,
+                                         env->top(0).to_string());
+                         }
+                         
+                     } else if (type == 5) {
+                         bool  bool_val = m_buffer[3 + i] ? true : false;
+                         i++;
+//                                                     log_msg("bool(%d)\n", 
bool_val);
+                         env->push(bool_val);
+                         
+                         log_action("-------------- pushed %s",
+                                    (bool_val ? "true" : "false"));
+                     } else if (type == 6) {
+                         // double
+                         // wacky format: 45670123
+                         union {
+                             double    d;
+                             uint64    i;
+                             struct {
+                                 uint32_t      lo;
+                                 uint32_t      hi;
+                             } sub;
+                         } u;
+                         compiler_assert(sizeof(u) == sizeof(u.i));
+                         
+                         memcpy(&u.sub.hi, &m_buffer[3 + i], 4);
+                         memcpy(&u.sub.lo, &m_buffer[3 + i + 4], 4);
+                         u.i = swap_le64(u.i);
+                         i += 8;
+                         
+                         env->push(u.d);
+                         
+                         log_action("-------------- pushed double %g", u.d);
+                     } else if (type == 7) {
+                         // int32
+                         int32_t       val = m_buffer[3 + i]
+                             | (m_buffer[3 + i + 1] << 8)
+                             | (m_buffer[3 + i + 2] << 16)
+                             | (m_buffer[3 + i + 3] << 24);
+                         i += 4;
+                         
+                         env->push(val);
+                         
+                         log_action("-------------- pushed int32 %d",val);
+                     } else if (type == 8) {
+                         int   id = m_buffer[3 + i];
+                         i++;
+                         if (id < (int) m_dictionary.size()) {
+                             env->push(m_dictionary[id]);
+                             
+                             log_action("-------------- pushed '%s'",
+                                        m_dictionary[id]);
+                         } else {
+                             log_error("dict_lookup(%d) is out of bounds!\n", 
id);
+                             env->push(0);
+                             log_action("-------------- pushed 0");
+                         }
+                     } else if (type == 9) {
+                         int   id = m_buffer[3 + i] | (m_buffer[4 + i] << 8);
+                         i += 2;
+                         if (id < (int) m_dictionary.size()) {
+                             env->push(m_dictionary[id]);
+                             log_action("-------------- pushed '%s'\n", 
m_dictionary[id]);
+                         } else {
+                             log_error("dict_lookup(%d) is out of bounds!\n", 
id);
+                             env->push(0);
+                             
+                             log_action("-------------- pushed 0");
+                         }
+                     }
+                 }
+                 
+                 break;
+             }
+             case SWF::ACTION_BRANCHALWAYS:    // branch always (goto)
+             {
+                 int16_t       offset = m_buffer[pc + 3] | (m_buffer[pc + 4] 
<< 8);
+                 next_pc += offset;
+                 // @@ TODO range checks
+                 break;
+             }
+             case SWF::ACTION_GETURL2: // get url 2
+             {
+                 int   method = m_buffer[pc + 3];
+                 UNUSED(method);
+                 
+                 const char*   target = env->top(0).to_string();
+                 const char*   url = env->top(1).to_string();
+                 
+                 // If the url starts with "FSCommand:", then this is
+                 // a message for the host app.
+                 if (strncmp(url, "FSCommand:", 10) == 0) {
+                     if (s_fscommand_handler) {
+                         // Call into the app.
+                         
(*s_fscommand_handler)(env->get_target()->get_root_interface(), url + 10, 
target);
+                     }
+                 } else {
+#ifdef EXTERN_MOVIE
+//            log_error("get url2: target=%s, url=%s\n", target, url);
+                     
+                     movie* target_movie = env->find_target(env->top(0));
+                     if (target_movie != NULL) {
+                         movie*        root_movie = 
env->get_target()->get_root_movie();
+                         attach_extern_movie(url, target_movie, root_movie);
+                     } else {
+                         log_error("get url2: target %s not found\n", target);
+                     }
+#endif // EXTERN_MOVIE
+                 }
+                 env->drop(2);
+                 break;
+             }
+             
+             case SWF::ACTION_DEFINEFUNCTION: // declare function
+                 doActionDefineFunction(env, with_stack, pc, &next_pc);
+                 break;
+                 
+             case SWF::ACTION_BRANCHIFTRUE:    // branch if true
+             {
+                 int16_t       offset = m_buffer[pc + 3] | (m_buffer[pc + 4] 
<< 8);
+                 
+                 bool  test = env->top(0).to_bool();
+                 env->drop(1);
+                 if (test) {
+                     next_pc += offset;
+                     
+                     if (next_pc > stop_pc) {
+                         log_error("branch to offset %d -- this section only 
runs to %d\n",
+                                   next_pc,
+                                   stop_pc);
+                     }
+                 }
+                 break;
+             }
+             case SWF::ACTION_CALLFRAME:       // call frame
+             {
+                 // Note: no extra data in this instruction!
+                 assert(env->m_target);
+                 env->m_target->call_frame_actions(env->top(0));
+                 env->drop(1);
+                 
+                 break;
+             }
+             
+             case SWF::ACTION_GOTOEXPRESSION:  // goto frame expression, 
goto_frame_exp
+             {
+                 // From Alexi's SWF ref:
+                 //
+                 // Pop a value or a string and jump to the specified
+                 // frame. When a string is specified, it can include a
+                 // path to a sprite as in:
+                 // 
+                 //   /Test:55
+                 // 
+                 // When f_play is ON, the action is to play as soon as
+                 // that frame is reached. Otherwise, the
+                 // frame is shown in stop mode.
+                 
+                 unsigned char play_flag = m_buffer[pc + 3];
+                 movie::play_state     state = play_flag ? movie::PLAY : 
movie::STOP;
+                 
+                 movie* target = env->get_target();
+                 bool success = false;
+                 
+                 if (env->top(0).get_type() == as_value::UNDEFINED) {
+                     // No-op.
+                 } else if (env->top(0).get_type() == as_value::STRING) {
+                     // @@ TODO: parse possible sprite path...
+                     
+                     // Also, if the frame spec is actually a number (not a 
label), then
+                     // we need to do the conversion...
+                     
+                     const char* frame_label = env->top(0).to_string();
+                     if (target->goto_labeled_frame(frame_label)) {
+                         success = true;
+                     } else {
+                         // Couldn't find the label.  Try converting to a 
number.
+                         double num;
+                         if (string_to_number(&num, env->top(0).to_string())) {
+                             int frame_number = int(num);
+                             target->goto_frame(frame_number);
+                             success = true;
+                         }
+                         // else no-op.
+                     }
+                 } else if (env->top(0).get_type() == as_value::OBJECT) {
+                     // This is a no-op; see test_goto_frame.swf
+                 } else if (env->top(0).get_type() == as_value::NUMBER) {
+                     // Frame numbers appear to be 0-based!  @@ Verify.
+                     int frame_number = int(env->top(0).to_number());
+                     target->goto_frame(frame_number);
+                     success = true;
+                 }
+                 
+                 if (success) {
+                     target->set_play_state(state);
+                 }
+                 
+                 env->drop(1);  
+                 break;
+             }       
+           }
+           pc = next_pc;
+       }
+    }
+    
+    env->set_target(original_target);
+}
+
+//
+// Disassembler
+//
+
+// Disassemble one instruction to the log.
+void
+log_disasm(const unsigned char* instruction_data)
+{    
+    as_arg_t fmt = ARG_HEX;
+    action_type        action_id = (action_type)instruction_data[0];
+    unsigned char num[10];
+    memset(num, 0, 10);
+
+    dbglogfile.setStamp(false);
+    // Show instruction.
+    if (action_id > ash.lastType()) {
+       dbglogfile << "<unknown>[0x" << action_id  << "]" << endl;
+    } else {
+       dbglogfile << ash[action_id].getName().c_str() << endl;
+       fmt = ash[action_id].getArgFormat();
+    }
+
+    // Show instruction argument(s).
+    if (action_id & 0x80) {
+       assert(fmt != ARG_NONE);
+       int length = instruction_data[1] | (instruction_data[2] << 8);
+       if (fmt == ARG_HEX) {
+           for (int i = 0; i < length; i++) {
+               hexify(num, (const unsigned char *)&instruction_data[3 + i], 1);
+               dbglogfile << "0x" << num << " ";
+//             dbglogfile << instruction_data[3 + i] << " ";
+           }
+           dbglogfile << endl;
+       } else if (fmt == ARG_STR) {
+           string str;
+           for (int i = 0; i < length; i++) {
+               str = instruction_data[3 + i];
+           }
+           dbglogfile << "\"" << str.c_str() << "\"" << endl;
+       } else if (fmt == ARG_U8) {
+           int val = instruction_data[3];
+           dbglogfile << " " << val << endl;
+       } else if (fmt == ARG_U16) {
+           int val = instruction_data[3] | (instruction_data[4] << 8);
+           dbglogfile << " " << val << endl;
+       } else if (fmt == ARG_S16) {
+           int val = instruction_data[3] | (instruction_data[4] << 8);
+           if (val & 0x8000) val |= ~0x7FFF;   // sign-extend
+           dbglogfile << " " << val << endl;
+       } else if (fmt == ARG_PUSH_DATA) {
+           dbglogfile << endl;
+           int i = 0;
+           while (i < length) {
+               int     type = instruction_data[3 + i];
+               i++;
+               if (type == 0) {
+                   // string
+                   string str;
+                   while (instruction_data[3 + i]) {
+                       str += instruction_data[3 + i];
+                       i++;
+                   }
+                   i++;
+                   dbglogfile << "\t\"" << str.c_str() << "\"" << endl;
+               } else if (type == 1) {
+                   // float (little-endian)
+                   union {
+                       float   f;
+                       uint32_t        i;
+                   } u;
+                   compiler_assert(sizeof(u) == sizeof(u.i));
+                   
+                   memcpy(&u.i, instruction_data + 3 + i, 4);
+                   u.i = swap_le32(u.i);
+                   i += 4;
+                   
+                   dbglogfile << "(float) " << u.f << endl;
+               } else if (type == 2) {
+                   dbglogfile << "NULL" << endl;
+               } else if (type == 3) {
+                   dbglogfile << "undef" << endl;
+               } else if (type == 4) {
+                   // contents of register
+                   int reg = instruction_data[3 + i];
+                   i++;
+                   dbglogfile << "reg[" << reg << "]" << endl;
+               } else if (type == 5) {
+                   int bool_val = instruction_data[3 + i];
+                   i++;
+                   dbglogfile << "bool(" << bool_val << ")" << endl;
+               } else if (type == 6) {
+                   // double
+                   // wacky format: 45670123
+                   union {
+                       double  d;
+                       uint64  i;
+                       struct {
+                           uint32_t    lo;
+                           uint32_t    hi;
+                       } sub;
+                   } u;
+                   compiler_assert(sizeof(u) == sizeof(u.i));
+                   
+                   memcpy(&u.sub.hi, instruction_data + 3 + i, 4);
+                   memcpy(&u.sub.lo, instruction_data + 3 + i + 4, 4);
+                   u.i = swap_le64(u.i);
+                   i += 8;
+                   
+                   dbglogfile << "(double) " << u.d << endl;
+               } else if (type == 7) {
+                   // int32
+                   int32_t     val = instruction_data[3 + i]
+                       | (instruction_data[3 + i + 1] << 8)
+                       | (instruction_data[3 + i + 2] << 16)
+                       | (instruction_data[3 + i + 3] << 24);
+                   i += 4;
+                   dbglogfile << "(int) " << val << endl;
+               } else if (type == 8) {
+                   int id = instruction_data[3 + i];
+                   i++;
+                   dbglogfile << "dict_lookup[" << id << "]" << endl;
+               } else if (type == 9) {
+                   int id = instruction_data[3 + i] | (instruction_data[3 + i 
+ 1] << 8);
+                   i += 2;
+                   dbglogfile << "dict_lookup_lg[" << id << "]" << endl;
+               }
+           }
+       } else if (fmt == ARG_DECL_DICT) {
+           int i = 0;
+           int count = instruction_data[3 + i] | (instruction_data[3 + i + 1] 
<< 8);
+           i += 2;
+           
+           dbglogfile << " [" << count << "]" << endl;
+           
+           // Print strings.
+           for (int ct = 0; ct < count; ct++) {
+               dbglogfile << "\t" << endl;     // indent
+               
+               string str;
+               while (instruction_data[3 + i]) {
+                       // safety check.
+                   if (i >= length) {
+                       dbglogfile << "<disasm error -- length exceeded>" << 
endl;
+                       break;
+                   }
+                   str += instruction_data[3 + i];
+                   i++;
+               }
+               dbglogfile << "\"" << str.c_str() << "\"" << endl;
+               i++;
+           }
+       } else if (fmt == ARG_FUNCTION2) {
+           // Signature info for a function2 opcode.
+           int i = 0;
+           const char* function_name = (const char*) &instruction_data[3 + i];
+           i += strlen(function_name) + 1;
+           
+           int arg_count = instruction_data[3 + i] | (instruction_data[3 + i + 
1] << 8);
+           i += 2;
+           
+           int reg_count = instruction_data[3 + i];
+           i++;
+
+           dbglogfile << "\t\tname = '" << function_name << "'"
+                      << " arg_count = " << arg_count
+                      << " reg_count = " << reg_count << endl;
+           
+           uint16      flags = (instruction_data[3 + i]) | (instruction_data[3 
+ i + 1] << 8);
+           i += 2;
+           
+           // @@ What is the difference between "super" and "_parent"?
+           
+           bool        preload_global = (flags & 0x100) != 0;
+           bool        preload_parent = (flags & 0x80) != 0;
+           bool        preload_root   = (flags & 0x40) != 0;
+           bool        suppress_super = (flags & 0x20) != 0;
+           bool        preload_super  = (flags & 0x10) != 0;
+           bool        suppress_args  = (flags & 0x08) != 0;
+           bool        preload_args   = (flags & 0x04) != 0;
+           bool        suppress_this  = (flags & 0x02) != 0;
+           bool        preload_this   = (flags & 0x01) != 0;
+           
+           log_msg("\t\t        pg = %d\n"
+                   "\t\t        pp = %d\n"
+                   "\t\t        pr = %d\n"
+                   "\t\tss = %d, ps = %d\n"
+                   "\t\tsa = %d, pa = %d\n"
+                   "\t\tst = %d, pt = %d\n",
+                   int(preload_global),
+                   int(preload_parent),
+                   int(preload_root),
+                   int(suppress_super),
+                   int(preload_super),
+                   int(suppress_args),
+                   int(preload_args),
+                   int(suppress_this),
+                   int(preload_this));
+           
+           for (int argi = 0; argi < arg_count; argi++) {
+               int     arg_register = instruction_data[3 + i];
+               i++;
+               const char*     arg_name = (const char*) &instruction_data[3 + 
i];
+               i += strlen(arg_name) + 1;
+               
+               dbglogfile << "\t\targ[" << argi << "]"
+                          << " - reg[" << arg_register << "]"
+                          << " - '" << arg_name << "'" << endl;
+           }
+           
+           int function_length = instruction_data[3 + i] | (instruction_data[3 
+ i + 1] << 8);
+           i += 2;
+           
+           dbglogfile << "\t\tfunction length = " << function_length << endl;
+       }
+    } else {
+       dbglogfile << endl;
+    }
+    dbglogfile.setStamp(true);
+}
+
+
+
+};
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: server/action_buffer.h
===================================================================
RCS file: server/action_buffer.h
diff -N server/action_buffer.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/action_buffer.h      20 Jun 2006 11:12:36 -0000      1.1
@@ -0,0 +1,165 @@
+// 
+//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
+//
+
+#ifndef GNASH_ACTION_BUFFER_H
+#define GNASH_ACTION_BUFFER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "gnash.h"
+//#include "as_object.h"
+#include "types.h"
+#include <wchar.h>
+
+#include "container.h"
+#include "smart_ptr.h"
+//#include "log.h"
+#include "with_stack_entry.h"
+
+namespace gnash {
+
+// Forward declarations
+//struct movie;
+struct as_environment;
+//class as_object;
+struct as_value;
+//class function_as_object;
+
+/// Base class for actions.
+class action_buffer
+{
+
+public:
+
+       action_buffer();
+
+       /// Read action bytes from input stream
+       void    read(stream* in);
+
+       /// \brief
+       /// Interpret the actions in this action buffer, and evaluate
+       /// them in the given environment. 
+       //
+       /// Execute our whole buffer,
+       /// without any arguments passed in.
+       ///
+       void    execute(as_environment* env);
+
+       /// Interpret the specified subset of the actions in our buffer.
+       //
+       /// Caller is responsible for cleaning up our local
+       /// stack frame (it may have passed its arguments in via the
+       /// local stack frame).
+       void    execute(
+               as_environment* env,
+               size_t start_pc,
+               size_t exec_bytes,
+               as_value* retval, // we should probably drop this parameter
+               const std::vector<with_stack_entry>& initial_with_stack,
+               bool is_function2);
+
+       bool    is_null()
+       {
+               return m_buffer.size() < 1 || m_buffer[0] == 0;
+       }
+
+       int     get_length() const { return m_buffer.size(); }
+
+private:
+       // Don't put these as values in std::vector<>!  They contain
+       // internal pointers and cannot be moved or copied.
+       // If you need to keep an array of them, keep pointers
+       // to new'd instances.
+       action_buffer(const action_buffer& a) { assert(0); }
+       void operator=(const action_buffer& a) { assert(0); }
+
+       void    process_decl_dict(int start_pc, int stop_pc);
+
+       // data:
+       std::vector<unsigned char>      m_buffer;
+       std::vector<const char*>        m_dictionary;
+       int     m_decl_dict_processed_at;
+
+       void doActionNew(as_environment* env, 
+               std::vector<with_stack_entry>& with_stack);
+
+       void doActionInstanceOf(as_environment* env);
+
+       void doActionCast(as_environment* env);
+
+       void doActionCallMethod(as_environment* env);
+
+       void doActionCallFunction(as_environment* env,
+               std::vector<with_stack_entry>& with_stack);
+
+       void doActionDefineFunction(as_environment* env,
+               std::vector<with_stack_entry>& with_stack,
+               size_t pc, size_t* next_pc);
+
+       void doActionDefineFunction2(as_environment* env,
+               std::vector<with_stack_entry>& with_stack,
+               size_t pc, size_t* next_pc);
+
+       void doActionGetMember(as_environment* env);
+
+       void doActionStrictEquals(as_environment* env);
+
+       void doActionEquals(as_environment* env);
+
+       void doActionDelete(as_environment* env,
+               std::vector<with_stack_entry>& with_stack);
+
+       void doActionDelete2(as_environment* env,
+               std::vector<with_stack_entry>& with_stack);
+
+};
+
+
+}      // end namespace gnash
+
+
+#endif // GNASH_ACTION_BUFFER_H
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:

Index: server/with_stack_entry.h
===================================================================
RCS file: server/with_stack_entry.h
diff -N server/with_stack_entry.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ server/with_stack_entry.h   20 Jun 2006 11:12:36 -0000      1.1
@@ -0,0 +1,101 @@
+// 
+//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
+//
+
+#ifndef GNASH_WITH_STACK_ENTRY_H
+#define GNASH_WITH_STACK_ENTRY_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "as_object.h" // for dtor visibility by smart_ptr
+#include "smart_ptr.h"
+
+namespace gnash {
+
+//
+// with_stack_entry
+//
+
+/// The "with" stack is for Pascal-like with-scoping.
+struct with_stack_entry
+{
+       // should be private
+       smart_ptr<as_object>    m_object;
+
+       with_stack_entry()
+               :
+               m_object(NULL),
+               m_block_end_pc(0)
+       {
+       }
+
+       with_stack_entry(as_object* obj, size_t end)
+               :
+               m_object(obj),
+               m_block_end_pc(end)
+       {
+       }
+
+       size_t end_pc()
+       {
+               return m_block_end_pc;
+       }
+
+       const as_object* object() const
+       {
+               return m_object.get_ptr();
+       }
+
+private:
+
+       size_t m_block_end_pc;
+
+};
+
+}      // end namespace gnash
+
+
+#endif // GNASH_WITH_STACK_ENTRY_H
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:




reply via email to

[Prev in Thread] Current Thread [Next in Thread]