8 Commits
1.3 ... d1
8 changed files with 514 additions and 253 deletions
+9
View File
@@ -1,6 +1,15 @@
RABCDAsm Changelog
==================
RABCDAsm v1.4 (2011.02.xx)
--------------------------
* Add support for forward-references for TypeName-kind Multinames
* Correctly order classes by dependencies (extends/implements) and reference
count
* Finish Metadata support
* Documentation updates
RABCDAsm v1.3 (2010.11.11)
--------------------------
+7 -23
View File
@@ -125,7 +125,7 @@ use [this handy list][avm2i] as well). You will find it difficult to understand
the disassembly without good understanding of concepts such as namespaces and
multinames.
[avm2]: http://www.adobe.com/devnet/actionscript/articles/avm2overview.pdf
[avm2]: http://www.adobe.com/devnet-archive/actionscript/articles/avm2overview.pdf
[avm2i]: http://www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html
Overview
@@ -171,7 +171,10 @@ are the trait fields, varying by trait kind:
* `method` / `getter` / `setter` : `dispid` (unsigned integer), `method`
Additionally, all traits may have `flag` fields, describing the trait's
attributes (`FINAL` / `OVERRIDE` / `METADATA`).
attributes (`FINAL` / `OVERRIDE` / `METADATA`), and `metadata` blocks.
`metadata` blocks (which are ignored by the AVM) consist of a name string, and
a series of `item` fields - each item having a key and value string.
`class` blocks have mandatory `instance` and `cinit` fields, defining the class
instance and the class initializer method respectively. They may also have
@@ -363,10 +366,7 @@ follows:
`AStoABC` will rebuild the constant pools, in a manner similar to Adobe's
compilers (reverse-sorted by reference count). The exact order will almost
surely be different, however. Also, some records (classes and methods) are
currently not sorted by reference count, which may cause `rabcasm` to generate
slightly larger files than the originals (due to variable-length encoding of
integers).
surely be different, however.
Should you need to write an utility to manipulate ABC, you can use the existing
code to load the file to either an `ABCFile` or `ASProgram` instance, and
@@ -420,23 +420,7 @@ RABCDAsm users.
Limitations
===========
* Metadata is currently ignored. I haven't noticed any metadata blocks in any
SWF files I've disassembled.
* `rabcasm` may create a broken file due to not ordering classes by ancestry.
The problem originates from the fact that a class's ancestors (extended
class and implemented interfaces) are stored as multinames, and not as
class indices. (This makes sense, since classes may extend objects outside
the current ABC file.) Since `rabcasm` currently doesn't decode multinames,
it is unaware of the class dependencies, and may thus write the classes out
of order. This results in a file that, when opened, will fail to load with
an error message similar to:
VerifyError: Error #1014: Class AncestorClassName could not be found.
The simple work-around is to re-order the classes as they are declared in
the `.main.asasm` file, and place ancestors before descendants.
* None known.
License
=======
+1 -1
View File
@@ -1716,7 +1716,7 @@ private final class ABCWriter
if (v.attr & TraitAttributes.Metadata)
{
writeU30(v.metadata.length);
foreach (ref value; v.metadata)
foreach (value; v.metadata)
writeU30(value);
}
}
+2
View File
@@ -74,10 +74,12 @@
<word name="implements"/>
<word name="initscopedepth"/>
<word name="instance"/>
<word name="item"/>
<word name="localcount"/>
<word name="majorversion"/>
<word name="maxscopedepth"/>
<word name="maxstack"/>
<word name="metadata"/>
<word name="method"/>
<word name="minorversion"/>
<word name="name"/>
+366 -157
View File
@@ -87,6 +87,7 @@ final class ASProgram
}
mixin AutoCompare;
mixin AutoToString;
R processData(R, string prolog, string epilog, H)(ref H handler)
{
@@ -124,6 +125,30 @@ final class ASProgram
}
mixin(epilog);
}
private Multiname[] toQNames()
{
switch (kind)
{
case ASType.QName:
case ASType.QNameA:
return [this];
case ASType.Multiname:
case ASType.MultinameA:
Multiname[] result;
foreach (ns; vMultiname.nsSet)
{
auto n = new Multiname;
n.kind = kind==ASType.Multiname ? ASType.QName : ASType.QNameA;
n.vQName.ns = ns;
n.vQName.name = vMultiname.name;
result ~= n;
}
return result;
default:
throw new .Exception("Can't expand Multiname of this kind");
}
}
}
static class Method
@@ -143,10 +168,16 @@ final class ASProgram
struct Item
{
string key, value;
mixin AutoCompare;
mixin ProcessAllData;
}
string name;
Item[] items;
mixin AutoCompare;
mixin ProcessAllData;
}
static class Instance
@@ -212,6 +243,11 @@ final class ASProgram
Trait[] traits;
Instance instance;
string toString()
{
return instance.name.toString();
}
}
static class Script
@@ -371,7 +407,7 @@ private final class ABCtoAS
return n;
}
ASProgram.Multiname convertMultiname(ref ABCFile.Multiname multiname, uint i)
ASProgram.Multiname convertMultiname(ref ABCFile.Multiname multiname)
{
auto n = new ASProgram.Multiname();
n.kind = multiname.kind;
@@ -399,16 +435,7 @@ private final class ABCtoAS
n.vMultinameL.nsSet = namespaceSets[multiname.MultinameL.nsSet];
break;
case ASType.TypeName:
if (multiname.TypeName.name >= i)
throw new Exception("Forward Multiname/TypeName reference");
n.vTypeName.name = multinames[multiname.TypeName.name];
n.vTypeName.params.length = multiname.TypeName.params.length;
foreach (j, param; multiname.TypeName.params)
{
if (param >= i)
throw new Exception("Forward Multiname/TypeName parameter reference");
n.vTypeName.params[j] = multinames[param];
}
// handled in postConvertMultiname
break;
default:
throw new Exception("Unknown Multiname kind");
@@ -416,6 +443,20 @@ private final class ABCtoAS
return n;
}
void postConvertMultiname(ref ABCFile.Multiname multiname, ASProgram.Multiname n)
{
switch (multiname.kind)
{
case ASType.TypeName:
n.vTypeName.name = multinames[multiname.TypeName.name];
n.vTypeName.params.length = multiname.TypeName.params.length;
foreach (j, param; multiname.TypeName.params)
n.vTypeName.params[j] = multinames[param];
default:
break;
}
}
ASProgram.Method convertMethod(ref ABCFile.MethodInfo method)
{
auto n = new ASProgram.Method();
@@ -482,6 +523,9 @@ private final class ABCtoAS
default:
throw new Exception("Unknown trait kind");
}
r[i].metadata.length = trait.metadata.length;
foreach (j, index; trait.metadata)
r[i].metadata[j] = metadata[index];
}
return r;
}
@@ -626,7 +670,10 @@ private final class ABCtoAS
multinames.length = abc.multinames.length;
foreach (i, ref multiname; abc.multinames)
if (i)
multinames[i] = convertMultiname(multiname, i);
multinames[i] = convertMultiname(multiname);
foreach (i, ref multiname; abc.multinames)
if (i)
postConvertMultiname(multiname, multinames[i]);
methods.length = methodAdded.length = abc.methods.length;
foreach (i, ref method; abc.methods)
@@ -686,19 +733,36 @@ private final class AStoABC
}
/// Maintain an unordered set of values; sort/index by usage count
struct Constant(T)
struct ConstantPool(T, bool haveNull = true)
{
static Constant!(T)[T] pool;
static T[] values;
static bool add(T value) // return true if added
struct Entry
{
if (isNull(value))
uint hits;
T value;
uint index;
mixin AutoCompare;
R processData(R, string prolog, string epilog, H)(ref H handler)
{
mixin(prolog);
mixin(addAutoField("hits", true));
mixin(addAutoField("value"));
mixin(epilog);
}
}
Entry[T] pool;
T[] values;
bool add(T value) // return true if added
{
if (haveNull && isNull(value))
return false;
auto cp = value in pool;
if (cp is null)
{
pool[value] = Constant!(T)(1, value);
pool[value] = Entry(1, value);
return true;
}
else
@@ -708,113 +772,196 @@ private final class AStoABC
}
}
static bool notAdded(T value)
bool notAdded(T value)
{
return !(isNull(value) || value in pool);
auto ep = value in pool;
if (ep)
ep.hits++;
return !((haveNull && isNull(value)) || ep);
}
static void sort()
void finalize()
{
auto all = pool.values;
all.sort;
values.length = all.length+1;
enum { NullOffset = haveNull ? 1 : 0 }
values.length = all.length + NullOffset;
foreach (i, ref c; all)
{
pool[c.value].index = i+1;
values[i+1] = c.value;
pool[c.value].index = i + NullOffset;
values[i + NullOffset] = c.value;
}
}
static uint get(T value)
uint get(T value)
{
if (isNull(value))
if (haveNull && isNull(value))
return 0;
return pool[value].index;
}
mixin AutoCompare;
R processData(R, string prolog, string epilog, H)(ref H handler)
{
mixin(prolog);
mixin(addAutoField("hits", true));
mixin(addAutoField("value"));
mixin(epilog);
}
uint hits;
T value;
uint index;
}
/// Pair an index with class instances
struct Reference(T)
struct ReferencePool(T : Object)
{
static Reference[void*] references;
static T[] objects;
struct Entry
{
uint hits;
void* object;
uint addIndex, index;
void*[] parents;
static bool add(T obj) // return true if added
int opCmp(Entry* o)
{
if (this.parents.contains(o.object))
return 1;
if (o.parents.contains(this.object))
return -1;
if (o.hits==hits)
return addIndex-o.addIndex;
else
return o.hits-hits;
}
}
Entry[void*] pool;
T[] objects;
bool add(T obj) // return true if added
{
if (obj is null)
return false;
auto p = cast(void*)obj;
auto rp = p in references;
auto rp = p in pool;
if (rp is null)
{
references[p] = Reference!(T)(1); //, objects.length
objects ~= obj;
pool[p] = Entry(1, p, pool.length);
return true;
}
else
{
rp.hits++;
return false;
}
}
static bool notAdded(T obj)
bool notAdded(T obj)
{
return !(obj is null || (cast(void*)obj) in references);
auto ep = (cast(void*)obj) in pool;
if (ep)
ep.hits++;
return !(obj is null || ep);
}
static void reindex()
void registerDependency(T from, T to)
{
foreach (i, o; objects)
references[cast(void*)o].index = i;
auto pfrom = (cast(void*)from) in pool;
assert(pfrom, "Unknown dependency source");
auto vto = cast(void*)to;
auto pto = vto in pool;
assert(pto, "Unknown dependency target");
assert(!pfrom.parents.contains(vto), "Dependency already set");
pfrom.parents ~= vto;
}
static uint get(T obj)
T[] getPreliminaryObjects()
{
return cast(T[])pool.keys;
}
void finalize()
{
// assign unique index
int i=0;
foreach (ref e; pool)
e.index = i++;
// topographical sort
bool done;
while (!done)
{
done = true;
foreach (ref a; pool)
foreach (parent; a.parents)
{
auto pb = parent in pool;
assert(pb !is null, "Can't find referenced object");
if (pb.index > a.index)
{
auto t = pb.index;
pb.index = a.index;
a.index = t;
done = false;
break;
}
}
}
// copy to array
auto all = new Entry[i];
foreach (ref e; pool)
all[e.index] = e;
// sort
//all.sort; // sort preserving topological integrity demands compared items to always be adjacent
done = false;
while (!done)
{
done = true;
for (int j=0; j<all.length-1; j++)
if (all[j] > &all[j+1])
{
auto t = all[j];
all[j] = all[j+1];
all[j+1] = t;
done = false;
}
}
objects.length = i;
foreach (j, ref e; all)
{
pool[e.object].index = j;
objects[j] = cast(T)e.object;
}
}
uint get(T obj)
{
assert(obj !is null, "Trying to get index of null object");
return references[cast(void*)obj].index;
return pool[cast(void*)obj].index;
}
uint index;
}
typedef Constant!(long) IntC;
typedef Constant!(ulong) UIntC;
typedef Constant!(double) DoubleC;
typedef Constant!(string) StringC;
typedef Constant!(ASProgram.Namespace) NamespaceC;
typedef Constant!(ASProgram.Namespace[]) NamespaceSetC;
typedef Constant!(ASProgram.Multiname) MultinameC;
typedef Reference!(ASProgram.Class) ClassR;
typedef Reference!(ASProgram.Method) MethodR;
ConstantPool!(long) ints;
ConstantPool!(ulong) uints;
ConstantPool!(double) doubles;
ConstantPool!(string) strings;
ConstantPool!(ASProgram.Namespace) namespaces;
ConstantPool!(ASProgram.Namespace[]) namespaceSets;
ConstantPool!(ASProgram.Multiname) multinames;
ConstantPool!(ASProgram.Metadata, false) metadatas;
ReferencePool!(ASProgram.Class) classes;
ReferencePool!(ASProgram.Method) methods;
void visitNamespace(ASProgram.Namespace ns)
{
if (NamespaceC.add(ns))
StringC.add(ns.name);
if (namespaces.add(ns))
strings.add(ns.name);
}
void visitNamespaceSet(ASProgram.Namespace[] nsSet)
{
if (NamespaceSetC.add(nsSet))
if (namespaceSets.add(nsSet))
foreach (ns; nsSet)
visitNamespace(ns);
}
void visitMultiname(ASProgram.Multiname multiname)
{
if (MultinameC.notAdded(multiname))
if (multinames.notAdded(multiname))
{
with (multiname)
switch (kind)
@@ -822,18 +969,18 @@ private final class AStoABC
case ASType.QName:
case ASType.QNameA:
visitNamespace(vQName.ns);
StringC.add(vQName.name);
strings.add(vQName.name);
break;
case ASType.RTQName:
case ASType.RTQNameA:
StringC.add(vRTQName.name);
strings.add(vRTQName.name);
break;
case ASType.RTQNameL:
case ASType.RTQNameLA:
break;
case ASType.Multiname:
case ASType.MultinameA:
StringC.add(vMultiname.name);
strings.add(vMultiname.name);
visitNamespaceSet(vMultiname.nsSet);
break;
case ASType.MultinameL:
@@ -848,7 +995,7 @@ private final class AStoABC
default:
throw new .Exception("Unknown Multiname kind");
}
bool r = MultinameC.add(multiname);
bool r = multinames.add(multiname);
assert(r);
}
}
@@ -885,6 +1032,21 @@ private final class AStoABC
default:
throw new Exception("Unknown trait kind");
}
foreach (metadata; trait.metadata)
visitMetadata(metadata);
}
}
void visitMetadata(ASProgram.Metadata metadata)
{
if (metadatas.add(metadata))
{
strings.add(metadata.name);
foreach (ref item; metadata.items)
{
strings.add(item.key);
strings.add(item.value);
}
}
}
@@ -893,16 +1055,16 @@ private final class AStoABC
switch (value.vkind)
{
case ASType.Integer:
IntC.add(value.vint);
ints.add(value.vint);
break;
case ASType.UInteger:
UIntC.add(value.vuint);
uints.add(value.vuint);
break;
case ASType.Double:
DoubleC.add(value.vdouble);
doubles.add(value.vdouble);
break;
case ASType.Utf8:
StringC.add(value.vstring);
strings.add(value.vstring);
break;
case ASType.Namespace:
case ASType.PackageNamespace:
@@ -925,31 +1087,31 @@ private final class AStoABC
void visitClass(ASProgram.Class vclass)
{
if (ClassR.notAdded(vclass))
if (classes.notAdded(vclass))
{
visitMethod(vclass.cinit);
visitTraits(vclass.traits);
visitInstance(vclass.instance);
bool r = ClassR.add(vclass);
bool r = classes.add(vclass);
assert(r);
}
}
void visitMethod(ASProgram.Method method)
{
if (MethodR.add(method))
if (methods.add(method))
with (method)
{
foreach (type; paramTypes)
visitMultiname(type);
visitMultiname(returnType);
StringC.add(name);
strings.add(name);
foreach (ref value; options)
visitValue(value);
foreach (name; paramNames)
StringC.add(name);
strings.add(name);
if (vbody)
visitMethodBody(vbody);
@@ -971,16 +1133,16 @@ private final class AStoABC
break;
case OpcodeArgumentType.Int:
IntC.add(instruction.arguments[i].intv);
ints.add(instruction.arguments[i].intv);
break;
case OpcodeArgumentType.UInt:
UIntC.add(instruction.arguments[i].uintv);
uints.add(instruction.arguments[i].uintv);
break;
case OpcodeArgumentType.Double:
DoubleC.add(instruction.arguments[i].doublev);
doubles.add(instruction.arguments[i].doublev);
break;
case OpcodeArgumentType.String:
StringC.add(instruction.arguments[i].stringv);
strings.add(instruction.arguments[i].stringv);
break;
case OpcodeArgumentType.Namespace:
visitNamespace(instruction.arguments[i].namespacev);
@@ -1010,6 +1172,7 @@ private final class AStoABC
visitMultiname(exception.varName);
}
visitMethod(vbody.method);
visitTraits(vbody.traits);
}
@@ -1029,13 +1192,13 @@ private final class AStoABC
switch (value.vkind)
{
case ASType.Integer:
return IntC.get(value.vint);
return ints.get(value.vint);
case ASType.UInteger:
return UIntC.get(value.vuint);
return uints.get(value.vuint);
case ASType.Double:
return DoubleC.get(value.vdouble);
return doubles.get(value.vdouble);
case ASType.Utf8:
return StringC.get(value.vstring);
return strings.get(value.vstring);
case ASType.Namespace:
case ASType.PackageNamespace:
case ASType.PackageInternalNs:
@@ -1043,7 +1206,7 @@ private final class AStoABC
case ASType.ExplicitNamespace:
case ASType.StaticProtectedNs:
case ASType.PrivateNamespace:
return NamespaceC.get(value.vnamespace);
return namespaces.get(value.vnamespace);
case ASType.True:
case ASType.False:
case ASType.Null:
@@ -1054,6 +1217,28 @@ private final class AStoABC
}
}
void registerClassDependencies()
{
ASProgram.Class[ASProgram.Multiname] classByName;
ASProgram.Class[] classObjects = classes.getPreliminaryObjects();
foreach (c; classObjects)
{
assert(!(c.instance.name in classByName), "Duplicate class name " ~ c.instance.name.toString());
classByName[c.instance.name] = c;
}
foreach (c; classObjects)
foreach (dependency; [c.instance.superName] ~ c.instance.interfaces)
if (dependency)
foreach (dependencyName; dependency.toQNames())
{
auto pp = dependencyName in classByName;
if (pp)
classes.registerDependency(c, *pp);
}
}
this(ASProgram as)
{
this.abc = new ABCFile();
@@ -1069,43 +1254,43 @@ private final class AStoABC
foreach (method; as.orphanMethods)
visitMethod(method);
IntC.sort();
UIntC.sort();
DoubleC.sort();
StringC.sort();
NamespaceC.sort();
NamespaceSetC.sort();
MultinameC.sort();
//MultinameC.flip();
//MultinameC.reindex();
//ClassR.flip();
ClassR.reindex();
MethodR.reindex();
registerClassDependencies();
abc.ints = IntC.values;
abc.uints = UIntC.values;
abc.doubles = DoubleC.values;
abc.strings = StringC.values;
ints.finalize();
uints.finalize();
doubles.finalize();
strings.finalize();
namespaces.finalize();
namespaceSets.finalize();
multinames.finalize();
metadatas.finalize();
classes.finalize();
methods.finalize();
abc.namespaces.length = NamespaceC.values.length;
foreach (i, v; NamespaceC.values[1..$])
abc.ints = ints.values;
abc.uints = uints.values;
abc.doubles = doubles.values;
abc.strings = strings.values;
abc.namespaces.length = namespaces.values.length;
foreach (i, v; namespaces.values[1..$])
{
auto n = &abc.namespaces[i+1];
n.kind = v.kind;
n.name = StringC.get(v.name);
n.name = strings.get(v.name);
}
abc.namespaceSets.length = NamespaceSetC.values.length;
foreach (i, v; NamespaceSetC.values[1..$])
abc.namespaceSets.length = namespaceSets.values.length;
foreach (i, v; namespaceSets.values[1..$])
{
auto n = new uint[v.length];
foreach (j, ns; v)
n[j] = NamespaceC.get(ns);
n[j] = namespaces.get(ns);
abc.namespaceSets[i+1] = n;
}
abc.multinames.length = MultinameC.values.length;
foreach (i, v; MultinameC.values[1..$])
abc.multinames.length = multinames.values.length;
foreach (i, v; multinames.values[1..$])
{
auto n = &abc.multinames[i+1];
n.kind = v.kind;
@@ -1113,47 +1298,60 @@ private final class AStoABC
{
case ASType.QName:
case ASType.QNameA:
n.QName.ns = NamespaceC.get(v.vQName.ns);
n.QName.name = StringC.get(v.vQName.name);
n.QName.ns = namespaces.get(v.vQName.ns);
n.QName.name = strings.get(v.vQName.name);
break;
case ASType.RTQName:
case ASType.RTQNameA:
n.RTQName.name = StringC.get(v.vRTQName.name);
n.RTQName.name = strings.get(v.vRTQName.name);
break;
case ASType.RTQNameL:
case ASType.RTQNameLA:
break;
case ASType.Multiname:
case ASType.MultinameA:
n.Multiname.name = StringC.get(v.vMultiname.name);
n.Multiname.nsSet = NamespaceSetC.get(v.vMultiname.nsSet);
n.Multiname.name = strings.get(v.vMultiname.name);
n.Multiname.nsSet = namespaceSets.get(v.vMultiname.nsSet);
break;
case ASType.MultinameL:
case ASType.MultinameLA:
n.MultinameL.nsSet = NamespaceSetC.get(v.vMultinameL.nsSet);
n.MultinameL.nsSet = namespaceSets.get(v.vMultinameL.nsSet);
break;
case ASType.TypeName:
n.TypeName.name = MultinameC.get(v.vTypeName.name);
n.TypeName.name = multinames.get(v.vTypeName.name);
n.TypeName.params.length = v.vTypeName.params.length;
foreach (j, param; v.vTypeName.params)
n.TypeName.params[j] = MultinameC.get(param);
n.TypeName.params[j] = multinames.get(param);
break;
default:
throw new Exception("Unknown Multiname kind");
}
}
abc.metadata.length = metadatas.values.length;
foreach (i, m; metadatas.values)
{
auto n = &abc.metadata[i];
n.name = strings.get(m.name);
n.items.length = m.items.length;
foreach (j, ref item; m.items)
{
n.items[j].key = strings.get(m.items[j].key);
n.items[j].value = strings.get(m.items[j].value);
}
}
ASProgram.MethodBody[] bodies;
abc.methods.length = MethodR.objects.length;
foreach (i, o; MethodR.objects)
abc.methods.length = methods.objects.length;
foreach (i, o; methods.objects)
{
auto n = &abc.methods[i];
n.paramTypes.length = o.paramTypes.length;
foreach (j, p; o.paramTypes)
n.paramTypes[j] = MultinameC.get(p);
n.returnType = MultinameC.get(o.returnType);
n.name = StringC.get(o.name);
n.paramTypes[j] = multinames.get(p);
n.returnType = multinames.get(o.returnType);
n.name = strings.get(o.name);
n.flags = o.flags;
n.options.length = o.options.length;
foreach (j, ref value; o.options)
@@ -1163,34 +1361,34 @@ private final class AStoABC
}
n.paramNames.length = o.paramNames.length;
foreach (j, name; o.paramNames)
n.paramNames[j] = StringC.get(name);
n.paramNames[j] = strings.get(name);
if (o.vbody)
bodies ~= o.vbody;
}
abc.instances.length = ClassR.objects.length;
foreach (i, c; ClassR.objects)
abc.instances.length = classes.objects.length;
foreach (i, c; classes.objects)
{
auto o = c.instance;
auto n = &abc.instances[i];
n.name = MultinameC.get(o.name);
n.superName = MultinameC.get(o.superName);
n.name = multinames.get(o.name);
n.superName = multinames.get(o.superName);
n.flags = o.flags;
n.protectedNs = NamespaceC.get(o.protectedNs);
n.protectedNs = namespaces.get(o.protectedNs);
n.interfaces.length = o.interfaces.length;
foreach (j, intf; o.interfaces)
n.interfaces[j] = MultinameC.get(intf);
n.iinit = MethodR.get(o.iinit);
n.interfaces[j] = multinames.get(intf);
n.iinit = methods.get(o.iinit);
n.traits = convertTraits(o.traits);
}
abc.classes.length = ClassR.objects.length;
foreach (i, o; ClassR.objects)
abc.classes.length = classes.objects.length;
foreach (i, o; classes.objects)
{
auto n = &abc.classes[i];
n.cinit = MethodR.get(o.cinit);
n.cinit = methods.get(o.cinit);
n.traits = convertTraits(o.traits);
}
@@ -1198,7 +1396,7 @@ private final class AStoABC
foreach (i, o; as.scripts)
{
auto n = &abc.scripts[i];
n.sinit = MethodR.get(o.sinit);
n.sinit = methods.get(o.sinit);
n.traits = convertTraits(o.traits);
}
@@ -1206,7 +1404,7 @@ private final class AStoABC
foreach (i, o; bodies)
{
auto n = &abc.bodies[i];
n.method = MethodR.get(o.method);
n.method = methods.get(o.method);
n.maxStack = o.maxStack;
n.localCount = o.localCount;
n.initScopeDepth = o.initScopeDepth;
@@ -1221,8 +1419,8 @@ private final class AStoABC
ne.from = oe.from;
ne.to = oe.to;
ne.target = oe.target;
ne.excType = MultinameC.get(oe.excType);
ne.varName = MultinameC.get(oe.varName);
ne.excType = multinames.get(oe.excType);
ne.varName = multinames.get(oe.varName);
}
n.traits = convertTraits(o.traits);
}
@@ -1233,7 +1431,7 @@ private final class AStoABC
auto r = new ABCFile.TraitsInfo[traits.length];
foreach (i, ref trait; traits)
{
r[i].name = MultinameC.get(trait.name);
r[i].name = multinames.get(trait.name);
r[i].kind = trait.kind;
r[i].attr = trait.attr;
switch (trait.kind)
@@ -1241,27 +1439,30 @@ private final class AStoABC
case TraitKind.Slot:
case TraitKind.Const:
r[i].Slot.slotId = trait.vSlot.slotId;
r[i].Slot.typeName = MultinameC.get(trait.vSlot.typeName);
r[i].Slot.typeName = multinames.get(trait.vSlot.typeName);
r[i].Slot.vkind = trait.vSlot.value.vkind;
r[i].Slot.vindex = getValueIndex(trait.vSlot.value);
break;
case TraitKind.Class:
r[i].Class.slotId = trait.vClass.slotId;
r[i].Class.classi = ClassR.get(trait.vClass.vclass);
r[i].Class.classi = classes.get(trait.vClass.vclass);
break;
case TraitKind.Function:
r[i].Function.slotId = trait.vFunction.slotId;
r[i].Function.functioni = MethodR.get(trait.vFunction.vfunction);
r[i].Function.functioni = methods.get(trait.vFunction.vfunction);
break;
case TraitKind.Method:
case TraitKind.Getter:
case TraitKind.Setter:
r[i].Method.dispId = trait.vMethod.dispId;
r[i].Method.method = MethodR.get(trait.vMethod.vmethod);
r[i].Method.method = methods.get(trait.vMethod.vmethod);
break;
default:
throw new Exception("Unknown trait kind");
}
r[i].metadata.length = trait.metadata.length;
foreach (j, ref m; trait.metadata)
r[i].metadata[j] = metadatas.get(m);
}
return r;
}
@@ -1289,28 +1490,28 @@ private final class AStoABC
break;
case OpcodeArgumentType.Int:
r.arguments[i].index = IntC.get(instruction.arguments[i].intv);
r.arguments[i].index = ints.get(instruction.arguments[i].intv);
break;
case OpcodeArgumentType.UInt:
r.arguments[i].index = UIntC.get(instruction.arguments[i].uintv);
r.arguments[i].index = uints.get(instruction.arguments[i].uintv);
break;
case OpcodeArgumentType.Double:
r.arguments[i].index = DoubleC.get(instruction.arguments[i].doublev);
r.arguments[i].index = doubles.get(instruction.arguments[i].doublev);
break;
case OpcodeArgumentType.String:
r.arguments[i].index = StringC.get(instruction.arguments[i].stringv);
r.arguments[i].index = strings.get(instruction.arguments[i].stringv);
break;
case OpcodeArgumentType.Namespace:
r.arguments[i].index = NamespaceC.get(instruction.arguments[i].namespacev);
r.arguments[i].index = namespaces.get(instruction.arguments[i].namespacev);
break;
case OpcodeArgumentType.Multiname:
r.arguments[i].index = MultinameC.get(instruction.arguments[i].multinamev);
r.arguments[i].index = multinames.get(instruction.arguments[i].multinamev);
break;
case OpcodeArgumentType.Class:
r.arguments[i].index = ClassR.get(instruction.arguments[i].classv);
r.arguments[i].index = classes.get(instruction.arguments[i].classv);
break;
case OpcodeArgumentType.Method:
r.arguments[i].index = MethodR.get(instruction.arguments[i].methodv);
r.arguments[i].index = methods.get(instruction.arguments[i].methodv);
break;
case OpcodeArgumentType.JumpTarget:
@@ -1376,3 +1577,11 @@ class ASTraitsVisitor
}
}
}
private bool contains(T)(T[] arr, T val)
{
foreach (v; arr)
if (v == val)
return true;
return false;
}
+29
View File
@@ -656,6 +656,9 @@ final class Assembler
case "value":
t.vSlot.value = readValue();
break;
case "metadata":
t.metadata ~= readMetadata();
break;
case "end":
return t;
default:
@@ -678,6 +681,9 @@ final class Assembler
mustBeNull(t.vClass.vclass);
t.vClass.vclass = readClass();
break;
case "metadata":
t.metadata ~= readMetadata();
break;
case "end":
return t;
default:
@@ -700,6 +706,9 @@ final class Assembler
mustBeNull(t.vFunction.vfunction);
t.vFunction.vfunction = readMethod();
break;
case "metadata":
t.metadata ~= readMetadata();
break;
case "end":
return t;
default:
@@ -724,6 +733,9 @@ final class Assembler
mustBeNull(t.vMethod.vmethod);
t.vMethod.vmethod = readMethod();
break;
case "metadata":
t.metadata ~= readMetadata();
break;
case "end":
return t;
default:
@@ -735,6 +747,23 @@ final class Assembler
}
}
ASProgram.Metadata readMetadata()
{
auto metadata = new ASProgram.Metadata;
metadata.name = readString();
while (true)
switch (readWord())
{
case "item":
metadata.items ~= ASProgram.Metadata.Item(readString(), readString());
break;
case "end":
return metadata;
default:
throw new Exception("Expected item or end");
}
}
ASProgram.Method readMethod()
{
ASProgram.Method m = new ASProgram.Method;
+33 -5
View File
@@ -551,6 +551,7 @@ final class Disassembler
dumpMultiname(sb, trait.name);
if (trait.attr)
dumpFlags!(true)(sb, trait.attr, TraitAttributeNames);
bool inLine = false;
switch (trait.kind)
{
case TraitKind.Slot:
@@ -570,8 +571,7 @@ final class Disassembler
sb ~= " value ";
dumpValue(sb, trait.vSlot.value);
}
sb ~= " end";
sb.newLine();
inLine = true;
break;
case TraitKind.Class:
if (trait.vClass.slotId)
@@ -582,7 +582,6 @@ final class Disassembler
sb.indent++; sb.newLine();
sb ~= "class";
dumpClass(sb, trait.vClass.vclass);
sb.indent--; sb ~= "end ; trait"; sb.newLine();
break;
case TraitKind.Function:
if (trait.vFunction.slotId)
@@ -593,7 +592,6 @@ final class Disassembler
sb.indent++; sb.newLine();
sb ~= "method";
dumpMethod(sb, trait.vFunction.vfunction);
sb.indent--; sb ~= "end ; trait"; sb.newLine();
break;
case TraitKind.Method:
case TraitKind.Getter:
@@ -606,14 +604,44 @@ final class Disassembler
sb.indent++; sb.newLine();
sb ~= "method";
dumpMethod(sb, trait.vMethod.vmethod);
sb.indent--; sb ~= "end ; trait"; sb.newLine();
break;
default:
throw new Exception("Unknown trait kind");
}
foreach (metadata; trait.metadata)
{
if (inLine)
{
sb.indent++; sb.newLine();
inLine = false;
}
dumpMetadata(sb, metadata);
}
if (inLine)
{ sb ~= " end"; sb.newLine(); }
else
{ sb.indent--; sb ~= "end ; trait"; sb.newLine(); }
}
}
void dumpMetadata(StringBuilder sb, ASProgram.Metadata metadata)
{
sb ~= "metadata ";
dumpString(sb, metadata.name);
sb.indent++; sb.newLine();
foreach (ref item; metadata.items)
{
sb ~= "item ";
dumpString(sb, item.key);
sb ~= " ";
dumpString(sb, item.value);
sb.newLine();
}
sb.indent--; sb ~= "end ; metadata"; sb.newLine();
}
void dumpFlags(bool oneLine = false)(StringBuilder sb, ubyte flags, string[] names)
{
for (int i=0; flags; i++, flags>>=1)
+67 -67
View File
@@ -152,73 +152,73 @@ private final class SWFReader
enum TagType
{
End = 0,
ShowFrame = 1,
DefineShape = 2,
FreeCharacter = 3,
PlaceObject = 4,
RemoveObject = 5,
DefineBits = 6,
DefineButton = 7,
JPEGTables = 8,
SetBackgroundColor = 9,
DefineFont = 10,
DefineText = 11,
DoAction = 12,
DefineFontInfo = 13,
DefineSound = 14,
StartSound = 15,
DefineButtonSound = 17,
SoundStreamHead = 18,
SoundStreamBlock = 19,
DefineBitsLossless = 20,
DefineBitsJPEG2 = 21,
DefineShape2 = 22,
DefineButtonCxform = 23,
Protect = 24,
PathsArePostScript = 25,
PlaceObject2 = 26,
RemoveObject2 = 28,
DefineShape3 = 32,
DefineText2 = 33,
DefineButton2 = 34,
DefineBitsJPEG3 = 35,
DefineBitsLossless2 = 36,
DefineSprite = 39,
ProductInfo = 41,
FrameLabel = 43,
SoundStreamHead2 = 45,
DefineMorphShape = 46,
DefineFont2 = 48,
DefineEditText = 37,
ExportAssets = 56,
ImportAssets = 57,
EnableDebugger = 58,
DoInitAction = 59,
DefineVideoStream = 60,
VideoFrame = 61,
DefineFontInfo2 = 62,
DebugID = 63,
EnableDebugger2 = 64,
ScriptLimits = 65,
SetTabIndex = 66,
FileAttributes = 69,
PlaceObject3 = 70,
ImportAssets2 = 71,
DoABC = 72,
DefineFontAlignZones = 73,
CSMTextSettings = 74,
DefineFont3 = 75,
SymbolClass = 76,
Metadata = 77,
DefineScalingGrid = 78,
DoABC2 = 82,
DefineShape4 = 83,
DefineMorphShape2 = 84,
DefineSceneAndFrameLabelData = 86,
DefineBinaryData = 87,
DefineFontName = 88,
DefineFont4 = 91
End = 0,
ShowFrame = 1,
DefineShape = 2,
FreeCharacter = 3,
PlaceObject = 4,
RemoveObject = 5,
DefineBits = 6,
DefineButton = 7,
JPEGTables = 8,
SetBackgroundColor = 9,
DefineFont = 10,
DefineText = 11,
DoAction = 12,
DefineFontInfo = 13,
DefineSound = 14,
StartSound = 15,
DefineButtonSound = 17,
SoundStreamHead = 18,
SoundStreamBlock = 19,
DefineBitsLossless = 20,
DefineBitsJPEG2 = 21,
DefineShape2 = 22,
DefineButtonCxform = 23,
Protect = 24,
PathsArePostScript = 25,
PlaceObject2 = 26,
RemoveObject2 = 28,
DefineShape3 = 32,
DefineText2 = 33,
DefineButton2 = 34,
DefineBitsJPEG3 = 35,
DefineBitsLossless2 = 36,
DefineSprite = 39,
ProductInfo = 41,
FrameLabel = 43,
SoundStreamHead2 = 45,
DefineMorphShape = 46,
DefineFont2 = 48,
DefineEditText = 37,
ExportAssets = 56,
ImportAssets = 57,
EnableDebugger = 58,
DoInitAction = 59,
DefineVideoStream = 60,
VideoFrame = 61,
DefineFontInfo2 = 62,
DebugID = 63,
EnableDebugger2 = 64,
ScriptLimits = 65,
SetTabIndex = 66,
FileAttributes = 69,
PlaceObject3 = 70,
ImportAssets2 = 71,
DoABC = 72,
DefineFontAlignZones = 73,
CSMTextSettings = 74,
DefineFont3 = 75,
SymbolClass = 76,
Metadata = 77,
DefineScalingGrid = 78,
DoABC2 = 82,
DefineShape4 = 83,
DefineMorphShape2 = 84,
DefineSceneAndFrameLabelData = 86,
DefineBinaryData = 87,
DefineFontName = 88,
DefineFont4 = 91
}
private final class SWFWriter