gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11934: Test and implement LocalConn


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11934: Test and implement LocalConnection for POSIX systems.
Date: Thu, 11 Feb 2010 14:13:42 +0100
User-agent: Bazaar (2.0.3)

------------------------------------------------------------
revno: 11934 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Thu 2010-02-11 14:13:42 +0100
message:
  Test and implement LocalConnection for POSIX systems.
  
  Drop AudioDecoderNellymoser.
removed:
  libmedia/AudioDecoderNellymoser.cpp
  libmedia/AudioDecoderNellymoser.h
added:
  libcore/AMF.cpp
  libcore/AMF.h
  testsuite/misc-ming.all/LC-Receive.as
  testsuite/misc-ming.all/LC-Send.as
  testsuite/simultaneous-testrunner.sh
renamed:
  libbase/shm.cpp => libbase/SharedMem.cpp
  libbase/shm.h => libbase/SharedMem.h
modified:
  gui/Kde4Gui.cpp
  gui/gtk.cpp
  libamf/Makefile.am
  libamf/lcshm.cpp
  libamf/lcshm.h
  libbase/Makefile.am
  libbase/rc.cpp
  libbase/rc.h
  libcore/Makefile.am
  libcore/as_value.cpp
  libcore/as_value.h
  libcore/asobj/Makefile.am
  libcore/asobj/flash/net/LocalConnection_as.cpp
  libcore/asobj/flash/net/NetConnection_as.cpp
  libcore/asobj/flash/net/NetStream_as.cpp
  libcore/asobj/flash/net/NetStream_as.h
  libcore/asobj/flash/net/SharedObject_as.cpp
  libcore/asobj/flash/xml/XMLDocument_as.cpp
  libcore/asobj/flash/xml/XMLDocument_as.h
  libmedia/Makefile.am
  libmedia/MediaHandler.cpp
  testsuite/Makefile.am
  testsuite/actionscript.all/LocalConnection.as
  testsuite/gnashrc.in
  testsuite/libamf.all/Makefile.am
  testsuite/libamf.all/test_amf.cpp
  testsuite/libamf.all/test_lc.cpp
  testsuite/libbase.all/gnashrc.in
  testsuite/libnet.all/generate_amfbins.cpp
  testsuite/misc-ming.all/Makefile.am
  utilities/Makefile.am
  libbase/SharedMem.cpp
  libbase/SharedMem.h
=== modified file 'gui/Kde4Gui.cpp'
--- a/gui/Kde4Gui.cpp   2010-02-01 07:29:29 +0000
+++ b/gui/Kde4Gui.cpp   2010-02-11 08:33:14 +0000
@@ -898,12 +898,6 @@
     _ASCodingErrorToggle->setChecked(_rcfile.showASCodingErrors());
     layout->addWidget(_ASCodingErrorToggle);
 
-    _lcTraceToggle = new QCheckBox(_q("Log Local Connection activity"),
-                                        loggingTab);
-    _lcTraceToggle->setChecked(_rcfile.getLCTrace());
-    layout->addWidget(_lcTraceToggle);
-    layout->addStretch();
-
     // Security tab
     QFrame* securityTab = new QFrame(tabs);
     tabs->addTab(securityTab, _q("Security"));
@@ -1070,7 +1064,6 @@
     _rcfile.useActionDump(_actionDumpToggle->isChecked());
     _rcfile.showMalformedSWFErrors(_malformedSWFToggle->isChecked());
     _rcfile.showASCodingErrors(_ASCodingErrorToggle->isChecked());
-    _rcfile.setLCTrace(_lcTraceToggle->isChecked());
 
     // Security tab widgets
     _rcfile.useLocalHost(_localHostToggle->isChecked());

=== modified file 'gui/gtk.cpp'
--- a/gui/gtk.cpp       2010-01-30 18:33:03 +0000
+++ b/gui/gtk.cpp       2010-02-11 08:33:14 +0000
@@ -992,7 +992,6 @@
         GtkWidget *solLocalDomainToggle;
         GtkWidget *localConnectionToggle;
         GtkWidget *insecureSSLToggle; 
-        GtkWidget *lcTraceToggle;
         GtkWidget *solSandbox;
         GtkWidget *osText;
         GtkWidget *versionText;
@@ -1023,7 +1022,6 @@
                solLocalDomainToggle(0),
                localConnectionToggle(0),
                insecureSSLToggle(0), 
-               lcTraceToggle(0),
                solSandbox(0),
                osText(0),
                versionText(0),
@@ -1182,11 +1180,6 @@
                 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs->insecureSSLToggle)));
         }
 
-        if ( prefs->lcTraceToggle ) {
-            _rcfile.setLCTrace(
-                
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs->lcTraceToggle)));
-        }
-               
         if ( prefs->solSandbox ) {
             tmp = gtk_entry_get_text(GTK_ENTRY(prefs->solSandbox));
             _rcfile.setSOLSafeDir(tmp);
@@ -1389,13 +1382,6 @@
     
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->ASCodingErrorToggle),
                        _rcfile.showASCodingErrors());
 
-    _prefs->lcTraceToggle = gtk_check_button_new_with_mnemonic(
-                               _("Log _Local Connection activity"));
-    gtk_box_pack_start (GTK_BOX(loggingvbox), _prefs->lcTraceToggle, FALSE,
-            FALSE, 0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->lcTraceToggle),
-                       _rcfile.getLCTrace()); 
-
 #ifdef USE_DEBUGGER
 
     _prefs->DebuggerToggle = 

=== modified file 'libamf/Makefile.am'
--- a/libamf/Makefile.am        2010-01-01 17:48:26 +0000
+++ b/libamf/Makefile.am        2010-02-08 20:38:34 +0000
@@ -24,8 +24,8 @@
        amf_msg.cpp \
        buffer.cpp \
        element.cpp \
+       sol.cpp \
        lcshm.cpp \
-       sol.cpp \
        flv.cpp
 
 libgnashamf_la_LIBADD = \
@@ -53,10 +53,10 @@
        amfutf8.h \
        amf.h \
        amf_msg.h \
+       lcshm.h \
        buffer.h \
        element.h \
        flv.h \
-       lcshm.h \
        protocol.h \
        sol.h
 

=== modified file 'libamf/lcshm.cpp'
--- a/libamf/lcshm.cpp  2010-02-02 11:45:01 +0000
+++ b/libamf/lcshm.cpp  2010-02-09 16:03:15 +0000
@@ -28,7 +28,7 @@
 #include "buffer.h"
 //#include "network.h"
 #include "amf.h"
-#include "shm.h"
+#include "SharedMem.h"
 #include "element.h"
 #include "GnashException.h"
 #include "lcshm.h"
@@ -95,7 +95,9 @@
 ///     each other Flash Objects, but does not initialize the memory
 ///     segment.
 LcShm::LcShm() 
-    : _baseaddr(0)
+    :
+    SharedMem(64528),
+    _baseaddr(0)
 {
 //    GNASH_REPORT_FUNCTION;
 }
@@ -104,6 +106,8 @@
 ///
 /// @param addr The address to use for the memory segment.
 LcShm::LcShm(boost::uint8_t *addr)
+    :
+    SharedMem(64528)
 {
 //    GNASH_REPORT_FUNCTION;
     _baseaddr = addr;
@@ -112,10 +116,11 @@
 /// \brief Construct an initialized shared memory segment.
 ///
 /// @param key The SYSV style key to use for the memory segment.
-LcShm::LcShm(key_t key)
+LcShm::LcShm(key_t /*key*/)
+    :
+    SharedMem(64528)
 {
 //    GNASH_REPORT_FUNCTION;
-    _shmkey = key;
 }
 
 /// \brief Delete the shared memory segment.
@@ -322,7 +327,6 @@
 LcShm::close()
 {
     GNASH_REPORT_FUNCTION;
-    closeMem();
 }
 
 /// @note
@@ -504,22 +508,22 @@
     // When using sysv shared memory segments in compatibility mode,
     // the name is ignored, and the SHMkey is specified in the user's
     // ~/.gnashrc file.
-    if (Shm::attach(names.c_str(), true) == false) {
+    if (SharedMem::attach() == false) {
         return false;
     }
 
-    if (Shm::getAddr() <= 0) {
+    if (SharedMem::begin() <= 0) {
         log_error("Failed to open shared memory segment: \"%s\"", 
names.c_str());
         return false; 
     }
     
-       boost::uint8_t* baseAddress = reinterpret_cast<boost::uint8_t 
*>(Shm::getAddr());
+       boost::uint8_t* baseAddress = reinterpret_cast<boost::uint8_t 
*>(SharedMem::begin());
        
-       boost::uint8_t* tooFar = baseAddress+Shm::getSize();
+       boost::uint8_t* tooFar = SharedMem::end();
     Listener::setBaseAddress(baseAddress);
     _baseaddr = baseAddress;
     parseHeader(baseAddress, tooFar);
-//     log_debug("Base address in 'connect' is: 0x%x, 0x%x",(unsigned int) 
Shm::getAddr(), (unsigned int) _baseaddr);
+//     log_debug("Base address in 'connect' is: 0x%x, 0x%x",(unsigned int) 
SharedMem::begin(), (unsigned int) _baseaddr);
 //  vector<boost::shared_ptr<Element> > ellist = parseBody(ptr);
 //  log_debug("Base address is: 0x%x, 0x%x",
 //               (unsigned int)Listener::getBaseAddress(), (unsigned 
int)_baseaddr);
@@ -545,17 +549,17 @@
        boost::mutex::scoped_lock lock(_localconnection_mutex);
    // GNASH_REPORT_FUNCTION;
     
-    if (Shm::attach(key, true) == false) {
+    if (SharedMem::attach() == false) {
         return false;
     }
 
-    if (Shm::getAddr() <= 0) {
+    if (SharedMem::begin() <= 0) {
         log_error("Failed to open shared memory segment: 0x%x", key);
         return false; 
     }
     
-       boost::uint8_t* baseAddress = reinterpret_cast<boost::uint8_t 
*>(Shm::getAddr());
-       boost::uint8_t* tooFar = baseAddress+Shm::getSize();
+       boost::uint8_t* baseAddress = reinterpret_cast<boost::uint8_t 
*>(SharedMem::begin());
+       boost::uint8_t* tooFar = SharedMem::end();
     Listener::setBaseAddress(baseAddress);
     _baseaddr = baseAddress;
     parseHeader(baseAddress, tooFar);

=== modified file 'libamf/lcshm.h'
--- a/libamf/lcshm.h    2010-01-11 06:41:38 +0000
+++ b/libamf/lcshm.h    2010-02-09 16:03:15 +0000
@@ -26,7 +26,7 @@
 
 #include "amf.h"
 #include "element.h"
-#include "shm.h"
+#include "SharedMem.h"
 #include "dsodefs.h"
 
 /// \namespace amf
@@ -111,7 +111,7 @@
 
 /// \class LcShm
 ///    This class is formanipulating the LocalConnection memory segment.
-class DSOEXPORT LcShm : public Listener, public gnash::Shm {
+class DSOEXPORT LcShm : public Listener, public gnash::SharedMem {
 public:
     /// \struct LcShm::lc_header_t
     ///                Hold the data in the memory segment's header.

=== modified file 'libbase/Makefile.am'
--- a/libbase/Makefile.am       2010-02-03 12:23:38 +0000
+++ b/libbase/Makefile.am       2010-02-09 07:41:18 +0000
@@ -1,4 +1,5 @@
-#   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, 
Inc.
+#   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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
@@ -64,7 +65,7 @@
        log.cpp \
        memory.cpp \
        rc.cpp \
-       shm.cpp \
+       SharedMem.cpp \
        sharedlib.cpp \
        string_table.cpp \
        tu_file.cpp \
@@ -133,7 +134,7 @@
        GnashSleep.h \
        gmemory.h \
        ogl.h \
-       shm.h \
+       SharedMem.h \
        sharedlib.h \
        tree.hh \
        tu_file.h \

=== renamed file 'libbase/shm.cpp' => 'libbase/SharedMem.cpp'
--- a/libbase/shm.cpp   2010-01-11 06:41:38 +0000
+++ b/libbase/SharedMem.cpp     2010-02-11 12:15:10 +0000
@@ -29,6 +29,7 @@
 #include <sys/mman.h>
 #include <sys/shm.h>
 #include <sys/ipc.h>
+#include <sys/sem.h>
 #elif !defined(__riscos__) && !defined(__OS2__)
 #include <windows.h>
 #include <process.h>
@@ -39,567 +40,188 @@
 #include <cerrno>
 
 #include "log.h"
-#include "shm.h"
+#include "SharedMem.h"
+
+#if (defined(USE_SYSV_SHM) && defined(HAVE_SHMGET)) || defined(_WIN32)
+# define ENABLE_SHARED_MEM 1
+#else
+# undef ENABLE_SHARED_MEM
+#endif
 
 namespace {
-gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
+    gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
 }
 
-using namespace std;
-
 namespace gnash {
 
-const int DEFAULT_SHM_SIZE = 64528;
-
-#ifdef darwin
-# ifndef MAP_INHERIT
-# define MAP_INHERIT 0
-#endif
-#ifndef PROT_EXEC
-# define PROT_EXEC
-# endif
-#endif
-
-#ifndef _SC_PAGESIZE
-#define _SC_PAGESIZE 8
-#endif
-
-#define FLAT_ADDR_SPACE 1
-
-  Shm::Shm() :_addr(0), _alloced(0), _size(0), _shmkey(0), _shmfd(0)
-{
-//    GNASH_REPORT_FUNCTION;
-    memset(_filespec, 0, MAX_SHM_NAME_SIZE);
-}
-
-Shm::~Shm()
-{
-//    GNASH_REPORT_FUNCTION;
-}
-
-bool
-Shm::attach()
-{
-//    GNASH_REPORT_FUNCTION;
-    return attach(static_cast<key_t>(0), false);
-}
-
-bool
-Shm::attach(key_t key, bool /* nuke */)
-{
-//    GNASH_REPORT_FUNCTION;
-    
-#if (defined(USE_SYSV_SHM) && defined(HAVE_SHMGET)) || defined(_WIN32)
-    // this is the magic size of shared memory segments used by the Flash 
player;
-    _size = 64528;
-    // this is the magic shared memory key used by the Flash player.
-    if (key != 0) {
-       _shmkey = key;
+SharedMem::SharedMem(size_t size)
+    :
+    _addr(0),
+    _size(size),
+    _semid(0),
+    _shmid(0),
+    _shmkey(0)
+{
+}
+
+SharedMem::~SharedMem()
+{
+#ifndef _WIN32
+    shmdt(_addr);
+    struct shmid_ds ds;
+    shmctl(_shmid, IPC_STAT, &ds);
+
+    // Note that this isn't completely reliable.
+    if (!ds.shm_nattch) {
+        log_debug("No shared memory users left. Removing segment.");
+        shmctl(_shmid, IPC_RMID, 0);
     }
-    
-    // If there is no SYSV style shared memory key in the users ~/.gnashrc 
file, warn them
-    // that compatibility will be broken, and then just pick our own key so 
things still work
-    // finer when using just Gnash.
+#else
+    // Windows code here.
+#endif
+}
+
+bool
+SharedMem::lock()
+{
+#ifndef _WIN32
+    struct sembuf sb = { 0, -1, SEM_UNDO };
+    int ret = semop(_semid, &sb, 1);
+    return ret >= 0;
+#else
+    // Windows code here.
+    return false;
+#endif
+}
+
+bool
+SharedMem::unlock()
+{
+#ifndef _WIN32
+    struct sembuf sb = { 0, 1, SEM_UNDO };
+    int ret = semop(_semid, &sb, 1);
+    return ret >= 0;
+#else
+    // Windows code here
+    return false;
+#endif
+}
+
+bool
+SharedMem::attach()
+{
+#if ENABLE_SHARED_MEM
+    
+    // Don't try to attach twice.
+    if (_addr) return true;
+    
+    _shmkey = rcfile.getLCShmKey();
+
+    // Check rcfile for key; if there isn't one, use the Adobe key.
     if (_shmkey == 0) {
-       log_error("No Shared Memory key specified in ~/.gnashrc! Please run 
\"dumpshm -i\" to find your key if you want to be compatible with the other swf 
player.");
-       _shmkey = 0xdd3adabd;
+        log_debug("No shared memory key specified in rcfile. Using default "
+                "for communication with other players");
+        _shmkey = 0xdd3adabd;
     }
     
+    log_debug("Using shared memory key %s",
+            boost::io::group(std::hex, std::showbase, _shmkey));
+
 #ifndef _WIN32
-    {
-       const int shmflg = 0660 | IPC_CREAT;
-
-       _shmfd = shmget(_shmkey, _size, shmflg);
-       if (_shmfd < 0 && errno == EEXIST) {
-           // Get the shared memory id for this segment
-           _shmfd = shmget(_shmkey, _size, 0);
-       }
-       _addr = static_cast<char *>(shmat(_shmfd, 0, 0));
-       if (_addr <= 0) {
-           log_debug("WARNING: shmat() failed: %s\n", strerror(errno));
-           return false;
-       }
-    }
+
+    // First get semaphore.
+    
+    // Struct for semctl
+    union semun {
+        int val;
+        struct semi_ds* buf;
+        unsigned short* array;
+    };
+
+    // Check if it exists already.
+    _semid = semget(_shmkey, 1, 0600);
+    
+    semun s;
+
+    // If it does not exist, create it and set its value to 1.
+    if (_semid < 0) {
+
+        _semid = semget(_shmkey, 1, IPC_CREAT | 0600);
+        
+        if (_semid < 0) {
+            log_error("Failed to get semaphore for shared memory!");
+            return false;
+        }    
+
+        s.val = 1;
+        int ret = semctl(_semid, 0, SETVAL, s);
+        if (ret < 0) {
+            log_error("Failed to set semaphore value");
+            return false;
+        }
+    }
+    
+    // The 4th argument is neither necessary nor used, but we pass it
+    // anyway for fun.
+    int semval = semctl(_semid, 0, GETVAL, s);
+
+    if (semval != 1) {
+        log_error("Need semaphore value of 1 for locking. Cannot "
+                "attach shared memory!");
+        return false;
+    }
+
+    Lock lock(*this);
+
+    // Then attach shared memory. See if it exists.
+    _shmid = shmget(_shmkey, _size, 0600);
+
+    // If not create it.
+    if (_shmid < 0) {
+        _shmid = shmget(_shmkey, _size, IPC_CREAT | 0660);
+    }
+
+    if (_shmid < 0) {
+        log_error("Unable to get shared memory segment!");
+        return false;
+    }
+
+    _addr = static_cast<iterator>(shmat(_shmid, 0, 0));
+
+    if (!_addr) {
+        log_error("Unable to attach shared memory: %s",
+                std::strerror(errno));
+        return false;
+    }
+
 #else
+
     _shmhandle = CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,
-           PAGE_READWRITE, 0, _size, NULL);
+        PAGE_READWRITE, 0, _size, NULL);
+
     if (_shmhandle == NULL) {
-       log_debug("WARNING: CreateFileMapping failed: %ld\n", GetLastError());
-        return false;
+        log_debug("WARNING: CreateFileMapping failed: %ld\n", GetLastError());
+            return false;
     }
-    _addr = static_cast<char *>(MapViewOfFile(_shmhandle, FILE_MAP_ALL_ACCESS,
+    _addr = static_cast<iterator>(MapViewOfFile(_shmhandle, 
FILE_MAP_ALL_ACCESS,
             0, 0, _size));
-    if (_addr == NULL) {
-       log_debug("WARNING: MapViewOfFile() failed: %ld\n", GetLastError());
-       return false;
+
+    if (!_addr) {
+        log_debug("WARNING: MapViewOfFile() failed: %ld\n", GetLastError());
+        return false;
     }
 #endif
 
+    assert(_addr);
     return true;
-#else
-#error "You need SYSV Shared memory support to use this option"
-#endif  // end of USE_SYSV_SHM
-}      
-
-// \brief Initialize the shared memory segment
-///
-/// This creates or attaches to an existing shared memory segment.
-bool
-Shm::attach(char const *filespec, bool nuke)
-{
-//    GNASH_REPORT_FUNCTION;
-    
-    bool exists = false;
-    long addr;
-    // #ifdef FLAT_ADDR_SPACE
-    //     off_t off;
-    // #endif
-    Shm *sc;
-    string absfilespec;
-
-    _size = DEFAULT_SHM_SIZE;
-
-#ifdef USE_POSIX_SHM
-#ifdef darwin
-    absfilespec = "/tmp";
-#else
-    absfilespec = "/";
-#endif
-    absfilespec += filespec;
-    filespec = absfilespec.c_str();
-    strncpy(_filespec, absfilespec.c_str(), MAX_SHM_NAME_SIZE);
-    if (static_cast<int>(absfilespec.size()) > MAX_SHM_NAME_SIZE) {
-       log_error("Shared Memory segment name is %d bytes too long!",
-                 absfilespec.size() - MAX_SHM_NAME_SIZE);
-    }    
-    
-    //     log_debug("%s: Initializing %d bytes of memory for \"%s\"\n",
-    //             __PRETTY_FUNCTION__, DEFAULT_SHM_SIZE, absfilespec.c_str());
-
-    // Adjust the allocated amount of memory to be on a page boundary.
-    // We can only do this on POSIX systems, so for braindead win32,
-    // don't readjust the size.
-#ifdef HAVE_SYSCONF
-    long pageSize = sysconf(_SC_PAGESIZE);
-    if (_size % pageSize) {
-       _size += pageSize - _size % pageSize;
-//     log_debug("Adjusting segment size to %d to be page aligned.\n", _size);
-    }
-#endif
-
-    errno = 0;
-#ifdef HAVE_SHM_OPEN
-    // Create the shared memory segment
-    _shmfd = shm_open(filespec, O_RDWR|O_CREAT|O_EXCL|O_TRUNC,
-                     S_IRUSR|S_IWUSR);
-    if (_shmfd < 0 && errno == EEXIST)
-#else
-#error "You need POSIX Shared memory support to use this option"
-#endif
-#endif // USE_POSIX_SHM    
-
-#ifdef USE_SYSV_SHM
-# ifdef HAVE_SHMGET
-    const int shmflg = 0660 | IPC_CREAT;
-    // this is the magic size of shared memory segments used by the Flash 
player;
-    _size = 64528;
-    // this is the magic shared memory key used by the Flash player.
-    _shmkey = rcfile.getLCShmKey();
-    // If there is no SYSV style shared memory key in the users ~/.gnashrc 
file, warn them
-    // that compatibility will be broken, and then just pick our own key so 
things still work
-    // finer when using just Gnash.
-    if (_shmkey == 0) {
-       log_error("No Shared Memory key specified in ~/.gnashrc! Please run 
\"dumpshm -i\" to find your key if you want to be compatible with the other swf 
player.");
-       _shmkey = 0xdd3adabd;
-    }
-    
-    filespec = "default";      // this is unused for sysv memory segments
-    _shmfd = shmget(_shmkey, _size, shmflg);
-    if (_shmfd <= 0 && errno == EACCES) {
-       log_error("You don't have the proper permisisons to access shared 
memory");
-       return false;
-    }
-    if (_shmfd <= 0 && errno == EEXIST)
-# else
-#  ifdef __riscos__
-    if (0)
-#  else
-       _shmhandle = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL,
-                                       PAGE_READWRITE, 0,
-                                       _size, filespec);
-    if (_shmhandle <= 0)
-#  endif
-# endif         // end of HAVE_SHMGET
-#else
-#error "You need SYSV Shared memory support to use this option"
-#endif  // end of USE_SYSV_SHM
-       {
-    // If it already exists, then just attach to it.
-       exists = true;
-       log_debug("Shared Memory segment \"%s\" already exists\n",
-               filespec);
-#ifdef USE_POSIX_SHM
-//     shm_unlink(filespec);
-       _shmfd = shm_open(filespec, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
-#else
-# ifdef USE_SYSV_SHM
-#  ifdef HAVE_SHMGET
-       // Get the shared memory id for this segment
-       _shmfd = shmget(_shmkey, _size, 0);
-#  else
-#   ifdef __riscos__
-        // do nothing, we never get here.
-#   else
-       _shmhandle = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL,
-                                       PAGE_READWRITE, 0,
-                                       _size, filespec);
-#   endif
-#  endif
-# else
+
+
+#else
 # error "You need SYSV Shared memory support to use this option"
-# endif
-#endif
-    }
-    
-    // MacOSX returns this when you use O_EXCL for shm_open() instead
-    // of EEXIST
-#if defined(HAVE_SHMGET) || defined(HAVE_SHM_OPEN)
-    if (_shmfd < 0 && errno == EINVAL)
-#else
-# ifdef __riscos__
-    if (0)
-# else
-    if (_shmhandle <= 0 && errno == EINVAL)
-#endif
-#endif
-       {
-       exists = true;
-       log_error(
-#ifdef USE_POSIX_SHM
-           "shm_open() failed, retrying: %s\n",
-#else
-# ifdef USE_SYSV_SHM
-           "shmget() failed, retrying: %s\n",
-# else
-           "CreateFileMapping() failed, retrying: %s\n",
-# endif
-#endif
-           strerror(errno));
-//        fd = shm_open(filespec, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
-       return false;
-    }
-    
-    // We got the file descriptor, now map it into our process.
-#if defined(HAVE_SHMGET) || defined(HAVE_SHM_OPEN)
-    if (_shmfd >= 0)
-#else
-# ifdef __riscos__
-    if (1)
-# else
-    if (_shmhandle >= 0)
-#endif
-#endif
-    {
-#ifdef USE_POSIX_SHM
-       if (!exists) {
-           // Set the size so we can write to new segment
-           ftruncate(_shmfd, _size);
-       }
-       _addr = static_cast<char *>(mmap(0, _size,
-                                PROT_READ|PROT_WRITE,
-                                        
MAP_SHARED|MAP_INHERIT|MAP_HASSEMAPHORE,
-                                _shmfd, 0));
-       if (_addr == MAP_FAILED) {
-           log_error("mmap() failed: %s\n", strerror(errno));
-           return false;
-       }
-#else  // else of HAVE_SHM_OPEN
-# ifdef HAVE_SHMAT
-       _addr = static_cast<char *>(shmat(_shmfd, 0, 0));
-       if (_addr <= 0) {
-           log_error("shmat() failed: %s\n", strerror(errno));
-           return false;
-       }
-# else
-#  ifdef __riscos__
-        _addr = static_cast<char *>(malloc(_size));
-        if (_addr == 0) {
-            log_error("malloc() failed\n");
-            return false;
-        }
-#  else
-       _addr = static_cast<char *>(MapViewOfFile(_shmhandle, 
FILE_MAP_ALL_ACCESS,
-                                      0, 0, _size));
-# endif
-#endif
-#endif
-//     log_debug("The address to the shared memory segment is: %p", _addr);
-        if (exists && !nuke) {
-           // If there is an existing memory segment that we don't
-           // want to trash, we just want to attach to it. We know
-           // that a Shm data class has been instantiated in
-           // the base of memory, and the first field is the address
-           // used for the previous mmap(), so we grab that value,
-           // unmap the old address, and map the original address
-           // into this process. This is done so that memory
-           // allocations between processes all have the same
-           // addresses. Otherwise, one can't do globally shared data
-           // among processes that requires any dynamic memory
-           // allocation. All of this is so our custom memory
-           // allocator for STL containers will work.
-           addr = *(reinterpret_cast<long *>(_addr));
-           if (addr == 0) {
-               log_error("No address found in memory segment!\n");
-               nuke = true;
-           } else {
-#ifdef FLAT_ADDR_SPACE
-           log_debug("Adjusting address to 0x%lx\n", addr);
-#ifdef USE_POSIX_SHM
-           munmap(_addr, _size);
-           log_debug("Unmapped address %p\n", _addr);
-#ifdef darwin
-           _addr = static_cast<char *>(mmap(reinterpret_cast<char *>(addr),
-                                            _size, PROT_READ,
-                                            
MAP_SHARED|MAP_FIXED|MAP_INHERIT|MAP_HASSEMAPHORE,
-                                            _shmfd, static_cast<off_t>(0)));
-#else
-           //                 off = (off_t)((long)addr - (long)_addr);
-           _addr = static_cast<char *>(mmap(reinterpret_cast<char *>(addr),
-                                            _size, PROT_READ|PROT_WRITE,
-                                            MAP_FIXED|MAP_SHARED, _shmfd, 0));
-#endif
-           if (_addr == MAP_FAILED) {
-               log_error("MMAP failed: %s\n", strerror(errno));
-               return static_cast<Shm *>(0);
-           }
-        }
-#else  // HAVE_SHM_OPEN
-# ifdef HAVE_SHMAT         
-       shmdt(_addr);
-       _addr = static_cast<char *>(shmat(_shmfd, reinterpret_cast<void 
*>(addr), 0));
-# else
-#  ifdef __riscos__
-        _addr = _addr;
-#  else
-       CloseHandle(_shmhandle);        
-       _addr = static_cast<char *>(MapViewOfFile(_shmhandle, 
FILE_MAP_ALL_ACCESS,
-                              0, 0, _size));
-#  endif
-# endif // end of HAVE_SHMAT
-       }
-#endif // end of HAVE_SHM_OPEN
-#else // else of FLAT_ADDR_SPACE
-#endif // end of FLAT_ADDR_SPACE
-    
-       log_debug("Opened Shared Memory segment \"%s\": %d bytes at %p.",
-               filespec, _size, _addr);
-       }
-
-#ifdef USE_POSIX_SHM
-       if (nuke) {
-           log_debug("Zeroing %d bytes at %p.\n", _size, _addr);
-           // Nuke all the segment, so we don't have any problems
-           // with leftover data.
-           memset(_addr, 0, _size);
-           sc = cloneSelf();
-       } else {
-           sc = reinterpret_cast<Shm *>(_addr);
-       }
-#else
-           sc = reinterpret_cast<Shm *>(_addr);
-#endif
-    } else {
-       log_error("Couldn't open the Shared Memory segment \"%s\"! %s\n",
-               filespec, strerror(errno));
-       return false;
-    }
-    
-#ifdef USE_POSIX_SHM
-// don't close it on an error
-    if (_shmfd) {
-       ::close(_shmfd);
-    }
-#endif
-      
-    return true; 
-}
-
-/// \brief Copy the current data for the shared memory segment to the
-/// head of the segment.
-Shm *
-Shm::cloneSelf(void)
-{
-//    GNASH_REPORT_FUNCTION;
-
-    if (_addr > 0) {
-//         log_debug("Cloning ShmControl, %d bytes to %p\n",
-//                 sizeof(Shm), _addr);
-        // set the allocated bytes before we copy so the value is
-        // correct in both instantiations of this object.
-        _alloced = sizeof(Shm);
-        memcpy(_addr, this, sizeof(Shm));
-        return reinterpret_cast<Shm *>(_addr);
-    }
-    
-    log_error("Can't clone Self, address 0x0\n");
-
-    return static_cast<Shm *>(0);
-}
-
-// Resize the allocated memory segment
-bool
-Shm::resize()
-{
-//    GNASH_REPORT_FUNCTION;
-    // Increase the size by 10 %
-    return resize(DEFAULT_SHM_SIZE + (DEFAULT_SHM_SIZE/10)); 
-}
-
-bool
-Shm::resize(int bytes)
-    
-{
-//    GNASH_REPORT_FUNCTION;
-#ifdef HAVE_MREMAP
-    _addr = mremap(_shmAddr, _shmSize, _shmSize + bytes, MREMAP_MAYMOVE);
-    if (_addr != 0) {
-        return true;
-    }
-#else
-    // FIXME: alloc a whole new segment, and copy this one
-    // into it. Yeuch...
-    // Get rid of the compiler warning, this will get optimized out anyway.
-    bytes += 0;
-#endif
-    return false;
-}
-
-// Allocate a memory from the shared memory segment
-void *
-Shm::brk(int bytes)
-{
-//    GNASH_REPORT_FUNCTION;
-    int wordsize = sizeof(long);
-    
-    // Adjust the allocated amount of memory to be on a word boundary.
-    if (bytes % wordsize) {
-        int wordsize = sizeof(long);
-        
-        // Adjust the allocated amount of memory to be on a word boundary.
-        if (bytes % wordsize) {
-            bytes += wordsize - bytes % wordsize;
-        }
-        
-        void *addr = (static_cast<char *>(_addr)) + _alloced;
-        
-        log_debug("%s: Allocating %d bytes at %p\n",
-                __PRETTY_FUNCTION__, bytes, addr);
-        // Zero out the block before returning it
-        memset(addr, 0, bytes);
-        
-        // Increment the counter
-        _alloced += bytes;
-        
-        // Return a pointer to the beginning of the block
-        return addr;
-        bytes += wordsize - bytes % wordsize;
-    }
-    
-    void *addr = (static_cast<char *>(_addr)) + _alloced;
-    
-    log_debug("%s: Allocating %d bytes at %p\n",
-            __PRETTY_FUNCTION__, bytes, addr);
-
-    // Zero out the block before returning it
-    memset(addr, 0, bytes);
-    
-    
-    // Increment the counter
-    _alloced += bytes;
-    
-    // Return a pointer to the beginning of the block
-    return addr; 
-}
-
-// Close the memory segment. This removes it from the system.
-bool
-Shm::closeMem()
-{
-//    GNASH_REPORT_FUNCTION;
-    // Only nuke the shared memory segement if we're the last one.
-#ifdef USE_POSIX_SHM
-#ifdef HAVE_SHM_UNLINK
-    if (strlen(_filespec) != 0) {
-        shm_unlink(_filespec);
-    }
-    
-     // flush the shared memory to disk
-     if (_addr > 0) {
-         // detach memory
-         munmap(_addr, _size);
-     }
-#endif
-#ifdef USE_SYSV_SHM
-     shmctl(_shmfd, IPC_RMID, 0);
-#else
-# ifdef __riscos__
-     free(_addr);
-# else
-     CloseHandle(_shmhandle);
-#endif
-#endif
-#endif
-    
-    _addr = 0;
-    _alloced = 0;
-    memset(_filespec, 0, MAX_SHM_NAME_SIZE);
-
-    return true;    
-}
-
-bool
-Shm::exists()
-{
-//    GNASH_REPORT_FUNCTION;
-    struct stat           stats;
-    struct dirent         *entry;
-    vector<const char *>  dirlist;
-    string                realname;
-    DIR                   *library_dir = NULL;
-
-    // Solaris stores shared memory segments in /var/tmp/.SHMD and
-    // /tmp/.SHMD. Linux stores them in /dev/shm.
-    dirlist.push_back("/dev/shm");
-    dirlist.push_back("/var/tmp/.SHMD");
-    dirlist.push_back("/tmp/.SHMD");
-
-    // Open the directory where the raw POSIX shared memory files are
-    for (unsigned int i=0; i<dirlist.size(); i++)
-    {
-        library_dir = opendir (dirlist[i]);
-        if (library_dir != NULL) {
-            realname = dirlist[i];
-            
-            // By convention, the first two entries in each directory
-            // are for . and .. (``dot'' and ``dot dot''), so we
-            // ignore those. The next directory read will get a real
-            // file, if any exists.
-            entry = readdir(library_dir);
-            entry = readdir(library_dir);
-            break;
-        }
-    }
-
-    if (strlen(_filespec)) {
-       realname += _filespec;
-    
-       if (stat(realname.c_str(), &stats) == 0) {
-           return true;
-       }
-    }
-    
-    return false;
-}
+#endif
+}    
+
+
 
 } // end of gnash namespace
 

=== renamed file 'libbase/shm.h' => 'libbase/SharedMem.h'
--- a/libbase/shm.h     2010-01-25 18:52:20 +0000
+++ b/libbase/SharedMem.h       2010-02-09 14:21:15 +0000
@@ -16,10 +16,11 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-#ifndef __SHM_H__
-#define __SHM_H__
+#ifndef GNASH_SHM_H
+#define GNASH_SHM_H
 
 #include <string>
+#include <boost/cstdint.hpp>
 
 #include <sys/types.h>
 #if !defined(HAVE_WINSOCK_H) && !defined(__riscos__) && !defined(__OS2__)
@@ -48,124 +49,94 @@
 
 const int MAX_SHM_NAME_SIZE = 48;
 
-class Shm {
+class SharedMem
+{
 public:
 
-    DSOEXPORT Shm();
-    DSOEXPORT ~Shm();
+    typedef boost::uint8_t* iterator;
+
+    /// The beginning of the SharedMem section.
+    //
+    /// This is only valid after attach() has returned true. You can check
+    /// with the function attached().
+    iterator begin() const {
+        return _addr;
+    }
+
+    /// The end of the SharedMem section.
+    //
+    /// This is only valid after attach() has returned true.
+    iterator end() const {
+        return _addr + _size;
+    }
+
+    /// Construct a SharedMem with the requested size.
+    //
+    /// @param size     The size of the shared memory section. If successfully
+    ///                 created, the segment will be exactly this size and
+    ///                 is not resizable.
+    DSOEXPORT SharedMem(size_t size);
+
+    /// Destructor.
+    DSOEXPORT ~SharedMem();
     
-    // Initialize the shared memory segment
+    /// Initialize the shared memory segment
+    //
+    /// This is called by LocalConnection when either connect() or send()
+    /// is called.
     bool attach();
-    bool DSOEXPORT attach(char const *filespec, bool nuke);
-    bool DSOEXPORT attach(key_t key, bool nuke);
-    
-    // Resize the allocated memory segment
-    bool resize(int bytes);
-    bool resize();
-    
-    // Allocate a memory from the shared memory segment
-    void *brk(int bytes);
-    
-    // Close the memory segment. This removes it from the system.
-    bool DSOEXPORT closeMem();
-    
-    Shm *cloneSelf(void);
-
-    // Accessors for testing
-    char *getAddr()             { return _addr; };
-    char *getName()             { return _filespec; };
-    size_t getSize()            { return _size; };
-    int getAllocated()          { return _alloced; };
-    bool exists();
-protected:
-    char        *_addr;
-    long        _alloced;
-    size_t      _size;
-    char        _filespec[MAX_SHM_NAME_SIZE];
+
+    /// Use to get a scoped semaphore lock on the shared memory.
+    class Lock
+    {
+    public:
+        Lock(SharedMem& s) : _s(s), _locked(s.lock()) {}
+        ~Lock() { if (_locked) _s.unlock(); }
+        bool locked() const {
+            return _locked;
+        }
+    private:
+        SharedMem& _s;
+        bool _locked;
+    };
+
+private:
+    
+    /// Get a semaphore lock if possible
+    //
+    /// @return     true if successful, false if not.
+    bool lock();
+    
+    /// Release a semaphore lock if possible
+    //
+    /// @return     true if successful, false if not.
+    bool unlock();
+
+    iterator _addr;
+
+    const size_t _size;
+
+    // Semaphore ID.
+    int _semid;
+
+    // Shared memory ID.
+    int _shmid;
+
 #if !defined(HAVE_WINSOCK_H) || defined(__OS2__)
     key_t      _shmkey;
 #else
     long       _shmkey;
     HANDLE      _shmhandle;
 #endif
-    int                _shmfd;
 };
 
-// Custome memory allocator for the shared memory segment
-template<typename _Tp>
-class ShmAlloc
-{
-private:
-    Shm *mmptr;
-    Shm mem;
-public:
-    typedef size_t     size_type;
-    typedef ptrdiff_t  difference_type;
-    typedef _Tp*       pointer;
-    typedef const _Tp* const_pointer;
-    typedef _Tp&       reference;
-    typedef const _Tp& const_reference;
-    typedef _Tp        value_type;
-    
-    template<typename _Tp1>
-    struct rebind
-    { typedef ShmAlloc<_Tp1> other; };
-    
-    ShmAlloc() throw() { }
-    
-    ShmAlloc(const ShmAlloc& other) throw() 
-        : mem(other.mem)
-        { }
-    
-    template<typename _Tp1>
-    ShmAlloc(const ShmAlloc<_Tp1>& other) throw() 
-        : mem(other.mem)
-        { }
-    
-    ~ShmAlloc() throw() { }
-    
-    pointer
-    address(reference __x) const        { return &__x; }
-    
-    const_pointer
-    address(const_reference __x) const { return &__x; }
-    
-    // Allocate memory
-    _Tp*
-    allocate(size_type n, const void* p = 0) {
-        // If the memory manager has no blocks, it hasn't been
-        // initialized.
-//         if (mminit == false) {
-//             mmptr = mem.initMemManager(true);
-//             mminit = true;
-//         } else {
-//             mmptr = mem.initMemManager(false);
-//         }
-        
-        _Tp* ret = 0;
-        if (n) {
-            ret = (_Tp*)mmptr->brk(n * sizeof(_Tp));
-            if (ret == 0)
-                throw std::bad_alloc();
-        }
-        return ret;
-    }
-    
-    // Deallocate memory
-    void
-    deallocate(pointer __p, size_type __n) {
-        //mmptr->free(__p);
-    }
-    
-    void construct(pointer __p, const _Tp& __val) {
-        new(__p) _Tp(__val);
-    }
-    void destroy(pointer __p)   { __p->~_Tp(); }
-};
+bool
+attached(const SharedMem& mem) {
+    return (mem.begin());
+}
 
 } // end of gnash namespace
 
-// end of __SHM_H__
 #endif
 
 // Local Variables:

=== modified file 'libbase/rc.cpp'
--- a/libbase/rc.cpp    2010-01-18 07:23:41 +0000
+++ b/libbase/rc.cpp    2010-02-11 08:33:14 +0000
@@ -547,9 +547,6 @@
                  extractSetting(_lcdisabled, "LocalConnection", variable,
                            value)
             ||
-                 extractSetting(_lctrace, "LCTrace", variable,
-                           value)
-            ||
                  extractNumber(_movieLibraryLimit, "movieLibraryLimit",
                          variable, value)
             ||
@@ -728,7 +725,6 @@
        cmd << "solLocalDomain " << _sollocaldomain << endl <<
     cmd << "SOLSafeDir " << _solsandbox << endl <<
     cmd << "localConnection " << _lcdisabled << endl <<
-    cmd << "LCTrace " << _lctrace << endl <<
     cmd << "LCShmkey " << std::hex << (boost::uint32_t) _lcshmkey << endl <<
     cmd << "ignoreFSCommand " << _ignoreFSCommand << endl <<    
     cmd << "saveStreamingMedia " << _saveStreamingMedia << endl <<    

=== modified file 'libbase/rc.h'
--- a/libbase/rc.h      2010-01-25 18:52:20 +0000
+++ b/libbase/rc.h      2010-02-11 08:33:14 +0000
@@ -259,11 +259,6 @@
     
     void setLocalConnection(bool x) { _lcdisabled = x; }
     
-    /// \brief Enable tracing all LocalConnection traffic
-    bool getLCTrace() const { return _lctrace; }
-    
-    void setLCTrace(bool x) { _lctrace = x; }
-
     key_t getLCShmKey() const { return static_cast<key_t>(_lcshmkey); }
     
     void setLCShmKey(bool x) { _lcshmkey = x; }

=== added file 'libcore/AMF.cpp'
--- a/libcore/AMF.cpp   1970-01-01 00:00:00 +0000
+++ b/libcore/AMF.cpp   2010-02-10 13:57:22 +0000
@@ -0,0 +1,801 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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 3 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
+
+
+#include <map>
+
+#include "SimpleBuffer.h"
+#include "AMF.h"
+#include "namedStrings.h"
+#include "as_value.h"
+#include "as_object.h"
+#include "ObjectURI.h"
+#include "VM.h"
+#include "Date_as.h"
+#include "xml/XMLDocument_as.h"
+#include "Array_as.h"
+
+
+// Define this macro to make AMF parsing verbose
+//#define GNASH_DEBUG_AMF_DESERIALIZE 1
+
+// Define this macto to make AMF writing verbose
+// #define GNASH_DEBUG_AMF_SERIALIZE 1
+
+namespace gnash {
+
+namespace AMF {
+
+namespace {
+
+    as_value readNumber(const boost::uint8_t*& pos, const boost::uint8_t* 
_end);
+    as_value readBoolean(const boost::uint8_t*& pos,
+            const boost::uint8_t* _end);
+    as_value readString(const boost::uint8_t*& pos, const boost::uint8_t* 
_end);
+    as_value readLongString(const boost::uint8_t*& pos,
+            const boost::uint8_t* _end);
+
+    inline boost::uint16_t readNetworkShort(const boost::uint8_t* buf);
+    inline boost::uint32_t readNetworkLong(const boost::uint8_t* buf);
+
+}
+
+namespace {
+
+/// Class used to serialize properties of an object to a buffer
+class PropsBufSerializer : public AbstractPropertyVisitor
+{
+
+public:
+    PropsBufSerializer(Writer& w, VM& vm)
+        :
+        _writer(w),
+        _st(vm.getStringTable()),
+        _error(false)
+    {}
+    
+    bool success() const { return !_error; }
+
+    bool accept(const ObjectURI& uri, const as_value& val) {
+        if (_error) return true;
+
+        // Tested with SharedObject and AMFPHP
+        if (val.is_function()) {
+            log_debug("AMF0: skip serialization of FUNCTION property");
+            return true;
+        }
+
+        const string_table::key key = getName(uri);
+
+        // Test conducted with AMFPHP:
+        // '__proto__' and 'constructor' members
+        // of an object don't get back from an 'echo-service'.
+        // Dunno if they are not serialized or just not sent back.
+        // A '__constructor__' member gets back, but only if 
+        // not a function. Actually no function gets back.
+        if (key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR)
+        {
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+            log_debug(" skip serialization of specially-named property %s",
+                    _st.value(key));
+#endif
+            return true;
+        }
+
+        // write property name
+        const std::string& name = _st.value(key);
+
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+        log_debug(" serializing property %s", name);
+#endif
+        _writer.writePropertyName(name);
+        if (!val.writeAMF0(_writer)) {
+            log_error("Problems serializing an object's member");
+            _error = true;
+        }
+        return true;
+    }
+
+private:
+
+    Writer& _writer;
+    string_table& _st;
+    mutable bool _error;
+
+};
+
+/// Exception for handling malformed buffers.
+//
+/// This exception is for internal use only! Do not throw it outside this
+/// TU.
+struct
+AMFException : public GnashException
+{
+    AMFException(const std::string& msg)
+        :
+        GnashException(msg)
+    {}
+};
+
+}
+
+bool
+Writer::writePropertyName(const std::string& name)
+{
+    boost::uint16_t namelen = name.size();
+    _buf.appendNetworkShort(namelen);
+    _buf.append(name.c_str(), namelen);
+    return true;
+}
+
+bool
+Writer::writeObject(as_object* obj)
+{
+    assert(obj);
+
+    // This probably shouldn't happen.
+    if (obj->to_function()) return false;
+
+    OffsetTable::iterator it = _offsets.find(obj);
+
+    // Handle references first.
+    if (it != _offsets.end()) {
+        const size_t idx = it->second;
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+        log_debug(_("amf: serializing object (or function) "
+                    "as reference to %d"), idx);
+#endif
+        _buf.appendByte(REFERENCE_AMF0);
+        _buf.appendNetworkShort(idx);
+        return true;
+    }
+     
+    // 1 for the first, etc...
+    const size_t idx = _offsets.size() + 1;
+    _offsets[obj] = idx;
+
+    /// Native objects are handled specially.
+    if (obj->relay()) {
+        
+        Date_as* date;
+        if (isNativeType(obj, date))
+        {
+            double d = date->getTimeValue(); 
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+            log_debug(_("amf: serializing date object "
+                        "with index %d and value %g"), idx, d);
+#endif
+            _buf.appendByte(DATE_AMF0);
+
+            // This actually only swaps on little-endian machines
+            swapBytes(&d, 8);
+            _buf.append(&d, 8);
+
+            // This should be timezone
+            boost::uint16_t tz = 0; 
+            _buf.appendNetworkShort(tz);
+
+            return true;
+        }
+
+        /// XML is written like a long string (but with an XML marker).
+        XMLDocument_as* xml;
+        if (isNativeType(obj, xml)) {
+            _buf.appendByte(XML_OBJECT_AMF0);
+            std::ostringstream s;
+            xml->toString(s, true);
+
+            const std::string& xmlstr = s.str();
+            _buf.appendNetworkLong(xmlstr.size());
+            _buf.append(xmlstr.c_str(), xmlstr.size());
+            return true;
+        }
+
+        // Any native objects not explicitly handled are unsupported (this
+        // is just a guess).
+        _buf.appendByte(UNSUPPORTED_AMF0);
+        return true;
+    }
+
+    VM& vm = getVM(*obj);
+
+    // Arrays are handled specially.
+    if (obj->array()) {
+
+        string_table& st = vm.getStringTable();
+        const size_t len = arrayLength(*obj);
+        if (_strictArray) {
+            IsStrictArray s(st);
+            // Check if any non-hidden properties are non-numeric.
+            obj->visitProperties<IsEnumerable>(s);
+
+            if (s.strict()) {
+
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+                log_debug(_("amf: serializing array of %d "
+                            "elements as STRICT_ARRAY (index %d)"),
+                            len, idx);
+#endif
+                _buf.appendByte(STRICT_ARRAY_AMF0);
+                _buf.appendNetworkLong(len);
+
+                as_value elem;
+                for (size_t i = 0; i < len; ++i) {
+                    elem = obj->getMember(arrayKey(st, i));
+                    if (!elem.writeAMF0(*this)) {
+                        log_error("Problems serializing strict array "
+                                "member %d=%s", i, elem);
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+
+        // A normal array.
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+        log_debug(_("amf: serializing array of %d "
+                    "elements as ECMA_ARRAY (index %d) "
+                    "[allowStrict:%d, isStrict:%d]"),
+                    len, idx, allowStrict, isStrict);
+#endif
+        _buf.appendByte(ECMA_ARRAY_AMF0);
+        _buf.appendNetworkLong(len);
+    }
+    else {
+        // It's a simple object
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+        log_debug(_("amf: serializing object (or function) "
+                    "with index %d"), idx);
+#endif
+        _buf.appendByte(OBJECT_AMF0);
+    }
+
+    PropsBufSerializer props(*this, vm);
+    obj->visitProperties<IsEnumerable>(props);
+    if (!props.success()) {
+        log_error("Could not serialize object");
+        return false;
+    }
+    _buf.appendNetworkShort(0);
+    _buf.appendByte(OBJECT_END_AMF0);
+    return true;
+}
+
+bool
+Writer::writeString(const std::string& str)
+{
+    const size_t strlen = str.size();
+    if (strlen <= 65535) {
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+        log_debug(_("amf: serializing string '%s'"), str);
+#endif
+        _buf.appendByte(STRING_AMF0);
+        _buf.appendNetworkShort(strlen);
+        _buf.append(str.c_str(), strlen);
+        return true;
+    }
+
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+    log_debug(_("amf: serializing long string '%s'"), str);
+#endif
+    _buf.appendByte(LONG_STRING_AMF0);
+    _buf.appendNetworkLong(strlen);
+    _buf.append(str.c_str(), strlen);
+    return true;
+}
+
+bool
+Writer::writeNumber(double d)
+{
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+    log_debug(_("amf: serializing number '%g'"), d);
+#endif
+    _buf.appendByte(NUMBER_AMF0);
+    swapBytes(&d, 8);
+    _buf.append(&d, 8);
+    return true;
+}
+
+bool
+Writer::writeUndefined()
+{
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+    log_debug(_("amf: serializing undefined"));
+#endif
+    _buf.appendByte(UNDEFINED_AMF0);
+    return true;
+}
+
+bool
+Writer::writeNull()
+{
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+    log_debug(_("amf: serializing null"));
+#endif
+    _buf.appendByte(NULL_AMF0);
+    return true;
+}
+
+void
+Writer::writeData(boost::uint8_t* data, size_t length)
+{
+    _buf.append(data, length);
+}
+
+bool
+Writer::writeBoolean(bool b)
+{
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+    log_debug(_("amf: serializing boolean '%s'"), b);
+#endif
+    _buf.appendByte(BOOLEAN_AMF0);
+    
+    if (b) _buf.appendByte(1);
+    else _buf.appendByte(0);
+
+    return true;
+}
+
+
+bool
+Reader::operator()(as_value& val, Type t)
+{
+
+    // No more reads possible.
+    if (_pos == _end) {
+        return false;
+    }
+
+    // This may leave the read position at the _end of the buffer, but
+    // some types are complete with the type byte (null, undefined).
+    if (t == NOTYPE) {
+        t = static_cast<Type>(*_pos);
+        ++_pos;
+    }
+    
+    try {
+
+        switch (t) {
+            
+            default:
+                log_error("Unknown AMF type %s! Cannot proceed", t);
+                // A fatal error, since we don't know how much to parse
+                return false;
+
+            // Simple types.
+            case BOOLEAN_AMF0:
+                val = readBoolean(_pos, _end);
+                return true;
+            
+            case STRING_AMF0:
+                val = readString(_pos, _end);
+                return true;
+            
+            case LONG_STRING_AMF0:
+                 val = readLongString(_pos, _end);
+                 return true;
+            
+            case NUMBER_AMF0:
+                val = readNumber(_pos, _end);
+                return true;
+            
+            case UNSUPPORTED_AMF0:
+            case UNDEFINED_AMF0:
+                val = as_value();
+                return true;
+            
+            case NULL_AMF0:
+                val = static_cast<as_object*>(0);
+                return true;
+            
+            // Object types need access to Global_as to create objects.
+            case REFERENCE_AMF0:
+                val = readReference();
+                return true;
+            
+            case OBJECT_AMF0:
+                val = readObject();
+                return true;
+            
+            case ECMA_ARRAY_AMF0:
+                val = readArray();
+                return true;
+            
+            case STRICT_ARRAY_AMF0:
+                val = readStrictArray();
+                return true;
+            
+            case DATE_AMF0:
+                val = readDate();
+                return true;
+
+            case XML_OBJECT_AMF0:
+                val = readXML();
+                return true;
+        }
+    }
+    catch (const AMFException& e) {
+        log_error("AMF parsing error: %s", e.what());
+        return false;
+    }
+
+}
+
+/// Construct an XML object.
+//
+/// Note that the pp seems not to call the constructor or parseXML, but
+/// rather to create it magically. It could do this by calling an ASNative
+/// function.
+as_value
+Reader::readXML()
+{
+    as_value str = readLongString(_pos, _end);
+    as_function* ctor = _global.getMember(NSV::CLASS_XML).to_function();
+    
+    as_value xml;
+    if (ctor) {
+        fn_call::Args args;
+        args += str;
+        VM& vm = getVM(_global);
+        xml = constructInstance(*ctor, as_environment(vm), args);
+    }
+    return xml;
+}
+
+as_value
+Reader::readStrictArray()
+{
+    if (_end - _pos < 4) {
+        throw AMFException("Read past _end of buffer for strict array length");
+    }
+
+    const boost::uint32_t li = readNetworkLong(_pos);
+    _pos += 4;
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 starting read of STRICT_ARRAY with %i elements", li);
+#endif
+    
+    as_object* array = _global.createArray();
+    _objectRefs.push_back(array);
+
+    as_value arrayElement;
+    for (size_t i = 0; i < li; ++i) {
+
+        // Recurse.
+        if (!operator()(arrayElement)) {
+            throw AMFException("Unable to read array elements");
+        }
+
+        callMethod(array, NSV::PROP_PUSH, arrayElement);
+    }
+
+    return as_value(array);
+}
+
+// TODO: this function is inconsistent about when it interrupts parsing
+// if the AMF is truncated. If it doesn't interrupt, the next read will
+// fail.
+as_value
+Reader::readArray()
+{
+
+    if (_end - _pos < 4) {
+        throw AMFException("Read past _end of buffer for array length");
+    }
+
+    const boost::uint32_t li = readNetworkLong(_pos);
+    _pos += 4;
+    
+    as_object* array = _global.createArray();
+    _objectRefs.push_back(array);
+
+    // the count specifies array size, so to have that even if none
+    // of the members are indexed
+    // if short, will be incremented everytime an indexed member is
+    // found
+    array->set_member(NSV::PROP_LENGTH, li);
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 starting read of ECMA_ARRAY with %i elements", li);
+#endif
+
+    as_value objectElement;
+    string_table& st = getStringTable(_global);
+    for (;;) {
+
+        // It seems we don't mind about this situation, although it means
+        // the next read will fail.
+        if (_end - _pos < 2) {
+            log_error("MALFORMED AMF: premature _end of ECMA_ARRAY "
+                    "block");
+            break;
+        }
+        const boost::uint16_t strlen = readNetworkShort(_pos);
+        _pos += 2; 
+
+        // _end of ECMA_ARRAY is signalled by an empty string
+        // followed by an OBJECT_END_AMF0 (0x09) byte
+        if (!strlen) {
+            // expect an object terminator here
+            if (*_pos != AMF::OBJECT_END_AMF0) {
+                log_error("MALFORMED AMF: empty member name not "
+                        "followed by OBJECT_END_AMF0 byte");
+            }
+            ++_pos;
+            break;
+        }
+        
+        // Throw exception instead?
+        if (_end - _pos < strlen) {
+            log_error("MALFORMED AMF: premature _end of ECMA_ARRAY "
+                    "block");
+            break;
+        }
+
+        const std::string name(reinterpret_cast<const char*>(_pos), strlen);
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+        log_debug("amf0 ECMA_ARRAY prop name is %s", name);
+#endif
+
+        _pos += strlen;
+
+        // Recurse to read element.
+        if (!operator()(objectElement)) {
+            throw AMFException("Unable to read array element");
+        }
+        array->set_member(st.find(name), objectElement);
+    }
+    return as_value(array);
+}
+
+as_value
+Reader::readObject()
+{
+
+    string_table& st = getStringTable(_global);
+    as_object* obj = _global.createObject(); 
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 starting read of OBJECT");
+#endif
+
+    _objectRefs.push_back(obj);
+
+    as_value tmp;
+    std::string keyString;
+    for(;;) {
+
+        if (!operator()(tmp, AMF::STRING_AMF0)) {
+            throw AMFException("Could not read object property name");
+        }
+        keyString = tmp.to_string();
+
+        if (keyString.empty()) {
+            if (_pos < _end) {
+                // AMF0 has a redundant "object _end" byte
+                ++_pos; 
+            }
+            else {
+                // What is the point?
+                log_error("AMF buffer terminated just before "
+                        "object _end byte. continuing anyway.");
+            }
+            return as_value(obj);
+        }
+
+        if (!operator()(tmp)) {
+            throw AMFException("Unable to read object member");
+        }
+        obj->set_member(st.find(keyString), tmp);
+    }
+}
+
+as_value
+Reader::readReference()
+{
+
+    if (_end - _pos < 2) {
+        throw AMFException("Read past _end of buffer for reference index");
+    }
+    const boost::uint16_t si = readNetworkShort(_pos);
+    _pos += 2;
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("readAMF0: reference #%d", si);
+#endif
+    if (si < 1 || si > _objectRefs.size()) {
+        log_error("readAMF0: invalid reference to object %d (%d known "
+                "objects)", si, _objectRefs.size());
+        throw AMFException("Reference to invalid object reference");
+    }
+    return as_value(_objectRefs[si - 1]);
+}
+
+as_value
+Reader::readDate()
+{
+
+    if (_end - _pos < 8) {
+        throw AMFException("Read past _end of buffer for date type");
+    }
+
+    double dub;
+
+    // TODO: may we avoid a copy and swapBytes call
+    //       by bitshifting b[0] trough b[7] ?
+    std::copy(_pos, _pos + 8, reinterpret_cast<char*>(&dub));
+    _pos += 8; 
+    swapBytes(&dub, 8);
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 read date: %e", dub);
+#endif
+
+    as_function* ctor = _global.getMember(NSV::CLASS_DATE).to_function();
+    VM& vm = getVM(_global);
+
+    as_value date;
+    if (ctor) {
+        fn_call::Args args;
+        args += dub;
+        date = constructInstance(*ctor, as_environment(vm), args);
+
+        if (_end - _pos < 2) {
+            throw AMFException("premature _end of input reading "
+                        "timezone from Date type");
+        }
+        LOG_ONCE(log_unimpl("Timezone info from AMF0 encoded Date object "
+                    "ignored"));
+        _pos += 2;
+    }
+    return date;
+}
+
+void*
+swapBytes(void *word, size_t size)
+{
+    union {
+    boost::uint16_t s;
+    struct {
+        boost::uint8_t c0;
+        boost::uint8_t c1;
+    } c;
+    } u;
+       
+    u.s = 1;
+        if (u.c.c0 == 0) {
+        // Big-endian machine: do nothing
+        return word;
+    }
+
+    // Little-endian machine: byte-swap the word
+    // A conveniently-typed pointer to the source data
+    boost::uint8_t *x = static_cast<boost::uint8_t *>(word);
+
+    /// Handle odd as well as even counts of bytes
+    std::reverse(x, x + size);
+    
+    return word;
+}
+
+namespace {
+
+as_value
+readBoolean(const boost::uint8_t*& pos, const boost::uint8_t* _end)
+{
+    if (pos == _end) {
+        throw AMFException("Read past _end of buffer for boolean type");
+    }
+
+    const bool val = *pos;
+    ++pos;
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 read bool: %d", val);
+#endif
+    return val;
+}
+
+as_value
+readNumber(const boost::uint8_t*& pos, const boost::uint8_t* _end)
+{
+
+    if (_end - pos < 8) {
+        throw AMFException("Read past _end of buffer for number type");
+    }
+
+    double d;
+    // TODO: may we avoid a copy and swapBytes call
+    //       by bitshifting b[0] trough b[7] ?
+    std::copy(pos, pos + 8, reinterpret_cast<char*>(&d));
+    pos += 8; 
+    swapBytes(&d, 8);
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 read double: %e", dub);
+#endif
+
+    return as_value(d);
+}
+
+as_value
+readString(const boost::uint8_t*& pos, const boost::uint8_t* _end)
+{
+    if (_end - pos < 2) {
+        throw AMFException("Read past _end of buffer for string length");
+    }
+
+    const boost::uint16_t si = readNetworkShort(pos);
+    pos += 2;
+
+    if (_end - pos < si) {
+        throw AMFException("Read past _end of buffer for string type");
+    }
+
+    const std::string str(reinterpret_cast<const char*>(pos), si);
+    pos += si;
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 read string: %s", str);
+#endif
+    return as_value(str);
+}
+
+as_value
+readLongString(const boost::uint8_t*& pos, const boost::uint8_t* _end)
+{
+    if (_end - pos < 4) {
+        throw AMFException("Read past _end of buffer for long string length");
+    }
+
+    const boost::uint32_t si = readNetworkLong(pos);
+    pos += 4;
+    if (_end - pos < si) {
+        throw AMFException("Read past _end of buffer for long string type");
+    }
+
+    const std::string str(reinterpret_cast<const char*>(pos), si);
+    pos += si;
+
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+    log_debug("amf0 read long string: %s", str);
+#endif
+
+    return as_value(str);
+
+}
+
+inline boost::uint16_t
+readNetworkShort(const boost::uint8_t* buf)
+{
+    boost::uint16_t s = buf[0] << 8 | buf[1];
+    return s;
+}
+
+inline boost::uint32_t
+readNetworkLong(const boost::uint8_t* buf)
+{
+    boost::uint32_t s = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+    return s;
+}
+
+} // anonymous namespace
+
+
+} // namespace AMF
+} // namespace gnash

=== added file 'libcore/AMF.h'
--- a/libcore/AMF.h     1970-01-01 00:00:00 +0000
+++ b/libcore/AMF.h     2010-02-10 13:58:27 +0000
@@ -0,0 +1,209 @@
+// 
+//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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 3 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
+
+
+#ifndef GNASH_AMF_H
+#define GNASH_AMF_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "as_value.h"
+#include "dsodefs.h"
+
+namespace gnash {
+    class as_object;
+    class SimpleBuffer;
+    class Global_as;
+}
+
+namespace gnash {
+
+/// Simple functions and classes for handling AMF.
+//
+/// AMF is a simple serialization format for ActionScript objects and values,
+/// allowing them to be stored and transmitted. These classes convert between
+/// AMF buffers and the objects they contain.
+namespace AMF {
+
+enum Type {
+    NOTYPE            = -1,
+    NUMBER_AMF0       = 0x00,
+    BOOLEAN_AMF0      = 0x01,
+    STRING_AMF0       = 0x02,
+    OBJECT_AMF0       = 0x03,
+    MOVIECLIP_AMF0    = 0x04,
+    NULL_AMF0         = 0x05,
+    UNDEFINED_AMF0    = 0x06,
+    REFERENCE_AMF0    = 0x07,
+    ECMA_ARRAY_AMF0   = 0x08,
+    OBJECT_END_AMF0   = 0x09,
+    STRICT_ARRAY_AMF0 = 0x0a,
+    DATE_AMF0         = 0x0b,
+    LONG_STRING_AMF0  = 0x0c,
+    UNSUPPORTED_AMF0  = 0x0d,
+    RECORD_SET_AMF0   = 0x0e,
+    XML_OBJECT_AMF0   = 0x0f,
+    TYPED_OBJECT_AMF0 = 0x10,
+};
+
+/// A class to compose AMF buffers.
+//
+/// A single AMF::Writer class can take successive values and encode them
+/// in a single buffer. The class takes care of object references.
+//
+/// This class merely encodes basic types such as strings, numbers, and
+/// ActionScript Objects. It does not handle as_values. However, it
+/// is designed for use with as_value::writeAMF0(), which uses an
+/// instance of this class to serialize itself.
+class Writer
+{
+public:
+
+    typedef std::map<as_object*, size_t> OffsetTable;
+
+    Writer(SimpleBuffer& buf, bool strictArray = false)
+        :
+        _buf(buf),
+        _strictArray(strictArray)
+    {}
+
+    /// Write any simple Object type: not DisplayObjects.
+    //
+    /// Handles functions, dates, XML, and arrays. The object must not be null.
+    bool writeObject(as_object* obj);
+
+    /// Write a string.
+    //
+    /// Handles long and short strings.
+    bool writeString(const std::string& str);
+
+    /// Write a null value.
+    bool writeNull();
+
+    /// Write an undefined value.
+    bool writeUndefined();
+
+    /// Write a double.
+    bool writeNumber(double d);
+
+    /// Write a boolean.
+    bool writeBoolean(bool b);
+
+    /// Encode the name of an object's property.
+    //
+    /// You should encode the value of the property immediately afterwards.
+    bool writePropertyName(const std::string& name);
+
+    /// Write custom data for special cases.
+    void writeData(boost::uint8_t* data, size_t length);
+
+private:
+
+    OffsetTable _offsets;
+    SimpleBuffer& _buf;
+    bool _strictArray;
+
+};
+
+/// Deserialize an AMF buffer to as_values.
+//
+/// This class relies on the public interface of as_value because we don't
+/// necessarily know in advance what basic type will be read from the
+/// buffer.
+//
+/// Note that callers may change the current buffer position. They must
+/// check that the read position is not past the end when a Reader object
+/// is called. This is very important!
+//
+/// For reading of basic types, there is no need to use VM resources. Object
+/// types required the construction of objects, which in turn needs a
+/// reference to a Global_as. For this reason, object reading functions
+/// are member functions, and the Reader requires a Global_as& reference
+/// in case it encounters object data.
+class Reader
+{
+public:
+    Reader(const boost::uint8_t*& pos, const boost::uint8_t* end, Global_as& 
gl)
+        :
+        _pos(pos),
+        _end(end),
+        _global(gl)
+    {}
+
+    /// Create a type from current position in the AMF buffer.
+    //
+    /// @param val      An as_value to be created from the AMF data.
+    /// @param type     The type of the data to read.
+    /// @return         false if this read failed for any reason.
+    ///                 The constructed as_value is then invalid. True if
+    ///                 the read succeeded and the as_value is valid.
+    bool operator()(as_value& val, Type t = NOTYPE);
+
+private:
+
+    /// Read an XML type.
+    as_value readXML();
+
+    /// Read a Date object type.
+    as_value readDate();
+    
+    /// Read a simple object type.
+    as_value readObject();
+    
+    /// Read an object reference type.
+    as_value readReference();
+    
+    /// Read an array object type.
+    as_value readArray();
+    
+    /// Read a strict array object type.
+    as_value readStrictArray();
+
+    /// Object references.
+    std::vector<as_object*> _objectRefs;
+
+    /// The current position in the buffer.
+    const boost::uint8_t*& _pos;
+
+    /// The end of the buffer.
+    const boost::uint8_t* const _end;
+
+    /// For creating objects if necessary.
+    Global_as& _global;
+
+};
+
+/// Swap bytes in raw data.
+//
+///    This only swaps bytes if the host byte order is little endian.
+///
+/// @param word The address of the data to byte swap.
+///
+/// @param size The number of bytes in the data.
+///
+/// @return A pointer to the raw data.
+///
+DSOEXPORT void* swapBytes(void *word, size_t size);
+
+
+} // namespace amf
+} // namespace gnash
+
+#endif

=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am       2010-02-08 00:05:16 +0000
+++ b/libcore/Makefile.am       2010-02-08 20:38:34 +0000
@@ -28,8 +28,8 @@
 
 # Only enable if we're configured with --enable-mp3
 AM_CPPFLAGS = \
-       -I$(top_srcdir)/libamf \
        -I$(top_srcdir)/libnet \
+       -I$(top_srcdir)/libamf \
        -I$(top_srcdir)/backend \
        -I$(top_srcdir)/libcore/swf \
        -I$(top_srcdir)/libcore/abc \
@@ -41,7 +41,6 @@
        -I$(top_srcdir)/libbase \
        -I$(top_srcdir)/libmedia \
        -I$(top_srcdir)/libsound \
-       -I$(top_srcdir)/libamf \
        $(PTHREAD_CFLAGS) \
        $(GLIB_CFLAGS) \
        $(BOOST_CFLAGS) \
@@ -61,6 +60,7 @@
        event_id.cpp \
        Relay.cpp \
        as_object.cpp \
+       AMF.cpp \
        as_value.cpp \
        DisplayObjectContainer.cpp \
        DisplayObject.cpp \
@@ -232,6 +232,7 @@
        ObjectURI.h \
        Property.h \
        PropertyList.h \
+       AMF.h \
        as_value.h \
        PropFlags.h     \
        CharacterProxy.h \
@@ -288,7 +289,6 @@
 
 libgnashcore_la_LIBADD = \
        $(top_builddir)/libbase/libgnashbase.la \
-       $(top_builddir)/libamf/libgnashamf.la \
        $(top_builddir)/libnet/libgnashnet.la \
        $(top_builddir)/libcore/parser/libgnashparser.la \
        $(top_builddir)/libcore/vm/libgnashvm.la \

=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2010-02-03 16:26:11 +0000
+++ b/libcore/as_value.cpp      2010-02-10 09:47:04 +0000
@@ -30,15 +30,15 @@
 #include "utility.h" // for typeName() 
 #include "GnashNumeric.h"
 #include "namedStrings.h"
-#include "element.h"
 #include "GnashException.h"
-#include "amf.h"
 #include "Array_as.h"
 #include "Date_as.h" // for Date type (readAMF0)
 #include "SimpleBuffer.h"
 #include "StringPredicates.h"
 #include "Global_as.h"
 #include "String_as.h"
+#include "AMF.h"
+
 
 #include <boost/shared_ptr.hpp>
 #include <cmath> 
@@ -61,12 +61,6 @@
 // Define this macro to make soft references activity verbose
 #define GNASH_DEBUG_SOFT_REFERENCES
 
-// Define this macro to make AMF parsing verbose
-//#define GNASH_DEBUG_AMF_DESERIALIZE 1
-
-// Define this macto to make AMF writing verbose
-// #define GNASH_DEBUG_AMF_SERIALIZE 1
-
 namespace gnash {
 
 namespace {
@@ -78,18 +72,6 @@
     return obj.get_member(m, &ret) && ret.is_object();
 }
 
-inline boost::uint16_t
-readNetworkShort(const boost::uint8_t* buf) {
-       boost::uint16_t s = buf[0] << 8 | buf[1];
-       return s;
-}
-
-inline boost::uint32_t
-readNetworkLong(const boost::uint8_t* buf) {
-       boost::uint32_t s = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
-       return s;
-}
-
 /// Truncates a double to a 32-bit unsigned int.
 //
 /// In fact, it is a 32-bit unsigned int with an additional sign, cast
@@ -100,9 +82,9 @@
 truncateToInt(double d)
 {
     if (d < 0) {   
-           return - static_cast<boost::uint32_t>(std::fmod(-d, 4294967296.0));
+        return - static_cast<boost::uint32_t>(std::fmod(-d, 4294967296.0));
     }
-       
+    
     return static_cast<boost::uint32_t>(std::fmod(d, 4294967296.0));
 }
 
@@ -230,213 +212,55 @@
     return boost::lexical_cast<double>(std::string(start, last));
 }
 
-
-// This class is used to iterate through all the properties of an AS object,
-// so we can change them to children of an AMF0 element.
-class PropsSerializer : public AbstractPropertyVisitor
-{
-
-public:
-
-    PropsSerializer(amf::Element& el, VM& vm)
-        :
-        _obj(el),
-           _st(vm.getStringTable())
-       {}
-    
-    bool accept(const ObjectURI& uri, const as_value& val) 
-    {
-
-        // We are not taking account of the namespace.
-        const string_table::key key = getName(uri);
-
-        // Test conducted with AMFPHP:
-        // '__proto__' and 'constructor' members
-        // of an object don't get back from an 'echo-service'.
-        // Dunno if they are not serialized or just not sent back.
-        // A '__constructor__' member gets back, but only if 
-        // not a function. Actually no function gets back.
-        // 
-        if (key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR)
-        {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(" skip serialization of specially-named property %s",
-                    _st.value(key));
-#endif
-            return true;
-        }
-
-        amf::AMF amf;
-        boost::shared_ptr<amf::Element> el;
-    
-        const std::string& name = _st.value(key);
-
-        if (val.is_string()) {
-            std::string str;
-            if (!val.is_undefined()) {
-                str = val.to_string();
-            }
-            el.reset(new amf::Element(name, str));
-        } else if (val.is_bool()) {
-            bool flag = val.to_bool();
-            el.reset(new amf::Element(name, flag));
-        } else if (val.is_object()) {
-//            el.reset(new amf::Element(name, flag));
-        } else if (val.is_null()) {
-           boost::shared_ptr<amf::Element> tmpel(new amf::Element);
-           tmpel->setName(name);
-           tmpel->makeNull();
-            el = tmpel;
-        } else if (val.is_undefined()) {
-           boost::shared_ptr<amf::Element> tmpel(new amf::Element);
-           tmpel->setName(name);
-           tmpel->makeUndefined();
-            el = tmpel;
-        } else if (val.is_number()) { 
-            double dub;
-            if (val.is_undefined()) {
-                dub = 0.0;
-            } else {
-                dub = val.to_number();
-            }
-            el.reset(new amf::Element(name, dub));
-        }
-    
-        if (el) {
-            _obj.addProperty(el);
-        }
-        return true;
-    }
-
-private:
-
-    amf::Element& _obj;
-    string_table& _st;
-
-};
-
 } // anonymous namespace
 
-/// Class used to serialize properties of an object to a buffer
-class PropsBufSerializer : public AbstractPropertyVisitor
-{
-
-    typedef std::map<as_object*, size_t> PropertyOffsets;
-
-public:
-    PropsBufSerializer(SimpleBuffer& buf, VM& vm,
-            PropertyOffsets& offsetTable, bool allowStrict)
-        :
-        _allowStrict(allowStrict),
-        _buf(buf),
-        _vm(vm),
-        _st(vm.getStringTable()),
-        _offsetTable(offsetTable),
-        _error(false)
-       {}
-    
-    bool success() const { return !_error; }
-
-    bool accept(const ObjectURI& uri, const as_value& val) 
-    {
-        if ( _error ) return true;
-
-        // Tested with SharedObject and AMFPHP
-        if (val.is_function())
-        {
-            log_debug("AMF0: skip serialization of FUNCTION property");
-            return true;
-        }
-
-        const string_table::key key = getName(uri);
-
-        // Test conducted with AMFPHP:
-        // '__proto__' and 'constructor' members
-        // of an object don't get back from an 'echo-service'.
-        // Dunno if they are not serialized or just not sent back.
-        // A '__constructor__' member gets back, but only if 
-        // not a function. Actually no function gets back.
-        if (key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR)
-        {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(" skip serialization of specially-named property %s",
-                    _st.value(key));
-#endif
-            return true;
-        }
-
-        // write property name
-        const std::string& name = _st.value(key);
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-        log_debug(" serializing property %s", name);
-#endif
-        boost::uint16_t namelen = name.size();
-        _buf.appendNetworkShort(namelen);
-        _buf.append(name.c_str(), namelen);
-        if (!val.writeAMF0(_buf, _offsetTable, _vm, _allowStrict)) {
-            log_error("Problems serializing an object's member");
-            _error = true;
-        }
-        return true;
-    }
-private:
-
-    bool _allowStrict;
-    SimpleBuffer& _buf;
-    VM& _vm;
-    string_table& _st;
-    PropertyOffsets& _offsetTable;
-    mutable bool _error;
-
-};
-    
 // Conversion to const std::string&.
 std::string
 as_value::to_string(int version) const
 {
-       switch (_type)
-       {
-               case STRING:
-                       return getStr();
-               case DISPLAYOBJECT:
-               {
-                       const CharacterProxy& sp = getCharacterProxy();
-                       if (!sp.get()) return "";
+    switch (_type)
+    {
+        case STRING:
+            return getStr();
+        case DISPLAYOBJECT:
+        {
+            const CharacterProxy& sp = getCharacterProxy();
+            if (!sp.get()) return "";
             return sp.getTarget();
-               }
-               case NUMBER:
-                       return doubleToString(getNum());
-               case UNDEFINED: 
-                   if (version <= 6) return "";
-                       return "undefined";
-               case NULLTYPE:
-                       return "null";
-               case BOOLEAN:
-                       return getBool() ? "true" : "false";
-               case OBJECT:
-               {
+        }
+        case NUMBER:
+            return doubleToString(getNum());
+        case UNDEFINED: 
+            if (version <= 6) return "";
+            return "undefined";
+        case NULLTYPE:
+            return "null";
+        case BOOLEAN:
+            return getBool() ? "true" : "false";
+        case OBJECT:
+        {
             as_object* obj = getObj();
             String_as* s;
             if (isNativeType(obj, s)) return s->value();
 
-                       try {
-                               as_value ret = to_primitive(STRING);
-                               // This additional is_string test is NOT 
compliant with ECMA-262
-                               // specification, but seems required for 
compatibility with the
-                               // reference player.
-                               if (ret.is_string()) return ret.getStr();
-                       }
-                       catch (ActionTypeError& e) {
-                       }
+            try {
+                as_value ret = to_primitive(STRING);
+                // This additional is_string test is NOT compliant with 
ECMA-262
+                // specification, but seems required for compatibility with the
+                // reference player.
+                if (ret.is_string()) return ret.getStr();
+            }
+            catch (ActionTypeError& e) {
+            }
 
-                       if (_type == OBJECT) {
+            if (_type == OBJECT) {
                 return is_function() ? "[type Function]" : "[type Object]";
             }
 
-               }
+        }
 
-               default:
-                       return "[exception]";
+        default:
+            return "[exception]";
     }
     
 }
@@ -446,8 +270,8 @@
 as_value::ptype() const
 {
 
-       switch (_type)
-       {
+    switch (_type)
+    {
         case STRING:
             return PTYPE_STRING;
         case NUMBER: 
@@ -461,13 +285,13 @@
         default:
             break;
     }
-       return PTYPE_NUMBER;
+    return PTYPE_NUMBER;
 }
 
 as_value::AsType
 as_value::defaultPrimitive(int version) const
 {
-       if (_type == OBJECT && version > 5) {
+    if (_type == OBJECT && version > 5) {
         Date_as* d;
         if (isNativeType(getObj(), d)) return STRING;
     }
@@ -478,56 +302,56 @@
 as_value
 as_value::to_primitive(AsType hint) const
 {
-       if (_type != OBJECT) return *this; 
+    if (_type != OBJECT) return *this; 
 
 #if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE
-       log_debug("to_primitive(%s)", hint==NUMBER ? "NUMBER" : "STRING");
+    log_debug("to_primitive(%s)", hint==NUMBER ? "NUMBER" : "STRING");
 #endif 
 
-       // TODO: implement as_object::DefaultValue (ECMA-262 - 8.6.2.6)
-
-       as_value method;
-       as_object* obj(0);
-
-       if (hint == NUMBER) {
+    // TODO: implement as_object::DefaultValue (ECMA-262 - 8.6.2.6)
+
+    as_value method;
+    as_object* obj(0);
+
+    if (hint == NUMBER) {
         assert(_type == OBJECT);
-               obj = getObj();
+        obj = getObj();
 
-               if (!findMethod(*obj, NSV::PROP_VALUE_OF, method)) {
+        if (!findMethod(*obj, NSV::PROP_VALUE_OF, method)) {
             // Returning undefined here instead of throwing
             // a TypeError passes tests in actionscript.all/Object.as
             // and many swfdec tests, with no new failures (though
             // perhaps we aren't testing enough).
             return as_value();
-               }
-       }
-       else {
-               assert(hint == STRING);
+        }
+    }
+    else {
+        assert(hint == STRING);
         assert(_type == OBJECT);
-               obj = getObj();
+        obj = getObj();
 
-               // @@ Moock says, "the value that results from
-               // calling toString() on the object".
-               if (!findMethod(*obj, NSV::PROP_TO_STRING, method) &&
+        // @@ Moock says, "the value that results from
+        // calling toString() on the object".
+        if (!findMethod(*obj, NSV::PROP_TO_STRING, method) &&
                 !findMethod(*obj, NSV::PROP_VALUE_OF, method)) {
-                               throw ActionTypeError();
+                throw ActionTypeError();
         }
-       }
-
-       assert(obj);
-
-       as_environment env(getVM(*obj));
+    }
+
+    assert(obj);
+
+    as_environment env(getVM(*obj));
     fn_call::Args args;
-       as_value ret = invoke(method, env, obj, args);
+    as_value ret = invoke(method, env, obj, args);
 
 #if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE
-       log_debug("to_primitive: method call returned %s", ret);
+    log_debug("to_primitive: method call returned %s", ret);
 #endif
 
-       if (ret._type == OBJECT) {
-               throw ActionTypeError();
-       }
-       return ret;
+    if (ret._type == OBJECT) {
+        throw ActionTypeError();
+    }
+    return ret;
 }
 
 double
@@ -638,47 +462,6 @@
     }
 }
 
-boost::shared_ptr<amf::Element>
-as_value::to_element() const
-{
-    VM& vm = VM::get();
-    //int swfVersion = vm.getSWFVersion();
-    boost::shared_ptr<amf::Element> el ( new amf::Element );
-    as_object* ptr = to_object(*vm.getGlobal());
-
-    switch (_type) {
-      case UNDEFINED:
-         el->makeUndefined();
-         break;
-      case NULLTYPE:
-         el->makeNull();
-         break;
-      case BOOLEAN:
-         el->makeBoolean(getBool());
-         break;
-      case  STRING:
-         el->makeString(getStr());
-         break;
-      case NUMBER:
-         el->makeNumber(getNum());
-         break;
-      case OBJECT:
-      {
-          if (is_function()) break;
-          el->makeObject();
-          PropsSerializer props(*el, vm);
-          ptr->visitProperties<Exists>(props);
-         break;
-      }
-      case DISPLAYOBJECT:
-         log_unimpl("Converting a Movie Clip to an element is not supported");
-         break;
-      default:
-         break;
-    }
-
-    return el;
-}
 
 // Conversion to boolean 
 bool
@@ -687,72 +470,72 @@
     const int version = VM::get().getSWFVersion();
     switch (_type)
     {
-               case STRING:
-               {
+        case STRING:
+        {
             if (version >= 7) return !getStr().empty();
-                       const double num = to_number();
-                       return num && !isNaN(num);
-               }
-               case NUMBER:
-               {
-                       const double d = getNum();
+            const double num = to_number();
+            return num && !isNaN(num);
+        }
+        case NUMBER:
+        {
+            const double d = getNum();
             // see testsuite/swfdec/if-6.swf
-                       return d && ! isNaN(d);
-               }
-               case BOOLEAN:
-                       return getBool();
-               case OBJECT:
-                       return true;
-               case DISPLAYOBJECT:
-                       return true;
-               default:
-                       assert(_type == UNDEFINED || _type == NULLTYPE || 
is_exception());
-                       return false;
-       }
+            return d && ! isNaN(d);
+        }
+        case BOOLEAN:
+            return getBool();
+        case OBJECT:
+            return true;
+        case DISPLAYOBJECT:
+            return true;
+        default:
+            assert(_type == UNDEFINED || _type == NULLTYPE || is_exception());
+            return false;
+    }
 }
 
 // Return value as an object.
 as_object*
 as_value::to_object(Global_as& global) const
 {
-       switch (_type)
-       {
-               case OBJECT:
-                       return getObj();
-
-               case DISPLAYOBJECT:
-                       return getObject(toDisplayObject());
-
-               case STRING:
-                       return global.createString(getStr());
-
-               case NUMBER:
-                       return global.createNumber(getNum());
-
-               case BOOLEAN:
-                       return global.createBoolean(getBool());
-
-               default:
-                       // Invalid to convert exceptions.
-                       return NULL;
-       }
+    switch (_type)
+    {
+        case OBJECT:
+            return getObj();
+
+        case DISPLAYOBJECT:
+            return getObject(toDisplayObject());
+
+        case STRING:
+            return global.createString(getStr());
+
+        case NUMBER:
+            return global.createNumber(getNum());
+
+        case BOOLEAN:
+            return global.createBoolean(getBool());
+
+        default:
+            // Invalid to convert exceptions.
+            return NULL;
+    }
 }
 
 MovieClip*
 as_value::toMovieClip(bool allowUnloaded) const
 {
-       if ( _type != DISPLAYOBJECT ) return 0;
+    if ( _type != DISPLAYOBJECT ) return 0;
 
-       DisplayObject *ch = getCharacter(allowUnloaded);
-       if ( ! ch ) return 0;
-       return ch->to_movie();
+    DisplayObject *ch = getCharacter(allowUnloaded);
+    if ( ! ch ) return 0;
+    return ch->to_movie();
 }
 
 DisplayObject*
 as_value::toDisplayObject(bool allowUnloaded) const
 {
-       if (_type != DISPLAYOBJECT) return NULL;
-       return getCharacter(allowUnloaded);
+    if (_type != DISPLAYOBJECT) return NULL;
+    return getCharacter(allowUnloaded);
 }
 
 // Return value as an ActionScript function.  Returns NULL if value is
@@ -761,7 +544,7 @@
 as_value::to_function() const
 {
     if (_type == OBJECT) {
-           return getObj()->to_function();
+        return getObj()->to_function();
     }
 
     return 0;
@@ -770,37 +553,37 @@
 void
 as_value::set_undefined()
 {
-       _type = UNDEFINED;
-       _value = boost::blank();
+    _type = UNDEFINED;
+    _value = boost::blank();
 }
 
 void
 as_value::set_null()
 {
-       _type = NULLTYPE;
-       _value = boost::blank();
+    _type = NULLTYPE;
+    _value = boost::blank();
 }
 
 void
 as_value::set_as_object(as_object* obj)
 {
-       if ( ! obj )
-       {
-               set_null();
-               return;
-       }
+    if ( ! obj )
+    {
+        set_null();
+        return;
+    }
     if (obj->displayObject()) {
         // The static cast is fine as long as the as_object is genuinely
         // a DisplayObject.
         _type = DISPLAYOBJECT;
         _value = CharacterProxy(obj->displayObject());
-               return;
-       }
+        return;
+    }
 
-       if (_type != OBJECT || getObj() != obj) {
-               _type = OBJECT;
-               _value = obj;
-       }
+    if (_type != OBJECT || getObj() != obj) {
+        _type = OBJECT;
+        _value = obj;
+    }
 }
 
 bool
@@ -893,7 +676,7 @@
         try {
             // Date objects default to primitive type STRING from SWF6 up,
             // but we always prefer valueOf to toString in this case.
-               as_value v2 = to_primitive(NUMBER); 
+            as_value v2 = to_primitive(NUMBER); 
             if (strictly_equals(v2)) return false;
 #ifdef GNASH_DEBUG_EQUALITY
             log_debug(" 21: convertion to primitive : %s -> %s", *this, v2);
@@ -910,141 +693,141 @@
     }
 
 #ifdef GNASH_DEBUG_EQUALITY
-       // Both operands are objects (OBJECT,DISPLAYOBJECT)
-       if (!is_object() || !v.is_object()) {
-               log_debug("Equals(%s,%s)", *this, v);
-       }
+    // Both operands are objects (OBJECT,DISPLAYOBJECT)
+    if (!is_object() || !v.is_object()) {
+        log_debug("Equals(%s,%s)", *this, v);
+    }
 #endif
 
     // If any of the two converts to a primitive, we recurse
 
-       as_value p = *this;
-       as_value vp = v;
+    as_value p = *this;
+    as_value vp = v;
 
     bool converted(false);
 
-       try {
-               p = to_primitive(p.defaultPrimitive(SWFVersion)); 
-               if (!strictly_equals(p)) converted = true;
-#ifdef GNASH_DEBUG_EQUALITY
-               log_debug(" conversion to primitive (this): %s -> %s", *this, 
p);
-#endif
-       }
-       catch (ActionTypeError& e) {
-#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE 
-               log_debug(" %s.to_primitive() threw an ActionTypeError %s",
-                       *this, e.what());
-#endif
-       }
-
-       try {
-               vp = v.to_primitive(v.defaultPrimitive(SWFVersion)); 
-               if (!v.strictly_equals(vp)) converted = true;
-#ifdef GNASH_DEBUG_EQUALITY
-               log_debug(" conversion to primitive (that): %s -> %s", v, vp);
-#endif
-       }
-       catch (ActionTypeError& e) {
-#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE 
-               log_debug(" %s.to_primitive() threw an ActionTypeError %s",
-                       v, e.what());
-#endif
-       }
-
-       if (converted)
-       {
-#ifdef GNASH_DEBUG_EQUALITY
-               log_debug(" some conversion took place, recursing");
-#endif
-               return p.equals(vp);
-       }
-       else {
-#ifdef GNASH_DEBUG_EQUALITY
-               log_debug(" no conversion took place, returning false");
-#endif
-               return false;
-       }
+    try {
+        p = to_primitive(p.defaultPrimitive(SWFVersion)); 
+        if (!strictly_equals(p)) converted = true;
+#ifdef GNASH_DEBUG_EQUALITY
+        log_debug(" conversion to primitive (this): %s -> %s", *this, p);
+#endif
+    }
+    catch (ActionTypeError& e) {
+#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE 
+        log_debug(" %s.to_primitive() threw an ActionTypeError %s",
+            *this, e.what());
+#endif
+    }
+
+    try {
+        vp = v.to_primitive(v.defaultPrimitive(SWFVersion)); 
+        if (!v.strictly_equals(vp)) converted = true;
+#ifdef GNASH_DEBUG_EQUALITY
+        log_debug(" conversion to primitive (that): %s -> %s", v, vp);
+#endif
+    }
+    catch (ActionTypeError& e) {
+#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE 
+        log_debug(" %s.to_primitive() threw an ActionTypeError %s",
+            v, e.what());
+#endif
+    }
+
+    if (converted)
+    {
+#ifdef GNASH_DEBUG_EQUALITY
+        log_debug(" some conversion took place, recursing");
+#endif
+        return p.equals(vp);
+    }
+    else {
+#ifdef GNASH_DEBUG_EQUALITY
+        log_debug(" no conversion took place, returning false");
+#endif
+        return false;
+    }
 
 
 }
-       
+    
 const char*
 as_value::typeOf() const
 {
-       switch (_type)
-       {
-               case UNDEFINED:
-                       return "undefined"; 
-
-               case STRING:
-                       return "string";
-
-               case NUMBER:
-                       return "number";
-
-               case BOOLEAN:
-                       return "boolean";
-
-               case OBJECT:
+    switch (_type)
+    {
+        case UNDEFINED:
+            return "undefined"; 
+
+        case STRING:
+            return "string";
+
+        case NUMBER:
+            return "number";
+
+        case BOOLEAN:
+            return "boolean";
+
+        case OBJECT:
             return is_function() ? "function" : "object";
 
-               case DISPLAYOBJECT:
-               {
-                       DisplayObject* ch = getCharacter();
-                       if ( ! ch ) return "movieclip"; // dangling
-                       if ( ch->to_movie() ) return "movieclip"; // bound to 
movieclip
-                       return "object"; // bound to some other DisplayObject
-               }
-
-               case NULLTYPE:
-                       return "null";
-
-               default:
-                       if (is_exception()) return "exception";
+        case DISPLAYOBJECT:
+        {
+            DisplayObject* ch = getCharacter();
+            if ( ! ch ) return "movieclip"; // dangling
+            if ( ch->to_movie() ) return "movieclip"; // bound to movieclip
+            return "object"; // bound to some other DisplayObject
+        }
+
+        case NULLTYPE:
+            return "null";
+
+        default:
+            if (is_exception()) return "exception";
             std::abort();
-                       return 0;
-       }
+            return 0;
+    }
 }
 
 bool
 as_value::equalsSameType(const as_value& v) const
 {
-       assert(_type == v._type);
-
-       switch (_type)
-       {
-               case UNDEFINED:
-               case NULLTYPE:
-                       return true;
-
-               case OBJECT:
-               case BOOLEAN:
-               case STRING:
-                       return _value == v._value;
-
-               case DISPLAYOBJECT:
-                       return toDisplayObject() == v.toDisplayObject(); 
-
-               case NUMBER:
-               {
-                       const double a = getNum();
-                       const double b = v.getNum();
-                       if (isNaN(a) && isNaN(b)) return true;
-                       return a == b;
-               }
-               default:
-                       if (is_exception()) return false; 
-
-       }
+    assert(_type == v._type);
+
+    switch (_type)
+    {
+        case UNDEFINED:
+        case NULLTYPE:
+            return true;
+
+        case OBJECT:
+        case BOOLEAN:
+        case STRING:
+            return _value == v._value;
+
+        case DISPLAYOBJECT:
+            return toDisplayObject() == v.toDisplayObject(); 
+
+        case NUMBER:
+        {
+            const double a = getNum();
+            const double b = v.getNum();
+            if (isNaN(a) && isNaN(b)) return true;
+            return a == b;
+        }
+        default:
+            if (is_exception()) return false; 
+
+    }
     std::abort();
-       return false;
+    return false;
 }
 
 bool
 as_value::strictly_equals(const as_value& v) const
 {
-       if ( _type != v._type ) return false;
-       return equalsSameType(v);
+    if ( _type != v._type ) return false;
+    return equalsSameType(v);
 }
 
 std::string
@@ -1052,167 +835,167 @@
 {
     boost::format ret;
 
-       switch (_type)
-       {
-               case UNDEFINED:
-                       return "[undefined]";
-               case NULLTYPE:
-                       return "[null]";
-               case BOOLEAN:
-                   ret = boost::format("[bool:%s]") % (getBool() ? "true" : 
"false");
+    switch (_type)
+    {
+        case UNDEFINED:
+            return "[undefined]";
+        case NULLTYPE:
+            return "[null]";
+        case BOOLEAN:
+            ret = boost::format("[bool:%s]") % (getBool() ? "true" : "false");
             return ret.str();
-               case OBJECT:
-               {
-                       as_object* obj = getObj();
-                       ret = boost::format("[object(%s):%p]") % typeName(*obj) 
%
+        case OBJECT:
+        {
+            as_object* obj = getObj();
+            ret = boost::format("[object(%s):%p]") % typeName(*obj) %
                                               static_cast<void*>(obj);
-                       return ret.str();
-               }
-               case STRING:
-                       return "[string:" + getStr() + "]";
-               case NUMBER:
-               {
-                       std::stringstream stream;
-                       stream << getNum();
-                       return "[number:" + stream.str() + "]";
-               }
-               case DISPLAYOBJECT:
-               {
-                       const CharacterProxy& sp = getCharacterProxy();
-                       if (sp.isDangling()) {
-                               DisplayObject* rebound = sp.get();
-                               if (rebound) {
-                                   ret = boost::format("[rebound %s(%s):%p]") 
% 
-                                               typeName(*rebound) % 
sp.getTarget() %
-                                               static_cast<void*>(rebound);
-                               }
-                               else {
-                                   ret = boost::format("[dangling 
DisplayObject:%s]") % 
-                                           sp.getTarget();
-                               }
-                       }
-                       else {
-                               DisplayObject* ch = sp.get();
-                               ret = boost::format("[%s(%s):%p]") % 
typeName(*ch) %
-                                               sp.getTarget() % 
static_cast<void*>(ch);
-                       }
-                       return ret.str();
-               }
-               default:
-                       if (is_exception()) return "[exception]";
+            return ret.str();
+        }
+        case STRING:
+            return "[string:" + getStr() + "]";
+        case NUMBER:
+        {
+            std::stringstream stream;
+            stream << getNum();
+            return "[number:" + stream.str() + "]";
+        }
+        case DISPLAYOBJECT:
+        {
+            const CharacterProxy& sp = getCharacterProxy();
+            if (sp.isDangling()) {
+                DisplayObject* rebound = sp.get();
+                if (rebound) {
+                    ret = boost::format("[rebound %s(%s):%p]") % 
+                        typeName(*rebound) % sp.getTarget() %
+                        static_cast<void*>(rebound);
+                }
+                else {
+                    ret = boost::format("[dangling DisplayObject:%s]") % 
+                        sp.getTarget();
+                }
+            }
+            else {
+                DisplayObject* ch = sp.get();
+                ret = boost::format("[%s(%s):%p]") % typeName(*ch) %
+                                sp.getTarget() % static_cast<void*>(ch);
+            }
+            return ret.str();
+        }
+        default:
+            if (is_exception()) return "[exception]";
             std::abort();
-       }
+    }
 }
 
 void
 as_value::operator=(const as_value& v)
 {
-       _type = v._type;
-       _value = v._value;
+    _type = v._type;
+    _value = v._value;
 }
 
 void
 as_value::setReachable() const
 {
-       switch (_type)
-       {
-               case OBJECT:
-               {
-                       as_object* op = getObj();
-                       if (op) op->setReachable();
-                       break;
-               }
-               case DISPLAYOBJECT:
-               {
-                       CharacterProxy sp = getCharacterProxy();
-                       sp.setReachable();
-                       break;
-               }
-               default: break;
-       }
+    switch (_type)
+    {
+        case OBJECT:
+        {
+            as_object* op = getObj();
+            if (op) op->setReachable();
+            break;
+        }
+        case DISPLAYOBJECT:
+        {
+            CharacterProxy sp = getCharacterProxy();
+            sp.setReachable();
+            break;
+        }
+        default: break;
+    }
 }
 
 as_object*
 as_value::getObj() const
 {
-       assert(_type == OBJECT);
-       return boost::get<as_object*>(_value);
+    assert(_type == OBJECT);
+    return boost::get<as_object*>(_value);
 }
 
 CharacterProxy
 as_value::getCharacterProxy() const
 {
-       assert(_type == DISPLAYOBJECT);
-       return boost::get<CharacterProxy>(_value);
+    assert(_type == DISPLAYOBJECT);
+    return boost::get<CharacterProxy>(_value);
 }
 
 DisplayObject*
 as_value::getCharacter(bool allowUnloaded) const
 {
-       return getCharacterProxy().get(allowUnloaded);
+    return getCharacterProxy().get(allowUnloaded);
 }
 
 void
 as_value::set_string(const std::string& str)
 {
-       _type = STRING;
-       _value = str;
+    _type = STRING;
+    _value = str;
 }
 
 void
 as_value::set_double(double val)
 {
-       _type = NUMBER;
-       _value = val;
+    _type = NUMBER;
+    _value = val;
 }
 
 void
 as_value::set_bool(bool val)
 {
-       _type = BOOLEAN;
-       _value = val;
+    _type = BOOLEAN;
+    _value = val;
 }
 
 as_value::as_value()
-       :
-       _type(UNDEFINED),
-       _value(boost::blank())
+    :
+    _type(UNDEFINED),
+    _value(boost::blank())
 {
 }
 
 as_value::as_value(const as_value& v)
-       :
-       _type(v._type),
-       _value(v._value)
+    :
+    _type(v._type),
+    _value(v._value)
 {
 }
 
 as_value::as_value(const char* str)
-       :
-       _type(STRING),
-       _value(std::string(str))
+    :
+    _type(STRING),
+    _value(std::string(str))
 {
 }
 
 as_value::as_value(const std::string& str)
-       :
-       _type(STRING),
-       _value(str)
+    :
+    _type(STRING),
+    _value(str)
 {
 }
 
 as_value::as_value(double num)
-       :
-       _type(NUMBER),
-       _value(num)
+    :
+    _type(NUMBER),
+    _value(num)
 {
 }
 
 as_value::as_value(as_object* obj)
-       :
-       _type(UNDEFINED)
+    :
+    _type(UNDEFINED)
 {
-       set_as_object(obj);
+    set_as_object(obj);
 }
 
 bool
@@ -1221,350 +1004,9 @@
     return _type == OBJECT && getObj()->to_function();
 }
 
-// Pass pointer to buffer and pointer to end of buffer. Buffer is raw AMF
-// encoded data. Must start with a type byte unless third parameter is set.
-//
-// On success, sets the given as_value and returns true.
-// On error (premature end of buffer, etc.) returns false and leaves the given
-// as_value untouched.
-//
-// IF you pass a fourth parameter, it WILL NOT READ A TYPE BYTE, but use what
-// you passed instead.
-//
-// The l-value you pass as the first parameter (buffer start) is updated to
-// point just past the last byte parsed
-//
-// TODO restore first parameter on parse errors
-//
-static bool
-amf0_read_value(const boost::uint8_t *&b, const boost::uint8_t *end, 
-        as_value& ret, int inType, std::vector<as_object*>& objRefs, VM& vm)
-{
-       int amf_type;
-
-       if (b > end) {
-               return false;
-       }
-       
-       if (inType != -1) {
-               amf_type = inType;
-       }
-       else {
-               if (b < end) {
-                       amf_type = *b; b += 1;
-               } else {
-                       return false;
-               }
-       }
-
-    Global_as& gl = *vm.getGlobal();
-
-       switch (amf_type)
-    {
-
-               case amf::Element::BOOLEAN_AMF0:
-               {
-                       bool val = *b; b += 1;
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                       log_debug("amf0 read bool: %d", val);
-#endif
-                       ret.set_bool(val);
-                       return true;
-               }
-
-               case amf::Element::NUMBER_AMF0:
-        {
-                       if (b + 8 > end) {
-                               log_error(_("AMF0 read: premature end of input 
reading Number type"));
-                               return false;
-                       }
-                       double dub;
-            // TODO: may we avoid a copy and swapBytes call
-            //       by bitshifting b[0] trough b[7] ?
-            std::copy(b, b+8, (char*)&dub); b+=8; 
-                       amf::swapBytes(&dub, 8);
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                       log_debug("amf0 read double: %e", dub);
-#endif
-                       ret.set_double(dub);
-                       return true;
-        }
-
-               case amf::Element::STRING_AMF0:
-        {
-                       if (b + 2 > end) {
-                               log_error(_("AMF0 read: premature end of input 
reading String "
-                            " type"));
-                               return false;
-                       }
-            boost::uint16_t si = readNetworkShort(b); b += 2;
-                       if (b + si > end) {
-                               log_error(_("AMF0 read: premature end of input 
reading String "
-                            "type"));
-                               return false;
-                       }
-
-                       {
-                               std::string str(reinterpret_cast<const 
char*>(b), si); b += si;
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                               log_debug("amf0 read string: %s", str);
-#endif
-                               ret.set_string(str);
-                               return true;
-
-                       }
-                       break;
-        }
-
-               case amf::Element::LONG_STRING_AMF0:
-        {
-                       if (b + 4 > end) {
-                               log_error(_("AMF0 read: premature end of input "
-                            "reading Long String type"));
-                               return false;
-                       }
-            boost::uint32_t si = readNetworkLong(b); b += 4;
-                       if (b + si > end) {
-                               log_error(_("AMF0 read: premature end of input "
-                            "reading Long String type"));
-                               return false;
-                       }
-
-                       {
-                               std::string str(reinterpret_cast<const 
char*>(b), si); b += si;
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                               log_debug("amf0 read long string: %s", str);
-#endif
-                               ret.set_string(str);
-                               return true;
-
-                       }
-                       break;
-        }
-
-               case amf::Element::STRICT_ARRAY_AMF0:
-        {
-            as_object* array = gl.createArray();
-            objRefs.push_back(array);
-
-            boost::uint32_t li = readNetworkLong(b); b += 4;
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("amf0 starting read of STRICT_ARRAY with %i elements", 
li);
-#endif
-            as_value arrayElement;
-            for (size_t i = 0; i < li; ++i)
-            {
-                if ( ! amf0_read_value(b, end, arrayElement, -1,
-                            objRefs, vm) )
-                {
-                    return false;
-                }
-                callMethod(array, NSV::PROP_PUSH, arrayElement);
-            }
-
-            ret.set_as_object(array);
-            return true;
-        }
-
-               case amf::Element::ECMA_ARRAY_AMF0:
-        {
-            as_object* obj = gl.createArray();
-            objRefs.push_back(obj);
-
-            // set the value immediately, so if there's any problem parsing
-            // (like premature end of buffer) we still get something.
-            ret.set_as_object(obj);
-
-            boost::uint32_t li = readNetworkLong(b); b += 4;
-            
-            log_debug("array size: %d", li);
-            
-            // the count specifies array size, so to have that even if none
-            // of the members are indexed
-            // if short, will be incremented everytime an indexed member is
-            // found
-            obj->set_member(NSV::PROP_LENGTH, li);
-
-            // TODO: do boundary checking (if b >= end...)
-
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("amf0 starting read of ECMA_ARRAY with %i elements", li);
-#endif
-            as_value objectElement;
-            string_table& st = vm.getStringTable();
-            for (;;)
-            {
-                if ( b+2 >= end )
-                {
-                    log_error("MALFORMED SOL: premature end of ECMA_ARRAY "
-                            "block");
-                    break;
-                }
-                boost::uint16_t strlen = readNetworkShort(b); b+=2; 
-
-                // end of ECMA_ARRAY is signalled by an empty string
-                // followed by an OBJECT_END_AMF0 (0x09) byte
-                if (!strlen) {
-                    // expect an object terminator here
-                    if (*b++ != amf::Element::OBJECT_END_AMF0) {
-                        log_error("MALFORMED SOL: empty member name not "
-                                "followed by OBJECT_END_AMF0 byte");
-                    }
-                    break;
-                }
-
-                std::string name(reinterpret_cast<const char*>(b), strlen);
-
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                log_debug("amf0 ECMA_ARRAY prop name is %s", name);
-#endif
-                b += strlen;
-                if (!amf0_read_value(b, end, objectElement, -1, objRefs, vm)) {
-                    return false;
-                }
-                obj->set_member(st.find(name), objectElement);
-            }
-
-            return true;
-        }
-
-               case amf::Element::OBJECT_AMF0:
-        {
-            string_table& st = vm.getStringTable();
-
-            as_object* obj = gl.createObject(); 
-
-            // set the value immediately, so if there's any problem parsing
-            // (like premature end of buffer) we still get something.
-            ret.set_as_object(obj);
-
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("amf0 starting read of OBJECT");
-#endif
-            objRefs.push_back(obj);
-
-            as_value tmp;
-            std::string keyString;
-            for(;;)
-            {
-                if ( ! amf0_read_value(b, end, tmp, 
-                            amf::Element::STRING_AMF0, objRefs, vm) )
-                {
-                    return false;
-                }
-                keyString = tmp.to_string();
-
-                if (keyString.empty()) {
-                    if (b < end) {
-                        b += 1; // AMF0 has a redundant "object end" byte
-                    } else {
-                        log_error("AMF buffer terminated just before "
-                                "object end byte. continuing anyway.");
-                    }
-                    return true;
-                }
-
-                if (!amf0_read_value(b, end, tmp, -1, objRefs, vm)) {
-                    return false;
-                }
-                obj->set_member(st.find(keyString), tmp);
-            }
-        }
-
-               case amf::Element::UNDEFINED_AMF0:
-        {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                               log_debug("readAMF0: undefined value");
-#endif
-                               ret.set_undefined();
-                               return true;
-        }
-
-               case amf::Element::NULL_AMF0:
-        {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                               log_debug("readAMF0: null value");
-#endif
-                               ret.set_null();
-                               return true;
-        }
-
-               case amf::Element::REFERENCE_AMF0:
-        {
-            boost::uint16_t si = readNetworkShort(b); b += 2;
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                               log_debug("readAMF0: reference #%d", si);
-#endif
-                if ( si < 1 || si > objRefs.size() )
-                {
-                    log_error("readAMF0: invalid reference to object %d (%d 
known objects)", si, objRefs.size());
-                    return false;
-                }
-                ret.set_as_object(objRefs[si-1]);
-                return true;
-        }
-
-               case amf::Element::DATE_AMF0:
-        {
-                       if (b + 8 > end) {
-                               log_error(_("AMF0 read: premature end of input 
reading Date "
-                            "type"));
-                               return false;
-                       }
-                       double dub;
-            // TODO: may we avoid a copy and swapBytes call
-            //       by bitshifting b[0] trough b[7] ?
-            std::copy(b, b+8, (char*)&dub); b+=8; 
-                       amf::swapBytes(&dub, 8);
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-                       log_debug("amf0 read date: %e", dub);
-#endif
-
-            as_function* ctor = gl.getMember(NSV::CLASS_DATE).to_function();
-            if (ctor) {
-                fn_call::Args args;
-                args += dub;
-                ret.set_as_object(constructInstance(*ctor, as_environment(vm),
-                            args));
-            }
-
-                       if (b + 2 > end) {
-                               log_error(_("AMF0 read: premature end of input 
reading "
-                            "timezone from Date type"));
-                               return false;
-                       }
-            LOG_ONCE(log_unimpl("Timezone info from AMF0 encoded Date object "
-                        "ignored"));
-            b+=2;
-
-                       return true;
-        }
-
-               // TODO define other types (function, sprite, etc)
-               default:
-        {
-                       log_unimpl("AMF0 to as_value: unsupported type: %i", 
amf_type);
-                       return false;
-        }
-       }
-
-       // this function was called with a zero-length buffer
-       return false;
-}
-
-bool
-as_value::readAMF0(const boost::uint8_t *&b, const boost::uint8_t *const end,
-        int inType, std::vector<as_object*>& objRefs, VM& vm)
-{
-       return amf0_read_value(b, end, *this, inType, objRefs, vm);
-}
-
-bool
-as_value::writeAMF0(SimpleBuffer& buf, 
-        std::map<as_object*, size_t>& offsetTable, VM& vm,
-        bool allowStrict) const
-{
-    typedef std::map<as_object*, size_t> OffsetTable;
+bool
+as_value::writeAMF0(AMF::Writer& w) const
+{
 
     assert (!is_exception());
 
@@ -1575,184 +1017,24 @@
             return false;
 
         case OBJECT:
-        {
             if (is_function()) return false;
-            as_object* obj = getObj();
-            assert(obj);
-            OffsetTable::iterator it = offsetTable.find(obj);
-            if (it == offsetTable.end()) {
-                size_t idx = offsetTable.size() + 1; // 1 for the first, etc...
-                offsetTable[obj] = idx;
-                
-                Date_as* date;
-                if (isNativeType(obj, date))
-                {
-                    double d = date->getTimeValue(); 
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                    log_debug(_("writeAMF0: serializing date object "
-                                "with index %d and value %g"), idx, d);
-#endif
-                    buf.appendByte(amf::Element::DATE_AMF0);
-
-                    // This actually only swaps on little-endian machines
-                    amf::swapBytes(&d, 8);
-                    buf.append(&d, 8);
-
-                    // This should be timezone
-                    boost::uint16_t tz=0; 
-                    buf.appendNetworkShort(tz);
-
-                    return true;
-                }
-
-                if (obj->array()) {
-                    string_table& st = vm.getStringTable();
-                    const size_t len = arrayLength(*obj);
-                    if (allowStrict) {
-                        IsStrictArray s(st);
-                        // Check if any non-hidden properties are non-numeric.
-                        obj->visitProperties<IsEnumerable>(s);
-                        if (s.strict()) {
-
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                            log_debug(_("writeAMF0: serializing array of %d "
-                                        "elements as STRICT_ARRAY (index %d)"),
-                                        len, idx);
-#endif
-                            buf.appendByte(amf::Element::STRICT_ARRAY_AMF0);
-                            buf.appendNetworkLong(len);
-
-                            as_value elem;
-                            for (size_t i = 0; i < len; ++i) {
-                                elem = obj->getMember(arrayKey(st, i));
-                                if (!elem.writeAMF0(buf, offsetTable, vm,
-                                            allowStrict)) {
-                                    log_error("Problems serializing strict 
array "
-                                            "member %d=%s", i, elem);
-                                    return false;
-                                }
-                            }
-                            return true;
-                        }
-                    }
-
-                    // A normal array.
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                    log_debug(_("writeAMF0: serializing array of %d "
-                                "elements as ECMA_ARRAY (index %d) "
-                                "[allowStrict:%d, isStrict:%d]"),
-                                len, idx, allowStrict, isStrict);
-#endif
-                    buf.appendByte(amf::Element::ECMA_ARRAY_AMF0);
-                    buf.appendNetworkLong(len);
-                }
-                else {
-                    // It's a simple object
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                    log_debug(_("writeAMF0: serializing object (or function) "
-                                "with index %d"), idx);
-#endif
-                    buf.appendByte(amf::Element::OBJECT_AMF0);
-                }
-
-                PropsBufSerializer props(buf, vm, offsetTable, allowStrict);
-                obj->visitProperties<IsEnumerable>(props);
-                if (!props.success()) {
-                    log_error("Could not serialize object");
-                    return false;
-                }
-                buf.appendNetworkShort(0);
-                buf.appendByte(amf::Element::OBJECT_END_AMF0);
-                return true;
-            }
-            size_t idx = it->second;
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing object (or function) "
-                        "as reference to %d"), idx);
-#endif
-            buf.appendByte(amf::Element::REFERENCE_AMF0);
-            buf.appendNetworkShort(idx);
-            return true;
-        }
+            return w.writeObject(getObj());
 
         case STRING:
-        {
-            const std::string& str = getStr();
-            size_t strlen = str.size();
-            if ( strlen <= 65535 )
-            {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                log_debug(_("writeAMF0: serializing string '%s'"), str);
-#endif
-                buf.appendByte(amf::Element::STRING_AMF0);
-                buf.appendNetworkShort(strlen);
-                buf.append(str.c_str(), strlen);
-            }
-            else
-            {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-                log_debug(_("writeAMF0: serializing long string '%s'"), str);
-#endif
-                buf.appendByte(amf::Element::LONG_STRING_AMF0);
-                buf.appendNetworkLong(strlen);
-                buf.append(str.c_str(), strlen);
-            }
-            return true;
-        }
+            return w.writeString(getStr());
 
         case NUMBER:
-        {
-            double d = getNum();
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing number '%g'"), d);
-#endif
-            buf.appendByte(amf::Element::NUMBER_AMF0);
-            amf::swapBytes(&d, 8); // this actually only swaps on 
little-endian machines
-            buf.append(&d, 8);
-            return true;
-        }
+            return w.writeNumber(getNum());
 
         case DISPLAYOBJECT:
-        {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing DISPLAYOBJECT (as 
undefined)"));
-#endif
-            // See misc-ming.all/SharedObjectTest.as
-            buf.appendByte(amf::Element::UNDEFINED_AMF0);
-            return true;
-        }
+        case UNDEFINED:
+            return w.writeUndefined();
 
         case NULLTYPE:
-        {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing null"));
-#endif
-            buf.appendByte(amf::Element::NULL_AMF0);
-            return true;
-        }
-
-        case UNDEFINED:
-        {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing undefined"));
-#endif
-            buf.appendByte(amf::Element::UNDEFINED_AMF0);
-            return true;
-        }
+            return w.writeNull();
 
         case BOOLEAN:
-        {
-            bool tf = getBool();
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
-            log_debug(_("writeAMF0: serializing boolean '%s'"), tf);
-#endif
-
-            buf.appendByte(amf::Element::BOOLEAN_AMF0);
-            if (tf) buf.appendByte(1);
-            else buf.appendByte(0);
-
-            return true;
-        }
+            return w.writeBoolean(getBool());
     }
 }
 
@@ -1760,9 +1042,9 @@
 boost::int32_t
 toInt(const as_value& val) 
 {
-       const double d = val.to_number();
+    const double d = val.to_number();
 
-       if (!isFinite(d)) return 0;
+    if (!isFinite(d)) return 0;
 
     return truncateToInt(d);
 }
@@ -1842,36 +1124,36 @@
     // 1.23456789012346e-6
     // 1.23456789012346e-7
 
-       // Handle non-numeric values.
-       if (isNaN(val)) return "NaN";
-       
+    // Handle non-numeric values.
+    if (isNaN(val)) return "NaN";
+    
     if (isInf(val)) return val < 0 ? "-Infinity" : "Infinity";
 
     if (val == 0.0 || val == -0.0) return "0"; 
 
     std::ostringstream ostr;
 
-       if (radix == 10) {
+    if (radix == 10) {
 
-               // ActionScript always expects dot as decimal point.
-               ostr.imbue(std::locale::classic()); 
-               
-               // force to decimal notation for this range (because the
+        // ActionScript always expects dot as decimal point.
+        ostr.imbue(std::locale::classic()); 
+        
+        // force to decimal notation for this range (because the
         // reference player does)
-               if (std::abs(val) < 0.0001 && std::abs(val) >= 0.00001) {
+        if (std::abs(val) < 0.0001 && std::abs(val) >= 0.00001) {
 
-                       // All nineteen digits (4 zeros + up to 15 significant 
digits)
-                       ostr << std::fixed << std::setprecision(19) << val;
-                       
+            // All nineteen digits (4 zeros + up to 15 significant digits)
+            ostr << std::fixed << std::setprecision(19) << val;
+            
             std::string str = ostr.str();
-                       
-                       // Because 'fixed' also adds trailing zeros, remove 
them.
-                       std::string::size_type pos = str.find_last_not_of('0');
-                       if (pos != std::string::npos) {
-                               str.erase(pos + 1);
-                       }
+            
+            // Because 'fixed' also adds trailing zeros, remove them.
+            std::string::size_type pos = str.find_last_not_of('0');
+            if (pos != std::string::npos) {
+                str.erase(pos + 1);
+            }
             return str;
-               }
+        }
 
         ostr << std::setprecision(15) << val;
         
@@ -1885,30 +1167,30 @@
         }
 
         return str;
-       }
+    }
 
     // Radix isn't 10
-       bool negative = (val < 0);
-       if (negative) val = -val;
+    bool negative = (val < 0);
+    if (negative) val = -val;
 
-       double left = std::floor(val);
-       if (left < 1) return "0";
+    double left = std::floor(val);
+    if (left < 1) return "0";
 
     std::string str;
     const std::string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
 
     // Construct the string backwards for speed, then reverse.
     while (left) {
-               double n = left;
-               left = std::floor(left / radix);
-               n -= (left * radix);
-               str.push_back(digits[static_cast<int>(n)]);
-       }
-       if (negative) str.push_back('-'); 
+        double n = left;
+        left = std::floor(left / radix);
+        n -= (left * radix);
+        str.push_back(digits[static_cast<int>(n)]);
+    }
+    if (negative) str.push_back('-'); 
 
     std::reverse(str.begin(), str.end());
 
-       return str;
+    return str;
 }
 
 /// Force type to number.
@@ -1943,213 +1225,6 @@
     return v;
 }
 
-#if 0
-
-/// Instantiate this value from an AMF element 
-as_value::as_value(const amf::Element& el)
-       :
-       _type(UNDEFINED)
-{
-    
-    VM& vm = VM::get();
-    string_table& st = vm.getStringTable();
-    Global_as& gl = *vm.getGlobal();
-
-    switch (el.getType()) {
-      case amf::Element::NOTYPE:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-         log_debug("as_value(Element&) : AMF type NO TYPE!");
-#endif
-         break;
-      }
-      case amf::Element::NULL_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type NULL");
-#endif
-            set_null();
-            break;
-      }
-      case amf::Element::UNDEFINED_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type UNDEFINED");
-#endif
-            set_undefined();
-            break;
-      }
-      case amf::Element::MOVIECLIP_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type DISPLAYOBJECT");
-#endif
-            log_unimpl("DISPLAYOBJECT AMF0 type");
-            set_undefined();
-            //_type = DISPLAYOBJECT;
-            //_value = el.getData();
-
-            break;
-      }
-      case amf::Element::NUMBER_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type NUMBER");
-#endif
-            double num = el.to_number();
-            set_double(num);
-            break;
-      }
-      case amf::Element::BOOLEAN_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type BOOLEAN");
-#endif
-            bool flag = el.to_bool();
-            set_bool(flag);
-            break;
-      }
-
-      case amf::Element::STRING_AMF0:
-      case amf::Element::LONG_STRING_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-            log_debug("as_value(Element&) : AMF type STRING");
-#endif
-           std::string str;
-           // If there is data, convert it to a string for the as_value
-           if (el.getDataSize() != 0) {
-               str = el.to_string();
-               // Element's store the property name as the name, not as data.
-           } else if (el.getNameSize() != 0) {
-               str = el.getName();
-           }
-           
-           set_string(str);
-            break;
-      }
-
-      case amf::Element::OBJECT_AMF0:
-      {
-
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-          log_debug("as_value(Element&) : AMF type OBJECT");
-#endif
-          as_object* obj = gl.createObject();
-          if (el.propertySize()) {
-              for (size_t i=0; i < el.propertySize(); i++) {
-                 const boost::shared_ptr<amf::Element> prop = 
el.getProperty(i);
-                 if (prop == 0) {
-                     break;
-                 } else {
-                     if (prop->getNameSize() == 0) {
-                         log_debug("%s:(%d) Property has no name!", 
__PRETTY_FUNCTION__, __LINE__);
-                     } else {
-                         obj->set_member(st.find(prop->getName()), 
as_value(*prop));
-                     }
-                 }
-              }
-          }
-         set_as_object(obj);
-          break;
-      }
-
-      case amf::Element::ECMA_ARRAY_AMF0:
-      {
-          // TODO: fixme: ECMA_ARRAY has an additional fiedl, dunno
-          //              if accessible trought Element class
-          //              (the theoretic number of elements in it)
-
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-          log_debug("as_value(Element&) : AMF type ECMA_ARRAY");
-#endif
-
-          as_object* obj = gl.createArray();
-
-          if (el.propertySize()) {
-              for (size_t i=0; i < el.propertySize(); i++) {
-                 const boost::shared_ptr<amf::Element> prop = 
el.getProperty(i);
-                 if (prop == 0) {
-                     break;
-                 } else {
-                     obj->set_member(st.find(prop->getName()), 
as_value(*prop));
-                 }
-              }
-          }
-          set_as_object(obj);
-          break;
-      }
-    
-
-      case amf::Element::STRICT_ARRAY_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-          log_debug("as_value(Element&) : AMF type STRICT_ARRAY");
-#endif
-          as_object* obj = gl.createArray();
-          size_t len = el.propertySize();
-          obj->set_member(NSV::PROP_LENGTH, len);
-
-          for (size_t i=0; i < el.propertySize(); i++) {
-              const boost::shared_ptr<amf::Element> prop = el.getProperty(i);
-              if (prop == 0) {
-                  break;
-              } else {
-                 if (prop->getNameSize() == 0) {
-                     log_debug("%s:(%d) Property has no name!", 
__PRETTY_FUNCTION__, __LINE__);
-                 } else {
-                     obj->set_member(st.find(prop->getName()), 
as_value(*prop));
-                 }
-              }
-          }
-          
-          set_as_object(obj);
-          break;
-      }
-
-      case amf::Element::REFERENCE_AMF0:
-      {
-        log_unimpl("REFERENCE Element to as_value");
-        break;
-      }
-
-      case amf::Element::DATE_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-         log_debug("as_value(Element&) : AMF type DATE");
-#endif
-         double num = el.to_number();
-         set_double(num);
-         break;
-      }
-      //if (swfVersion > 5) _type = STRING;
-      
-      case amf::Element::UNSUPPORTED_AMF0:
-      {
-#ifdef GNASH_DEBUG_AMF_DESERIALIZE
-         log_debug("as_value(Element&) : AMF type UNSUPPORTED");
-#endif
-         break;
-      }
-      case amf::Element::RECORD_SET_AMF0:
-          log_unimpl("Record Set data type is not supported yet");
-          break;
-      case amf::Element::XML_OBJECT_AMF0:
-          log_unimpl("XML data type is not supported yet");
-          break;
-      case amf::Element::TYPED_OBJECT_AMF0:
-          log_unimpl("Typed Object data type is not supported yet");
-          break;
-      case amf::Element::AMF3_DATA:
-          log_unimpl("AMF3 data type is not supported yet");
-          break;
-      default:
-          log_unimpl("Element to as_value - unsupported Element type %d", 
-                  el.getType());
-          break;
-    }
-}
-#endif
 } // namespace gnash
 
 

=== modified file 'libcore/as_value.h'
--- a/libcore/as_value.h        2010-01-25 18:52:20 +0000
+++ b/libcore/as_value.h        2010-02-10 09:47:04 +0000
@@ -46,10 +46,9 @@
        class as_function;
        class MovieClip;
        class DisplayObject;
-    class SimpleBuffer;
-}
-namespace amf {
-       class Element;
+    namespace AMF {
+        class Writer;
+    }
 }
 
 namespace gnash {
@@ -160,11 +159,6 @@
        /// Copy constructor.
        as_value(const as_value& value);
 
-#if 0
-       /// Construct a value from an AMF element
-       as_value(const amf::Element& el);
-#endif
-
        /// Return the primitive type of this value as a string.
        const char* typeOf() const;
 
@@ -266,9 +260,6 @@
     /// is not a function.
        as_function* to_function() const;
 
-       /// Get an AMF element representation for this value
-    boost::shared_ptr<amf::Element> to_element() const;
-
     // Used for operator<< to give useful information about an
     // as_value object.
        DSOEXPORT std::string toDebugString() const;
@@ -366,49 +357,6 @@
        /// Object values are values stored by pointer (objects and functions)
        void setReachable() const;
 
-       /// Read AMF0 data from the given buffer
-       //
-       /// Pass pointer to buffer and pointer to end of buffer. Buffer is raw 
AMF
-       /// encoded data. Must start with a type byte unless third parameter is 
set.
-       ///
-       /// On success, sets the given as_value and returns true.
-       /// On error (premature end of buffer, etc.) returns false and
-    /// leaves the given as_value untouched.
-       ///
-       /// IF you pass a fourth parameter, it WILL NOT READ A TYPE BYTE, but
-    /// use what you passed instead.
-       ///
-       /// The l-value you pass as the first parameter (buffer start) is 
updated to
-       /// point just past the last byte parsed
-       ///
-       /// TODO restore first parameter on parse errors
-       ///
-       /// @param b
-    ///     Pointer to buffer where to start reading.
-    ///     Will be moved as data is read.
-    ///
-       /// @param end
-    ///     Pointer to end of buffer. Reading from this would
-    ///     be invalid.
-    ///
-       /// @param inType
-    ///     Type of the AMF object to read. If -1, type will be
-    ///     read from a type byte.
-    ///
-       /// @param objRefs
-       ///     A vector of already-parsed objects to properly interpret 
references.
-       ///     Pass an empty vector on first call as it will be used 
internally.
-       ///     On return, the vector will be filled with pointers to every
-    ///     complex object parsed from the stream.
-    ///
-       /// @param vm
-    ///     Virtual machine to use for initialization of the values
-    ///     (string_table)
-       ///
-       DSOEXPORT bool readAMF0(const boost::uint8_t*& b,
-            const boost::uint8_t* const end, int inType,
-            std::vector<as_object*>& objRefs, VM& vm);
-
     /// Serialize value in AMF0 format.
     //
     /// @param buf
@@ -425,8 +373,7 @@
        /// @param allowStrictArray
     ///     If true strict arrays will be encoded a STRICT_ARRAY types.
     ///
-    bool writeAMF0(SimpleBuffer& buf, std::map<as_object*, size_t>& 
offsetTable,
-                   VM& vm, bool allowStrictArray) const;
+    bool writeAMF0(AMF::Writer& w) const;
 
 private:
 

=== modified file 'libcore/asobj/Makefile.am'
--- a/libcore/asobj/Makefile.am 2010-02-08 00:05:16 +0000
+++ b/libcore/asobj/Makefile.am 2010-02-08 20:38:34 +0000
@@ -35,6 +35,7 @@
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/libnet \
+       -I$(top_srcdir)/libamf \
        -I$(top_srcdir)/backend \
        -I$(top_srcdir)/libcore \
        -I$(top_srcdir)/libcore/swf \

=== modified file 'libcore/asobj/flash/net/LocalConnection_as.cpp'
--- a/libcore/asobj/flash/net/LocalConnection_as.cpp    2010-02-02 11:45:01 
+0000
+++ b/libcore/asobj/flash/net/LocalConnection_as.cpp    2010-02-11 08:49:34 
+0000
@@ -1,5 +1,4 @@
 // LocalConnection.cpp:  Connect two SWF movies & send objects, for Gnash.
-// LocalConnection.cpp:  Connect two SWF movies & send objects, for Gnash.
 // 
 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
 //   Foundation, Inc
@@ -17,8 +16,6 @@
 // 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
-//
-
 
 #include "GnashSystemIOHeaders.h"
 
@@ -27,58 +24,101 @@
 #include "URLAccessManager.h"
 #include "URL.h"
 #include "log.h"
-#include "net/LocalConnection_as.h"
-#include "network.h"
+#include "LocalConnection_as.h"
 #include "fn_call.h"
 #include "Global_as.h"
 #include "builtin_function.h"
 #include "NativeFunction.h"
-#include "amf.h"
-#include "lcshm.h"
+#include "SharedMem.h"
 #include "namedStrings.h"
 #include "StringPredicates.h"
+#include "as_value.h"
+#include "AMF.h"
+#include "ClockTime.h"
+#include "GnashAlgorithm.h"
 
+#include <boost/shared_ptr.hpp>
 #include <cerrno>
 #include <cstring>
 #include <boost/cstdint.hpp> // for boost::?int??_t
 #include <boost/assign/list_of.hpp>
 #include <boost/bind.hpp>
-using namespace amf;
-
-// http://www.osflash.org/localconnection
-//
-// Listening
-// To create a listening LocalConnection, you just have to set a thread to:
-//
-//    1.register the application as a valid LocalConnection listener,
-//    2.require the mutex to have exclusive access to the shared memory,
-//    3.access the shared memory and check the recipient,
-//    4.if you are the recipient, read the message and mark it read,
-//    5.release the shared memory and the mutex,
-//    6.repeat indefinitely from step 2.
-//
-// Sending
-// To send a message to a LocalConnection apparently works like that:
-//    1. require the mutex to have exclusive access to the shared memory,
-//    2. access the shared memory and check that the listener is connected,
-//    3. if the recipient is registered, write the message,
-//    4. release the shared memory and the mutex.
-//
-// The main thing you have to care about is the timestamp - simply call 
GetTickCount()
-//  and the message size. If your message is correctly encoded, it should be 
received
-// by the listening LocalConnection 
-//
-// Some facts:
-//     * The header is 16 bytes,
-//     * The message can be up to 40k,
-//     * The listeners block starts at 40k+16 = 40976 bytes,
-//     * To add a listener, simply append its name in the listeners list (null 
terminated strings)
-//
+
+/// From observing the behaviour of the pp, the following seem to be true.
+//
+/// (Behaviour may be different on other platforms).
+//
+/// Sending
+///
+/// A sender checks the timestamp value. If it is zero, the data may be
+/// overwritten. If it is not, we check whether we can delete it.
+///
+/// Data expires after 4 seconds. Processes only delete data they (think they)
+/// wrote. If the timestamp matches the timestamp of the last data we sent,
+/// we assume it's our data. If it's expired, mark it for overwriting and
+/// continue.
+///
+/// We continue to check whether the data has expired as long as the data
+/// is not marked for overwriting. No changes are made to the buffer by a
+/// sender as long as the timestamp is there.
+///
+/// Once the buffer is ready for writing, check if the correct listener is
+/// present. If it is, send the first message in our queue and store its
+/// timestamp. If the listener is not present, go through the queue until
+/// a message for an existing listener is found. If none is found, the
+/// last message in the buffer is sent with no timestamp. (It's not clear if
+/// there's any point in sending it, but it happens).
+//
+/// Receiving
+///
+/// A listener registers itself by adding its name to the listeners section
+/// of the shared memory. The name is null-terminated and followed by a
+/// further marker, which is of the form "::x\0::y\0". The x and y characters
+/// are always numbers, e.g. ::3::4, ::3::1, ::3::2. We do not know the
+/// significance of these numbers.
+//
+/// A listener merely checks whether the data has a timestamp and if the
+/// data is intended for it (by reading the first string field). If it is,
+/// the data is deserialized, the encoded function called, and the data
+/// marked for deletion.
+//
+/// Functions are encoded in a particular order after the timestamp and length
+/// fields:
+///     1. connection name (domain:connection) [string]
+///     2. domain [string]
+/// {
+///     3. The following optional data:
+///         [boolean] (always false?)
+///         [boolean] (always false?)
+///         [number] (e.g. 0, 1)
+///         [number] (e.g. 8, 6)
+///     4. Sometimes the filename [string]. The presence of this may depend
+///        on the first number.
+/// }
+///     5. The name of the function to call.
+///     6. The arguments in reverse(!) order.   
+//
+/// Notes
+/// 1. We don't know what happens when data from another process is left in
+///    the buffer with a timestamp. Does it ever get overwritten?
+/// 2. The timestamp seems to be allocated when LocalConnection.send is called,
+///    even though the message may be sent much later.
+/// 3. We can probably stop checking the data if (a) we have nothing more to
+///    send, (b) we are not connected, and (c) the last data was not written
+///    by us. Gnash doesn't do the additional check for (c), so will never
+///    remove the advance callback if data with a timestamp from another
+///    process stays in the buffer. Note 1 also relates to this.
+//
+/// http://www.osflash.org/localconnection
+///
+/// Some facts:
+///     * The header is 16 bytes,
+///     * The message can be up to 40k,
+///     * The listeners block starts at 40k+16 = 40976 bytes,
+
 namespace {
-
-gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();    
-
-} // anonymous namespace
+    gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();    
+} 
 
 namespace gnash {
 
@@ -90,34 +130,109 @@
     as_value localconnection_close(const fn_call& fn);
 
     bool validFunctionName(const std::string& func);
-
     void attachLocalConnectionInterface(as_object& o);
-    as_object* getLocalConnectionInterface();
-}
-  
-// \class LocalConnection_as
-/// \brief Open a connection between two SWF movies so they can send
+
+    void removeListener(const std::string& name, SharedMem& mem);
+    bool addListener(const std::string& name, SharedMem& mem);
+    bool findListener(const std::string& name, SharedMem& mem);
+    void getMarker(SharedMem::iterator& i, SharedMem::iterator end);
+    void markRead(SharedMem& m);
+
+    /// Read the AMF data and invoke the function.
+    void executeAMFFunction(as_object& owner, AMF::Reader& rd);
+
+    struct ConnectionData
+    {
+        std::string name;
+        boost::uint32_t ts;
+        SimpleBuffer data; 
+    };
+}
+
+
+void
+writeLong(boost::uint8_t*& ptr, boost::uint32_t i)
+{
+    *ptr = i & 0xff;
+    ++ptr;
+    *ptr = (i & 0xff00) >> 8;
+    ++ptr;
+    *ptr = (i & 0xff0000) >> 16;
+    ++ptr;
+    *ptr = (i & 0xff000000) >> 24;
+    ++ptr;
+}
+
+inline boost::uint32_t
+readLong(const boost::uint8_t* buf) {
+       boost::uint32_t s = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+       return s;
+}
+
+
+/// A null byte after the marker or at the beginning of the listeners
+/// signifies the end of the list.
+template<typename T, size_t N>
+std::string
+fromByteString(T(&buf)[N])
+{
+       return std::string(buf, buf + N - 1);
+}
+    
+static const std::string marker(fromByteString("\0::3\0::4\0"));
+
+
+
+/// Open a connection between two SWF movies so they can send
 /// each other Flash Objects to be executed.
-///
-/// TODO: don't use multiple inheritance.
-class LocalConnection_as : public ActiveRelay, public amf::LcShm
+class LocalConnection_as : public ActiveRelay
 {
 
 public:
 
+    /// The size of the shared memory segment.
+    static const size_t defaultSize = 64528;
+    
+    /// Offset of listeners in the shared memory segment.
+    static const size_t listenersOffset = 40976;
+
+    /// Create a LocalConnection_as object.
     LocalConnection_as(as_object* owner);
-    virtual ~LocalConnection_as() {}
+    
+    virtual ~LocalConnection_as() {
+        close();
+    }
 
+    /// Remove ourself as a listener (if connected).
     void close();
 
     const std::string& domain() {
         return _domain;
     }
 
-    const std::string& name() { return _name; };
-
-    // TODO: implement this to check for changes.
-    virtual void update() {}
+    /// Called on advance().
+    //
+    /// Handles sending and receiving.
+    virtual void update();
+
+    bool connected() const {
+        return _connected;
+    }
+
+    void connect(const std::string& name);
+
+    void send(boost::shared_ptr<ConnectionData> d)
+    {
+        assert(d.get());
+        VM& vm = getVM(owner());
+        const boost::uint32_t time = vm.getTime();
+        d->ts = time;
+        _queue.push_back(d);
+        
+        // Register callback so we can send the data on the next advance.
+        movie_root& mr = getRoot(owner());
+        mr.addAdvanceCallback(this);
+    }
 
 private:
     
@@ -132,62 +247,242 @@
     // The immutable domain of this LocalConnection_as, based on the 
     // originating SWF's domain.
     const std::string _domain;
-    
+
+    bool _connected;
+
+    SharedMem _shm;
+
+    std::deque<boost::shared_ptr<ConnectionData> > _queue;
+
+    // The timestamp of our last write to the shared memory.
+    boost::uint32_t _lastTime;
+
 };
 
+const size_t LocalConnection_as::listenersOffset;
+const size_t LocalConnection_as::defaultSize;
+
 LocalConnection_as::LocalConnection_as(as_object* owner)
     :
     ActiveRelay(owner),
-    _domain(getDomain())
-{
-    log_debug("The domain for this host is: %s", _domain);
-    setconnected(false);
-}
-
-/// \brief Closes (disconnects) the LocalConnection object.
+    _domain(getDomain()),
+    _connected(false),
+    _shm(defaultSize),
+    _lastTime(0)
+{
+}
+
+void
+LocalConnection_as::update()
+{
+    // Check whether local connection is disabled(!): brilliant choice of
+    // function name.
+    if (rcfile.getLocalConnection()) {
+        log_security("Attempting to write to disabled LocalConnection!");
+        movie_root& mr = getRoot(owner());
+        mr.removeAdvanceCallback(this);
+        return;
+    }
+
+    // No-op if already attached. Nothing to do if it fails, but we
+    // should probably stop trying.
+    if (!_shm.attach()) {
+        log_error("Failed to attach shared memory segment");
+        return;
+    }
+
+    // We need the lock to prevent simultaneous reads/writes from other
+    // processes.
+    SharedMem::Lock lock(_shm);
+    if (!lock.locked()) {
+        log_debug("Failed to get shm lock");
+        return;
+    }
+
+    SharedMem::iterator ptr = _shm.begin();
+    
+    // First check timestamp data.
+
+    // These are not network byte order by default, but not sure about 
+    // host byte order.
+    const boost::uint32_t timestamp = readLong(ptr + 8);
+    const boost::uint32_t size = readLong(ptr + 12);
+
+    // As long as there is a timestamp in the shared memory, we mustn't
+    // write anything.
+    //
+    // We check if this is data we are listening for. If it is, read it and
+    // mark for overwriting.
+    //
+    // If not, we keep checking until the data has been overwritten by
+    // another listener or until it's expired. If it's expired, we
+    // mark for overwriting.
+    if (timestamp) {
+
+        // Start after 16-byte header.
+        const boost::uint8_t* b = ptr + 16;
+
+        // End at reported size of AMF sequence.
+        const boost::uint8_t* end = b + size;
+
+        AMF::Reader rd(b, end, getGlobal(owner()));
+        as_value a;
+
+        // Get the connection name. That's all we need to remove expired
+        // data.
+        if (!rd(a)) {
+            log_error("Invalid connection name data");
+            return;
+        }
+        const std::string& connection = a.to_string();
+
+        // Now check if data we wrote has expired. There's no really
+        // reliable way of checking that we genuinely wrote it.
+        if (_lastTime == timestamp) {
+            
+            const size_t timeout = 4 * 1000;
+
+            VM& vm = getVM(owner());
+            const boost::uint32_t timeNow = vm.getTime();
+
+            if (timeNow - timestamp > timeout) {
+                log_debug("Data %s expired at %s. Removing its target "
+                        "as a listener", timestamp, timeNow);
+                removeListener(connection, _shm);
+                markRead(_shm);
+                _lastTime = 0;
+            }
+        }
+
+        // If we are listening and the data is for us, get the rest of it
+        // and call the method.
+        if (_connected && connection == _domain + ":" + _name) {
+            executeAMFFunction(owner(), rd);
+            // Zero the timestamp bytes to signal that the shared memory
+            // can be written again.
+            markRead(_shm);
+        }
+        else {
+            // The data has not expired and we didn't read it. Leave it
+            // alone until it's expired or someone else has read it.
+            return;
+        }
+    }
+
+    // If we have no data to send, there's nothing more to do.
+    if (_queue.empty()) {
+        // ...except remove the callback if we aren't listening for anything.
+        if (!_connected) {
+            movie_root& mr = getRoot(owner());
+            mr.removeAdvanceCallback(this);
+        }
+        return;
+    }
+
+    // Get the first buffer.
+    boost::shared_ptr<ConnectionData> cd = _queue.front();
+    _queue.pop_front();
+
+    // If the correct listener isn't there, iterate until we find one or
+    // there aren't any left.
+    while (!findListener(_domain + ":" + cd->name, _shm)) {
+        if (_queue.empty()) {
+            // Make sure we send the empty header later.
+            cd->ts = 0;
+            break;
+        }
+        cd = _queue.front();
+        _queue.pop_front();
+    }
+
+    // Yes, there is data to send.
+    const char i[] = { 1, 0, 0, 0, 1, 0, 0, 0 };
+    std::copy(i, i + arraySize(i), ptr);
+
+    SimpleBuffer& buf = cd->data;
+
+    SharedMem::iterator tmp = ptr + 8;
+    writeLong(tmp, cd->ts);
+    writeLong(tmp, cd->ts ? buf.size() : 0);
+    std::copy(buf.data(), buf.data() + buf.size(), tmp);
+
+    // Note the timestamp of our last send. We will keep calling update()
+    // until the data has expired or been read.
+    _lastTime = cd->ts;
+
+}
+
+/// Closes the LocalConnection object.
+//
+/// This removes the advanceCallback (so we can be removed by the GC) and
+/// removes this object as a listener from the shared memory listeners
+/// section.
 void
 LocalConnection_as::close()
 {
-    setconnected(false);
-#ifndef NETWORK_CONN
-    closeMem();
-#endif
+    // We may be waiting either to send or to receive, so in both cases
+    // make sure update() isn't called again.
+    movie_root& mr = getRoot(owner());
+    mr.removeAdvanceCallback(this);
+    
+    if (!_connected) return;
+    _connected = false;
+    
+    SharedMem::Lock lock(_shm);
+    if (!lock.locked()) {
+        log_error("Failed to get lock on shared memory! Will not remove "
+                "listener");
+        return;
+    }
+
+    removeListener(_domain + ":" + _name, _shm);
+    
 }
 
-/// \brief Prepares the LocalConnection object to receive commands from a
-/// LocalConnection.send() command.
+/// Makes the LocalConnection object listen.
 /// 
-/// The name is a symbolic name like "lc_name", that is used by the
+/// The name is a symbolic name like "lc1", that is used by the
 /// send() command to signify which local connection to send the
 /// object to.
-/*void
+//
+/// When connect is called, this object adds its domain + name plus some
+/// other bits of information to the listeners portion of the shared memory.
+/// It also sets the initial bytes of the shared memory to a set
+/// pattern.
+//
+/// The connection will fail if a listener with the same id (domain + name)
+/// already exists. ActionScript isn't informed of this failure.
+void
 LocalConnection_as::connect(const std::string& name)
 {
-
     assert(!name.empty());
 
     _name = name;
     
-    // TODO: does this depend on success?
+    if (!_shm.attach()) {
+        log_error("Failed to open shared memory segment");
+        return;
+    }
+
+    SharedMem::iterator ptr = _shm.begin();
+
+    // We can't connect if there is already a listener with the same name.
+    if (!addListener(_domain + ":" + _name, _shm)) {
+        return;
+    }
+        
+    const char i[] = { 1, 0, 0, 0, 1, 0, 0, 0 };
+    std::copy(i, i + 8, ptr);
+
+    movie_root& mr = getRoot(owner());
+    mr.addAdvanceCallback(this);
+
     _connected = true;
     
-    log_debug("trying to open shared memory segment: \"%s\"", _name);
-    
-    if (Shm::attach(_name.c_str(), true) == false) {
-        return;
-    }
-
-    if (Shm::getAddr() <= 0) {
-        log_error("Failed to open shared memory segment: \"%s\"", _name);
-        return; 
-    }
-    
     return;
 }
-*/
 
-/// \brief Returns a string representing the superdomain of the
-/// location of the current SWF file.
+/// String representing the domain of the current SWF file.
 //
 /// This is set on construction, as it should be constant.
 /// The domain is either the "localhost", or the hostname from the
@@ -283,7 +578,7 @@
     LocalConnection_as* relay = ensure<ThisIsNative<LocalConnection_as> >(fn);
 
     // If already connected, don't try again until close() is called.
-    if (relay->getconnected()) return false;
+    if (relay->connected()) return false;
 
     if (!fn.nargs) {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -305,11 +600,9 @@
         return as_value(false);
     }
 
-    std::string connection_name = relay->domain();    
-    connection_name +=":";
-    connection_name += fn.arg(0).to_string();
+    std::string connection = fn.arg(0).to_string();
    
-    relay->connect(connection_name);
+    relay->connect(connection);
 
     // We don't care whether connected or not.
     return as_value(true);
@@ -326,12 +619,18 @@
 /// LocalConnection.send()
 //
 /// Returns false only if the call was syntactically incorrect.
+///
+/// The pp only ever seems have one send sequence (at least in the first 512
+/// bytes). Subsequent sends overwrite any sequence in shared memory.
+//
+/// The pp sometimes sends calls with no timestamp and no length. These
+/// appear to be ignored, so it's not clear what the point is.
 as_value
 localconnection_send(const fn_call& fn)
 {
     LocalConnection_as* relay = ensure<ThisIsNative<LocalConnection_as> >(fn);
+
     // At least 2 args (connection name, function) required.
-
     if (fn.nargs < 2) {
         IF_VERBOSE_ASCODING_ERRORS(
             std::ostringstream os;
@@ -353,7 +652,8 @@
         );
         return as_value(false);
     }
-
+    
+    const std::string& name = fn.arg(0).to_string();
     const std::string& func = fn.arg(1).to_string();
 
     if (!validFunctionName(func)) {
@@ -365,35 +665,28 @@
         );
         return as_value(false);
     }
-
-    
-    const std::string& connectionName = fn.arg(0).to_string();
-    const std::string& methodName = fn.arg(1).to_string();
-        
-    std::vector<amf::Element*> argument_to_send;
-    
-    const size_t numargs = fn.nargs;
-    for (size_t i = 2; i != numargs; ++i) {
-        amf::Element* temp_ptr = fn.arg(i).to_element().get();
-        argument_to_send.push_back(temp_ptr);
+    
+    boost::shared_ptr<ConnectionData> cd(new ConnectionData());
+
+    SimpleBuffer& buf = cd->data;
+
+    // Don't know whether strict arrays are allowed
+    AMF::Writer w(buf, false);
+    const std::string& domain = relay->domain();
+    
+    w.writeString(domain + ":" + name);
+    w.writeString(domain);
+    w.writeString(func);
+
+    for (size_t i = fn.nargs - 1; i > 1; --i) {
+        fn.arg(i).writeAMF0(w);
     }
-    
-    relay->amf::LcShm::send(connectionName, methodName, argument_to_send);
 
     // Now we have a valid call.
 
-    // It is useful to see what's supposed being sent, so we log
-    // this every time until implemented.
-    std::ostringstream os;
-    fn.dump_args(os);
-    log_unimpl(_("LocalConnection.send unimplemented %s"), os.str());
+    cd->name = name;
 
-    // We'll return true if the LocalConnection is disabled too, as
-    // the return value doesn't indicate success of the connection.
-    if (rcfile.getLocalConnection() ) {
-        log_security("Attempting to write to disabled LocalConnection!");
-        return as_value(true);
-    }
+    relay->send(cd);
 
     return as_value(true);
 }
@@ -433,8 +726,239 @@
     return (it == reserved.end());
 }
 
+// When a listener is removed, subsequent listeners are copied to the
+// beginning. The byte after the marker is overwritten. If no listeners
+// are left, the first byte becomes 0.
+void
+removeListener(const std::string& name, SharedMem& mem)
+{
+    assert(attached(mem));
+
+    SharedMem::iterator ptr = mem.begin() + 
LocalConnection_as::listenersOffset;
+
+    // No listeners if the first byte is 0.
+    if (!*ptr) return;
+
+    SharedMem::iterator found = 0;
+
+    SharedMem::iterator next;
+    
+    // Next should always point to the beginning of a listener.
+    while ((next = std::find(ptr, mem.end(), '\0')) != mem.end()) {
+
+        // Move next to where it should be (beginning of next string).
+        getMarker(next, mem.end());
+
+        // Check whether we've found the string (should only be once).
+        if (std::equal(name.c_str(), name.c_str() + name.size(), ptr)) {
+            found = ptr;
+        }
+
+        // Found last listener (or reached the end).
+        if (next == mem.end() || !*next) {
+
+            if (!found) return;
+
+            // Name and marker.
+            const ptrdiff_t size = name.size() + marker.size();
+
+            // Copy listeners backwards to fill in the gaps.
+            std::copy(found + size, next, found);
+
+            return;
+        }
+
+        ptr = next;
+    }
+    
+
+}
+
+/// Two listeners with the same name are never added.
+bool
+findListener(const std::string& name, SharedMem& mem)
+{
+    assert(attached(mem));
+
+    SharedMem::iterator ptr = mem.begin() + 
LocalConnection_as::listenersOffset;
+
+    SharedMem::iterator next;
+
+    // No listeners at all.
+    if (!*ptr) return false;
+
+    while ((next = std::find(ptr, mem.end(), '\0')) != mem.end()) {
+
+        if (std::equal(name.c_str(), name.c_str() + name.size(), ptr)) {
+            return true;
+        }
+
+        getMarker(next, mem.end());
+
+        // Found last listener.
+        if (!*next) return false;
+        ptr = next;
+    }
+    return false;
+}
+
+/// Two listeners with the same name are never added.
+bool
+addListener(const std::string& name, SharedMem& mem)
+{
+    assert(attached(mem));
+
+    SharedMem::iterator ptr = mem.begin() + 
LocalConnection_as::listenersOffset;
+
+    SharedMem::iterator next;
+
+    if (!*ptr) {
+        // There are no listeners.
+        next = ptr;
+    }
+    else {
+        while ((next = std::find(ptr, mem.end(), '\0')) != mem.end()) {
+
+            getMarker(next, mem.end());
+            
+            if (std::equal(name.c_str(), name.c_str() + name.size(), ptr)) {
+                log_debug("Not adding duplicated listener");
+                return false;
+            }
+
+            // Found last listener.
+            if (!*next) break;
+            ptr = next;
+        }
+        if (next == mem.end()) {
+            log_error("No space for listener in shared memory!");
+            return false;
+        }
+    }
+
+    // Copy name and marker to listeners section.
+    std::string id(name + marker);
+    std::copy(id.c_str(), id.c_str() + id.size(), next);
+
+    // Always add an extra null after the final listener.
+    *(next + id.size()) = '\0';
+
+    return true;
+}
+
+/// Check whether there is a marker after the listener name and skip it.
+//
+/// @param i        Always moved to point to the next listener string.
+/// @param end      The end of the shared memory second to read.
+//
+/// A marker looks like this "::3\0::4\0" or "::3\0::2\0". We don't know
+/// what the numbers mean, or which ones are valid.
+//
+/// Currently this check ignores the digits.
+void
+getMarker(SharedMem::iterator& i, SharedMem::iterator end)
+{
+    // i points to 0 before marker.
+    assert(*i == '\0');
+    if (i == end) return;
+
+    // Move to after null.
+    ++i;
+
+    // Then check for marker.
+    if (end - i < 8) return;
+
+    const char m[] = "::";
+
+    // Check for "::" patterns.
+    if (!std::equal(i, i + 2, m) || !std::equal(i + 4, i + 6, m)) {
+        return;
+    }
+
+    // Check for terminating 0.
+    if (*(i + 7) != '\0') return;
+
+    i += 8;
+    return;
+
+}
+
+/// Read the function data, call the function.
+//
+/// This function does not mark the data for overwriting.
+void
+executeAMFFunction(as_object& o, AMF::Reader& rd)
+{
+    as_value a;
+
+    if (!rd(a) || !a.is_string()) {
+        log_error("Invalid domain %s", a);
+        return;
+    }
+    const std::string& domain = a.to_string();
+    log_debug("Domain: %s", domain);
+    
+    if (!rd(a)) {
+        log_error("Invalid function name %s", a);
+        return;
+    }
+
+    // This is messy and verbose because we don't know what it means.
+    // If the value after the domain is a boolean, it appears to signify a
+    // set of extra data. It's logged so that we can find exceptions more
+    // easily.
+    if (a.is_bool()) {
+
+        // Both bools have been false in all the examples I've seen.
+        log_debug("First bool: %s", a);
+        if (rd(a)) log_debug("Second Bool: %s", a);
+
+        // We guess that the first number describes the number of data fields
+        // after the second number, before the function name.
+        if (rd(a)) log_debug("First Number: %s", a);
+
+        // Handle negative numbers.
+        const size_t count = std::max<int>(0, toInt(a));
+
+        // We don't know what the second number signifies.
+        if (rd(a)) log_debug("Second Number: %s", a);
+
+
+        for (size_t i = 0; i < count; ++i) {
+            if (!rd(a)) {
+                log_error("Fewer AMF fields than expected.");
+                return;
+            }
+            log_debug("Data: %s", a);
+        }
+
+        // Now we expect the next field to be the method to call.
+        if (!rd(a)) return;
+    }
+
+    const std::string& meth = a.to_string();
+
+    // These are in reverse order!
+    std::vector<as_value> d;
+    while(rd(a)) d.push_back(a);
+    std::reverse(d.begin(), d.end());
+    fn_call::Args args;
+    args.swap(d);
+
+    // Call the method on this LocalConnection object.
+    string_table& st = getStringTable(o);
+    as_function* f = o.getMember(st.find(meth)).to_function();
+
+    invoke(f, as_environment(getVM(o)), &o, args);
+}
+
+/// Zero timestamp and length bytes to mark the data as overwritable.
+void
+markRead(SharedMem& m)
+{
+    std::fill_n(m.begin() + 8, 8, 0);
+}
 } // anonymous namespace
 
 } // end of gnash namespace
 
-//Adding for testing commit

=== modified file 'libcore/asobj/flash/net/NetConnection_as.cpp'
--- a/libcore/asobj/flash/net/NetConnection_as.cpp      2010-01-18 14:43:24 
+0000
+++ b/libcore/asobj/flash/net/NetConnection_as.cpp      2010-02-10 09:32:07 
+0000
@@ -33,12 +33,12 @@
 #include "URLAccessManager.h"
 #include "URL.h"
 #include "VM.h"
-#include "amf.h"
 #include "SimpleBuffer.h"
 #include "namedStrings.h"
 #include "GnashAlgorithm.h"
 #include "fn_call.h"
 #include "Global_as.h"
+#include "AMF.h"
 
 #include <iostream>
 #include <string>
@@ -292,33 +292,27 @@
 #ifdef GNASH_DEBUG_REMOTING
     log_debug("advancing HTTPRemotingHandler");
 #endif
-    if(_connection)
-    {
-
-        VM& vm = getVM(_nc.owner());
+    if (_connection) {
 
 #ifdef GNASH_DEBUG_REMOTING
         log_debug("have connection");
 #endif
 
         // Fill last chunk before reading in the next
-        size_t toRead = reply.capacity()-reply.size();
-        if ( ! toRead ) toRead = NCCALLREPLYCHUNK;
+        size_t toRead = reply.capacity() - reply.size();
+        if (! toRead) toRead = NCCALLREPLYCHUNK;
 
 #ifdef GNASH_DEBUG_REMOTING
         log_debug("Attempt to read %d bytes", toRead);
 #endif
 
-        //
         // See if we need to allocate more bytes for the next
         // read chunk
-        //
-        if ( reply.capacity() < reply.size()+toRead )
-        {
+        if (reply.capacity() < reply.size() + toRead) {
             // if _connection->size() >= 0, reserve for it, so
             // if HTTP Content-Length response header is correct
             // we'll be allocating only once for all.
-            size_t newCapacity = reply.size()+toRead;
+            const size_t newCapacity = reply.size() + toRead;
 
 #ifdef GNASH_DEBUG_REMOTING
             log_debug("NetConnection.call: reply buffer capacity (%d) "
@@ -334,13 +328,15 @@
 #endif
         }
 
-        int read = _connection->readNonBlocking(reply.data() + reply.size(), 
toRead);
-        if(read > 0) {
+        const int read =
+            _connection->readNonBlocking(reply.data() + reply.size(), toRead);
+
+        if (read > 0) {
 #ifdef GNASH_DEBUG_REMOTING
             log_debug("read '%1%' bytes: %2%", read, 
                     hexify(reply.data() + reply.size(), read, false));
 #endif
-            reply.resize(reply.size()+read);
+            reply.resize(reply.size() + read);
         }
 
         // There is no way to tell if we have a whole amf reply without
@@ -356,8 +352,7 @@
         // the buffer is full, 2) when we have a "length in bytes" value
         // thas is satisfied
 
-        if (_connection->bad())
-        {
+        if (_connection->bad()) {
             log_debug("connection is in error condition, calling "
                     "NetConnection.onStatus");
             reply.resize(0);
@@ -369,35 +364,35 @@
             // 'undefined'
             _nc.notifyStatus(NetConnection_as::CALL_FAILED);
         }
-        else if(_connection->eof() )
-        {
-            if ( reply.size() > 8)
-            {
-                std::vector<as_object*> objRefs;
+        else if (_connection->eof()) {
+
+            if (reply.size() > 8) {
+
 
 #ifdef GNASH_DEBUG_REMOTING
                 log_debug("hit eof");
 #endif
-                boost::int16_t si;
                 boost::uint16_t li;
                 const boost::uint8_t *b = reply.data() + reply_start;
                 const boost::uint8_t *end = reply.data() + reply.size();
+                
+                AMF::Reader rd(b, end, getGlobal(_nc.owner()));
 
                 // parse header
                 b += 2; // skip version indicator and client id
 
                 // NOTE: this looks much like parsing of an OBJECT_AMF0
-                si = readNetworkShort(b); b += 2; // number of headers
+                boost::int16_t si = readNetworkShort(b);
+                b += 2; // number of headers
                 uint8_t headers_ok = 1;
-                if (si != 0)
-                {
+                if (si != 0) {
+
 #ifdef GNASH_DEBUG_REMOTING
                     log_debug("NetConnection::call(): amf headers "
                             "section parsing");
 #endif
                     as_value tmp;
-                    for(int i = si; i > 0; --i)
-                    {
+                    for (size_t i = si; i > 0; --i) {
                         if(b + 2 > end) {
                             headers_ok = 0;
                             break;
@@ -417,8 +412,7 @@
                             break;
                         }
                         b += 5; // skip past bool and length long
-                        if( !tmp.readAMF0(b, end, -1, objRefs, vm) )
-                        {
+                        if(!rd(tmp)) {
                             headers_ok = 0;
                             break;
                         }
@@ -498,9 +492,8 @@
                             log_debug("about to parse amf value");
 #endif
                             // this updates b to point to the next unparsed 
byte
-                            as_value reply_as_value;
-                            if ( ! reply_as_value.readAMF0(b, end, -1, 
objRefs, vm) )
-                            {
+                            as_value replyval;
+                            if (!rd(replyval)) {
                                 log_error("parse amf failed");
                                 // this will happen if we get
                                 // bogus data, or if the data runs
@@ -516,28 +509,35 @@
                             // update variable to show how much we've parsed
                             reply_start = b - reply.data();
 
-                            // if actionscript specified a callback object, 
call it
+                            // if actionscript specified a callback object,
+                            // call it
                             as_object* callback = pop_callback(id);
                             if (callback) {
 
                                 string_table::key methodKey;
                                 if ( methodName == "onResult" ) {
                                     methodKey = NSV::PROP_ON_RESULT;
-                                } else if ( methodName == "onStatus" ) {
+                                }
+                                else if (methodName == "onStatus") {
                                     methodKey = NSV::PROP_ON_STATUS;
-                                } else {
-                                    // NOTE: the pp is known to actually 
invoke the custom
-                                    //       method, but with 7 undefined 
arguments (?)
-                                    //methodKey = 
getStringTable(_nc).find(methodName);
-                                    log_error("Unsupported HTTP Remoting 
response callback: '%s' (size %d)", methodName, methodName.size());
+                                }
+                                else {
+                                    // NOTE: the pp is known to actually
+                                    // invoke the custom method, but with 7
+                                    // undefined arguments (?)
+                                    log_error("Unsupported HTTP Remoting "
+                                            "response callback: '%s' "
+                                            "(size %d)", methodName,
+                                            methodName.size());
                                     continue;
                                 }
 
 #ifdef GNASH_DEBUG_REMOTING
                                 log_debug("calling onResult callback");
 #endif
-                                // FIXME check if above line can fail and we 
have to react
-                                callMethod(callback, methodKey, 
reply_as_value);
+                                // FIXME check if above line can fail and we
+                                // have to react
+                                callMethod(callback, methodKey, replyval);
 #ifdef GNASH_DEBUG_REMOTING
                                 log_debug("callback called");
 #endif
@@ -600,51 +600,47 @@
 HTTPRemotingHandler::call(as_object* asCallback, const std::string& methodName,
             const std::vector<as_value>& args, size_t firstArg)
 {
-    boost::scoped_ptr<SimpleBuffer> buf (new SimpleBuffer(32));
+    SimpleBuffer buf(32);
 
     // method name
-    buf->appendNetworkShort(methodName.size());
-    buf->append(methodName.c_str(), methodName.size());
+    buf.appendNetworkShort(methodName.size());
+    buf.append(methodName.c_str(), methodName.size());
 
     // client id (result number) as counted string
     // the convention seems to be / followed by a unique (ascending) number
     std::ostringstream os;
     os << "/";
     // Call number is not used if the callback is undefined
-    if ( asCallback )
-    {
+    if (asCallback) {
         os << ++_numCalls; 
     }
     const std::string callNumberString = os.str();
 
-    buf->appendNetworkShort(callNumberString.size());
-    buf->append(callNumberString.c_str(), callNumberString.size());
-
-    size_t total_size_offset = buf->size();
-    buf->append("\000\000\000\000", 4); // total size to be filled in later
-
-    std::map<as_object*, size_t> offsetTable;
+    buf.appendNetworkShort(callNumberString.size());
+    buf.append(callNumberString.c_str(), callNumberString.size());
+
+    size_t total_size_offset = buf.size();
+    buf.append("\000\000\000\000", 4); // total size to be filled in later
 
     // encode array of arguments to remote method
-    buf->appendByte(amf::Element::STRICT_ARRAY_AMF0);
-    buf->appendNetworkLong(args.size()-firstArg);
+    buf.appendByte(AMF::STRICT_ARRAY_AMF0);
+    buf.appendNetworkLong(args.size() - firstArg);
 
-    VM& vm = getVM(_nc.owner());
+    // STRICT_ARRAY encoding is allowed for remoting
+    AMF::Writer w(buf, true);
 
     for (unsigned int i = firstArg; i < args.size(); ++i)
     {
         const as_value& arg = args[i];
-        // STRICT_ARRAY encoding is allowed for remoting
-        if ( ! arg.writeAMF0(*buf, offsetTable, vm, true) )
-        {
+        if (!arg.writeAMF0(w)) {
             log_error("Could not serialize NetConnection.call argument %d",
                     i);
         }
     }
 
     // Set the "total size" parameter.
-    *(reinterpret_cast<uint32_t*>(buf->data() + total_size_offset)) = 
-        htonl(buf->size() - 4 - total_size_offset);
+    *(reinterpret_cast<uint32_t*>(buf.data() + total_size_offset)) = 
+        htonl(buf.size() - 4 - total_size_offset);
 
 #ifdef GNASH_DEBUG_REMOTING
     log_debug(_("NetConnection.call(): encoded args: %s"),
@@ -655,14 +651,14 @@
 #ifdef GNASH_DEBUG_REMOTING
         log_debug("calling enqueue with callback");
 #endif
-        enqueue(*buf, callNumberString, asCallback);
+        enqueue(buf, callNumberString, asCallback);
     }
     
     else {
 #ifdef GNASH_DEBUG_REMOTING
         log_debug("calling enqueue without callback");
 #endif
-        enqueue(*buf);
+        enqueue(buf);
     }
 }
 

=== modified file 'libcore/asobj/flash/net/NetStream_as.cpp'
--- a/libcore/asobj/flash/net/NetStream_as.cpp  2010-01-25 18:52:20 +0000
+++ b/libcore/asobj/flash/net/NetStream_as.cpp  2010-02-10 09:47:04 +0000
@@ -39,6 +39,7 @@
 #include "StreamProvider.h"
 #include "sound_handler.h"
 #include "GnashSystemNetHeaders.h"
+#include "AMF.h"
 
 // Define the following macro to have status notification handling debugged
 //#define GNASH_DEBUG_STATUS
@@ -137,22 +138,6 @@
 }
 
 void
-NetStream_as::processNotify(const std::string& funcname, as_object* info_obj)
-{
-    // TODO: check for System.onStatus too ! use a private
-    // getStatusHandler() method for this.
-
-#ifdef GNASH_DEBUG_METADATA
-  log_debug(" Invoking onMetaData");
-#endif
-
-    string_table::key func = getStringTable(owner()).find(funcname);
-
-    callMethod(&owner(), func, as_value(info_obj));
-}
-
-
-void
 NetStream_as::processStatusNotifications()
 {
     // TODO: check for System.onStatus too ! use a private
@@ -1936,24 +1921,23 @@
 void
 executeTag(const SimpleBuffer& _buffer, as_object& thisPtr)
 {
-    VM& vm = getVM(thisPtr);
 
        const boost::uint8_t* ptr = _buffer.data();
        const boost::uint8_t* endptr = ptr + _buffer.size();
 
-       if ( ptr + 2 > endptr ) {
+       if (endptr - ptr < 2) {
                log_error("Premature end of AMF in NetStream metatag");
                return;
        }
-       boost::uint16_t length = ntohs((*(boost::uint16_t *)ptr) & 0xffff);
+       const boost::uint16_t length = ntohs((*(boost::uint16_t *)ptr) & 
0xffff);
        ptr += 2;
 
-       if ( ptr + length > endptr ) {
+       if (endptr - ptr < length) {
                log_error("Premature end of AMF in NetStream metatag");
                return;
        }
 
-       std::string funcName(reinterpret_cast<const char*>(ptr), length); 
+       const std::string funcName(reinterpret_cast<const char*>(ptr), length); 
        ptr += length;
 
        log_debug("funcName: %s", funcName);
@@ -1961,10 +1945,10 @@
        string_table& st = getStringTable(thisPtr);
        string_table::key funcKey = st.find(funcName);
 
+    AMF::Reader rd(ptr, endptr, getGlobal(thisPtr));
+
        as_value arg;
-       std::vector<as_object*> objRefs;
-       if (!arg.readAMF0(ptr, endptr, -1, objRefs, vm))
-       {
+       if (!rd(arg)) {
                log_error("Could not convert FLV metatag to as_value, but will 
try "
                 "passing it anyway. It's an %s", arg);
        }

=== modified file 'libcore/asobj/flash/net/NetStream_as.h'
--- a/libcore/asobj/flash/net/NetStream_as.h    2010-01-25 18:52:20 +0000
+++ b/libcore/asobj/flash/net/NetStream_as.h    2010-02-10 09:42:08 +0000
@@ -385,9 +385,6 @@
     ///
     void processStatusNotifications();
     
-    
-    void processNotify(const std::string& funcname, as_object* metadata_obj);
-
     // The size of the buffer in milliseconds
     boost::uint32_t m_bufferTime;
 

=== modified file 'libcore/asobj/flash/net/SharedObject_as.cpp'
--- a/libcore/asobj/flash/net/SharedObject_as.cpp       2010-01-11 06:41:38 
+0000
+++ b/libcore/asobj/flash/net/SharedObject_as.cpp       2010-02-10 09:21:47 
+0000
@@ -28,10 +28,7 @@
 #include "GnashFileUtilities.h" // stat
 #include "SimpleBuffer.h"
 #include "as_value.h"
-#include "amf.h"
-#include "element.h"
-#include "sol.h"
-#include "net/SharedObject_as.h"
+#include "SharedObject_as.h"
 #include "as_object.h" // for inheritance
 #include "log.h"
 #include "fn_call.h"
@@ -44,23 +41,19 @@
 #include "rc.h" // for use of rcfile
 #include "URLAccessManager.h"
 #include "network.h"
-#include "rtmp_client.h"
 #include "URL.h"
 #include "NetConnection_as.h"
 #include "Object.h"
+#include "AMF.h"
+#include "sol.h"
 
 #include <boost/scoped_array.hpp>
 #include <boost/shared_ptr.hpp>
 
-// Undefine this to use the Element-based AMF0 decoder/encoder.
-// May be useful to test libamf.
-#define BUFFERED_AMF_SOL
-
 namespace {
-gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
+    gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
 }
 
-using namespace amf;
 
 namespace gnash {
 
@@ -96,74 +89,17 @@
 // Serializer helper
 namespace { 
 
-class PropsSerializer : public AbstractPropertyVisitor
-{
-public:
-
-    PropsSerializer(SOL& sol, VM& vm)
-        :
-        _sol(sol),
-        _st(vm.getStringTable())
-    {};
-
-    bool accept(const ObjectURI& uri, const as_value& val) 
-    {
-        AMF amf;
-        boost::shared_ptr<amf::Element> el;
-        
-        // We omit the namespace.
-        const std::string& name = _st.string_table::value(getName(uri));
-
-        //log_debug("Serializing SharedObject property %s:%s", name, val);
-
-        if (val.is_string()) {
-            std::string str;
-            if (!val.is_undefined()) {
-                str = val.to_string();
-            }
-            el.reset(new amf::Element(name, str));
-        }
-        if (val.is_bool()) {
-            bool flag = val.to_bool();
-            el.reset(new amf::Element(name, flag));
-        }
-        if (val.is_number()) { 
-            double dub;
-            if (val.is_undefined()) {
-                dub = 0.0;
-            } else {
-                dub = val.to_number();
-            }
-            el.reset(new amf::Element(name, dub));
-        }
-
-        if (el) {
-            _sol.addObj(el);
-        }
-        return true;
-    }
-
-private:
-
-    SOL& _sol;
-    string_table& _st;
-};
-
 /// Class used to serialize properties of an object to a buffer in SOL format
 class SOLPropsBufSerializer : public AbstractPropertyVisitor
 {
 
-    typedef std::map<as_object*, size_t> PropertiesOffsetTable;
-
 public:
 
-    SOLPropsBufSerializer(SimpleBuffer& buf, VM& vm,
-            PropertiesOffsetTable& offsetTable)
+    SOLPropsBufSerializer(AMF::Writer w, VM& vm)
         :
-        _buf(buf),
+        _writer(w),
         _vm(vm),
         _st(vm.getStringTable()),
-        _offsetTable(offsetTable),
         _error(false)
        {};
     
@@ -201,11 +137,9 @@
 #ifdef GNASH_DEBUG_AMF_SERIALIZE
         log_debug(" serializing property %s", name);
 #endif
-        boost::uint16_t namelen = name.size();
-        _buf.appendNetworkShort(namelen);
-        _buf.append(name.c_str(), namelen);
+        _writer.writePropertyName(name);
         // Strict array are never encoded in SharedObject
-        if (!val.writeAMF0(_buf, _offsetTable, _vm, false))
+        if (!val.writeAMF0(_writer))
         {
             log_error("Problems serializing an object's member %s=%s",
                     name, val);
@@ -214,23 +148,23 @@
             // Stop visiting....
             return false;
         }
-        // SOL-specific
-        _buf.appendByte(0); 
+
+        boost::uint8_t end(0);
+        _writer.writeData(&end, 1);
         return true;
     }
 
 private:
 
-    SimpleBuffer& _buf;
+    AMF::Writer _writer;
     VM& _vm;
     string_table& _st;
-    PropertiesOffsetTable& _offsetTable;
     bool _error;
 };
 
 } // anonymous namespace
 
-class SharedObject_as : public Relay, public RTMPClient
+class SharedObject_as : public Relay
 {
 public:
 
@@ -317,7 +251,7 @@
     as_object& _owner;
     as_object* _data;
     bool _persistence;
-    SOL _sol;
+    amf::SOL _sol;
     bool _connected;
     std::string        _uri;
 };
@@ -364,8 +298,6 @@
         return false;
     }
     
-#ifdef BUFFERED_AMF_SOL
-
     gnash::SimpleBuffer buf;
     // see http://osflash.org/documentation/amf/envelopes/sharedobject
 
@@ -384,8 +316,10 @@
     // append properties of object
     VM& vm = getVM(_owner);
 
-    std::map<as_object*, size_t> offsetTable;
-    SOLPropsBufSerializer props(buf, vm, offsetTable);
+    // Do not encode strict arrays!
+    AMF::Writer w(buf, false);
+
+    SOLPropsBufSerializer props(w, vm);
     _data->visitProperties<Exists>(props);
     if (!props.success()) {
         log_error("Could not serialize object");
@@ -395,7 +329,7 @@
     // fix length field
     *(reinterpret_cast<uint32_t*>(buf.data() + 2)) = htonl(buf.size() - 6);
     
-    // TODO write file
+    // Write file
     std::ofstream ofs(filespec.c_str(), std::ios::binary);
     if (!ofs) {
         log_error("SharedObject::flush(): Failed opening file '%s' in "
@@ -412,23 +346,6 @@
     }
     ofs.close();
 
-#else // amf::SOL-based serialization
-
-    // append properties of object
-    VM& vm = getVM(*this)
-
-    SOL sol;
-    PropsSerializer props(sol, vm);
-    _data->visitPropertyValues(props);
-    // We only want to access files in this directory
-    bool ret = sol.writeFile(filespec, getObjectName().c_str());
-    if ( ! ret )
-    {
-        log_error("writing SharedObject file to %s", filespec);
-        return false;
-    }
-#endif
-
     log_security("SharedObject '%s' written to filesystem.", filespec);
     return true;
 }
@@ -461,8 +378,7 @@
 
     // Check if the base dir exists here
     struct stat statbuf;
-    if ( -1 == stat(_solSafeDir.c_str(), &statbuf) )
-    {
+    if (stat(_solSafeDir.c_str(), &statbuf) == -1) {
        log_debug("Invalid SOL safe dir %s: %s. Will try to create on "
                "flush/exit.", _solSafeDir, std::strerror(errno));
     }
@@ -484,7 +400,6 @@
     // blindly trusting the SWF publisher as base url is changed
     // by the 'base' attribute of OBJECT or EMBED tags trough
     // -P base=xxx
-    //
     const movie_root& mr = _vm.getRoot();
     const std::string& swfURL = mr.getOriginalURL();
 
@@ -849,6 +764,7 @@
     GNASH_REPORT_FUNCTION;    
 
     SharedObject_as* obj = ensure<ThisIsNative<SharedObject_as> >(fn);
+    UNUSED(obj);
 
     if (fn.nargs < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -877,7 +793,7 @@
 
     // This is always set without validification.fooc->setURI(uriStr);
     std::string str = nc->getURI();
-    obj->setPath(str);
+    //obj->setPath(str);
     URL uri = nc->getURI();
     Network *net = new Network;
 
@@ -928,7 +844,7 @@
     SharedObject_as* obj = ensure<ThisIsNative<SharedObject_as> >(fn);
 
     if (!obj->isConnected()) {
-        obj->connectToServer(obj->getURI());
+        //obj->connectToServer(obj->getURI());
     }
     
     return as_value();
@@ -1127,8 +1043,6 @@
 readSOL(VM& vm, const std::string& filespec)
 {
 
-#ifdef BUFFERED_AMF_SOL
-
     Global_as& gl = *vm.getGlobal();
 
     // The 'data' member is initialized only on getLocal() (and probably
@@ -1176,31 +1090,41 @@
             return data;
         }
 
-        std::vector<as_object*> objRefs;
-
-        while (buf < end) {
+        AMF::Reader rd(buf, end, gl);
+
+        while (buf != end) {
+
             log_debug("SharedObject::readSOL: reading property name at "
                     "byte %s", buf - sbuf.get());
             // read property name
-            boost::uint16_t len = 
+            
+            if (end - buf < 2) {
+                log_error("SharedObject: end of buffer while reading length");
+                break;
+            }
+
+            const boost::uint16_t len = 
                 ntohs(*(reinterpret_cast<const boost::uint16_t*>(buf)));
             buf += 2;
 
-            if( buf + len >= end ) {
+            if (!len) {
+                log_error("SharedObject::readSOL: empty property name");
+                break;
+            }
+
+            if (end - buf < len) {
                 log_error("SharedObject::readSOL: premature end of input");
                 break;
             }
-            if ( ! len ) {
-                log_error("SharedObject::readSOL: empty property name");
-                break;
-            }
+
             std::string prop_name(reinterpret_cast<const char*>(buf), len);
             buf += len;
 
             // read value
             as_value as;
-            if (!as.readAMF0(buf, end, -1, objRefs, vm)) {
-                log_error("SharedObject::readSOL: Parsing SharedObject '%s'",
+
+            if (!rd(as)) {
+                log_error("SharedObject: error parsing SharedObject '%s'",
                         filespec);
                 return false;
             }
@@ -1212,6 +1136,8 @@
             string_table& st = vm.getStringTable();
             data->set_member(st.find(prop_name), as);
             
+            if (buf == end) break;;
+
             buf += 1; // skip null byte after each property
         }
         return data;
@@ -1223,72 +1149,6 @@
         return 0;
     }
 
-#else
-    SOL sol;
-    log_security("Opening SharedObject file: %s", filespec);
-    if (sol.readFile(filespec) == false) {
-        log_security("empty or non-existing SOL file \"%s\", will be "
-                "created on flush/exit", filespec);
-        return false;
-    }
-    
-    std::vector<boost::shared_ptr<amf::Element> >::const_iterator it, e;
-    std::vector<boost::shared_ptr<amf::Element> > els = sol.getElements();
-    log_debug("Read %d AMF objects from %s", els.size(), filespec);
-
-    as_value as = getMember(NSV::PROP_DATA);
-    as_object* ptr = as.to_object(getGlobal(fn));
-    
-    for (it = els.begin(), e = els.end(); it != e; it++) {
-        boost::shared_ptr<amf::Element> el = *it;
-
-        switch (el->getType())
-        {
-            case Element::NUMBER_AMF0:
-            {
-                double dub =  *(reinterpret_cast<double*>(el->getData()));
-                ptr->set_member(st.string_table::find(el->getName()),
-                        as_value(dub));
-                break;
-            }
-
-            case Element::BOOLEAN_AMF0:
-                ptr->set_member(st.string_table::find(el->getName()),
-                                            as_value(el->to_bool()));
-                break;
-
-            case Element::STRING_AMF0:
-            {
-                if (el->getLength() == 0) {
-                    ptr->set_member(st.string_table::find(el->getName()), "");
-                    break;
-                }
-                
-                std::string str(reinterpret_cast<const char*>(el->getData()),
-                        el->getLength());
-                ptr->set_member(st.string_table::find(el->getName()), str);
-                break;
-            }
-
-            case Element::OBJECT_AMF0:
-                // TODO: implement!
-                log_unimpl("Reading OBJECT type from SharedObject");
-                //data.convert_to_object(getGlobal(fn));
-                //ptr->set_member(st.string_table::find(el->name), data);
-                return false;
-                break;
-
-            default:
-                // TODO: what about other types?
-                log_unimpl("Reading SOL type %d", el->getType());
-                return false;
-                break;
-        } 
-
-    }
-
-    return true;
-#endif
 }
 
 

=== modified file 'libcore/asobj/flash/xml/XMLDocument_as.cpp'
--- a/libcore/asobj/flash/xml/XMLDocument_as.cpp        2010-01-25 18:52:20 
+0000
+++ b/libcore/asobj/flash/xml/XMLDocument_as.cpp        2010-02-10 13:56:56 
+0000
@@ -61,7 +61,7 @@
     as_value xml_loaded(const fn_call& fn);
     as_value xml_status(const fn_call& fn);
 
-    typedef std::string::const_iterator xml_iterator;
+    typedef XMLDocument_as::xml_iterator xml_iterator;
 
     bool textAfterWhitespace(xml_iterator& it, xml_iterator end);
     bool textMatch(xml_iterator& it, xml_iterator end,
@@ -81,142 +81,6 @@
 }
 
 
-/// Implements XML (AS2) and flash.xml.XMLDocument (AS3) class.
-//
-/// This class interface is identical in AS3 and AS2; it is probably 
-/// included in AS3 for backward compatibility.
-class XMLDocument_as : public XMLNode_as
-{
-public:
-
-    enum ParseStatus {
-            XML_OK = 0,
-            XML_UNTERMINATED_CDATA = -2,
-            XML_UNTERMINATED_XML_DECL = -3,
-            XML_UNTERMINATED_DOCTYPE_DECL = -4,
-            XML_UNTERMINATED_COMMENT = -5,
-            XML_UNTERMINATED_ELEMENT = -6,
-            XML_OUT_OF_MEMORY = -7,
-            XML_UNTERMINATED_ATTRIBUTE = -8,
-            XML_MISSING_CLOSE_TAG = -9,
-            XML_MISSING_OPEN_TAG = -10
-    };
-
-    enum LoadStatus {
-        XML_LOADED_UNDEFINED = -1,
-        XML_LOADED_FALSE = false,
-        XML_LOADED_TRUE = true
-    };
-
-    /// Create an XML object.
-    //
-    /// An XMLDocument is always user-created, so always starts with an
-    /// associated object.
-    XMLDocument_as(as_object& object);
-
-    XMLDocument_as(as_object& object, const std::string& xml);
-
-    ~XMLDocument_as() {};
-    
-    /// Convert the XML object to a string
-    //
-    /// This calls XMLNode::toString after adding an xmlDecl and
-    /// docTypeDecl
-    //
-    /// @param o        The ostream to write the string to.
-    /// @param encode   Whether to URL encode the node values.
-    void toString(std::ostream& o, bool encode) const;
-
-    const std::string& getXMLDecl() const {
-        return _xmlDecl;
-    }
-
-    void setXMLDecl(const std::string& xml) {
-        _xmlDecl = xml;
-    }
-
-    const std::string& getDocTypeDecl() const {
-        return _docTypeDecl;
-    }
-
-    void setDocTypeDecl(const std::string& docType) {
-        _docTypeDecl = docType;
-    }
-
-    // Methods
-
-    /// Parses an XML document into the specified XML object tree.
-    //
-    /// This reads in an XML file from disk and parses into into a memory
-    /// resident tree which can be walked through later.
-    ///
-    /// Calls to this function clear any precedently parsed data.
-    ///
-    void parseXML(const std::string& xml);
-
-    XMLNode_as* createElement(const std::string& name);
-
-    XMLNode_as* createTextNode(const std::string& name);
-
-    ParseStatus status() const {
-        return _status;
-    }
-
-    void setStatus(ParseStatus st) {
-        _status = st;
-    }
-
-    LoadStatus loaded() const {
-        return _loaded;
-    }
-
-    void setLoaded(LoadStatus st) {
-        _loaded = st;
-    }
-
-private:
-
-    typedef std::map<std::string, std::string, StringNoCaseLessThan> 
Attributes;
-
-    void parseTag(XMLNode_as*& node, xml_iterator& it, xml_iterator end);
-
-    void parseAttribute(XMLNode_as* node, xml_iterator& it,
-            xml_iterator end, Attributes& attributes);
-
-    void parseDocTypeDecl( xml_iterator& it, xml_iterator end);
-
-    void parseText(XMLNode_as* node, xml_iterator& it, xml_iterator end);
-
-    void parseXMLDecl(xml_iterator& it, xml_iterator end);
-
-    void parseComment(XMLNode_as* node, xml_iterator& it, xml_iterator end);
-
-    void parseCData(XMLNode_as* node, xml_iterator& it, xml_iterator end);
- 
-    /// Clear all properties.
-    //
-    /// This removes all children, resets doctype and xml decls, and
-    /// sets status to XML.
-    void clear();
-  
-    /// \brief
-    /// Return true if ignoreWhite property was set to anything evaluating
-    /// to true.
-    bool ignoreWhite();
-
-    // -1 if never asked to load anything
-    //  0 if asked to load but not yet loaded (or failure)
-    //  1 if successfully loaded
-    LoadStatus _loaded;
-
-    ParseStatus _status;       
- 
-    std::string _docTypeDecl;
-
-    std::string _xmlDecl;
-
-};
-
 XMLDocument_as::XMLDocument_as(as_object& object) 
     :
     XMLNode_as(getGlobal(object)),
@@ -1012,7 +876,7 @@
 ///                 the tag.
 /// @param xml      The complete XML string.
 bool
-parseNodeWithTerminator( xml_iterator& it, const xml_iterator end,
+parseNodeWithTerminator(xml_iterator& it, const xml_iterator end,
         const std::string& terminator, std::string& content)
 {
     xml_iterator ourend = std::search(it, end, terminator.begin(),

=== modified file 'libcore/asobj/flash/xml/XMLDocument_as.h'
--- a/libcore/asobj/flash/xml/XMLDocument_as.h  2010-01-25 18:52:20 +0000
+++ b/libcore/asobj/flash/xml/XMLDocument_as.h  2010-02-10 13:56:56 +0000
@@ -20,7 +20,6 @@
 #ifndef GNASH_ASOBJ3_XMLDOCUMENT_H
 #define GNASH_ASOBJ3_XMLDOCUMENT_H
 
-
 #include "LoadableObject.h"
 #include "xml/XMLNode_as.h"
 #include "log.h"
@@ -37,6 +36,147 @@
 class fn_call;
 class URL;
 
+/// Implements XML (AS2) and flash.xml.XMLDocument (AS3) class.
+//
+/// This class interface is identical in AS3 and AS2; it is probably 
+/// included in AS3 for backward compatibility.
+//
+/// The class definition is necessary because XML is encoded differently
+/// in AMF.
+class XMLDocument_as : public XMLNode_as
+{
+public:
+
+    typedef std::string::const_iterator xml_iterator;
+
+    enum ParseStatus {
+            XML_OK = 0,
+            XML_UNTERMINATED_CDATA = -2,
+            XML_UNTERMINATED_XML_DECL = -3,
+            XML_UNTERMINATED_DOCTYPE_DECL = -4,
+            XML_UNTERMINATED_COMMENT = -5,
+            XML_UNTERMINATED_ELEMENT = -6,
+            XML_OUT_OF_MEMORY = -7,
+            XML_UNTERMINATED_ATTRIBUTE = -8,
+            XML_MISSING_CLOSE_TAG = -9,
+            XML_MISSING_OPEN_TAG = -10
+    };
+
+    enum LoadStatus {
+        XML_LOADED_UNDEFINED = -1,
+        XML_LOADED_FALSE = false,
+        XML_LOADED_TRUE = true
+    };
+
+    /// Create an XML object.
+    //
+    /// An XMLDocument is always user-created, so always starts with an
+    /// associated object.
+    XMLDocument_as(as_object& object);
+
+    XMLDocument_as(as_object& object, const std::string& xml);
+
+    ~XMLDocument_as() {};
+    
+    /// Convert the XML object to a string
+    //
+    /// This calls XMLNode::toString after adding an xmlDecl and
+    /// docTypeDecl
+    //
+    /// @param o        The ostream to write the string to.
+    /// @param encode   Whether to URL encode the node values.
+    void toString(std::ostream& o, bool encode) const;
+
+    const std::string& getXMLDecl() const {
+        return _xmlDecl;
+    }
+
+    void setXMLDecl(const std::string& xml) {
+        _xmlDecl = xml;
+    }
+
+    const std::string& getDocTypeDecl() const {
+        return _docTypeDecl;
+    }
+
+    void setDocTypeDecl(const std::string& docType) {
+        _docTypeDecl = docType;
+    }
+
+    // Methods
+
+    /// Parses an XML document into the specified XML object tree.
+    //
+    /// This reads in an XML file from disk and parses into into a memory
+    /// resident tree which can be walked through later.
+    ///
+    /// Calls to this function clear any precedently parsed data.
+    ///
+    void parseXML(const std::string& xml);
+
+    XMLNode_as* createElement(const std::string& name);
+
+    XMLNode_as* createTextNode(const std::string& name);
+
+    ParseStatus status() const {
+        return _status;
+    }
+
+    void setStatus(ParseStatus st) {
+        _status = st;
+    }
+
+    LoadStatus loaded() const {
+        return _loaded;
+    }
+
+    void setLoaded(LoadStatus st) {
+        _loaded = st;
+    }
+
+private:
+
+    typedef std::map<std::string, std::string, StringNoCaseLessThan> 
Attributes;
+
+    void parseTag(XMLNode_as*& node, xml_iterator& it, xml_iterator end);
+
+    void parseAttribute(XMLNode_as* node, xml_iterator& it,
+            xml_iterator end, Attributes& attributes);
+
+    void parseDocTypeDecl( xml_iterator& it, xml_iterator end);
+
+    void parseText(XMLNode_as* node, xml_iterator& it, xml_iterator end);
+
+    void parseXMLDecl(xml_iterator& it, xml_iterator end);
+
+    void parseComment(XMLNode_as* node, xml_iterator& it, xml_iterator end);
+
+    void parseCData(XMLNode_as* node, xml_iterator& it, xml_iterator end);
+ 
+    /// Clear all properties.
+    //
+    /// This removes all children, resets doctype and xml decls, and
+    /// sets status to XML.
+    void clear();
+  
+    /// \brief
+    /// Return true if ignoreWhite property was set to anything evaluating
+    /// to true.
+    bool ignoreWhite();
+
+    // -1 if never asked to load anything
+    //  0 if asked to load but not yet loaded (or failure)
+    //  1 if successfully loaded
+    LoadStatus _loaded;
+
+    ParseStatus _status;       
+ 
+    std::string _docTypeDecl;
+
+    std::string _xmlDecl;
+
+};
+
 
 /// Escape using XML entities.
 //

=== removed file 'libmedia/AudioDecoderNellymoser.cpp'
--- a/libmedia/AudioDecoderNellymoser.cpp       2010-01-01 17:48:26 +0000
+++ b/libmedia/AudioDecoderNellymoser.cpp       1970-01-01 00:00:00 +0000
@@ -1,926 +0,0 @@
-// AudioDecoderNellymoser.cpp: Nellymoser decoding
-// 
-//   Copyright (C) 2007, 2008, 2009, 2010 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 3 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
-//
-
-
-// This file incorporates work covered by the following copyright and 
permission
-// notice:
-
-
-/*
- * Copyright (c) 2007 a840bda5870ba11f19698ff6eb9581dfb0f95fa5,
- *                    539459aeb7d425140b62a3ec7dbf6dc8e408a306, and
- *                    520e17cd55896441042b14df2566a6eb610ed444
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "AudioDecoderNellymoser.h"
-#include "SoundInfo.h"
-#include "log.h"
-
-#include <ctime>
-#include <cmath>
-#include <boost/random.hpp>
-
-namespace gnash {
-namespace media {
-
-const double sqrt1_2 = 0.70710678118654752440;
-
-float nelly_neg_unpack_table[64] = {
--0.0061359000, -0.0306748003, -0.0551952012, -0.0796824023, -0.1041216031,
--0.1284981072, -0.1527972072, -0.1770042032, -0.2011045963, -0.2250839025,
--0.2489275932, -0.2726213932, -0.2961508930, -0.3195019960, -0.3426606953,
--0.3656130135, -0.3883450031, -0.4108431935, -0.4330937862, -0.4550836086,
--0.4767991900, -0.4982276857, -0.5193560123, -0.5401715040, -0.5606616139,
--0.5808140039, -0.6006165147, -0.6200572252, -0.6391243935, -0.6578066945,
--0.6760926843, -0.6939715147, -0.7114322186, -0.7284644246, -0.7450578213,
--0.7612023950, -0.7768884897, -0.7921066284, -0.8068475723, -0.8211025000,
--0.8348628879, -0.8481202722, -0.8608669043, -0.8730949759, -0.8847970963,
--0.8959661722, -0.9065957069, -0.9166790843, -0.9262102246, -0.9351835251,
--0.9435935020, -0.9514350295, -0.9587035179, -0.9653943777, -0.9715039134,
--0.9770280719, -0.9819638729, -0.9863080978, -0.9900581837, -0.9932119250,
--0.9957674146, -0.9977231026, -0.9990776777, -0.9998306036
-};
-
-float nelly_huff_table[127] = {
-0.0000000000,
-
--0.8472560048, 0.7224709988,
-
--1.5247479677, -0.4531480074, 0.3753609955, 1.4717899561,
-
--1.9822579622, -1.1929379702, -0.5829370022, -0.0693780035, 0.3909569979,
-0.9069200158, 1.4862740040, 2.2215409279,
-
--2.3887870312, -1.8067539930, -1.4105420113, -1.0773609877, -0.7995010018,
--0.5558109879, -0.3334020078, -0.1324490011, 0.0568020009, 0.2548770010,
-0.4773550034, 0.7386850119, 1.0443060398, 1.3954459429, 1.8098750114,
-2.3918759823,
-
--2.3893830776, -1.9884680510, -1.7514040470, -1.5643119812, -1.3922129869,
--1.2164649963, -1.0469499826, -0.8905100226, -0.7645580173, -0.6454579830,
--0.5259280205, -0.4059549868, -0.3029719889, -0.2096900046, -0.1239869967,
--0.0479229987, 0.0257730000, 0.1001340002, 0.1737180054, 0.2585540116,
-0.3522900045, 0.4569880068, 0.5767750144, 0.7003160119, 0.8425520062,
-1.0093879700, 1.1821349859, 1.3534560204, 1.5320819616, 1.7332619429,
-1.9722349644, 2.3978140354,
-
-
--2.5756309032, -2.0573320389, -1.8984919786, -1.7727810144, -1.6662600040,
--1.5742180347, -1.4993319511, -1.4316639900, -1.3652280569, -1.3000990152,
--1.2280930281, -1.1588579416, -1.0921250582, -1.0135740042, -0.9202849865,
--0.8287050128, -0.7374889851, -0.6447759867, -0.5590940118, -0.4857139885,
--0.4110319912, -0.3459700048, -0.2851159871, -0.2341620028, -0.1870580018,
--0.1442500055, -0.1107169986, -0.0739680007, -0.0365610011, -0.0073290002,
-0.0203610007, 0.0479039997, 0.0751969963, 0.0980999991, 0.1220389977,
-0.1458999962, 0.1694349945, 0.1970459968, 0.2252430022, 0.2556869984,
-0.2870100141, 0.3197099864, 0.3525829911, 0.3889069855, 0.4334920049,
-0.4769459963, 0.5204820037, 0.5644530058, 0.6122040153, 0.6685929894,
-0.7341650128, 0.8032159805, 0.8784040213, 0.9566209912, 1.0397069454,
-1.1293770075, 1.2211159468, 1.3080279827, 1.4024800062, 1.5056819916,
-1.6227730513, 1.7724959850, 1.9430880547, 2.2903931141
-};
-
-float nelly_pos_unpack_table[64] = {
-0.9999812245, 0.9995294213, 0.9984756112, 0.9968202710, 0.9945645928,
-0.9917098284, 0.9882575870, 0.9842100739, 0.9795697927, 0.9743394256,
-0.9685220718, 0.9621214271, 0.9551411867, 0.9475855827, 0.9394592047,
-0.9307669997, 0.9215139747, 0.9117059708, 0.9013488293, 0.8904486895,
-0.8790122271, 0.8670461774, 0.8545579910, 0.8415549994, 0.8280450106,
-0.8140363097, 0.7995373011, 0.7845566273, 0.7691032887, 0.7531868219,
-0.7368165851, 0.7200024724, 0.7027546763, 0.6850836873, 0.6669998765,
-0.6485143900, 0.6296381950, 0.6103827953, 0.5907596946, 0.5707806945,
-0.5504580140, 0.5298035741, 0.5088300705, 0.4875501990, 0.4659765065,
-0.4441221058, 0.4220002890, 0.3996241987, 0.3770073950, 0.3541634977,
-0.3311063051, 0.3078495860, 0.2844074965, 0.2607941031, 0.2370236069,
-0.2131102979, 0.1890687048, 0.1649131030, 0.1406581998, 0.1163185984,
-0.0919089988, 0.0674438998, 0.0429382995, 0.0184067003
-};
-
-int nelly_copy_count[23] = {
-2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 12, 14, 15
-};
-
-float nelly_signal_table[64] = {
-0.1250000000, 0.1249623969, 0.1248494014, 0.1246612966, 0.1243980974,
-0.1240599006, 0.1236471012, 0.1231596991, 0.1225982010, 0.1219628006,
-0.1212539002, 0.1204719990, 0.1196174994, 0.1186909974, 0.1176929995,
-0.1166241020, 0.1154849008, 0.1142762005, 0.1129987016, 0.1116530001,
-0.1102401987, 0.1087609008, 0.1072160974, 0.1056066975, 0.1039336994,
-0.1021981016, 0.1004009023, 0.0985433012, 0.0966262966, 0.0946511030,
-0.0926188976, 0.0905309021, 0.0883883014, 0.0861926004, 0.0839449018,
-0.0816465989, 0.0792991966, 0.0769039020, 0.0744623989, 0.0719759986,
-0.0694463030, 0.0668746978, 0.0642627999, 0.0616123006, 0.0589246005,
-0.0562013984, 0.0534444004, 0.0506552011, 0.0478353985, 0.0449868999,
-0.0421111993, 0.0392102003, 0.0362856016, 0.0333391018, 0.0303725004,
-0.0273876991, 0.0243862998, 0.0213702004, 0.0183412991, 0.0153013002,
-0.0122520998, 0.0091955997, 0.0061335000, 0.0030677000
-};
-
-short nelly_init_table[64] = {
-3134, 5342, 6870, 7792, 8569, 9185, 9744, 10191, 10631, 11061, 11434, 11770,
-12116, 12513, 12925, 13300, 13674, 14027, 14352, 14716, 15117, 15477, 15824,
-16157, 16513, 16804, 17090, 17401, 17679, 17948, 18238, 18520, 18764, 19078,
-19381, 19640, 19921, 20205, 20500, 20813, 21162, 21465, 21794, 22137, 22453,
-22756, 23067, 23350, 23636, 23926, 24227, 24521, 24819, 25107, 25414, 25730,
-26120, 26497, 26895, 27344, 27877, 28463, 29426, 31355
-};
-
-float nelly_state_table[128] = {
-0.0061359000, 0.0184067003, 0.0306748003, 0.0429382995, 0.0551952012,
-0.0674438998, 0.0796824023, 0.0919089988, 0.1041216031, 0.1163185984,
-0.1284981072, 0.1406581998, 0.1527972072, 0.1649131030, 0.1770042032,
-0.1890687048, 0.2011045963, 0.2131102979, 0.2250839025, 0.2370236069,
-0.2489275932, 0.2607941031, 0.2726213932, 0.2844074965, 0.2961508930,
-0.3078495860, 0.3195019960, 0.3311063051, 0.3426606953, 0.3541634977,
-0.3656130135, 0.3770073950, 0.3883450031, 0.3996241987, 0.4108431935,
-0.4220002890, 0.4330937862, 0.4441221058, 0.4550836086, 0.4659765065,
-0.4767991900, 0.4875501990, 0.4982276857, 0.5088300705, 0.5193560123,
-0.5298035741, 0.5401715040, 0.5504580140, 0.5606616139, 0.5707806945,
-0.5808140039, 0.5907596946, 0.6006165147, 0.6103827953, 0.6200572252,
-0.6296381950, 0.6391243935, 0.6485143900, 0.6578066945, 0.6669998765,
-0.6760926843, 0.6850836873, 0.6939715147, 0.7027546763, 0.7114322186,
-0.7200024724, 0.7284644246, 0.7368165851, 0.7450578213, 0.7531868219,
-0.7612023950, 0.7691032887, 0.7768884897, 0.7845566273, 0.7921066284,
-0.7995373011, 0.8068475723, 0.8140363097, 0.8211025000, 0.8280450106,
-0.8348628879, 0.8415549994, 0.8481202722, 0.8545579910, 0.8608669043,
-0.8670461774, 0.8730949759, 0.8790122271, 0.8847970963, 0.8904486895,
-0.8959661722, 0.9013488293, 0.9065957069, 0.9117059708, 0.9166790843,
-0.9215139747, 0.9262102246, 0.9307669997, 0.9351835251, 0.9394592047,
-0.9435935020, 0.9475855827, 0.9514350295, 0.9551411867, 0.9587035179,
-0.9621214271, 0.9653943777, 0.9685220718, 0.9715039134, 0.9743394256,
-0.9770280719, 0.9795697927, 0.9819638729, 0.9842100739, 0.9863080978,
-0.9882575870, 0.9900581837, 0.9917098284, 0.9932119250, 0.9945645928,
-0.9957674146, 0.9968202710, 0.9977231026, 0.9984756112, 0.9990776777,
-0.9995294213, 0.9998306036, 0.9999812245
-};
-
-short nelly_delta_table[32] = {
--11725, -9420, -7910, -6801, -5948, -5233, -4599, -4039, -3507, -3030, -2596,
--2170, -1774, -1383, -1016, -660, -329, -1, 337, 696, 1085, 1512, 1962, 2433,
-2968, 3569, 4314, 5279, 6622, 8154, 10076, 12975
-};
-
-float nelly_inv_dft_table[129] = {
-0.0000000000, 0.0122715384, 0.0245412290, 0.0368072242, 0.0490676723,
-0.0613207370, 0.0735645667, 0.0857973099, 0.0980171412, 0.1102222130,
-0.1224106774, 0.1345807165, 0.1467304677, 0.1588581353, 0.1709618866,
-0.1830398887, 0.1950903237, 0.2071113735, 0.2191012353, 0.2310581058,
-0.2429801822, 0.2548656464, 0.2667127550, 0.2785196900, 0.2902846932,
-0.3020059466, 0.3136817515, 0.3253102899, 0.3368898630, 0.3484186828,
-0.3598950505, 0.3713171780, 0.3826834261, 0.3939920366, 0.4052413106,
-0.4164295495, 0.4275550842, 0.4386162460, 0.4496113360, 0.4605387151,
-0.4713967443, 0.4821837842, 0.4928981960, 0.5035383701, 0.5141027570,
-0.5245896578, 0.5349976420, 0.5453249812, 0.5555702448, 0.5657318234,
-0.5758081675, 0.5857978463, 0.5956993103, 0.6055110693, 0.6152315736,
-0.6248595119, 0.6343932748, 0.6438315511, 0.6531728506, 0.6624158025,
-0.6715589762, 0.6806010008, 0.6895405650, 0.6983762383, 0.7071067691,
-0.7157308459, 0.7242470980, 0.7326542735, 0.7409511209, 0.7491363883,
-0.7572088242, 0.7651672959, 0.7730104327, 0.7807372212, 0.7883464098,
-0.7958369255, 0.8032075167, 0.8104572296, 0.8175848126, 0.8245893121,
-0.8314695954, 0.8382247090, 0.8448535800, 0.8513551950, 0.8577286005,
-0.8639728427, 0.8700869679, 0.8760700822, 0.8819212317, 0.8876396418,
-0.8932242990, 0.8986744881, 0.9039893150, 0.9091680050, 0.9142097831,
-0.9191138744, 0.9238795042, 0.9285060763, 0.9329928160, 0.9373390079,
-0.9415440559, 0.9456073046, 0.9495281577, 0.9533060193, 0.9569403529,
-0.9604305029, 0.9637760520, 0.9669764638, 0.9700312614, 0.9729399681,
-0.9757021070, 0.9783173800, 0.9807852507, 0.9831054807, 0.9852776527,
-0.9873014092, 0.9891765118, 0.9909026623, 0.9924795032, 0.9939069748,
-0.9951847196, 0.9963126183, 0.9972904325, 0.9981181026, 0.9987954497,
-0.9993223548, 0.9996988177, 0.9999247193, 1.0000000000
-};
-
-unsigned char nelly_center_table[64] = {
-0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120,
-4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124,
-2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122,
-6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126
-};
-
-static void center(float *audio)
-{
-       int i, j;
-       float ftmp;
-
-       for (i = 0; i < NELLY_BUF_LEN; i+=2) {
-               j = nelly_center_table[i/2];
-               if (j > i) {
-                       ftmp = audio[j];
-                       audio[j] = audio[i];
-                       audio[i] = ftmp;
-                       ftmp = audio[j+1];
-                       audio[j+1] = audio[i+1];
-                       audio[i+1] = ftmp;
-               }
-       }
-}
-
-static void inverse_dft(float *audio)
-{
-       int i, j, k, advance;
-       float *aptr, a, b, c, d, e, f;
-
-       aptr = audio;
-       for (i = 0; i < NELLY_BUF_LEN/4; i++) {
-               a = *aptr;
-               b = *(aptr+2);
-               c = *(aptr+1);
-               d = *(aptr+3);
-
-               *(aptr+2) = a-b;
-               *aptr = a+b;
-               *(aptr+3) = c-d;
-               *(aptr+1) = c+d;
-
-               aptr += 4;
-       }
-
-       aptr = audio;
-       for (i = 0; i < NELLY_BUF_LEN/8; i++) {
-               a = *aptr;
-               b = *(aptr+4);
-               c = *(aptr+1);
-               d = *(aptr+5);
-
-               *(aptr+4) = a-b;
-               *(aptr+5) = c-d;
-               *aptr = a+b;
-               *(aptr+1) = c+d;
-
-               aptr += 2;
-
-               a = *aptr;
-               b = *(aptr+5);
-               c = *(aptr+1);
-               d = *(aptr+4);
-
-               *(aptr+4) = a-b;
-               *aptr = a+b;
-               *(aptr+5) = c+d;
-               *(aptr+1) = c-d;
-
-               aptr += 6;
-       }
-
-       i = 0;
-       for (advance = 8; advance < NELLY_BUF_LEN; advance *= 2) {
-               aptr = audio;
-
-               for (k = 0; k < NELLY_BUF_LEN/(2*advance); k++) {
-                       for (j = 0; j < advance/4; j++) {
-                               a = nelly_inv_dft_table[128-i];
-                               b = *(aptr+advance);
-                               c = nelly_inv_dft_table[i];
-                               d = *(aptr+advance+1);
-                               e = *aptr;
-                               f = *(aptr+1);
-
-                               *(aptr+advance) = e-(a*b+c*d);
-                               *aptr = e+(a*b+c*d);
-                               *(aptr+advance+1) = f+(b*c-a*d);
-                               *(aptr+1) = f-(b*c-a*d);
-
-                               i += 512/advance;
-                               aptr += 2;
-                       }
-
-                       for (j = 0; j < advance/4; j++) {
-                               a = nelly_inv_dft_table[128-i];
-                               b = *(aptr+advance);
-                               c = nelly_inv_dft_table[i];
-                               d = *(aptr+advance+1);
-                               e = *aptr;
-                               f = *(aptr+1);
-
-                               *(aptr+advance) = e+(a*b-c*d);
-                               *aptr = e-(a*b-c*d);
-                               *(aptr+advance+1) = f+(a*d+b*c);
-                               *(aptr+1) = f-(a*d+b*c);
-
-                               i -= 512/advance;
-                               aptr += 2;
-                       }
-
-                       aptr += advance;
-               }
-       }
-}
-
-static void unpack_coeffs(float *buf, float *audio)
-{
-       int i, end, mid_hi, mid_lo;
-       float a, b, c, d, e, f;
-
-       end = NELLY_BUF_LEN-1;
-       mid_hi = NELLY_BUF_LEN/2;
-       mid_lo = mid_hi-1;
-
-       for (i = 0; i < NELLY_BUF_LEN/4; i++) {
-               a = buf[end-(2*i)];
-               b = buf[2*i];
-               c = buf[(2*i)+1];
-               d = buf[end-(2*i)-1];
-               e = nelly_pos_unpack_table[i];
-               f = nelly_neg_unpack_table[i];
-
-               audio[2*i] = b*e-a*f;
-               audio[(2*i)+1] = a*e+b*f;
-
-               a = nelly_neg_unpack_table[mid_lo-i];
-               b = nelly_pos_unpack_table[mid_lo-i];
-
-               audio[end-(2*i)-1] = b*d-a*c;
-               audio[end-(2*i)] = b*c+a*d;
-       }
-}
-
-static void complex2signal(float *audio)
-{
-       int i, end, mid_hi, mid_lo;
-       float *aptr, *sigptr, a, b, c, d, e, f, g;
-
-       end = NELLY_BUF_LEN-1;
-       mid_hi = NELLY_BUF_LEN/2;
-       mid_lo = mid_hi-1;
-
-       a = audio[end];
-       b = audio[end-1];
-       c = audio[1];
-       d = nelly_signal_table[0];
-       e = audio[0];
-       f = nelly_signal_table[mid_lo];
-       g = nelly_signal_table[1];
-
-       audio[0] = d*e;
-       audio[1] = b*g-a*f;
-       audio[end-1] = a*g+b*f;
-       audio[end] = c*(-d);
-
-       aptr = audio+end-2;
-       sigptr = nelly_signal_table+mid_hi-1;
-
-       for (i = 3; i < NELLY_BUF_LEN/2; i += 2) {
-               a = audio[i-1];
-               b = audio[i];
-               c = nelly_signal_table[i/2];
-               d = *sigptr;
-               e = *(aptr-1);
-               f = *aptr;
-
-               audio[i-1] = a*c+b*d;
-               *aptr = a*d-b*c;
-
-               a = nelly_signal_table[(i/2)+1];
-               b = *(sigptr-1);
-
-               *(aptr-1) = b*e+a*f;
-               audio[i] = a*e-b*f;
-
-               sigptr--;
-               aptr -= 2;
-       }
-}
-
-static void apply_state(float *state, float *audio)
-{
-       int bot, mid_up, mid_down, top;
-       float s_bot, s_top;
-       float *t = nelly_state_table;
-
-       bot = 0;
-       top = NELLY_BUF_LEN-1;
-       mid_up = NELLY_BUF_LEN/2;
-       mid_down = (NELLY_BUF_LEN/2)-1;
-
-       while (bot < NELLY_BUF_LEN/4) {
-               s_bot = audio[bot];
-               s_top = audio[top];
-
-               audio[bot] = audio[mid_up]*t[bot]+state[bot]*t[top];
-               audio[top] = state[bot]*t[bot]-audio[mid_up]*t[top];
-               state[bot] = -audio[mid_down];
-
-               audio[mid_down] = s_top*t[mid_down]+state[mid_down]*t[mid_up];
-               audio[mid_up] = state[mid_down]*t[mid_down]-s_top*t[mid_up];
-               state[mid_down] = -s_bot;
-
-               bot++;
-               mid_up++;
-               mid_down--;
-               top--;
-       }
-}
-
-static int sum_bits(short *buf, short shift, short off)
-{
-       int b, i = 0, ret = 0;
-
-       for (i = 0; i < NELLY_FILL_LEN; i++) {
-               b = buf[i] - off;
-               if (b < 0)
-                       b = 0;
-               b = ((b>>(shift-1))+1)>>1;
-               if (b > NELLY_BIT_CAP)
-                       ret += NELLY_BIT_CAP;
-               else
-                       ret += b;
-       }
-
-       return ret;
-}
-
-static int headroom(int *la, short *sa)
-{
-       if (*la == 0)
-               *sa += 31;
-       else if (*la < 0) {
-               while (*la > -1<<30) {
-                       *la <<= 1;
-                       (*sa)++;
-               }
-       } else {
-               while (*la < 1<<30) {
-                       *la <<= 1;
-                       (*sa)++;
-               }
-       }
-
-       return *la;
-}
-
-static void get_sample_bits(float *buf, int *bits)
-{
-       int i = 0, j;
-       short sbuf[128];
-       int bitsum = 0, last_bitsum, small_bitsum, big_bitsum;
-       short shift = -16, shift_saved;
-       int tmp = 0;
-       int big_off;
-       int off, diff;
-
-       for (; i < NELLY_FILL_LEN; i++) {
-               if (buf[i] > tmp)
-                       tmp = static_cast<int>(buf[i]);
-       }
-
-       headroom(&tmp, &shift);
-
-       if (shift < 0)
-               for (i = 0; i < NELLY_FILL_LEN; i++)
-                       sbuf[i] = ((int)buf[i]) >> -shift;
-       else
-               for (i = 0; i < NELLY_FILL_LEN; i++)
-                       sbuf[i] = ((int)buf[i]) << shift;
-
-       for (i = 0; i < NELLY_FILL_LEN; i++)
-               sbuf[i] = (3*sbuf[i])>>2;
-
-       tmp = 0;
-       for (i = 0; i < NELLY_FILL_LEN; i++)
-               tmp += sbuf[i];
-
-       shift += 11;
-       shift_saved = shift;
-       tmp -= NELLY_DETAIL_BITS << shift;
-       headroom(&tmp, &shift);
-       off = (NELLY_BASE_OFF * (tmp>>16)) >> 15;
-       shift = shift_saved - (NELLY_BASE_SHIFT+shift-31);
-
-       if (shift < 0)
-               off >>= -shift;
-       else
-               off <<= shift;
-
-       bitsum = sum_bits(sbuf, shift_saved, off);
-
-       if (bitsum != NELLY_DETAIL_BITS) {
-               shift = 0;
-               diff = bitsum - NELLY_DETAIL_BITS;
-
-               if (diff > 0) {
-                       while (diff <= 16383) {
-                               shift++;
-                               diff *= 2;
-                       }
-               } else {
-                       while (diff >= -16383) {
-                               shift++;
-                               diff *= 2;
-                       }
-               }
-
-               diff = (diff * NELLY_BASE_OFF) >> 15;
-               shift = shift_saved-(NELLY_BASE_SHIFT+shift-15);
-
-               if (shift > 0) {
-                       diff <<= shift;
-               } else {
-                       diff >>= -shift;
-               }
-
-               for (j = 1; j < 20; j++) {
-                       tmp = off;
-                       off += diff;
-                       last_bitsum = bitsum;
-
-                       bitsum = sum_bits(sbuf, shift_saved, off);
-
-                       if ((bitsum-NELLY_DETAIL_BITS) * 
(last_bitsum-NELLY_DETAIL_BITS) <= 0)
-                               break;
-               }
-
-               if (bitsum != NELLY_DETAIL_BITS) {
-                       if (bitsum > NELLY_DETAIL_BITS) {
-                               big_off = off;
-                               off = tmp;
-                               big_bitsum=bitsum;
-                               small_bitsum=last_bitsum;
-                       } else {
-                               big_off = tmp;
-                               big_bitsum=last_bitsum;
-                               small_bitsum=bitsum;
-                       }
-
-                       while (bitsum != NELLY_DETAIL_BITS && j <= 19) {
-                               diff = (big_off+off)>>1;
-                               bitsum = sum_bits(sbuf, shift_saved, diff);
-                               if (bitsum > NELLY_DETAIL_BITS) {
-                                       big_off=diff;
-                                       big_bitsum=bitsum;
-                               } else {
-                                       off = diff;
-                                       small_bitsum=bitsum;
-                               }
-                               j++;
-                       }
-
-                       if (abs(big_bitsum-NELLY_DETAIL_BITS) >=
-                           abs(small_bitsum-NELLY_DETAIL_BITS)) {
-                               bitsum = small_bitsum;
-                       } else {
-                               off = big_off;
-                               bitsum = big_bitsum;
-                       }
-
-               }
-       }
-
-       for (i = 0; i < NELLY_FILL_LEN; i++) {
-               tmp = sbuf[i]-off;
-               if (tmp < 0)
-                       tmp = 0;
-               else
-                       tmp = ((tmp>>(shift_saved-1))+1)>>1;
-
-               if (tmp > NELLY_BIT_CAP)
-                       tmp = NELLY_BIT_CAP;
-               bits[i] = tmp;
-       }
-
-       if (bitsum > NELLY_DETAIL_BITS) {
-               tmp = i = 0;
-               while (tmp < NELLY_DETAIL_BITS) {
-                       tmp += bits[i];
-                       i++;
-               }
-
-               tmp -= bits[i-1];
-               bits[i-1] = NELLY_DETAIL_BITS-tmp;
-               bitsum = NELLY_DETAIL_BITS;
-               while (i < NELLY_FILL_LEN) {
-                       bits[i] = 0;
-                       i++;
-               }
-       }
-}
-
-static unsigned
-char get_bits(const unsigned char block[NELLY_BLOCK_LEN], int *off, int n)
-{
-       char ret;
-       int boff = *off/8, bitpos = *off%8, mask = (1<<n)-1;
-
-       if (bitpos+n > 8) {
-               ret = block[boff%NELLY_BLOCK_LEN] >> bitpos;
-               mask >>= 8-bitpos;
-               ret |= (block[(boff+1)%NELLY_BLOCK_LEN] & mask) << (8-bitpos);
-       } else {
-               ret = (block[boff%NELLY_BLOCK_LEN] >> bitpos) & mask;
-       }
-       
-       *off += n;
-       return ret;
-}
-
-static int
-gimme_random()
-{
-       using namespace boost;
-       
-    typedef boost::mt11213b RNG;
-
-    static RNG rnd;
-
-       uniform_int<> dist(0, std::numeric_limits<int>::max());
-       variate_generator<RNG, uniform_int<> > uni(rnd, dist);
-
-       return uni();
-}
-
-static void
-nelly_decode_block(nelly_handle* nh, const unsigned char 
block[NELLY_BLOCK_LEN], float audio[256])
-{
-       int i,j;
-       float buf[NELLY_BUF_LEN], pows[NELLY_BUF_LEN];
-       float *aptr, *bptr, *pptr, val, pval;
-       int bits[NELLY_BUF_LEN];
-       unsigned char v;
-       int bit_offset = 0;
-
-       bptr = buf;
-       pptr = pows;
-       val = nelly_init_table[get_bits(block, &bit_offset, 6)];
-       for (i = 0; i < 23; i++) {
-               if (i > 0)
-                       val += nelly_delta_table[get_bits(block, &bit_offset, 
5)];
-               pval = std::pow(2, val/2048);
-               for (j = 0; j < nelly_copy_count[i]; j++) {
-                       *bptr = val;
-                       *pptr = pval;
-                       bptr++;
-                       pptr++;
-               }
-
-       }
-
-       for (i = NELLY_FILL_LEN; i < NELLY_BUF_LEN; i++)
-               buf[i] = pows[i] = 0.0;
-
-       get_sample_bits(buf, bits);
-
-       for (i = 0; i < 2; i++) {
-               aptr = audio+i*128;
-               bit_offset = NELLY_HEADER_BITS + i*NELLY_DETAIL_BITS;
-
-               for (j = 0; j < NELLY_FILL_LEN; j++) {
-                       if (bits[j] <= 0) {
-                               buf[j] = sqrt1_2*pows[j];
-
-        
-                               if (gimme_random() % 2)
-                                       buf[j] *= -1.0;
-                       } else {
-                               v = get_bits(block, &bit_offset, bits[j]);
-                               buf[j] = 
nelly_huff_table[(1<<bits[j])-1+v]*pows[j];
-                       }
-               }
-
-               unpack_coeffs(buf, aptr);
-               center(aptr);
-               inverse_dft(aptr);
-               complex2signal(aptr);
-               apply_state(nh->state, aptr);
-       }
-}
-
-static void nelly_util_floats2shorts(float audio[256], short shorts[256])
-{
-       int i;
-
-       for (i = 0; i < 256; i++) {
-               if (audio[i] >= 32767.0)
-                       shorts[i] = 32767;
-               else if (audio[i] <= -32768.0)
-                       shorts[i] = -32768;
-               else
-                       shorts[i] = (short)audio[i];
-       }
-}
-
-static nelly_handle *nelly_get_handle()
-{
-       int i;
-       nelly_handle *nh;
-
-       nh = new nelly_handle;
-
-       if (nh != NULL)
-               for (i = 0; i < 64; i++)
-                       nh->state[i] = 0.0;
-
-       return nh;
-}
-
-static void nelly_free_handle(nelly_handle *nh)
-{
-       delete nh;
-}
-
-
-AudioDecoderNellymoser::AudioDecoderNellymoser()
-       :
-       _sampleRate(0),
-       _stereo(false)
-{
-       _nh = nelly_get_handle();
-}
-
-       
-AudioDecoderNellymoser::AudioDecoderNellymoser(const AudioInfo& info)
-       :
-       _sampleRate(0),
-       _stereo(false)
-{
-    setup(info);
-       _nh = nelly_get_handle();
-
-    assert(info.type == FLASH); // or we'd have thrown an exception
-    audioCodecType codec = (audioCodecType)info.codec;
-       log_debug(_("AudioDecoderNellymoser: initialized FLASH codec %s (%d)"),
-               (int)codec, codec);
-}
-
-
-AudioDecoderNellymoser::AudioDecoderNellymoser(const SoundInfo& info)
-       :
-       _sampleRate(0),
-       _stereo(false)
-{
-    setup(info);
-       _nh = nelly_get_handle();
-
-    audioCodecType codec = info.getFormat();
-       log_debug(_("AudioDecoderNellymoser: initialized FLASH codec %s (%d)"),
-               (int)codec, codec);
-}
-
-
-AudioDecoderNellymoser::~AudioDecoderNellymoser()
-{
-       nelly_free_handle(_nh);
-}
-
-void
-AudioDecoderNellymoser::setup(const SoundInfo& info)
-{
-       audioCodecType codec = info.getFormat();
-    switch (codec)
-    {
-        case AUDIO_CODEC_NELLYMOSER:
-        case AUDIO_CODEC_NELLYMOSER_8HZ_MONO:
-            _sampleRate = info.getSampleRate();
-            _stereo = info.isStereo();
-            break;
-
-        default:
-            boost::format err = boost::format(
-                _("AudioDecoderNellymoser: attempt to use with flash codec %d 
(%s)"))
-                % (int)codec % codec;
-            throw MediaException(err.str());
-       }
-}
-
-void AudioDecoderNellymoser::setup(const AudioInfo& info)
-{
-       if (info.type != FLASH)
-    {
-        boost::format err = boost::format(
-            _("AudioDecoderNellymoser: unable to intepret custom audio codec 
id %s"))
-            % info.codec;
-        throw MediaException(err.str());
-    }
-
-       audioCodecType codec = static_cast<audioCodecType>(info.codec);
-    switch (codec)
-    {
-        case AUDIO_CODEC_NELLYMOSER:
-        case AUDIO_CODEC_NELLYMOSER_8HZ_MONO:
-            _sampleRate = info.sampleRate;
-            _stereo = info.stereo;
-            break;
-
-        default:
-            boost::format err = boost::format(
-                _("AudioDecoderNellymoser: attempt to use with flash codec %d 
(%s)"))
-                % (int)codec % codec;
-            throw MediaException(err.str());
-       }
-}
-
-float*
-AudioDecoderNellymoser::decode(const boost::uint8_t* in_buf, boost::uint32_t 
inputSize, boost::uint32_t* outputSize)
-{
-    size_t out_buf_size = (inputSize / NELLY_BLOCK_LEN) * 256;
-       float* out_buf = new float[out_buf_size];
-       
-       const boost::uint8_t* input_ptr = in_buf;
-       float* output_ptr = out_buf;
-
-       while (inputSize > 0) {
-               nelly_decode_block(_nh, input_ptr, output_ptr);
-               input_ptr += NELLY_BLOCK_LEN;
-               inputSize -= NELLY_BLOCK_LEN;
-               output_ptr += 256;
-       }
-       
-       *outputSize = out_buf_size;
-       
-       return out_buf; 
-}
-
-boost::uint8_t*
-AudioDecoderNellymoser::decode(const boost::uint8_t* input,
-        boost::uint32_t inputSize, boost::uint32_t& outputSize,
-        boost::uint32_t& decodedBytes, bool /*parse*/)
-{
-
-       float float_buf[256];
-       boost::uint32_t out_buf_size = (inputSize / 64) * 256;
-       boost::int16_t* out_buf = new boost::int16_t[out_buf_size];
-       boost::int16_t* out_buf_start = out_buf;
-
-       while (inputSize > 0) {
-               nelly_decode_block(_nh, input, float_buf);
-               nelly_util_floats2shorts(float_buf, out_buf);
-               out_buf += 256;
-               input += 64;
-               inputSize -= 64;
-       }
-                       
-       boost::uint8_t* tmp_raw_buffer = 
reinterpret_cast<boost::uint8_t*>(out_buf_start);
-       boost::uint32_t tmp_raw_buffer_size = out_buf_size * 2;
-#if 0
-       // If we need to convert samplerate or/and from mono to stereo...
-       if (out_buf_size > 0 && (_sampleRate != 44100 || !_stereo)) {
-
-               boost::int16_t* adjusted_data = 0;
-               int     adjusted_size = 0;
-               int sample_count = out_buf_size / (_stereo ? 2 : 1);
-
-               // Convert to needed samplerate - this converter only support 
standard flash samplerates
-               convert_raw_data(&adjusted_data, &adjusted_size, 
tmp_raw_buffer, sample_count, 0, 
-                               _sampleRate, _stereo,
-                               44100,  true /* stereo */);
-
-               // Hopefully this wont happen
-               if (!adjusted_data) {
-                       log_error(_("Error in sound sample conversion"));
-                       delete[] tmp_raw_buffer;
-                       outputSize = 0;
-                       decodedBytes = 0;
-                       return NULL;
-               }
-
-               // Move the new data to the sound-struct
-               delete[] tmp_raw_buffer;
-               tmp_raw_buffer = 
reinterpret_cast<boost::uint8_t*>(adjusted_data);
-               tmp_raw_buffer_size = adjusted_size;
-
-       } else {
-#endif
-               tmp_raw_buffer_size = out_buf_size;
-#if 0
-       }
-#endif
-
-       outputSize = tmp_raw_buffer_size;
-       decodedBytes = inputSize;
-       return tmp_raw_buffer;
-}
-
-} // gnash.media namespace 
-} // namespace gnash
-

=== removed file 'libmedia/AudioDecoderNellymoser.h'
--- a/libmedia/AudioDecoderNellymoser.h 2010-01-01 17:48:26 +0000
+++ b/libmedia/AudioDecoderNellymoser.h 1970-01-01 00:00:00 +0000
@@ -1,140 +0,0 @@
-// AudioDecoderNellymoser.h: Nellymoser decoding
-// 
-//   Copyright (C) 2007, 2008, 2009, 2010 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 3 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
-
-
-// This file incorporates work covered by the following copyright and 
permission
-// notice:
-
-/*
- * Copyright (c) 2007 a840bda5870ba11f19698ff6eb9581dfb0f95fa5,
- *                    539459aeb7d425140b62a3ec7dbf6dc8e408a306, and
- *                    520e17cd55896441042b14df2566a6eb610ed444
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef GNASH_AUDIODECODERNELLYMOSER_H
-#define GNASH_AUDIODECODERNELLYMOSER_H
-
-#include "AudioDecoder.h" // for inheritance
-
-#define NELLY_BLOCK_LEN 64
-#define NELLY_HEADER_BITS 116
-#define NELLY_DETAIL_BITS 198
-#define NELLY_BUF_LEN 128
-#define NELLY_FILL_LEN 124
-#define NELLY_BIT_CAP 6
-#define NELLY_BASE_OFF 4228
-#define NELLY_BASE_SHIFT 19
-
-// Forward declarations
-namespace gnash {
-    namespace media {
-        class AudioInfo;
-        class SoundInfo;
-    }
-}
-
-
-typedef struct nelly_handle_struct {
-    float state[64];
-} nelly_handle;
-
-namespace gnash {
-namespace media {
-
-/// Audio decoding using internal Nellymoser decoder.
-//
-/// TODO: as ffmpeg now has Nellymoser support (maintained
-/// by people who know what they're doing, I hope), do
-/// we need this?
-class AudioDecoderNellymoser : public AudioDecoder {
-
-public:
-
-    /// This is needed by gstreamer still. TODO: drop.
-    AudioDecoderNellymoser();
-
-    /// @param info
-    ///     AudioInfo class with all the info needed to decode
-    ///     the sound correctly. Throws a MediaException on fatal
-    ///     error.
-    ///
-    /// @throws MediaException on failure
-    ///
-    AudioDecoderNellymoser(const AudioInfo& info);
-
-    /// @param info
-    ///     SoundInfo class with all the info needed to decode
-    ///     the sound correctly. Throws a MediaException on fatal
-    ///      error.
-    /// 
-    /// @deprecated use the AudioInfo based constructor
-    ///
-    /// @throws MediaException on failure
-    ///
-    AudioDecoderNellymoser(const SoundInfo& info);
-
-    ~AudioDecoderNellymoser();
-
-    // See dox in AudioDecoder.h
-    boost::uint8_t* decode(const boost::uint8_t* input,
-        boost::uint32_t inputSize, boost::uint32_t& outputSize,
-        boost::uint32_t& decodedBytes, bool parse);
-    
-private:
-
-    /// @return a new[]-allocated pointer to decoded data in floats.
-    float* decode(const boost::uint8_t* in_buf, boost::uint32_t inputSize,
-            boost::uint32_t* outputSize);
-
-
-    void setup(const AudioInfo& info);
-    void setup(const SoundInfo& info);
-
-    // The handle used by the decoder
-    nelly_handle* _nh;
-
-    // samplerate
-    boost::uint16_t _sampleRate;
-
-    // stereo
-    bool _stereo;
-};
-    
-} // gnash.media namespace 
-} // gnash namespace
-
-#endif // __AUDIODECODERNELLYMOSER_H__
-    

=== modified file 'libmedia/Makefile.am'
--- a/libmedia/Makefile.am      2010-02-08 00:05:16 +0000
+++ b/libmedia/Makefile.am      2010-02-10 17:02:22 +0000
@@ -58,7 +58,6 @@
 
 libgnashmedia_la_SOURCES = \
        MediaHandler.cpp \
-       AudioDecoderNellymoser.cpp \
        AudioDecoderSimple.cpp \
        MediaParser.cpp \
        FLVParser.cpp \
@@ -72,7 +71,6 @@
        MediaParser.h \
        MediaHandler.h \
        FLVParser.h \
-       AudioDecoderNellymoser.h \
        AudioDecoderSimple.h \
        SoundInfo.h \
        AudioResampler.h \

=== modified file 'libmedia/MediaHandler.cpp'
--- a/libmedia/MediaHandler.cpp 2010-01-18 09:26:03 +0000
+++ b/libmedia/MediaHandler.cpp 2010-02-10 17:02:22 +0000
@@ -26,7 +26,6 @@
 #include "FLVParser.h"
 #include "IOChannel.h"
 #include "AudioDecoderSimple.h"
-#include "AudioDecoderNellymoser.h"
 #include "log.h"
 
 #ifdef DECODING_SPEEX
@@ -88,13 +87,6 @@
     audioCodecType codec = static_cast<audioCodecType>(info.codec);
     switch (codec)
     {
-        case AUDIO_CODEC_NELLYMOSER:
-        case AUDIO_CODEC_NELLYMOSER_8HZ_MONO:
-        {
-            std::auto_ptr<AudioDecoder> ret(new AudioDecoderNellymoser(info));
-            return ret;
-        }
-
         case media::AUDIO_CODEC_ADPCM:
         case media::AUDIO_CODEC_RAW:
         {

=== modified file 'testsuite/Makefile.am'
--- a/testsuite/Makefile.am     2010-01-22 16:18:18 +0000
+++ b/testsuite/Makefile.am     2010-02-09 16:21:45 +0000
@@ -79,11 +79,6 @@
        media \
        $(DIR_AS3) \
        $(DIR_SWFDEC_TESTSUITE) \
-       libnet.all \
-       libbase.all     \
-       libamf.all \
-       libmedia.all \
-       libcore.all \
        samples \
        $(DIR_MING) \
        $(DIR_MTASC) \
@@ -91,6 +86,11 @@
        $(DIR_SWFMILL) \
        $(DIR_SWFC) \
        movies.all \
+       libnet.all \
+       libbase.all     \
+       libamf.all \
+       libmedia.all \
+       libcore.all \
        $(NULL)
 
 EXTRA_DIST = check.h DummyMovieDefinition.h DummyCharacter.h gnashrc.in 
simple.exp 

=== modified file 'testsuite/actionscript.all/LocalConnection.as'
--- a/testsuite/actionscript.all/LocalConnection.as     2010-01-11 06:41:38 
+0000
+++ b/testsuite/actionscript.all/LocalConnection.as     2010-02-08 16:22:09 
+0000
@@ -118,8 +118,8 @@
 result = rec.connect("lc_test");
 check_equals (rec.domain(), "localhost");
 
-// NOTE: This test will fail if a shared memory segment of the same
-// name exists. So the first time it'll pass, then it'll fail.
+// NOTE: This test will fail if already connected.
+// So the first time it'll pass, then it'll fail.
 check_equals (result, true);
 
 // Checks only for syntactical correctness, not success

=== modified file 'testsuite/gnashrc.in'
--- a/testsuite/gnashrc.in      2009-01-19 08:05:42 +0000
+++ b/testsuite/gnashrc.in      2010-02-11 08:53:19 +0000
@@ -44,4 +44,7 @@
 # Blacklist (for testing NetConnection)
 set blacklist www.blacklistedserver.org
 
+# LocalConnection must be enabled for testing.
+set localconnection false
+
 # TODO: enable extensions ?

=== modified file 'testsuite/libamf.all/Makefile.am'
--- a/testsuite/libamf.all/Makefile.am  2010-01-22 15:05:33 +0000
+++ b/testsuite/libamf.all/Makefile.am  2010-02-08 20:38:34 +0000
@@ -54,9 +54,9 @@
        test_amf \
        test_amfmsg \
        test_buffer \
+       test_lc \
        test_el \
        test_sol \
-       test_lc \
        test_flv
 
 test_el_SOURCES = test_el.cpp

=== modified file 'testsuite/libamf.all/test_amf.cpp'
--- a/testsuite/libamf.all/test_amf.cpp 2010-01-01 20:41:28 +0000
+++ b/testsuite/libamf.all/test_amf.cpp 2010-02-08 19:35:15 +0000
@@ -44,7 +44,11 @@
 #include "element.h"
 #include "gmemory.h"
 
-using namespace amf;
+using amf::AMF;
+using amf::Element;
+using amf::Buffer;
+using amf::swapBytes;
+
 using namespace gnash;
 using namespace std;
 
@@ -140,9 +144,9 @@
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
    if (memdebug) {
         if (mem->analyze()) {
-            runtest.pass("AMF doesn't leak memory");
+            runtest.pass("amf::AMF doesn't leak memory");
         } else {
-            runtest.fail("AMF leaks memory!");
+            runtest.fail("amf::AMF leaks memory!");
         }
     }
 #endif
@@ -168,8 +172,8 @@
         mem->addStats(__LINE__);             // take a sample
     }
 #endif    
-    boost::shared_ptr<Buffer> encnum = AMF::encodeNumber(num);
-    // A number AMF object has only one header byte, which is the type field.
+    boost::shared_ptr<Buffer> encnum = amf::AMF::encodeNumber(num);
+    // A number amf::AMF object has only one header byte, which is the type 
field.
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
     if (memdebug) {
         mem->addStats(__LINE__);             // take a sample
@@ -177,12 +181,12 @@
 #endif
     if ((*encnum->reference() == Element::NUMBER_AMF0) &&
         (memcmp(buf1->reference(), encnum->reference()+1, 
amf::AMF0_NUMBER_SIZE) == 0)) {
-        runtest.pass("Encoded AMF Number");
+        runtest.pass("Encoded amf::AMF Number");
     } else {
-        runtest.fail("Encoded AMF Number");
+        runtest.fail("Encoded amf::AMF Number");
     }
     
-    // Encode a boolean. Although we know a bool is only one character, for 
AMF,
+    // Encode a boolean. Although we know a bool is only one character, for 
amf::AMF,
     // it's actually a two byte short instead.
     {
         bool flag = true;
@@ -194,22 +198,22 @@
             mem->addStats(__LINE__);             // take a sample
         }
 #endif
-        boost::shared_ptr<Buffer> encbool = AMF::encodeBoolean(flag);
+        boost::shared_ptr<Buffer> encbool = amf::AMF::encodeBoolean(flag);
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
         if (memdebug) {
             mem->addStats(__LINE__);             // take a sample
         }
 #endif
     
-        // A boolean AMF object has only one header byte, which is the type 
field.
+        // A boolean amf::AMF object has only one header byte, which is the 
type field.
         // AMF3 changes this to being two different type, FALSE & TRUE
         // which are finally only one byte apiece.
         if ((*encbool->reference() == Element::BOOLEAN_AMF0) &&
             (encbool->size() == 2) &&
             (memcmp(buf2->reference(), encbool->reference(), 
sizeof(boost::uint16_t)) == 0)) {
-            runtest.pass("Encoded AMF Boolean");
+            runtest.pass("Encoded amf::AMF Boolean");
         } else {
-            runtest.fail("Encoded AMF Boolean");
+            runtest.fail("Encoded amf::AMF Boolean");
         }
     }
     
@@ -221,23 +225,23 @@
             mem->addStats(__LINE__);             // take a sample
         }
 #endif
-        boost::shared_ptr<Buffer> buf = AMF::encodeString(str);
+        boost::shared_ptr<Buffer> buf = amf::AMF::encodeString(str);
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
         if (memdebug) {
             mem->addStats(__LINE__);             // take a sample
         }
 #endif
         check_equals(*buf->reference(), Element::STRING_AMF0);
-        check_equals(buf->size(), str.size()+AMF_HEADER_SIZE);
-        // A String AMF object has a 3 bytes head, the type, and a two byte 
length.
+        check_equals(buf->size(), str.size()+amf::AMF_HEADER_SIZE);
+        // A String amf::AMF object has a 3 bytes head, the type, and a two 
byte length.
         check((memcmp(buf->reference() + 3, str.c_str(), str.size()) == 0));
 
         Element el(str);
-        buf = AMF::encodeElement(el);
+        buf = amf::AMF::encodeElement(el);
         
         check_equals(*buf->reference(), Element::STRING_AMF0);
-        check_equals(buf->size(), str.size()+AMF_HEADER_SIZE);
-        // A String AMF object has a 3 bytes head, the type, and a two byte 
length.
+        check_equals(buf->size(), str.size()+amf::AMF_HEADER_SIZE);
+        // A String amf::AMF object has a 3 bytes head, the type, and a two 
byte length.
         check((memcmp(buf->reference() + 3, str.c_str(), str.size()) == 0));
     }
     
@@ -248,7 +252,7 @@
             mem->addStats(__LINE__);             // take a sample
         }
 #endif
-        boost::shared_ptr<Buffer> buf = AMF::encodeNullString();
+        boost::shared_ptr<Buffer> buf = amf::AMF::encodeNullString();
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
         if (memdebug) {
             mem->addStats(__LINE__);             // take a sample
@@ -256,23 +260,23 @@
 #endif
         boost::uint16_t len = *(boost::uint16_t *)(buf->reference() + 1);
 
-        // A NULL String AMF object has just 3 bytes, the type, and a two byte 
length, which is zero.
+        // A NULL String amf::AMF object has just 3 bytes, the type, and a two 
byte length, which is zero.
         check_equals(*buf->reference(), Element::STRING_AMF0);
-        check_equals(buf->size(), (size_t)AMF_HEADER_SIZE);
+        check_equals(buf->size(), (size_t)amf::AMF_HEADER_SIZE);
         check_equals(len, 0);
 
         Element el;
         el.makeNullString();
-        buf = AMF::encodeElement(el);
+        buf = amf::AMF::encodeElement(el);
         len = *(boost::uint16_t *)(buf->reference() + 1);
 
-        // A NULL String AMF object has just 3 bytes, the type, and a two byte 
length, which is zero.
+        // A NULL String amf::AMF object has just 3 bytes, the type, and a two 
byte length, which is zero.
         check_equals(*buf->reference(), Element::STRING_AMF0);
-        check_equals(buf->size(), (size_t)AMF_HEADER_SIZE);
+        check_equals(buf->size(), (size_t)amf::AMF_HEADER_SIZE);
         check_equals(len, 0);
     }
 
-    AMF amf;
+    amf::AMF amf;
     Element el1;
     boost::uint16_t index = 1;
     el1.makeReference(index);
@@ -306,7 +310,7 @@
 test_array()
 {
     Element top;
-    AMF amf;
+    amf::AMF amf;
     top.makeObject();
 
     boost::shared_ptr<Buffer> hex1(new Buffer("08 00 00 00 0a 00 08 64 75 72 
61 74 69 6f 6e 00 40 ad 04 14 7a e1 47 ae 00 05 77 69 64 74 68 00 40 74 00 00 
00 00 00 00 00 06 68 65 69 67 68 74 00 40 6e 00 00 00 00 00 00 00 0d 76 69 64 
65 6f 64 61 74 61 72 61 74 65 00 40 72 c0 00 00 00 00 00 00 09 66 72 61 6d 65 
72 61 74 65 00 40 39 00 00 00 00 00 00 00 0c 76 69 64 65 6f 63 6f 64 65 63 69 
64 00 40 10 00 00 00 00 00 00 00 0d 61 75 64 69 6f 64 61 74 61 72 61 74 65 00 
40 58 00 00 00 00 00 00 00 0a 61 75 64 69 6f 64 65 6c 61 79 00 3f a3 74 bc 6a 
7e f9 db 00 0c 61 75 64 69 6f 63 6f 64 65 63 69 64 00 40 00 00 00 00 00 00 00 
00 0c 63 61 6e 53 65 65 6b 54 6f 45 6e 64 01 01 00 00 09"));
@@ -382,7 +386,7 @@
 
 //    buf1->dump();
     
-    AMF amf_obj;
+    amf::AMF amf_obj;
 #if defined(HAVE_MALLINFO) && defined(USE_STATS_MEMORY)
     if (memdebug) {
         mem->addStats(__LINE__);             // take a sample
@@ -408,8 +412,8 @@
 
 }
 
-// amf::AMF::extractAMF(unsigned char*)
-// amf::AMF::extractVariable(unsigned char*)
+// amf::amf::AMF::extractAMF(unsigned char*)
+// amf::amf::AMF::extractVariable(unsigned char*)
 
 static void
 usage (void)

=== modified file 'testsuite/libamf.all/test_lc.cpp'
--- a/testsuite/libamf.all/test_lc.cpp  2010-01-11 06:41:38 +0000
+++ b/testsuite/libamf.all/test_lc.cpp  2010-02-09 16:13:42 +0000
@@ -59,7 +59,7 @@
 #include "dejagnu.h"
 
 #include "amf.h"
-#include "shm.h"
+#include "SharedMem.h"
 #include "lcshm.h"
 
 using namespace amf;
@@ -132,12 +132,12 @@
     }
     
     //
-    shmaddr = lc.getAddr();
+    shmaddr = reinterpret_cast<char*>(lc.begin());
     if (shmaddr == 0) {
-        runtest.unresolved("LcShm::getAddr()");
+        runtest.unresolved("LcShm::begin()");
         return;
     } else {
-        runtest.pass("LcShm::getAddr()");
+        runtest.pass("LcShm::begin()");
     }
     
     char *addr = shmaddr + LC_LISTENERS_START;
@@ -215,7 +215,7 @@
         runtest.fail("LcShm::connect(localhost:lc_reply)");
     }
 
-    shmaddr = lcs.getAddr();     // for gdb
+    shmaddr = reinterpret_cast<char*>(lcs.begin());     // for gdb
 
     Element *el;
     vector<amf::Element *> els;
@@ -274,7 +274,7 @@
         exit(0);
     }
 
-    shmaddr = lc.getAddr();
+    shmaddr = reinterpret_cast<char*>(lc.begin());
 //    if (memcmp(shmaddr, con1.c_str():
     // Since this is a test case, populate the memory with known good data
     string srcdir = SRCDIR;
@@ -311,7 +311,7 @@
         runtest.fail("LcShm::connect()");
     }
 
-    shmaddr = lc.getAddr();
+    shmaddr = reinterpret_cast<char*>(lc.begin());
 //    if (memcmp(shmaddr, con1.c_str():
     // Since this is a test case, populate the memory with known good data
     string srcdir = SRCDIR;
@@ -586,7 +586,7 @@
 
 #if 0 // { // what are these Listeners ?
 
-    Listener::setBaseAddress(Shm::getAddr());
+    Listener::setBaseAddress(Shm::begin());
         
     string str1 = "HelloWorld";
     addListener(str1);

=== modified file 'testsuite/libbase.all/gnashrc.in'
--- a/testsuite/libbase.all/gnashrc.in  2009-07-21 21:54:27 +0000
+++ b/testsuite/libbase.all/gnashrc.in  2010-02-11 08:33:14 +0000
@@ -86,9 +86,6 @@
 # Disable using LocalConnection
 set LocalConnection on
 
-# Trace all object flowing gthrough LocalConnection
-set LCTrace on
-
 # This is the shared memory key for your system
 set LCShmKey 3711621821
 

=== modified file 'testsuite/libnet.all/generate_amfbins.cpp'
--- a/testsuite/libnet.all/generate_amfbins.cpp 2010-01-01 17:48:26 +0000
+++ b/testsuite/libnet.all/generate_amfbins.cpp 2010-02-08 19:47:22 +0000
@@ -44,7 +44,9 @@
 #include "amf.h"
 #include "element.h"
 
-using namespace amf;
+using amf::AMF;
+using amf::Element;
+using amf::Buffer;
 using namespace gnash;
 using namespace std;
 
@@ -176,46 +178,46 @@
     string str = "Guten Tag";
 
     Element elnum1(dub);
-    boost::shared_ptr<Buffer> bnum1 = AMF::encodeElement(elnum1);
+    boost::shared_ptr<Buffer> bnum1 = amf::AMF::encodeElement(elnum1);
     int fd = ::open("amf0-number.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bnum1->reference(), bnum1->allocated()); ::close(fd);
 
     flag = true;
     Element elbool1(flag);
-    boost::shared_ptr<Buffer> bbool1 = AMF::encodeElement(elbool1);
+    boost::shared_ptr<Buffer> bbool1 = amf::AMF::encodeElement(elbool1);
     fd = ::open("amf0-boolean.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bbool1->reference(), bbool1->allocated()); ::close(fd);
     
     Element elstr1(str);
-    boost::shared_ptr<Buffer> bstr1 = AMF::encodeElement(elstr1);
+    boost::shared_ptr<Buffer> bstr1 = amf::AMF::encodeElement(elstr1);
     fd = ::open("amf0-string.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bstr1->reference(), bstr1->allocated()); ::close(fd);
 
     Element el3;
     el3.clear();
     el3.makeNull();
-    boost::shared_ptr<Buffer> bel3 = AMF::encodeElement(el3);
+    boost::shared_ptr<Buffer> bel3 = amf::AMF::encodeElement(el3);
     fd = ::open("amf0-null-object.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bel3->reference(), bel3->allocated()); ::close(fd);
 
 
     Element el4;
     el4.makeUndefined();
-    boost::shared_ptr<Buffer> bel4 = AMF::encodeElement(el4);
+    boost::shared_ptr<Buffer> bel4 = amf::AMF::encodeElement(el4);
     fd = ::open("amf0-undefined-object.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bel4->reference(), bel4->allocated()); ::close(fd);
 
     Element el6;
     el6.clear();
     el6.makeNullString();
-    boost::shared_ptr<Buffer> bel6 = AMF::encodeElement(el6);
+    boost::shared_ptr<Buffer> bel6 = amf::AMF::encodeElement(el6);
     fd = ::open("amf0-null-string.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bel6->reference(), bel6->allocated()); ::close(fd);    
 
     Element el15;
     el15.clear();
     el15.makeUnsupported();
-    boost::shared_ptr<Buffer> bel15 = AMF::encodeElement(el15);
+    boost::shared_ptr<Buffer> bel15 = amf::AMF::encodeElement(el15);
     fd = ::open("amf0-unsupported-object.bin" ,O_WRONLY|O_CREAT, S_IRWXU);
     ::write(fd, bel15->reference(), bel15->allocated()); ::close(fd);
 

=== added file 'testsuite/misc-ming.all/LC-Receive.as'
--- a/testsuite/misc-ming.all/LC-Receive.as     1970-01-01 00:00:00 +0000
+++ b/testsuite/misc-ming.all/LC-Receive.as     2010-02-10 13:56:32 +0000
@@ -0,0 +1,86 @@
+#include "../actionscript.all/check.as"
+
+
+lc = new LocalConnection;
+lc.connect("lc576");
+
+lc.ready = function() {
+    trace("LC-Send is ready. Replying.");
+    lc.send("recv", "ready");
+};
+
+lc.nevercall = function()
+{
+     fail_check("Function nevercall should never be called!");
+};
+
+lc.test1 = function()
+{
+    pass_check("Function test1 called");
+};
+
+lc.test2 = function(a, b, c, d, e, f)
+{
+    check_equals(typeof(a), "number");
+    check_equals(a, 5);
+
+    check_equals(typeof(b), "boolean");
+    check_equals(b, false);
+
+    check_equals(typeof(c), "string");
+    check_equals(c, "A string");
+
+    d1 = new Date(0);
+    check_equals(typeof(d), "object");
+    check_equals(d.toString(), d1.toString());
+
+    check_equals(typeof(e), "object");
+    check(e.hasOwnProperty("aa"));
+    check_equals(typeof(e.aa), "number");
+    check(e.hasOwnProperty("bb"));
+    check(e.hasOwnProperty("cc"));
+    check(e.hasOwnProperty("dd"));
+
+};
+
+lc.test3 = function(f) {
+    check_equals(typeof(f), "object");
+    check_equals(f.toString(), "1,str,6");
+};
+
+lc.test4 = function(xml) {
+    check_equals(xml.toString(),
+        '<xml><t><t2 att="abob"><t3 /></t2><t2><t3>hi</t3></t2></t></xml>');
+    check(xml instanceof XML);
+};
+
+lc.test5 = function(g) {
+    check_equals(typeof(g), "object");
+    check_equals(g.length, 150);
+    check_equals(g[50], "element50");
+    check(g instanceof Array);
+};
+
+// Unsupported object.
+lc.test6 = function(f) {
+    check_equals(typeof(f), "undefined");
+};
+
+lc.test7 = function(c) {
+    check_equals(typeof(c), "object");
+};
+
+// Exit in 3 seconds.
+lc.endTests = function() {
+    totals();
+    trace("Finished tests. Alerting LC-Send and exiting in 3 seconds");
+    trace("ENDOFTEST");
+    lc.send("recv", "finished");
+    setInterval(exit, 3000);
+};
+
+exit = function() {
+    loadMovie ("FSCommand:quit", "");
+};
+
+stop();

=== added file 'testsuite/misc-ming.all/LC-Send.as'
--- a/testsuite/misc-ming.all/LC-Send.as        1970-01-01 00:00:00 +0000
+++ b/testsuite/misc-ming.all/LC-Send.as        2010-02-10 13:56:32 +0000
@@ -0,0 +1,87 @@
+
+#include "../actionscript.all/check.as"
+
+lc = new LocalConnection;
+lc.connect("recv");
+
+runtests = function() {
+
+    // This should not result in a call.
+    lc.send("notaconnection", "nevercalled");
+
+    // This should call the test1 function.
+    lc.send("lc576", "test1");
+
+    var a = 5;
+    var b = false;
+    var c = "A string";
+    var d = new Date(0);
+    var e = {};
+    e.aa = 6;
+    e.bb = 6;
+    e.cc = 6;
+    e.dd = 6;
+
+
+    lc.send("lc576", "test2", a, b, c, d, e);
+    
+    var f = [1, "str", 6];
+    
+    lc.send("lc576", "test3", f);
+
+    xml = new XML('<xml><t><t2 
att="abob"><t3/></t2><t2><t3>hi</t3></t2></t></xml>');
+
+    lc.send("lc576", "test4", xml);
+
+    g = [];
+    for (var i = 0; i < 150; ++i) {
+       g.push("element" + i);
+    };
+    
+    lc.send("lc576", "test5", g);
+
+    // Not supported, should become undefined.
+    xn = new XMLNode(1, "");
+    check_equals(typeof(xn), "object");
+    lc.send("lc576", "test6", xn);
+
+    // Not supported, should become undefined.
+    nc = new NetConnection;
+    check_equals(typeof(nc), "object");
+    lc.send("lc576", "test6", ns);
+
+    // Not native, should be fine.
+    c = new Color();
+    check_equals(typeof(c), "object");
+    lc.send("lc576", "test7", c);
+
+    lc.send("lc576", "endTests");
+};
+
+getit = function()
+{
+    trace("Waiting for LC-Receive to reply.");
+    lc.send("lc576", "ready");
+};
+
+// Wait until receiver is ready.
+id = setInterval(getit, 1000);
+
+lc.ready = function() {
+    trace("LC-Receive is ready. Running tests");
+    clearInterval(id);
+    runtests();
+};
+
+// Called when LC-Send has finished. Exit in 3 seconds.
+lc.finished = function() {
+    trace("Received finish signal from LC-Receive. Exiting in 3 seconds");
+    trace("ENDOFTEST");
+    setInterval(exit, 3000);
+};
+
+exit = function() {
+    loadMovie ("FSCommand:quit", "");
+};
+
+stop();

=== modified file 'testsuite/misc-ming.all/Makefile.am'
--- a/testsuite/misc-ming.all/Makefile.am       2010-01-27 19:09:02 +0000
+++ b/testsuite/misc-ming.all/Makefile.am       2010-02-10 11:43:33 +0000
@@ -37,6 +37,8 @@
        remoting.php \
        gotoFrame2Test.as \
        DrawingApiTest.as \
+       LC-Receive.as \
+       LC-Send.as \
        FlashVarsTest.as \
        SharedObjectTest.as \
        intervalTest.as \
@@ -166,6 +168,7 @@
        loadMovieTest \
        loadMovieTestRunner \
        DrawingApiTestRunner \
+       LCTestRunner \
        frame_label_test \
        path_format_test \
        callFunction_test \
@@ -1814,6 +1817,15 @@
        sh $< $(top_builddir) gotoFrame2Test.swf > $@
        chmod 755 $@
 
+LC-Receive.swf: $(srcdir)/LC-Receive.as 
+       $(MAKESWF) -v 8 -r 1 -o $@  $(srcdir)/empty.as $(srcdir)/LC-Receive.as
+
+LC-Send.swf: $(srcdir)/LC-Send.as 
+       $(MAKESWF) -v 8 -r 1 -o $@  $(srcdir)/empty.as $(srcdir)/LC-Send.as
+
+LCTestRunner: $(srcdir)/../simultaneous-testrunner.sh LC-Receive.swf 
LC-Send.swf
+       sh $< -c "ENDOFTEST" $(top_builddir) LC-Receive.swf LC-Send.swf > $@
+       chmod 755 $@
 
 DrawingApiTest.swf: $(srcdir)/DrawingApiTest.as 
        $(MAKESWF) -r 1 -o $@  $(srcdir)/empty.as $(srcdir)/DrawingApiTest.as
@@ -2048,6 +2060,7 @@
        action_execution_order_extend_testrunner \
        simple_loop_testrunner \
        loadMovieTestRunner \
+       LCTestRunner \
        DrawingApiTestRunner \
        TextSnapshotTest-Runner \
        action_execution_order_test1runner \

=== added file 'testsuite/simultaneous-testrunner.sh'
--- a/testsuite/simultaneous-testrunner.sh      1970-01-01 00:00:00 +0000
+++ b/testsuite/simultaneous-testrunner.sh      2010-02-10 11:43:33 +0000
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# 
+#   Copyright (C) 2005, 2006, 2009, 2010 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 3 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
+# 
+
+while getopts c:C: name; do
+       case $name in
+               c) endtagpat="$OPTARG" ;;
+               C) endtagpat="$OPTARG"; endtagexp=X ;;
+               ?)
+                  {
+                  echo "Usage: $0 [-r <runs>] [-f <advances>] [-c <string>]  
<swf> ..." 
+                  echo "   -c <pattern>    : verify that the test ends with a 
trace "
+           echo "                     matching <pattern>, or print a failure" 
+                  echo "   -C <pattern>    : same as -c <pattern> but a 
failure is "
+           echo "                     expected" 
+                  } >&2
+                  exit 1;;
+       esac
+done
+shift $(($OPTIND - 1))
+
+
+top_builddir=$1
+shift
+t1=$1
+shift
+t2=$1
+
+
+echo "#!/bin/sh"
+echo
+
+echo "# Environment"
+env | grep GNASH | while read REPLY; do
+       echo "export ${REPLY}"
+done
+
+timeout=10
+cat << EOF
+
+outlog1=${top_builddir}/testoutlog.\$$
+outlog2=${top_builddir}/testoutlog2.\$$
+(
+    echo "Running first process"
+    ${top_builddir}/gui/gnash -v -r0 ${t1} -t ${timeout} > \${outlog1}
+    cat \${outlog1}
+       if test "x${endtagpat}" != x; then
+               lasttrace=\`grep TRACE \${outlog1} | tail -1 | sed 's/.*TRACE: 
//'\`
+               if ! expr "\${lasttrace}" : '${endtagpat}' > /dev/null; then
+                       echo "${endtagexp}FAILED: consistency check: last trace 
from run of test \${t} (\${lasttrace}) doesn't match pattern (${endtagpat})"
+               else
+                       echo "${endtagexp}PASSED: consistency check: last trace 
from run of test \${t} (\${lasttrace}) matches pattern (${endtagpat})"
+               fi
+       fi
+    rm \${outlog1}
+) &
+(
+    echo "Running second process"
+    ${top_builddir}/gui/gnash -v -r0 ${t2} -t ${timeout} > \${outlog2}
+    cat \${outlog2}
+       if test "x${endtagpat}" != x; then
+               lasttrace=\`grep TRACE \${outlog2} | tail -1 | sed 's/.*TRACE: 
//'\`
+               if ! expr "\${lasttrace}" : '${endtagpat}' > /dev/null; then
+                       echo "${endtagexp}FAILED: consistency check: last trace 
from run of test \${t} (\${lasttrace}) doesn't match pattern (${endtagpat})"
+               else
+                       echo "${endtagexp}PASSED: consistency check: last trace 
from run of test \${t} (\${lasttrace}) matches pattern (${endtagpat})"
+               fi
+       fi
+    rm \${outlog2}
+)
+EOF

=== modified file 'utilities/Makefile.am'
--- a/utilities/Makefile.am     2010-02-08 00:05:16 +0000
+++ b/utilities/Makefile.am     2010-02-08 15:47:55 +0000
@@ -101,7 +101,7 @@
 endif
 endif
 
-bin_PROGRAMS = gprocessor soldumper dumpshm flvdumper
+bin_PROGRAMS = gprocessor soldumper flvdumper
 #check_PROGRAMS = gdebug.swf
 
 if USE_GST_ENGINE
@@ -117,8 +117,9 @@
 gprocessor_LDFLAGS = -export-dynamic
 gprocessor_LDADD = $(GNASH_LIBS) $(AM_LDFLAGS)
 
-dumpshm_SOURCES = dumpshm.cpp
-dumpshm_LDADD = $(GNASH_LIBS) $(AM_LDFLAGS)
+
+#dumpshm_SOURCES = dumpshm.cpp
+#dumpshm_LDADD = $(GNASH_LIBS) $(AM_LDFLAGS)
 
 soldumper_SOURCES = soldumper.cpp
 soldumper_LDADD = $(GNASH_LIBS) $(AM_LDFLAGS)


reply via email to

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