Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32909f3893 | ||
|
|
472a9cec57 | ||
|
|
6cbb185114 | ||
|
|
f32f6fb128 | ||
|
|
d6d7ecf47e | ||
|
|
0cefc587e6 | ||
|
|
a45b4e2bdc | ||
|
|
e383172765 | ||
|
|
c62b5438d7 | ||
|
|
a1a214ae72 | ||
|
|
222fa1109c | ||
|
|
9fa2d122fa | ||
|
|
93adc953c2 | ||
|
|
dc222f9e43 | ||
|
|
fb2f96b81a | ||
|
|
14f5e669ee |
@@ -1,6 +1,17 @@
|
||||
RABCDAsm Changelog
|
||||
==================
|
||||
|
||||
RABCDAsm v1.14 (2013.08.21)
|
||||
---------------------------
|
||||
|
||||
* Improved refid generation
|
||||
* Worked around liblzma dictionary size limitation, which prevented
|
||||
decompression of some LZMA-compressed files
|
||||
* Added an option to `swflzmacompress` to update the SWF version number
|
||||
* Added `finddef` instruction
|
||||
* Added unimplemented `{get|set|delete}propertylate` instructions
|
||||
* Documentation updates
|
||||
|
||||
RABCDAsm v1.13 (2012.09.29)
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ installed, compiling should be as straight-forward as:
|
||||
|
||||
Substitute `dmd` with `gdmd` if you're using gdc. You can use the `DC` and
|
||||
`DCFLAGS` environment variables to override the detected compiler and default
|
||||
compilation flags (`-w -O -inline`).
|
||||
compilation flags (`-O -inline`).
|
||||
|
||||
To be able to manipulate SWF files packed with LZMA compression, you'll need
|
||||
to have the liblzma library and development files installed on your system.
|
||||
@@ -82,11 +82,11 @@ to have the liblzma library and development files installed on your system.
|
||||
Pre-compiled binaries
|
||||
---------------------
|
||||
|
||||
You can find pre-compiled Windows binaries in the [Downloads section on
|
||||
GitHub][downloads]. However, please don't expect them to be up-to-date with
|
||||
the latest source versions.
|
||||
You can find pre-compiled Windows binaries on [my website][downloads].
|
||||
However, please don't expect them to be up-to-date with the latest source
|
||||
versions.
|
||||
|
||||
[downloads]: http://github.com/CyberShadow/RABCDAsm/downloads
|
||||
[downloads]: http://files.thecybershadow.net/RABCDAsm/
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -754,7 +754,7 @@ const OpcodeInfo[256] opcodeInfo = [
|
||||
/* 0x5C */ {"0x5C", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x5D */ {"findpropstrict", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x5E */ {"findproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x5F */ {"finddef", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x5F */ {"finddef", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x60 */ {"getlex", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x61 */ {"setproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x62 */ {"getlocal", [OpcodeArgumentType.UIntLiteral]},
|
||||
@@ -762,11 +762,11 @@ const OpcodeInfo[256] opcodeInfo = [
|
||||
/* 0x64 */ {"getglobalscope", []},
|
||||
/* 0x65 */ {"getscopeobject", [OpcodeArgumentType.UByteLiteral]},
|
||||
/* 0x66 */ {"getproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x67 */ {"getpropertylate", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x67 */ {"getpropertylate", []},
|
||||
/* 0x68 */ {"initproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x69 */ {"setpropertylate", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x69 */ {"setpropertylate", []},
|
||||
/* 0x6A */ {"deleteproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x6B */ {"deletepropertylate", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x6B */ {"deletepropertylate", []},
|
||||
/* 0x6C */ {"getslot", [OpcodeArgumentType.UIntLiteral]},
|
||||
/* 0x6D */ {"setslot", [OpcodeArgumentType.UIntLiteral]},
|
||||
/* 0x6E */ {"getglobalslot", [OpcodeArgumentType.UIntLiteral]},
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -266,7 +266,7 @@ final class Assembler
|
||||
{
|
||||
if (fileCount == files.length)
|
||||
throw new Exception("Recursion limit exceeded");
|
||||
files[1..fileCount+1] = files[0..fileCount].dup;
|
||||
files[1..fileCount+1] = files[0..fileCount].dup[];
|
||||
fileCount++;
|
||||
files[0] = file;
|
||||
}
|
||||
@@ -284,7 +284,7 @@ final class Assembler
|
||||
if (fileCount==1)
|
||||
throw new Exception("Unexpected end of file");
|
||||
fileCount--;
|
||||
files[0..fileCount] = files[1..fileCount+1].dup;
|
||||
files[0..fileCount] = files[1..fileCount+1].dup[];
|
||||
}
|
||||
|
||||
void expectWord(string expected)
|
||||
|
||||
+15
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
/// A simple tool to build RABCDAsm in one command.
|
||||
/// You can use the DC and DCFLAGS environment variables to override the detected compiler and compilation flags.
|
||||
/// You can also pass program names or compilation options on the command-line to override the default ones.
|
||||
|
||||
module build_rabcdasm;
|
||||
|
||||
@@ -59,10 +60,12 @@ void test(string code, string extraFlags=null)
|
||||
stderr.writeln(" >>> OK");
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto programs = ["rabcasm", "rabcdasm", "abcexport", "abcreplace", "swfbinexport", "swfbinreplace", "swfdecompress", "swf7zcompress"];
|
||||
|
||||
compiler = getenv("DC");
|
||||
if (compiler is null)
|
||||
compiler = DEFAULT_COMPILER;
|
||||
@@ -71,6 +74,15 @@ int main()
|
||||
if (flags is null)
|
||||
flags = DEFAULT_FLAGS;
|
||||
|
||||
string[] optionArgs, programArgs;
|
||||
foreach (arg; args[1..$])
|
||||
(arg.startsWith("-") ? optionArgs : programArgs) ~= arg;
|
||||
|
||||
if (optionArgs.length)
|
||||
flags = optionArgs.join(" ");
|
||||
if (programArgs.length)
|
||||
programs = programArgs;
|
||||
|
||||
stderr.writeln("* Checking for working compiler...");
|
||||
test(`
|
||||
void main() {}
|
||||
@@ -103,7 +115,7 @@ int main()
|
||||
if (haveLZMA)
|
||||
flags ~= " " ~ LZMA_FLAGS;
|
||||
|
||||
foreach (program; ["rabcasm", "rabcdasm", "abcexport", "abcreplace", "swfbinexport", "swfbinreplace", "swfdecompress", "swf7zcompress"])
|
||||
foreach (program; programs)
|
||||
compile(program);
|
||||
|
||||
if (haveLZMA)
|
||||
|
||||
+129
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -25,7 +25,7 @@ import std.conv;
|
||||
import std.exception;
|
||||
import std.algorithm;
|
||||
import std.path;
|
||||
import std.md5;
|
||||
import std.digest.md;
|
||||
import abcfile;
|
||||
import asprogram;
|
||||
import autodata;
|
||||
@@ -53,7 +53,7 @@ final class StringBuilder
|
||||
auto end = pos + s.length;
|
||||
while (buf.length < end)
|
||||
buf.length = buf.length*2;
|
||||
buf[pos..end] = s;
|
||||
buf[pos..end] = s[];
|
||||
pos = end;
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
assert(0);
|
||||
}
|
||||
case Type.String:
|
||||
return [Segment(filenameSuffix ? '.' : '/', str)];
|
||||
return [Segment((filename && filenameSuffix) ? '.' : '/', str)];
|
||||
case Type.Group:
|
||||
{
|
||||
Segment[] segments;
|
||||
@@ -257,18 +257,32 @@ final class RefBuilder : ASTraitsVisitor
|
||||
final switch (type)
|
||||
{
|
||||
case Type.Multiname:
|
||||
auto ns = multiname.vQName.ns;
|
||||
if (ns.kind == ASType.PrivateNamespace)
|
||||
switch (multiname.kind)
|
||||
{
|
||||
// auto pcontext = ns.id in refs.namespaces[ns.kind].contexts;
|
||||
// if (pcontext is null)
|
||||
// return (&this)[0..1];
|
||||
// assert(pcontext);
|
||||
auto context = refs.namespaces[ns.kind].getContext(refs, ns.id);
|
||||
debug(CONTEXTS) std.stdio.writefln("Context of namespace %s is:\n\t%s\n", ns, context);
|
||||
// auto expanded = expand(refs, context);
|
||||
// if (expanded is null) return null;
|
||||
return /*expanded*/context ~ (multiname.vQName.name.length ? [ContextItem(multiname.vQName.name)] : null); // hack
|
||||
case ASType.QName:
|
||||
{
|
||||
auto ns = multiname.vQName.ns;
|
||||
if (ns.kind == ASType.PrivateNamespace)
|
||||
{
|
||||
// auto pcontext = ns.id in refs.namespaces[ns.kind].contexts;
|
||||
// if (pcontext is null)
|
||||
// return (&this)[0..1];
|
||||
// assert(pcontext);
|
||||
auto context = refs.namespaces[ns.kind].getContext(refs, ns.id);
|
||||
debug(CONTEXTS) std.stdio.writefln("Context of namespace %s is:\n\t%s\n", ns, context);
|
||||
// auto expanded = expand(refs, context);
|
||||
// if (expanded is null) return null;
|
||||
return /*expanded*/context ~ (multiname.vQName.name.length ? [ContextItem(multiname.vQName.name)] : null); // hack
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ASType.Multiname:
|
||||
return multiname.vMultiname.name.length ? [ContextItem(multiname.vMultiname.name)] : null;
|
||||
default:
|
||||
debug
|
||||
assert(false, text(multiname.kind));
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Type.String:
|
||||
@@ -332,6 +346,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
case ContextItem.Type.String:
|
||||
return i1.str == i2.str;
|
||||
case ContextItem.Type.Multiname:
|
||||
assert(i1.multiname.kind == ASType.QName && i2.multiname.kind == ASType.QName);
|
||||
if (i1.multiname.vQName.name != i2.multiname.vQName.name) return false;
|
||||
return nsSimilar(i1.multiname.vQName.ns, i2.multiname.vQName.ns);
|
||||
case ContextItem.Type.Group:
|
||||
@@ -425,16 +440,24 @@ final class RefBuilder : ASTraitsVisitor
|
||||
void pushContext(T...)(T v) { context ~= ContextItem(v); }
|
||||
void popContext() { context = context[0..$-1]; }
|
||||
|
||||
enum ContextPriority
|
||||
{
|
||||
declaration,
|
||||
usage,
|
||||
orphan,
|
||||
max
|
||||
}
|
||||
|
||||
struct ContextSet(T, bool ALLOW_DUPLICATES)
|
||||
{
|
||||
ContextItem[][T] contexts;
|
||||
ContextItem[][][T] contextSets;
|
||||
ContextItem[][][ContextPriority.max][T] contextSets;
|
||||
debug bool contextsSealed;
|
||||
|
||||
string[T] names, filenames;
|
||||
debug bool coagulated;
|
||||
|
||||
bool add(U)(U obj, ContextItem[] context)
|
||||
bool add(U)(U obj, ContextItem[] context, ContextPriority priority)
|
||||
{
|
||||
debug assert(!coagulated);
|
||||
debug assert(!contextsSealed);
|
||||
@@ -444,23 +467,24 @@ final class RefBuilder : ASTraitsVisitor
|
||||
|
||||
if (!pset)
|
||||
{
|
||||
contextSets[p] ~= context.dup;
|
||||
contextSets[p] = contextSets[p].init;
|
||||
contextSets[p][priority] ~= context.dup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*pset)[$-1] != context)
|
||||
*pset ~= context.dup;
|
||||
if ((*pset)[priority].length==0 || (*pset)[priority][$-1] != context) // Optimization: don't add contexts identical to the last added
|
||||
(*pset)[priority] ~= context.dup;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool addIfNew(U)(U obj, ContextItem[] context)
|
||||
bool addIfNew(U)(U obj, ContextItem[] context, ContextPriority priority)
|
||||
{
|
||||
if (isAdded(obj))
|
||||
return false;
|
||||
else
|
||||
return add(obj, context);
|
||||
return add(obj, context, priority);
|
||||
}
|
||||
|
||||
void coagulate(RefBuilder refs)
|
||||
@@ -513,7 +537,10 @@ final class RefBuilder : ASTraitsVisitor
|
||||
if (pcontext)
|
||||
return *pcontext;
|
||||
|
||||
auto set = contextSets[p];
|
||||
ContextItem[][] set;
|
||||
foreach (prioritySet; contextSets[p])
|
||||
if (prioritySet)
|
||||
set = prioritySet;
|
||||
|
||||
static if (ALLOW_DUPLICATES)
|
||||
{
|
||||
@@ -597,31 +624,33 @@ final class RefBuilder : ASTraitsVisitor
|
||||
ContextItem[] classContexts;
|
||||
|
||||
foreach (trait; v.traits)
|
||||
if (trait.name.vQName.ns.kind != ASType.PrivateNamespace)
|
||||
{
|
||||
if (trait.name.kind == ASType.QName && trait.name.vQName.ns.kind != ASType.PrivateNamespace)
|
||||
classContexts ~= ContextItem(trait.name);
|
||||
}
|
||||
|
||||
if (!classContexts.length)
|
||||
foreach (trait; v.traits)
|
||||
classContexts ~= ContextItem(trait.name);
|
||||
|
||||
context = [ContextItem(classContexts, "script_" ~ to!string(i))];
|
||||
scripts.add(v, context);
|
||||
pushContext("sinit", true);
|
||||
addMethod(v.sinit);
|
||||
scripts.add(v, context, ContextPriority.declaration);
|
||||
pushContext("init", true);
|
||||
addMethod(v.sinit, ContextPriority.declaration);
|
||||
context = null;
|
||||
}
|
||||
foreach (i, vclass; as.orphanClasses)
|
||||
if (!objects.isAdded(vclass))
|
||||
{
|
||||
pushContext("orphan_class_" ~ to!string(i));
|
||||
addClass(vclass);
|
||||
addClass(vclass, ContextPriority.orphan);
|
||||
popContext();
|
||||
}
|
||||
foreach (i, method; as.orphanMethods)
|
||||
if (!objects.isAdded(method))
|
||||
{
|
||||
pushContext("orphan_method_" ~ to!string(i));
|
||||
addMethod(method);
|
||||
addMethod(method, ContextPriority.orphan);
|
||||
popContext();
|
||||
}
|
||||
|
||||
@@ -631,13 +660,13 @@ final class RefBuilder : ASTraitsVisitor
|
||||
foreach (v; as.scripts)
|
||||
foreach (trait; v.traits)
|
||||
if (trait.name.kind == ASType.QName)
|
||||
namespaces[trait.name.vQName.ns.kind].addIfNew(trait.name.vQName.ns.id, scripts.getContext(this, v));
|
||||
namespaces[trait.name.vQName.ns.kind].addIfNew(trait.name.vQName.ns.id, scripts.getContext(this, v), ContextPriority.declaration);
|
||||
|
||||
foreach (id, b; possibleOrphanPrivateNamespaces)
|
||||
if (!namespaces[ASType.PrivateNamespace].isAdded(id))
|
||||
{
|
||||
pushContext("orphan_namespace_" ~ to!string(id));
|
||||
namespaces[ASType.PrivateNamespace].add(id, context);
|
||||
namespaces[ASType.PrivateNamespace].add(id, context, ContextPriority.orphan);
|
||||
popContext();
|
||||
}
|
||||
|
||||
@@ -651,36 +680,59 @@ final class RefBuilder : ASTraitsVisitor
|
||||
{
|
||||
auto m = trait.name;
|
||||
|
||||
if (m.kind != ASType.QName)
|
||||
throw new Exception("Trait name is not a QName");
|
||||
// if (m.kind != ASType.QName)
|
||||
// throw new Exception("Trait name is not a QName");
|
||||
|
||||
pushContext(m);
|
||||
visitMultiname(m);
|
||||
visitMultiname(m, ContextPriority.declaration);
|
||||
switch (trait.kind)
|
||||
{
|
||||
case TraitKind.Slot:
|
||||
case TraitKind.Const:
|
||||
visitMultiname(trait.vSlot.typeName, ContextPriority.usage);
|
||||
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
case TraitKind.Class:
|
||||
addClass(trait.vClass.vclass);
|
||||
addClass(trait.vClass.vclass, ContextPriority.declaration);
|
||||
|
||||
pushContext("class", true);
|
||||
visitTraits(trait.vClass.vclass.traits);
|
||||
popContext();
|
||||
|
||||
pushContext("instance", true);
|
||||
visitTraits(trait.vClass.vclass.instance.traits);
|
||||
popContext();
|
||||
|
||||
break;
|
||||
case TraitKind.Function:
|
||||
addMethod(trait.vFunction.vfunction);
|
||||
addMethod(trait.vFunction.vfunction, ContextPriority.declaration);
|
||||
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
case TraitKind.Method:
|
||||
addMethod(trait.vMethod.vmethod);
|
||||
addMethod(trait.vMethod.vmethod, ContextPriority.declaration);
|
||||
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
case TraitKind.Getter:
|
||||
pushContext("getter");
|
||||
addMethod(trait.vMethod.vmethod);
|
||||
addMethod(trait.vMethod.vmethod, ContextPriority.declaration);
|
||||
popContext();
|
||||
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
case TraitKind.Setter:
|
||||
pushContext("setter");
|
||||
addMethod(trait.vMethod.vmethod);
|
||||
addMethod(trait.vMethod.vmethod, ContextPriority.declaration);
|
||||
popContext();
|
||||
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
default:
|
||||
super.visitTrait(trait);
|
||||
break;
|
||||
}
|
||||
super.visitTrait(trait);
|
||||
popContext();
|
||||
}
|
||||
|
||||
@@ -716,7 +768,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
|
||||
bool[uint] possibleOrphanPrivateNamespaces;
|
||||
|
||||
void visitNamespace(ASProgram.Namespace ns)
|
||||
void visitNamespace(ASProgram.Namespace ns, ContextPriority priority)
|
||||
{
|
||||
if (ns is null) return;
|
||||
|
||||
@@ -730,7 +782,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
|
||||
auto myPos = context.length;
|
||||
foreach (i, ref item; context)
|
||||
if (item.type == ContextItem.Type.Multiname && item.multiname.vQName.ns == ns)
|
||||
if (item.type == ContextItem.Type.Multiname && item.multiname.kind == ASType.QName && item.multiname.vQName.ns == ns)
|
||||
{
|
||||
myPos = i;
|
||||
break;
|
||||
@@ -742,16 +794,16 @@ final class RefBuilder : ASTraitsVisitor
|
||||
}
|
||||
|
||||
auto myContext = context[0..myPos].dup;
|
||||
namespaces[ns.kind].add(ns.id, myContext);
|
||||
namespaces[ns.kind].add(ns.id, myContext, priority);
|
||||
}
|
||||
|
||||
void visitNamespaceSet(ASProgram.Namespace[] nsSet)
|
||||
void visitNamespaceSet(ASProgram.Namespace[] nsSet, ContextPriority priority)
|
||||
{
|
||||
foreach (ns; nsSet)
|
||||
visitNamespace(ns);
|
||||
visitNamespace(ns, priority);
|
||||
}
|
||||
|
||||
void visitMultiname(ASProgram.Multiname m)
|
||||
void visitMultiname(ASProgram.Multiname m, ContextPriority priority)
|
||||
{
|
||||
if (m is null) return;
|
||||
with (m)
|
||||
@@ -759,20 +811,20 @@ final class RefBuilder : ASTraitsVisitor
|
||||
{
|
||||
case ASType.QName:
|
||||
case ASType.QNameA:
|
||||
visitNamespace(vQName.ns);
|
||||
visitNamespace(vQName.ns, priority);
|
||||
break;
|
||||
case ASType.Multiname:
|
||||
case ASType.MultinameA:
|
||||
visitNamespaceSet(vMultiname.nsSet);
|
||||
visitNamespaceSet(vMultiname.nsSet, priority);
|
||||
break;
|
||||
case ASType.MultinameL:
|
||||
case ASType.MultinameLA:
|
||||
visitNamespaceSet(vMultinameL.nsSet);
|
||||
visitNamespaceSet(vMultinameL.nsSet, priority);
|
||||
break;
|
||||
case ASType.TypeName:
|
||||
visitMultiname(vTypeName.name);
|
||||
visitMultiname(vTypeName.name, priority);
|
||||
foreach (param; vTypeName.params)
|
||||
visitMultiname(param);
|
||||
visitMultiname(param, priority);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -786,21 +838,21 @@ final class RefBuilder : ASTraitsVisitor
|
||||
switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.Namespace:
|
||||
visitNamespace(instruction.arguments[i].namespacev);
|
||||
visitNamespace(instruction.arguments[i].namespacev, ContextPriority.usage);
|
||||
break;
|
||||
case OpcodeArgumentType.Multiname:
|
||||
visitMultiname(instruction.arguments[i].multinamev);
|
||||
visitMultiname(instruction.arguments[i].multinamev, ContextPriority.usage);
|
||||
break;
|
||||
case OpcodeArgumentType.Class:
|
||||
pushContext("inline_class");
|
||||
if (isOrphan(instruction.arguments[i].classv))
|
||||
addClass(instruction.arguments[i].classv);
|
||||
addClass(instruction.arguments[i].classv, ContextPriority.usage);
|
||||
popContext();
|
||||
break;
|
||||
case OpcodeArgumentType.Method:
|
||||
pushContext("inline_method");
|
||||
if (isOrphan(instruction.arguments[i].methodv))
|
||||
addMethod(instruction.arguments[i].methodv);
|
||||
addMethod(instruction.arguments[i].methodv, ContextPriority.usage);
|
||||
popContext();
|
||||
break;
|
||||
default:
|
||||
@@ -867,7 +919,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
}
|
||||
|
||||
if (pathSegment.length > 240)
|
||||
pathSegment = pathSegment[0..200] ~ '-' ~ getDigestString(pathSegment);
|
||||
pathSegment = assumeUnique(pathSegment[0..200] ~ '-' ~ toHexString(md5Of(pathSegment)));
|
||||
}
|
||||
|
||||
return arrayJoin(pathSegments, "/");
|
||||
@@ -880,35 +932,38 @@ final class RefBuilder : ASTraitsVisitor
|
||||
return arrayJoin(strings);
|
||||
}
|
||||
|
||||
bool addObject(T)(T obj) { return objects.add(obj, context); }
|
||||
bool addObject(T)(T obj, ContextPriority priority) { return objects.add(obj, context, priority); }
|
||||
|
||||
void addClass(ASProgram.Class vclass)
|
||||
void addClass(ASProgram.Class vclass, ContextPriority priority)
|
||||
{
|
||||
addObject(vclass);
|
||||
addObject(vclass, priority);
|
||||
|
||||
pushContext("cinit");
|
||||
addMethod(vclass.cinit);
|
||||
popContext();
|
||||
pushContext("class", true);
|
||||
pushContext("init", true);
|
||||
addMethod(vclass.cinit, ContextPriority.declaration);
|
||||
popContext(); // init
|
||||
popContext(); // class
|
||||
|
||||
pushContext("iinit");
|
||||
addMethod(vclass.instance.iinit);
|
||||
popContext();
|
||||
pushContext("instance", true);
|
||||
pushContext("init", true);
|
||||
addMethod(vclass.instance.iinit, ContextPriority.declaration);
|
||||
popContext(); // init
|
||||
|
||||
pushContext("instance");
|
||||
visitMultiname(vclass.instance.name);
|
||||
visitMultiname(vclass.instance.superName);
|
||||
visitMultiname(vclass.instance.name, ContextPriority.declaration);
|
||||
visitMultiname(vclass.instance.superName, ContextPriority.usage);
|
||||
visitNamespace(vclass.instance.protectedNs, ContextPriority.declaration);
|
||||
foreach (iface; vclass.instance.interfaces)
|
||||
visitMultiname(iface);
|
||||
popContext();
|
||||
visitMultiname(iface, ContextPriority.usage);
|
||||
popContext(); // instance
|
||||
}
|
||||
|
||||
void addMethod(ASProgram.Method method)
|
||||
void addMethod(ASProgram.Method method, ContextPriority priority)
|
||||
{
|
||||
if (addObject(method))
|
||||
if (addObject(method, priority))
|
||||
{
|
||||
foreach (paramType; method.paramTypes)
|
||||
visitMultiname(paramType);
|
||||
visitMultiname(method.returnType);
|
||||
visitMultiname(paramType, ContextPriority.usage);
|
||||
visitMultiname(method.returnType, ContextPriority.usage);
|
||||
if (method.vbody)
|
||||
visitMethodBody(method.vbody);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -59,6 +59,7 @@ ubyte[] lzmaDecompress(LZMAHeader header, in ubyte[] compressedData)
|
||||
}
|
||||
|
||||
header.decompressedSize = -1; // Required as Flash uses End-of-Stream marker
|
||||
fixDictSize(header.dictionarySize);
|
||||
decompress(cast(ubyte[])(&header)[0..1]);
|
||||
decompress(compressedData);
|
||||
|
||||
@@ -84,7 +85,6 @@ ubyte[] lzmaCompress(in ubyte[] decompressedData, LZMAHeader* header)
|
||||
strm.next_in = decompressedData.ptr;
|
||||
strm.avail_in = decompressedData.length;
|
||||
lzmaEnforce(lzma_code(&strm, lzma_action.LZMA_RUN), "lzma_code (LZMA_RUN)");
|
||||
scope(failure) { import std.stdio; writeln("avail_in=", strm.avail_in); }
|
||||
enforce(strm.avail_in == 0, "Not all data was read");
|
||||
enforce(strm.avail_out != 0, "Ran out of compression space");
|
||||
|
||||
@@ -99,3 +99,18 @@ private void lzmaEnforce(bool STREAM_END_OK=false)(lzma_ret v, string f)
|
||||
if (v != lzma_ret.LZMA_OK && (!STREAM_END_OK || v != lzma_ret.LZMA_STREAM_END))
|
||||
throw new Exception(text(f, " error: ", v));
|
||||
}
|
||||
|
||||
/// Work around an artificial lzma_alone_decoder limitation in liblzma
|
||||
/// which prevents it from accepting any streams with a dictionary size
|
||||
/// that is not 2^n or 2^n + 2^(n-1).
|
||||
/// See xz\src\liblzma\common\alone_decoder.c (git commit e7b424d267), line 87
|
||||
private void fixDictSize(ref uint d)
|
||||
{
|
||||
--d;
|
||||
d |= d >> 2;
|
||||
d |= d >> 3;
|
||||
d |= d >> 4;
|
||||
d |= d >> 8;
|
||||
d |= d >> 16;
|
||||
++d;
|
||||
}
|
||||
|
||||
+35
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -18,18 +18,50 @@
|
||||
|
||||
module swflzmacompress;
|
||||
|
||||
import std.exception;
|
||||
import std.file;
|
||||
import std.getopt;
|
||||
import std.string;
|
||||
import swffile;
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
bool force, updateVersion;
|
||||
getopt(args,
|
||||
"--force", &force,
|
||||
"--update-version", &updateVersion,
|
||||
);
|
||||
|
||||
if (args.length == 1)
|
||||
throw new Exception("No file specified");
|
||||
enum MIN_LZMA_VER = 13;
|
||||
foreach (arg; args[1..$])
|
||||
{
|
||||
auto swf = SWFFile.read(cast(ubyte[])read(arg));
|
||||
if (swf.header.signature[0] == cast(ubyte)'Z')
|
||||
throw new Exception("Already LZMA-compressed");
|
||||
enforce(swf.header.signature[0] != cast(ubyte)'Z', "Already LZMA-compressed");
|
||||
if (swf.header.ver < MIN_LZMA_VER)
|
||||
{
|
||||
if (updateVersion)
|
||||
{
|
||||
if (swf.header.ver < 8 && !force)
|
||||
throw new Exception(format(
|
||||
"SWF version %d has different file format than version %d, " ~
|
||||
"required for LZMA. Resulting file may not work. " ~
|
||||
"Use --force to override and update version anyway.",
|
||||
swf.header.ver, MIN_LZMA_VER
|
||||
));
|
||||
swf.header.ver = MIN_LZMA_VER;
|
||||
}
|
||||
else
|
||||
if (!force)
|
||||
throw new Exception(format(
|
||||
"SWF version %d is too old to support SWF LZMA compression, " ~
|
||||
"which requires version %d. " ~
|
||||
"Use --update-version to update the version number, " ~
|
||||
"or --force to compress anyway without updating it.",
|
||||
swf.header.ver, MIN_LZMA_VER
|
||||
));
|
||||
}
|
||||
swf.header.signature[0] = cast(ubyte)'Z'; // LZMA
|
||||
write(arg, swf.write());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user