gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r9697: add as_value serializer (writ


From: Sandro Santilli
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r9697: add as_value serializer (writeAMF0) and support circular references
Date: Mon, 08 Sep 2008 21:45:40 +0200
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 9697
committer: Sandro Santilli <address@hidden>
branch nick: trunk
timestamp: Mon 2008-09-08 21:45:40 +0200
message:
  add as_value serializer (writeAMF0) and support circular references
modified:
  libcore/as_value.cpp
  libcore/as_value.h
  libcore/asobj/NetConnection.cpp
  libcore/asobj/Selection.cpp
  libmedia/FLVParser.cpp
    ------------------------------------------------------------
    revno: 9695.1.1
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Mon 2008-09-08 17:47:45 +0200
    message:
      log once about unimplemented Selection methods
    modified:
      libcore/asobj/Selection.cpp
    ------------------------------------------------------------
    revno: 9695.1.2
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Mon 2008-09-08 20:48:29 +0200
    message:
      dd as_value::writeAMF0, change readAMF0 to support circular references
    modified:
      libcore/as_value.cpp
      libcore/as_value.h
      libcore/asobj/NetConnection.cpp
      libmedia/FLVParser.cpp
    ------------------------------------------------------------
    revno: 9695.1.3
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Mon 2008-09-08 20:52:22 +0200
    message:
      Don't forget to record serialization of objects (for circular refs to 
work)
    modified:
      libcore/as_value.cpp
=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2008-09-04 10:48:29 +0000
+++ b/libcore/as_value.cpp      2008-09-08 18:52:22 +0000
@@ -37,6 +37,7 @@
 #include "Object.h"
 #include "amf.h"
 #include "array.h"
+#include "SimpleBuffer.h"
 
 #include <cmath> // std::fmod
 #include <boost/algorithm/string/case_conv.hpp>
@@ -144,6 +145,42 @@
             }
         }
 };
+
+/// Class used to serialize properties of an object to a buffer
+class PropsBufSerializer {
+    SimpleBuffer& _buf;
+    VM& _vm;
+    string_table& _st;
+    std::map<as_object*, size_t>& _offsetTable;
+    mutable bool _error;
+public:
+    PropsBufSerializer(SimpleBuffer& buf, VM& vm, std::map<as_object*, 
size_t>& offsetTable)
+        :
+        _buf(buf),
+        _vm(vm),
+        _st(vm.getStringTable()),
+        _offsetTable(offsetTable),
+        _error(false)
+       {};
+    
+    bool success() const { return !_error; }
+
+    void operator() (string_table::key key, const as_value& val) const
+    {
+        if ( _error ) return;
+
+        // write property name
+        const string& name = _st.string_table::value(key);
+        boost::uint16_t namelen = name.size();
+        _buf.appendNetworkShort(namelen);
+        _buf.append(name.c_str(), namelen);
+        if ( ! val.writeAMF0(_buf, _offsetTable, _vm) )
+        {
+            log_error("Problems serializing an object's member");
+            _error=true;
+        }
+    }
+};
     
 //
 // as_value -- ActionScript value type
@@ -1982,7 +2019,8 @@
 // TODO restore first parameter on parse errors
 //
 static bool
-amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int 
inType = -1)
+amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int 
inType,
+    std::vector<as_object*>& objRefs)
 {
        boost::uint16_t si;
        boost::uint16_t li;
@@ -2048,6 +2086,8 @@
                case amf::Element::STRICT_ARRAY_AMF0:
                        {
                                boost::intrusive_ptr<as_array_object> array(new 
as_array_object());
+                objRefs.push_back(array.get());
+
                                li = readNetworkLong(b); b += 4;
 #ifdef GNASH_DEBUG_AMF_PARSING
                                log_debug("amf0 starting read of array with %i 
elements", li);
@@ -2055,7 +2095,7 @@
                                as_value arrayElement;
                                for(int i = 0; i < li; ++i)
                                {
-                                       if ( ! amf0_read_value(b, end, 
arrayElement) )
+                                       if ( ! amf0_read_value(b, end, 
arrayElement, -1, objRefs) )
                                        {
                                                return false;
                                        }
@@ -2068,6 +2108,8 @@
                case amf::Element::ECMA_ARRAY_AMF0:
                        {
                                boost::intrusive_ptr<as_object> obj(new 
as_object(getObjectInterface()));
+                objRefs.push_back(obj.get());
+
                                li = readNetworkLong(b); b += 4;
 #ifdef GNASH_DEBUG_AMF_PARSING
                                log_debug("amf0 starting read of object with %i 
elements", li);
@@ -2083,7 +2125,7 @@
                                        log_debug("amf0 Object prop name is 
%s", name);
 #endif
                                        b += strlen;
-                                       if ( ! amf0_read_value(b, end, 
objectElement) )
+                                       if ( ! amf0_read_value(b, end, 
objectElement, -1, objRefs) )
                                        {
                                                return false;
                                        }
@@ -2100,11 +2142,13 @@
 #ifdef GNASH_DEBUG_AMF_PARSING
                                log_debug("amf0 starting read of object");
 #endif
+                objRefs.push_back(obj.get());
+
                                as_value tmp;
                                std::string keyString;
                                for(;;)
                                {
-                                       if ( ! amf0_read_value(b, end, tmp, 
amf::Element::STRING_AMF0) )
+                                       if ( ! amf0_read_value(b, end, tmp, 
amf::Element::STRING_AMF0, objRefs) )
                                        {
                                                return false;
                                        }
@@ -2121,7 +2165,7 @@
                                                return true;
                                        }
 
-                                       if ( ! amf0_read_value(b, end, tmp) )
+                                       if ( ! amf0_read_value(b, end, tmp, -1, 
objRefs) )
                                        {
                                                return false;
                                        }
@@ -2138,6 +2182,17 @@
                                ret.set_null();
                                return true;
                        }
+               case amf::Element::REFERENCE_AMF0:
+            {
+                           si = readNetworkShort(b); b += 2;
+                if ( si >= objRefs.size() )
+                {
+                    log_error("AMF reference to unparsed object %d", si);
+                    return false;
+                }
+                ret.set_as_object(objRefs[si]);
+                return true;
+            }
                // TODO define other types (function, sprite, etc)
                default:
                        log_unimpl("AMF0 to as_value: unsupported type: %i", 
amf_type);
@@ -2149,9 +2204,79 @@
 }
 
 bool
-as_value::readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType)
-{
-       return amf0_read_value(b, end, *this, inType);
+as_value::readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType, 
std::vector<as_object*>& objRefs)
+{
+       return amf0_read_value(b, end, *this, inType, objRefs);
+}
+
+bool
+as_value::writeAMF0(SimpleBuffer& buf, std::map<as_object*, size_t>& 
offsetTable, VM& vm) const
+{
+    typedef std::map<as_object*, size_t> OffsetTable;
+
+    assert ( ! is_exception() );
+
+    switch (m_type)
+    {
+        default:
+            log_unimpl(_("serialization of as_value of type %d"), m_type);
+            return false;
+
+        case AS_FUNCTION:
+        case OBJECT:
+        {
+            as_object* obj = to_object().get();
+            assert(obj);
+
+            size_t idx = offsetTable.size(); // 0 for the first, etc...
+            OffsetTable::iterator it = offsetTable.find(obj);
+            if ( it == offsetTable.end() )
+            {
+                log_debug("serializing object (or function) as reference to 
%d", idx);
+                offsetTable[obj] = idx;
+                buf.appendByte(amf::Element::OBJECT_AMF0);
+                PropsBufSerializer props(buf, vm, offsetTable);
+                obj->visitPropertyValues(props);
+                if ( ! props.success() ) 
+                {
+                    log_error("Could not serialize object");
+                    return false;
+                }
+            }
+            else // object already seen
+            {
+                log_debug("serializing object (or function) with index %d", 
idx);
+                offsetTable[obj] = idx;
+                buf.appendByte(amf::Element::REFERENCE_AMF0);
+                buf.appendNetworkShort(it->second);
+            }
+            return true;
+        }
+
+        case STRING:
+        {
+            buf.appendByte(amf::Element::STRING_AMF0);
+            std::string str = to_string();
+            buf.appendNetworkShort(str.size());
+            buf.append(str.c_str(), str.size());
+            return true;
+        }
+
+        case NUMBER:
+        {
+            double d = to_number();
+            buf.appendByte(amf::Element::NUMBER_AMF0);
+            amf::swapBytes(&d, 8); // this actually only swapps on 
little-endian machines
+            buf.append(&d, 8);
+            return true;
+        }
+
+        case MOVIECLIP:
+        {
+            log_unimpl(_(" serialization of MovieClip objects"));
+            return false;
+        }
+    }
 }
 
 } // namespace gnash

=== modified file 'libcore/as_value.h'
--- a/libcore/as_value.h        2008-09-04 10:48:29 +0000
+++ b/libcore/as_value.h        2008-09-08 18:48:29 +0000
@@ -30,6 +30,7 @@
 #include <cmath>
 #include <limits>
 #include <string>
+#include <vector>
 #include <boost/variant.hpp>
 #include <ostream> // for inlined output operator
 #include <boost/type_traits/is_floating_point.hpp>
@@ -41,6 +42,7 @@
 
 // Forward declarations
 namespace gnash {
+    class VM;
        class as_object;
        class fn_call;
        class as_function;
@@ -48,6 +50,7 @@
        class character;
        class asNamespace;
        class asName;
+    class SimpleBuffer;
 }
 namespace amf {
        class Element;
@@ -203,7 +206,24 @@
        ///
        /// TODO restore first parameter on parse errors
        ///
-       bool readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType = -1);
+       /// @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.
+       ///
+       bool readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType, 
std::vector<as_object*>& objRefs);
+
+    /// Serialize value in AMF0 format.
+    //
+    /// @param buf
+    ///     The buffer to append serialized version of this value to.
+    ///
+    /// @param offsetTable
+    ///     A map of already-parsed objects, pass an empty map on first call as
+    ///     it will be used internally.
+    ///
+    bool writeAMF0(SimpleBuffer& buf, std::map<as_object*, size_t>& 
offsetTable, VM& vm) const;
 
        /// Convert numeric value to string value, following ECMA-262 
specification
        //

=== modified file 'libcore/asobj/NetConnection.cpp'
--- a/libcore/asobj/NetConnection.cpp   2008-09-03 11:25:57 +0000
+++ b/libcore/asobj/NetConnection.cpp   2008-09-08 18:48:29 +0000
@@ -314,6 +314,8 @@
                        {
                                if ( reply_end > 8)
                                {
+                    std::vector<as_object*> objRefs;
+
                                        log_debug("hit eof");
                                        boost::int16_t si;
                                        boost::uint16_t li;
@@ -342,11 +344,6 @@
                                                                break;
                                                        }
                                                        std::string 
headerName((char*)b, si); // end-b);
-                                                       //if( !tmp.readAMF0(b, 
end) )
-                                                       //{
-                                                       //      headers_ok = 0;
-                                                       //      break;
-                                                       //}
                                                        log_debug("Header name 
%s", headerName);
                                                        b += si;
                                                        if ( b + 5 > end ) {
@@ -354,7 +351,7 @@
                                                                break;
                                                        }
                                                        b += 5; // skip past 
bool and length long
-                                                       if( !tmp.readAMF0(b, 
end) )
+                                                       if( !tmp.readAMF0(b, 
end, -1, objRefs) )
                                                        {
                                                                headers_ok = 0;
                                                                break;
@@ -412,7 +409,7 @@
                                                                
log_debug("about to parse amf value");
                                                                // this updates 
b to point to the next unparsed byte
                                                                as_value 
reply_as_value;
-                                                               if ( ! 
reply_as_value.readAMF0(b, end) )
+                                                               if ( ! 
reply_as_value.readAMF0(b, end, -1, objRefs) )
                                                                {
                                                                        
log_error("parse amf failed");
                                                                        // this 
will happen if we get

=== modified file 'libcore/asobj/Selection.cpp'
--- a/libcore/asobj/Selection.cpp       2008-01-21 20:55:39 +0000
+++ b/libcore/asobj/Selection.cpp       2008-09-08 15:47:45 +0000
@@ -84,35 +84,35 @@
 };
 
 as_value selection_addlistener(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_getbeginindex(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_getcaretindex(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_getendindex(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_getfocus(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_removelistener(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_setfocus(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 as_value selection_setselection(const fn_call& /*fn*/) {
-    log_unimpl (__FUNCTION__);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
     return as_value();
 }
 

=== modified file 'libmedia/FLVParser.cpp'
--- a/libmedia/FLVParser.cpp    2008-09-02 23:28:53 +0000
+++ b/libmedia/FLVParser.cpp    2008-09-08 18:48:29 +0000
@@ -627,7 +627,8 @@
        string_table::key funcKey = st.find(funcName);
 
        as_value arg;
-       if ( ! arg.readAMF0(ptr, endptr) )
+    std::vector<as_object*> objRefs;
+       if ( ! arg.readAMF0(ptr, endptr, -1, objRefs) )
        {
                log_error("Could not convert FLV metatag to as_value");
                return;


reply via email to

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