gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r9706: Fix AMF0 serializer/deseriali


From: Sandro Santilli
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r9706: Fix AMF0 serializer/deserializer (add OBJECT and ARRAY writing support,
Date: Tue, 09 Sep 2008 11:55:16 +0200
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 9706
committer: Sandro Santilli <address@hidden>
branch nick: trunk
timestamp: Tue 2008-09-09 11:55:16 +0200
message:
  Fix AMF0 serializer/deserializer (add OBJECT and ARRAY writing support,
  fix visibility of __proto__ and constructor members, fix reference indexing)
  Potlatch now works. 
modified:
  libcore/as_value.cpp
  libcore/as_value.h
  libcore/asobj/NetConnection.cpp
  libmedia/FLVParser.cpp
    ------------------------------------------------------------
    revno: 9695.1.4
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Tue 2008-09-09 11:20:50 +0200
    message:
      Have AMF reader take a VM ref and set members w/out hiding them, fix
      serializer for object, add one for array, skip members named __proto__
      or constructor on writing, skip FUNCTION encoding.
      Take a look here:
      http://www.openstreetmap.org/?lat=42.3153&lon=12.1823&zoom=14
      (edit if you don't notice anything interesting rendered yet)
    modified:
      libcore/as_value.cpp
      libcore/as_value.h
      libcore/asobj/NetConnection.cpp
      libmedia/FLVParser.cpp
=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2008-09-08 20:21:44 +0000
+++ b/libcore/as_value.cpp      2008-09-09 09:55:16 +0000
@@ -58,7 +58,10 @@
 //#define GNASH_DEBUG_SOFT_REFERENCES
 
 // Define this macto to make AMF parsing verbose
-//#define GNASH_DEBUG_AMF_PARSING
+//#define GNASH_DEBUG_AMF_DESERIALIZE
+
+// Define this macto to make AMF writing verbose
+//#define GNASH_DEBUG_AMF_SERIALIZE
 
 using namespace std;
 
@@ -169,8 +172,27 @@
     {
         if ( _error ) return;
 
+        // 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_DESERIALIZE
+            log_debug(" skip serialization of specially-named property %s", 
_st.value(key));
+#endif
+            return;
+        }
+
         // write property name
-        const string& name = _st.string_table::value(key);
+        const string& name = _st.value(key);
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
+        log_debug(" serializing property %s", name);
+#endif
         boost::uint16_t namelen = name.size();
         _buf.appendNetworkShort(namelen);
         _buf.append(name.c_str(), namelen);
@@ -251,8 +273,8 @@
                        return b ? "true" : "false";
                }
 
+               case AS_FUNCTION:
                case OBJECT:
-               case AS_FUNCTION:
                {
                        //as_object* obj = m_type == OBJECT ? getObj().get() : 
getFun().get();
                        try
@@ -2020,7 +2042,7 @@
 //
 static bool
 amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int 
inType,
-    std::vector<as_object*>& objRefs)
+    std::vector<as_object*>& objRefs, VM& vm)
 {
        boost::uint16_t si;
        boost::uint16_t li;
@@ -2044,7 +2066,7 @@
                case amf::Element::BOOLEAN_AMF0:
                {
                        bool val = *b; b += 1;
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                        log_debug("amf0 read bool: %d", val);
 #endif
                        ret.set_bool(val);
@@ -2057,7 +2079,7 @@
                        }
                        dub = *(reinterpret_cast<double*>(b)); b += 8;
                        amf::swapBytes(&dub, 8);
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                        log_debug("amf0 read double: %e", dub);
 #endif
                        ret.set_double(dub);
@@ -2075,7 +2097,7 @@
 
                        {
                                std::string str(reinterpret_cast<char *>(b), 
si); b += si;
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                                log_debug("amf0 read string: %s", str);
 #endif
                                ret.set_string(str);
@@ -2089,13 +2111,13 @@
                 objRefs.push_back(array.get());
 
                                li = readNetworkLong(b); b += 4;
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                                log_debug("amf0 starting read of array with %i 
elements", li);
 #endif
                                as_value arrayElement;
                                for(int i = 0; i < li; ++i)
                                {
-                                       if ( ! amf0_read_value(b, end, 
arrayElement, -1, objRefs) )
+                                       if ( ! amf0_read_value(b, end, 
arrayElement, -1, objRefs, vm) )
                                        {
                                                return false;
                                        }
@@ -2111,7 +2133,7 @@
                 objRefs.push_back(obj.get());
 
                                li = readNetworkLong(b); b += 4;
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                                log_debug("amf0 starting read of object with %i 
elements", li);
 #endif
                                as_value objectElement;
@@ -2121,11 +2143,11 @@
                                {
                                        boost::uint16_t strlen = 
readNetworkShort(b); b+=2; 
                                        std::string name((char*)b, strlen);
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                                        log_debug("amf0 Object prop name is 
%s", name);
 #endif
                                        b += strlen;
-                                       if ( ! amf0_read_value(b, end, 
objectElement, -1, objRefs) )
+                                       if ( ! amf0_read_value(b, end, 
objectElement, -1, objRefs, vm) )
                                        {
                                                return false;
                                        }
@@ -2137,9 +2159,11 @@
                        }
                case amf::Element::OBJECT_AMF0:
                        {
+                string_table& st = vm.getStringTable();
+
                                // TODO: need this? 
boost::intrusive_ptr<as_object> obj(new as_object(getObjectInterface()));
                                boost::intrusive_ptr<as_object> obj(new 
as_object());
-#ifdef GNASH_DEBUG_AMF_PARSING
+#ifdef GNASH_DEBUG_AMF_DESERIALIZE
                                log_debug("amf0 starting read of object");
 #endif
                 objRefs.push_back(obj.get());
@@ -2148,7 +2172,7 @@
                                std::string keyString;
                                for(;;)
                                {
-                                       if ( ! amf0_read_value(b, end, tmp, 
amf::Element::STRING_AMF0, objRefs) )
+                                       if ( ! amf0_read_value(b, end, tmp, 
amf::Element::STRING_AMF0, objRefs, vm) )
                                        {
                                                return false;
                                        }
@@ -2165,11 +2189,11 @@
                                                return true;
                                        }
 
-                                       if ( ! amf0_read_value(b, end, tmp, -1, 
objRefs) )
+                                       if ( ! amf0_read_value(b, end, tmp, -1, 
objRefs, vm) )
                                        {
                                                return false;
                                        }
-                                       obj->init_member(keyString, tmp);
+                                       obj->set_member(st.find(keyString), 
tmp);
                                }
                        }
                case amf::Element::UNDEFINED_AMF0:
@@ -2185,12 +2209,12 @@
                case amf::Element::REFERENCE_AMF0:
             {
                            si = readNetworkShort(b); b += 2;
-                if ( si >= objRefs.size() )
+                if ( si < 1 || si > objRefs.size() )
                 {
-                    log_error("AMF reference to unparsed object %d", si);
+                    log_error("readAMF0: invalid reference to object %d (%d 
known objects)", si, objRefs.size());
                     return false;
                 }
-                ret.set_as_object(objRefs[si]);
+                ret.set_as_object(objRefs[si-1]);
                 return true;
             }
                // TODO define other types (function, sprite, etc)
@@ -2204,9 +2228,9 @@
 }
 
 bool
-as_value::readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType, 
std::vector<as_object*>& objRefs)
+as_value::readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType, 
std::vector<as_object*>& objRefs, VM& vm)
 {
-       return amf0_read_value(b, end, *this, inType, objRefs);
+       return amf0_read_value(b, end, *this, inType, objRefs, vm);
 }
 
 bool
@@ -2223,32 +2247,66 @@
             return false;
 
         case AS_FUNCTION:
+            log_unimpl(_("serialization of as_value of type FUNCTION"), 
m_type);
+            return false;
+
         case OBJECT:
         {
             as_object* obj = to_object().get();
             assert(obj);
-
             OffsetTable::iterator it = offsetTable.find(obj);
             if ( it == offsetTable.end() )
             {
-                size_t idx = offsetTable.size(); // 0 for the first, etc...
-                log_debug("serializing object (or function) with index %d", 
idx);
+                size_t idx = offsetTable.size()+1; // 1 for the first, etc...
                 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;
+
+                as_array_object* ary = dynamic_cast<as_array_object*>(obj);
+                if ( ary )
+                {
+                    size_t len = ary->size();
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+                    log_debug(_("writeAMF0: serializing array of %d elements 
as index %d"), len, idx);
+#endif
+                    buf.appendByte(amf::Element::STRICT_ARRAY_AMF0);
+                    buf.appendNetworkLong(len);
+                                   for(size_t i = 0; i < len; ++i)
+                    {
+                        as_value element = ary->at(i);
+                        if ( ! element.writeAMF0(buf, offsetTable, vm) )
+                        {
+                            log_error("Error serializing array element %d 
(%s)", i, element);
+                            return false;
+                        }
+                    }
+                    return true;
+                }
+                else
+                {
+#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);
+                    obj->visitPropertyValues(props);
+                    if ( ! props.success() ) 
+                    {
+                        log_error("Could not serialize object");
+                        return false;
+                    }
+                    buf.appendNetworkShort(0);
+                    buf.appendByte(amf::Element::OBJECT_END_AMF0);
+                    return true;
                 }
             }
             else // object already seen
             {
                 size_t idx = it->second;
-                log_debug("serializing object (or function) as reference to 
%d", idx);
+#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 true;
         }
@@ -2256,7 +2314,10 @@
         case STRING:
         {
             buf.appendByte(amf::Element::STRING_AMF0);
-            std::string str = to_string();
+            const std::string& str = getStr();
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+            log_debug(_("writeAMF0: serializing string '%s"), str);
+#endif
             buf.appendNetworkShort(str.size());
             buf.append(str.c_str(), str.size());
             return true;
@@ -2264,7 +2325,10 @@
 
         case NUMBER:
         {
-            double d = to_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 swapps on 
little-endian machines
             buf.append(&d, 8);
@@ -2276,6 +2340,24 @@
             log_unimpl(_(" serialization of MovieClip objects"));
             return false;
         }
+
+        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;
+        }
     }
 }
 

=== modified file 'libcore/as_value.h'
--- a/libcore/as_value.h        2008-09-08 18:48:29 +0000
+++ b/libcore/as_value.h        2008-09-09 09:20:50 +0000
@@ -212,7 +212,7 @@
        ///     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);
+       bool readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType, 
std::vector<as_object*>& objRefs, VM& vm);
 
     /// Serialize value in AMF0 format.
     //

=== modified file 'libcore/asobj/NetConnection.cpp'
--- a/libcore/asobj/NetConnection.cpp   2008-09-08 18:48:29 +0000
+++ b/libcore/asobj/NetConnection.cpp   2008-09-09 09:20:50 +0000
@@ -275,6 +275,9 @@
                log_debug("tick running");
                if(connection)
                {
+
+            VM& vm = _nc.getVM();
+
                        log_debug("have connection");
                        int read = connection->readNonBlocking(reply.data() + 
reply_end, NCCALLREPLYMAX - reply_end);
                        if(read > 0) {
@@ -351,7 +354,7 @@
                                                                break;
                                                        }
                                                        b += 5; // skip past 
bool and length long
-                                                       if( !tmp.readAMF0(b, 
end, -1, objRefs) )
+                                                       if( !tmp.readAMF0(b, 
end, -1, objRefs, vm) )
                                                        {
                                                                headers_ok = 0;
                                                                break;
@@ -409,7 +412,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, -1, objRefs) )
+                                                               if ( ! 
reply_as_value.readAMF0(b, end, -1, objRefs, vm) )
                                                                {
                                                                        
log_error("parse amf failed");
                                                                        // this 
will happen if we get
@@ -604,44 +607,21 @@
        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;
+    VM& vm = ptr->getVM();
 
        // encode array of arguments to remote method
        buf->appendByte(amf::Element::STRICT_ARRAY_AMF0);
        buf->appendNetworkLong(fn.nargs - 2);
-       if (fn.nargs > 2) {
-
+       if (fn.nargs > 2)
+    {
                for (unsigned int i = 2; i < fn.nargs; ++i)
                {
                        const as_value& arg = fn.arg(i);
-
-                       if (arg.is_string()) {
-                               buf->appendByte(amf::Element::STRING_AMF0);
-                               std::string str = fn.arg(i).to_string();
-                               buf->appendNetworkShort(str.size());
-                               buf->append(str.c_str(), str.size());
-                       // FIXME implement this
-                       //} else if(fn.arg(i).is_function()) {
-                       //      as_function f = fn.arg(i).to_function();
-                       //      tmp = AMF::encodefunction(f);
-                       }
-
-                       else if(arg.is_number())
-                       {
-                               double d = fn.arg(i).to_number();
-                               buf->appendByte(amf::Element::NUMBER_AMF0);
-                               amf::swapBytes(&d, 8); // this actually only 
swapps on little-endian machines
-                               buf->append(&d, 8);
-                       // FIXME implement this
-                       //} else if(fn.arg(i).is_object()) {
-                       //      boost::intrusive_ptr<as_object> o = 
fn.arg(i).to_object();
-                       //      tmp = AMF::encodeObject(o);
-                       }
-                       
-                       else
-                       {
-                               log_unimpl(_("NetConnection.call(): unsupported 
argument type %s"), arg);
-                               buf->appendByte(amf::Element::UNDEFINED_AMF0);
-                       }
+            if ( ! arg.writeAMF0(*buf, offsetTable, vm) )
+            {
+                log_error("Could not serialize NetConnection.call argument 
%d", i);
+            }
                }
        }
 

=== modified file 'libmedia/FLVParser.cpp'
--- a/libmedia/FLVParser.cpp    2008-09-08 18:48:29 +0000
+++ b/libmedia/FLVParser.cpp    2008-09-09 09:20:50 +0000
@@ -628,7 +628,7 @@
 
        as_value arg;
     std::vector<as_object*> objRefs;
-       if ( ! arg.readAMF0(ptr, endptr, -1, objRefs) )
+       if ( ! arg.readAMF0(ptr, endptr, -1, objRefs, vm) )
        {
                log_error("Could not convert FLV metatag to as_value");
                return;


reply via email to

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