[Top][All Lists]
[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;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r9697: add as_value serializer (writeAMF0) and support circular references,
Sandro Santilli <=