[Top][All Lists]
[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;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r9706: Fix AMF0 serializer/deserializer (add OBJECT and ARRAY writing support,,
Sandro Santilli <=