Skip to content

Commit

Permalink
partially implement AMF0 serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
dbluelle committed Oct 2, 2015
1 parent 1f3548f commit d53364c
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 21 deletions.
64 changes: 58 additions & 6 deletions src/asobject.cpp
Expand Up @@ -1537,6 +1537,7 @@ void variables_map::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& s
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap) const
{
bool amf0 = out->getObjectEncoding() == ObjectEncoding::AMF0;
//Pairs of name, value
auto it=Variables.begin();
for(;it!=Variables.end();it++)
Expand All @@ -1545,26 +1546,41 @@ void variables_map::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& s
continue;
//Dynamic traits always have empty namespace
assert(it->first.ns.hasEmptyName());
out->writeStringVR(stringMap,getSys()->getStringFromUniqueId(it->first.nameId));
if (amf0)
out->writeStringAMF0(getSys()->getStringFromUniqueId(it->first.nameId));
else
out->writeStringVR(stringMap,getSys()->getStringFromUniqueId(it->first.nameId));
it->second.var->serialize(out, stringMap, objMap, traitsMap);
}
//The empty string closes the object
out->writeStringVR(stringMap, "");
if (!amf0) out->writeStringVR(stringMap, "");
}

void ASObject::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
//0x0A -> object marker
out->writeByte(object_marker);
bool amf0 = out->getObjectEncoding() == ObjectEncoding::AMF0;
if (amf0)
out->writeByte(amf0_object_marker);
else
out->writeByte(object_marker);
//Check if the object has been already serialized to send it by reference
auto it=objMap.find(this);
if(it!=objMap.end())
{
//The least significant bit is 0 to signal a reference
out->writeU29(it->second << 1);
if (amf0)
{
out->writeByte(amf0_reference_marker);
out->writeShort(it->second);
}
else
{
//The least significant bit is 0 to signal a reference
out->writeShort(it->second << 1);
}
return;

}

Class_base* type=getClass();
Expand All @@ -1590,6 +1606,13 @@ void ASObject::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& string
//Custom serialization necessary
if(!serializeTraits)
throwError<TypeError>(kInvalidParamError);
if (amf0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing IExternalizable in AMF0 not implemented");
out->writeShort(0);
out->writeByte(amf0_object_end_marker);
return;
}
out->writeU29(0x7);
out->writeStringVR(stringMap, alias);

Expand Down Expand Up @@ -1618,6 +1641,35 @@ void ASObject::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& string
const variables_map::const_var_iterator endIt = Variables.Variables.end();
//Check if the class traits has been already serialized to send it by reference
auto it2=traitsMap.find(type);

if (amf0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing ASObject in AMF0 not completely implemented");
if(it2!=traitsMap.end())
{
out->writeByte(amf0_reference_marker);
out->writeShort(it2->second);
for(variables_map::const_var_iterator varIt=beginIt; varIt != endIt; ++varIt)
{
if(varIt->second.kind==DECLARED_TRAIT)
{
if(!varIt->first.ns.hasEmptyName())
{
//Skip variable with a namespace, like protected ones
continue;
}
out->writeStringAMF0(getSys()->getStringFromUniqueId(varIt->first.nameId));
varIt->second.var->serialize(out, stringMap, objMap, traitsMap);
}
}
}
if(!type->isSealed)
serializeDynamicProperties(out, stringMap, objMap, traitsMap);
out->writeShort(0);
out->writeByte(amf0_object_end_marker);
return;
}

if(it2!=traitsMap.end())
out->writeU29((it2->second << 2) | 1);
else
Expand Down
30 changes: 22 additions & 8 deletions src/scripting/flash/utils/ByteArray.cpp
Expand Up @@ -552,14 +552,6 @@ uint32_t ByteArray::writeObject(ASObject* obj)
{
//Return the length of the serialized object

//TODO: support AMF0

if (objectEncoding==ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"ByteArray.writeObject: writing AMF0 objects not implemented");
//return 0;
}
//assert_and_throw(objectEncoding==ObjectEncoding::AMF3);
//TODO: support custom serialization
map<tiny_string, uint32_t> stringMap;
map<const ASObject*, uint32_t> objMap;
Expand Down Expand Up @@ -1178,6 +1170,23 @@ void ByteArray::writeStringVR(map<tiny_string, uint32_t>& stringMap, const tiny_
}
}

void ByteArray::writeStringAMF0(const tiny_string& s)
{
const uint32_t len=s.numBytes();
if(len <= 0xffff)
{
writeUTF(s);
}
else
{
getBuffer(position+len+4,true);
uint32_t numBytes=endianIn((uint32_t)len);
memcpy(bytes+position,&numBytes,4);
memcpy(bytes+position+4,s.raw_buf(),len);
position+=len+4;
}
}

void ByteArray::writeXMLString(std::map<const ASObject*, uint32_t>& objMap,
ASObject *xml,
const tiny_string& xmlstr)
Expand Down Expand Up @@ -1463,6 +1472,11 @@ void ByteArray::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& strin
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing ByteArray in AMF0 not implemented");
return;
}
assert_and_throw(objMap.find(this)==objMap.end());
out->writeByte(byte_array_marker);
//Check if the bytearray has been already serialized
Expand Down
2 changes: 2 additions & 0 deletions src/scripting/flash/utils/ByteArray.h
Expand Up @@ -62,6 +62,7 @@ friend class LoaderInfo;
void writeUTF(const tiny_string& str);
uint32_t writeObject(ASObject* obj);
void writeStringVR(std::map<tiny_string, uint32_t>& stringMap, const tiny_string& s);
void writeStringAMF0(const tiny_string& s);
void writeXMLString(std::map<const ASObject*, uint32_t>& objMap, ASObject *xml, const tiny_string& s);
void writeU29(uint32_t val);

Expand All @@ -73,6 +74,7 @@ friend class LoaderInfo;

void append(std::streambuf* data, int length);

uint8_t getObjectEncoding() const { return objectEncoding; }
uint8_t getCurrentObjectEncoding() const { return currentObjectEncoding; }
void setCurrentObjectEncoding(uint8_t encoding) { currentObjectEncoding = encoding; }

Expand Down
5 changes: 5 additions & 0 deletions src/scripting/flash/utils/Dictionary.cpp
Expand Up @@ -357,6 +357,11 @@ void Dictionary::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stri
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing Dictionary in AMF0 not implemented");
return;
}
assert_and_throw(objMap.find(this)==objMap.end());
out->writeByte(dictionary_marker);
//Check if the dictionary has been already serialized
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/flash/xml/flashxml.cpp
Expand Up @@ -309,6 +309,11 @@ void XMLDocument::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& str
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing XMLDocument in AMF0 not implemented");
return;
}
out->writeByte(xml_doc_marker);
out->writeXMLString(objMap, this, toString());
}
Expand Down
12 changes: 10 additions & 2 deletions src/scripting/toplevel/ASString.cpp
Expand Up @@ -585,8 +585,16 @@ void ASString::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& string
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
out->writeByte(string_marker);
out->writeStringVR(stringMap, data);
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
out->writeByte(amf0_string_marker);
out->writeStringAMF0(data);
}
else
{
out->writeByte(string_marker);
out->writeStringVR(stringMap, data);
}
}

ASFUNCTIONBODY(ASString,slice)
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/toplevel/Array.cpp
Expand Up @@ -1573,6 +1573,11 @@ void Array::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing Array in AMF0 not implemented");
return;
}
assert_and_throw(objMap.find(this)==objMap.end());
out->writeByte(array_marker);
//Check if the array has been already serialized
Expand Down
9 changes: 6 additions & 3 deletions src/scripting/toplevel/Boolean.cpp
Expand Up @@ -126,10 +126,13 @@ void Boolean::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringM
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if(val)
out->writeByte(true_marker);
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
out->writeByte(amf0_boolean_marker);
out->writeByte(val ? 1:0);
}
else
out->writeByte(false_marker);
out->writeByte(val ? true_marker : false_marker);
}

bool Boolean::isEqual(ASObject* r)
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/toplevel/Date.cpp
Expand Up @@ -1133,6 +1133,11 @@ void Date::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing Date in AMF0 not implemented");
return;
}
number_t val = getMsSinceEpoch();
out->writeByte(date_marker);
auto it=objMap.find(this);
Expand Down
7 changes: 7 additions & 0 deletions src/scripting/toplevel/Integer.cpp
Expand Up @@ -213,6 +213,13 @@ void Integer::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringM
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
// write as double
out->writeByte(amf0_number_marker);
out->serializeDouble(val);
return;
}
if(val>=0x40000000 || val<=(int32_t)0xbfffffff)
{
// write as double
Expand Down
6 changes: 6 additions & 0 deletions src/scripting/toplevel/Number.cpp
Expand Up @@ -529,6 +529,12 @@ void Number::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMa
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
out->writeByte(amf0_number_marker);
out->serializeDouble(val);
return;
}
out->writeByte(double_marker);
out->serializeDouble(val);
}
6 changes: 6 additions & 0 deletions src/scripting/toplevel/UInteger.cpp
Expand Up @@ -211,6 +211,12 @@ void UInteger::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& string
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
out->writeByte(amf0_number_marker);
out->serializeDouble(val);
return;
}
if(val>=0x40000000)
{
// write as double
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/toplevel/Vector.cpp
Expand Up @@ -1158,6 +1158,11 @@ void Vector::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMa
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing Vector in AMF0 not implemented");
return;
}
uint8_t marker = 0;
if (vec_type == Class<Integer>::getClass())
marker = vector_int_marker;
Expand Down
6 changes: 6 additions & 0 deletions src/scripting/toplevel/XML.cpp
Expand Up @@ -2402,6 +2402,12 @@ void XML::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
{
LOG(LOG_NOT_IMPLEMENTED,"serializing XML in AMF0 not implemented");
return;
}

out->writeByte(xml_marker);
out->writeXMLString(objMap, this, toString());
}
Expand Down
10 changes: 8 additions & 2 deletions src/scripting/toplevel/toplevel.cpp
Expand Up @@ -117,7 +117,10 @@ void Undefined::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& strin
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
out->writeByte(undefined_marker);
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
out->writeByte(amf0_undefined_marker);
else
out->writeByte(undefined_marker);
}

void Undefined::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
Expand Down Expand Up @@ -662,7 +665,10 @@ void Null::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap)
{
out->writeByte(null_marker);
if (out->getObjectEncoding() == ObjectEncoding::AMF0)
out->writeByte(amf0_null_marker);
else
out->writeByte(null_marker);
}

void Null::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
Expand Down

0 comments on commit d53364c

Please sign in to comment.