45 Commits
d1 ... 1.6
Author SHA1 Message Date
Vladimir Panteleev e49a6b3fec Update Changelog 2011-05-13 03:20:57 +03:00
Vladimir Panteleev bfa02943c6 disassembler: escape % too (the escape character) 2011-05-13 03:08:40 +03:00
Vladimir Panteleev cf8835b87d disassember: Escape space characters in filenames too (Windows forbids leading/trailing spaces) 2011-05-12 13:59:32 +03:00
Vladimir Panteleev 4c411ac1f2 Minor changes 2011-05-12 13:58:56 +03:00
Vladimir Panteleev 76cadf30cf Add swfbinexport and swfbinreplace utilities 2011-05-12 08:33:51 +03:00
Vladimir Panteleev 2498673231 Update copyright notices 2011-05-12 08:07:57 +03:00
Vladimir Panteleev a1b9ea05c0 Add a simple build tool 2011-05-12 07:59:26 +03:00
Vladimir Panteleev a766cf5919 Emit commented-out method body with raw hex bytes 2011-05-11 04:24:43 +03:00
Vladimir Panteleev e6f54db4c1 disassembler: Handle infinities in double shortening 2011-05-11 03:59:40 +03:00
Vladimir Panteleev 51e82bf985 Update Changelog 2011-05-11 03:45:39 +03:00
Vladimir Panteleev 282e8cbfc1 asprogram: Remove enum compiler hack 2011-05-11 01:06:09 +03:00
Vladimir Panteleev 4f53b789ee disassembler: aggressively try to shorten double literals 2011-04-17 22:46:12 +03:00
Vladimir Panteleev 0c5cbde348 disassembler: refuse to overwrite files 2011-04-17 08:29:03 +03:00
Vladimir Panteleev ff799d002f disassembler: place the contents of an entire script in one file 2011-04-17 08:11:35 +03:00
Vladimir Panteleev 1bf7a9a593 disassembler: handle private namespaces only referenced in initalizers 2011-04-16 20:53:50 +03:00
Vladimir Panteleev 1167b14471 disassembler: place script initializers in files near the rest of the script content 2011-04-16 20:09:39 +03:00
Vladimir Panteleev d3e8e47d54 disassembler: better refids and location for orphan classes and methods
This also changes the way classes are written (in a backwards-compatible
way).
2011-04-16 08:32:25 +03:00
Vladimir Panteleev 3f9be2b192 Whitespace 2011-04-16 08:25:39 +03:00
Vladimir Panteleev a690c82b7d disassembler: write exact context of private namespaces as a comment in the .privatens.asasm file 2011-04-16 07:15:49 +03:00
Vladimir Panteleev 2d7886bb0b disassembler: relax rootContext 2011-04-15 18:22:50 +03:00
Vladimir Panteleev 4cb179a1c6 disassembler: allow named private namespaces (ignore the name) 2011-04-15 18:21:45 +03:00
Vladimir Panteleev 0031be1f75 disassembler: improve context abbreviation for some cases 2011-04-15 17:58:06 +03:00
Vladimir Panteleev c7b7a5bce8 disassembler: Sort #privatens directives alphabetically 2011-04-15 17:46:29 +03:00
Vladimir Panteleev ac5d4b5e74 disassembler: rewrite the way refids/private namespace names are generated.
This will also place nested classes correctly in the directory structure.
2011-04-15 17:37:46 +03:00
Vladimir Panteleev eb07838668 Documentation: v1.1 change did not in fact break backwards compatibility 2011-04-15 07:15:45 +03:00
Vladimir Panteleev b80fe48bee Failing to decode a method body is now not a fatal error
Some obfuscators seem to append an orphan method to the end of the file
filled with junk. The disassembly will contain an empty body with a comment
describing the error message.
2011-04-14 13:26:17 +03:00
Vladimir Panteleev a083ed265f disassembler: always disassemble to the same location as the source file
Previously, rabcdasm would always create the disassembly directory in the
current directory.
2011-04-14 12:26:34 +03:00
Vladimir Panteleev 986ea47d03 Use "final switch" for opcode types 2011-04-14 11:50:31 +03:00
Vladimir Panteleev 3520d34cc2 Output correct opcode error location 2011-04-14 11:40:03 +03:00
Vladimir Panteleev 58ab6e3bf0 Documentation updates 2011-04-14 05:50:17 +03:00
Vladimir Panteleev 413aa9b5f0 Update Changelog 2011-04-14 05:28:22 +03:00
Vladimir Panteleev 5da1e26835 Add support for memory-access and sign-extend opcodes 2011-04-14 05:02:03 +03:00
Vladimir Panteleev 53a4173fd3 Improve exception handling code 2011-04-14 05:01:40 +03:00
Vladimir Panteleev 5737243606 Update Changelog 2011-03-22 12:33:46 +02:00
Vladimir Panteleev be727e67c6 Documentation: remove -release from compilation instructions 2011-03-22 10:37:43 +02:00
Vladimir Panteleev 9d67c46835 abcfile: Use preallocated initial buffer for writeMethodBody 2011-03-22 09:50:27 +02:00
Vladimir Panteleev 756a2fd060 assembler: Remove a TODO for a bad idea 2011-03-22 09:47:30 +02:00
Vladimir Panteleev 8ad1f85a45 asprogram: sort faster 2011-03-22 09:18:14 +02:00
Vladimir Panteleev ad6ae5d087 autodata: Fix grouping of array fields (D2 porting bug) 2011-03-22 05:46:42 +02:00
Vladimir Panteleev 580a1364d0 Clarify some asserts 2011-03-22 04:39:25 +02:00
Vladimir Panteleev d4f90f9c01 Documentation: compile with optimization 2011-03-22 04:33:50 +02:00
Vladimir Panteleev cecff913f1 Update Changelog 2011-03-07 20:26:52 +02:00
Vladimir Panteleev 7a4c78dac3 Documentation: svn no longer required 2011-03-07 20:26:37 +02:00
Vladimir Panteleev ee47075fda Merge branch 'd2' 2011-03-07 14:11:20 +02:00
Vladimir Panteleev 100f6b6bf4 Port to D2 2011-02-20 20:48:24 +02:00
19 changed files with 997 additions and 528 deletions
+38 -2
View File
@@ -1,9 +1,46 @@
RABCDAsm Changelog
==================
RABCDAsm v1.4 (2011.02.xx)
RABCDAsm v1.6 (2011.05.13)
--------------------------
* Overhaul of the structure of disassembler-generated files
* Private namespace names and `refid`s for nested classes are now generated
from their referenced contexts
* This also fixes problems caused by private namespaces being referenced
in multiple distinct contexts
* One `#include`d file per script instead of per class
* Nested classes, script initializers and other script traits are now in
the same file as their main class
* Inline methods are now in separate files, placed according to their usage
context
* Private namespaces are sorted by their autogenerated names in the
`.privatens.asasm` file
* No syntax changes, output is backwards-compatible
* Improved escaping of file names
* Output correct opcode error locations
* Disassembler will now refuse to overwrite files
* `rabcdasm` will now always generate output in the same directory as the
input file
* Failure to decode a method body is now not a fatal error
* Aggressively try to shorten double literals to their shortest representation
* Added the `swfbinexport` and `swfbinreplace` utilities, to aid in manipulating
contents of `DefineBinaryData` tags
* The package can now be built using a simple, dedicated build tool
* Documentation updates
RABCDAsm v1.5 (2011.04.14)
--------------------------
* Fixed v1.4 constant pool regression
* Added support for memory-access and sign-extend opcodes
* Speed optimizations
* Documentation updates
RABCDAsm v1.4 (2011.03.07)
--------------------------
* Source code ported to D2
* Add support for forward-references for TypeName-kind Multinames
* Correctly order classes by dependencies (extends/implements) and reference
count
@@ -33,7 +70,6 @@ RABCDAsm v1.1 (2010.06.30)
* Private namespaces are now referenced by auto-generated names
* Use `:` to delimit namespace and name in QNames for consistency
* Warning: this breaks compatibility with v1.0 disassemblies
* Fixed relative include paths
* Add optional byte offsets to labels, which allows lossless representation
of jumps inside instructions and outside the function bounds
+32 -31
View File
@@ -11,6 +11,8 @@ These are:
* `abcreplace` - replaces ABC in SWF files
* `swfdecompress` - decompresses zlib-compressed SWF files
* `swf7zcompress` - (re-)compress the contents of a SWF using 7-Zip
* `swfbinexport` / `swfbinreplace` - extract/replace contents of binary
data tags from SWF files
`abcexport` and `abcreplace` are reimplementations of similar utilities from
my [swfutilsex][] Java package, however these work faster as they do not parse
@@ -21,6 +23,9 @@ equivalent to [flasm][]'s `-x` option.
`swf7zcompress` is an utility to further reduce the size of SWF files. It uses
[7-Zip][] to compress the data better than the standard zlib library would. It
requires that the `7z` command-line program be installed and in `PATH`.
`swfbinexport` and `swfbinreplace` aid in the manipulation of
`DefineBinaryData` tags in SWF files (some files may contain nested SWF files
stored in these tags).
[RABCDAsm]: http://github.com/CyberShadow/RABCDAsm
[swfutilsex]: http://github.com/CyberShadow/swfutilsex
@@ -48,27 +53,23 @@ bytecode with the following properties:
Compiling from source
---------------------
RABCDAsm is written in the [D programming language, version 1][d1]. It uses one
third-party library, [std2][] (for some fancy template stuff).
RABCDAsm is written in the [D programming language, version 2][d2].
Assuming you have [dmd][], [git][] and [svn][] installed, compiling should be
as straight-forward as:
Assuming you have [git][] and a D2 compiler, such as [dmd][] or [gdc][]
installed, compiling should be as straight-forward as:
git clone git://github.com/CyberShadow/RABCDAsm.git
cd RABCDAsm
svn co http://svn.dsource.org/projects/std2/trunk/std2/std2
dmd rabcdasm abcfile asprogram disassembler autodata murmurhash2a
dmd rabcasm abcfile asprogram assembler autodata murmurhash2a
dmd abcexport swffile zlibx
dmd abcreplace swffile zlibx
dmd swfdecompress swffile zlibx
dmd swf7zcompress swffile zlibx
dmd -run build_rabcdasm
[d1]: http://www.digitalmars.com/d/1.0/
[std2]: http://dsource.org/projects/std2
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 (`-O -inline`).
[d2]: http://www.digitalmars.com/d/2.0/
[dmd]: http://www.digitalmars.com/d/download.html
[gdc]: http://bitbucket.org/goshawk/gdc/
[git]: http://git-scm.com/
[svn]: http://subversion.apache.org/
Pre-compiled binaries
---------------------
@@ -300,9 +301,9 @@ be instantiated in two ways:
although variables are defined using a string syntax, they are not
inserted as a string using this syntax. Thus, the code:
#set str "Hello, world!"
...
pushstring $str
#set str "Hello, world!"
...
pushstring $str
will expand to `pushstring Hello, world!`, which will result in an error.
To correct the problem, add escaped quotes around the variable contents
@@ -388,7 +389,7 @@ RABCDAsm users.
2. If you plan on making non-trivial changes to SWF files, you should install
the [debug Flash Player][]. This will allow you to see validation and
run-time error messages, instead of simply getting a blank rectangle.
run-time error messages, instead of simply getting an empty window.
[debug Flash Player]: http://www.adobe.com/support/flashplayer/downloads.html
@@ -397,19 +398,19 @@ RABCDAsm users.
placed in the `OnBeforeResponse` function) will automatically save all SWF
files while preserving the directory structure.
if (oSession.oResponse.headers.ExistsAndContains("Content-Type",
"application/x-shockwave-flash")) {
// Set desired path here
var path:String = "C:\\Temp\\FiddlerCapture\\" +
oSession.host + oSession.PathAndQuery;
if (path.Contains('?'))
path = path.Substring(0, path.IndexOf('?'));
var dir:String = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
oSession.utilDecodeResponse();
oSession.SaveResponseBody(path);
}
if (oSession.oResponse.headers.ExistsAndContains("Content-Type",
"application/x-shockwave-flash")) {
// Set desired path here
var path:String = "C:\\Temp\\FiddlerCapture\\" +
oSession.host + oSession.PathAndQuery;
if (path.Contains('?'))
path = path.Substring(0, path.IndexOf('?'));
var dir:String = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
oSession.utilDecodeResponse();
oSession.SaveResponseBody(path);
}
Once you have edited a SWF file, you can use Fiddler's [AutoResponder][] to
replace the original file with your modified version.
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -20,7 +20,7 @@ module abcexport;
import std.file;
import std.path;
import std.string;
import std.conv;
import std.stdio;
import swffile;
@@ -45,11 +45,11 @@ void main(string[] args)
while (*p++) {} // skip name
abc = tag.data[p-tag.data.ptr..$];
}
write(getName(arg) ~ .toString(count++) ~ ".abc", abc);
std.file.write(getName(arg) ~ to!string(count++) ~ ".abc", abc);
}
if (count == 0)
throw new Exception("No DoABC tags found");
}
catch (Object o)
writefln("Error while processing %s: %s", arg, o);
catch (Exception e)
writefln("Error while processing %s: %s", arg, e);
}
+50 -42
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -19,9 +19,10 @@
module abcfile;
import std.string : format; // exception formatting
import std.exception;
/**
* Implements a shallow representation of an .abc file.
/**
* Implements a shallow representation of an .abc file.
* Loading and saving an .abc file using this class should produce
* output identical to the input.
*/
@@ -181,7 +182,7 @@ class ABCFile
// TraitAttributes bitmask
ubyte attr() { return cast(ubyte)(kindAttr >> 4); }
void attr(ubyte value) { kindAttr = (kindAttr&0xF) | (value<<4); }
void attr(ubyte value) { kindAttr = cast(ubyte)((kindAttr&0xF) | (value<<4)); }
}
struct Class
@@ -206,6 +207,9 @@ class ABCFile
Instruction[] instructions;
ExceptionInfo[] exceptions;
TraitsInfo[] traits;
string error;
ubyte[] rawBytes;
}
/// Destination for a jump or exception block boundary
@@ -387,7 +391,7 @@ enum MethodFlags : ubyte
NEED_REST = 0x04, // This flag creates an ActionScript 3.0 rest arguments array. Must not be used with NEED_ARGUMENTS. See Chapter 3.
HAS_OPTIONAL = 0x08, // Must be set if this method has optional parameters and the options field is present in this method_info structure.
SET_DXNS = 0x40, // Must be set if this method uses the dxns or dxnslate opcodes.
HAS_PARAM_NAMES = 0x80, // Must be set when the param_names field is present in this method_info structure.
HAS_PARAM_NAMES = 0x80, // Must be set when the param_names field is present in this method_info structure.
}
const string[8] MethodFlagNames = ["NEED_ARGUMENTS", "NEED_ACTIVATION", "NEED_REST", "HAS_OPTIONAL", "0x10", "0x20", "SET_DXNS", "HAS_PARAM_NAMES"];
@@ -708,16 +712,16 @@ const OpcodeInfo[256] opcodeInfo = [
/* 0x32 */ {"hasnext2", [OpcodeArgumentType.UIntLiteral, OpcodeArgumentType.UIntLiteral]},
/* 0x33 */ {"pushdecimal", [OpcodeArgumentType.Unknown]},
/* 0x34 */ {"pushdnan", [OpcodeArgumentType.Unknown]},
/* 0x35 */ {"li8", [OpcodeArgumentType.Unknown]},
/* 0x36 */ {"li16", [OpcodeArgumentType.Unknown]},
/* 0x37 */ {"li32", [OpcodeArgumentType.Unknown]},
/* 0x38 */ {"lf32", [OpcodeArgumentType.Unknown]},
/* 0x39 */ {"lf64", [OpcodeArgumentType.Unknown]},
/* 0x3A */ {"si8", [OpcodeArgumentType.Unknown]},
/* 0x3B */ {"si16", [OpcodeArgumentType.Unknown]},
/* 0x3C */ {"si32", [OpcodeArgumentType.Unknown]},
/* 0x3D */ {"sf32", [OpcodeArgumentType.Unknown]},
/* 0x3E */ {"sf64", [OpcodeArgumentType.Unknown]},
/* 0x35 */ {"li8", []},
/* 0x36 */ {"li16", []},
/* 0x37 */ {"li32", []},
/* 0x38 */ {"lf32", []},
/* 0x39 */ {"lf64", []},
/* 0x3A */ {"si8", []},
/* 0x3B */ {"si16", []},
/* 0x3C */ {"si32", []},
/* 0x3D */ {"sf32", []},
/* 0x3E */ {"sf64", []},
/* 0x3F */ {"0x3F", [OpcodeArgumentType.Unknown]},
/* 0x40 */ {"newfunction", [OpcodeArgumentType.Method]},
/* 0x41 */ {"call", [OpcodeArgumentType.UIntLiteral]},
@@ -735,9 +739,9 @@ const OpcodeInfo[256] opcodeInfo = [
/* 0x4D */ {"callinterface", [OpcodeArgumentType.Unknown]},
/* 0x4E */ {"callsupervoid", [OpcodeArgumentType.Multiname, OpcodeArgumentType.UIntLiteral]},
/* 0x4F */ {"callpropvoid", [OpcodeArgumentType.Multiname, OpcodeArgumentType.UIntLiteral]},
/* 0x50 */ {"sxi1", [OpcodeArgumentType.Unknown]},
/* 0x51 */ {"sxi8", [OpcodeArgumentType.Unknown]},
/* 0x52 */ {"sxi16", [OpcodeArgumentType.Unknown]},
/* 0x50 */ {"sxi1", []},
/* 0x51 */ {"sxi8", []},
/* 0x52 */ {"sxi16", []},
/* 0x53 */ {"applytype", [OpcodeArgumentType.UIntLiteral]},
/* 0x54 */ {"0x54", [OpcodeArgumentType.Unknown]},
/* 0x55 */ {"newobject", [OpcodeArgumentType.UIntLiteral]},
@@ -992,13 +996,13 @@ private final class ABCReader
foreach (ref value; abc.bodies)
value = readMethodBody();
}
catch (Object o)
throw new Exception(format("Error at %d (0x%X): %s", pos, pos, o));
catch (Exception e)
throw new Exception(format("Error at %d (0x%X):", pos, pos), e);
}
ubyte readU8()
{
assert(pos < buf.length);
enforce(pos < buf.length, "End of file reached");
return buf[pos++];
}
@@ -1046,7 +1050,7 @@ private final class ABCReader
void readExact(void* ptr, size_t len)
{
assert(pos+len <= buf.length);
enforce(pos+len <= buf.length, "End of file reached");
(cast(ubyte*)ptr)[0..len] = buf[pos..pos+len];
pos += len;
}
@@ -1061,8 +1065,9 @@ private final class ABCReader
string readString()
{
string s = new char[readU30()];
readExact(s.ptr, s.length);
char[] buf = new char[readU30()];
readExact(buf.ptr, buf.length);
string s = assumeUnique(buf);
if (s.length == 0)
s = ""; // not null!
return s;
@@ -1276,6 +1281,7 @@ private final class ABCReader
size_t len = readU30();
uint[] instructionAtOffset = new uint[len];
r.rawBytes = buf[pos..pos+len];
void translateLabel(ref ABCFile.Label label)
{
@@ -1305,23 +1311,25 @@ private final class ABCReader
label.offset = absoluteOffset-instructionOffset;
}
size_t start = pos;
size_t end = pos + len;
uint offset() { return pos - start; }
try
{
size_t start = pos;
size_t end = pos + len;
uint offset() { return pos - start; }
instructionAtOffset[] = uint.max;
uint[] instructionOffsets;
while (pos < end)
{
uint instructionOffset = offset;
scope(failure) pos = start + instructionOffset;
instructionAtOffset[instructionOffset] = r.instructions.length;
ABCFile.Instruction instruction;
instruction.opcode = cast(Opcode)readU8();
instruction.arguments.length = opcodeInfo[instruction.opcode].argumentTypes.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to decode OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1361,9 +1369,6 @@ private final class ABCReader
foreach (ref label; instruction.arguments[i].switchTargets)
label.absoluteOffset = instructionOffset + readS24();
break;
default:
assert(0);
}
r.instructions ~= instruction;
instructionOffsets ~= instructionOffset;
@@ -1388,8 +1393,13 @@ private final class ABCReader
default:
break;
}
pos = end;
}
catch (Exception e)
{
r.instructions = null;
r.error = e.msg;
}
pos = end;
r.exceptions.length = readU30();
foreach (ref value; r.exceptions)
@@ -1471,7 +1481,7 @@ private final class ABCWriter
foreach (ref value; abc.instances)
writeInstance(value);
assert(abc.classes.length == abc.instances.length);
assert(abc.classes.length == abc.instances.length, "Number of classes and instances differs");
foreach (ref value; abc.classes)
writeClass(value);
@@ -1551,7 +1561,7 @@ private final class ABCWriter
writeU32(v);
}
void writeExact(void* ptr, size_t len)
void writeExact(const(void)* ptr, size_t len)
{
while (pos+len > buf.length)
buf.length = buf.length * 2;
@@ -1643,7 +1653,7 @@ private final class ABCWriter
}
if (v.flags & MethodFlags.HAS_PARAM_NAMES)
{
assert(v.paramNames.length == v.paramTypes.length);
assert(v.paramNames.length == v.paramTypes.length, "Mismatching number of parameter names and types");
foreach (value; v.paramNames)
writeU30(value);
}
@@ -1753,7 +1763,8 @@ private final class ABCWriter
// we don't know the length before writing all the instructions - swap buffer with a temporary one
auto globalBuf = buf;
auto globalPos = pos;
buf = new ubyte[1024];
static ubyte[1024*16] methodBuf;
buf = methodBuf[];
pos = 0;
struct Fixup { ABCFile.Label target; uint pos, base; }
@@ -1770,7 +1781,7 @@ private final class ABCWriter
throw new Exception("Mismatching number of arguments");
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to encode OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1816,9 +1827,6 @@ private final class ABCWriter
writeS24(0);
}
break;
default:
assert(0);
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -27,7 +27,7 @@ void main(string[] args)
if (args.length != 4)
throw new Exception("Bad arguments. Usage: abcreplace file.swf index code.abc");
auto swf = SWFFile.read(cast(ubyte[])read(args[1]));
auto index = toUint(args[2]);
auto index = to!uint(args[2]);
uint count;
foreach (ref tag; swf.tags)
if ((tag.type == TagType.DoABC || tag.type == TagType.DoABC2) && count++ == index)
+65 -93
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -18,10 +18,12 @@
module asprogram;
import std.algorithm;
import core.stdc.string;
import abcfile;
import autodata;
/**
/**
* Represents a hierarchically-organized ActionScript program,
* with all constants expanded and bytecode disassembled to separate instructions.
*/
@@ -41,16 +43,8 @@ final class ASProgram
uint privateIndex; // unique index for private namespaces
mixin AutoCompare;
//mixin ProcessAllData;
R processData(R, string prolog, string epilog, H)(ref H handler)
{
mixin(prolog);
mixin(addAutoField("kind"));
mixin(addAutoField("name"));
mixin(addAutoField("privateIndex"));
mixin(epilog);
}
mixin AutoToString;
mixin ProcessAllData;
}
static class Multiname
@@ -89,7 +83,7 @@ final class ASProgram
mixin AutoCompare;
mixin AutoToString;
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
mixin(addAutoField("kind"));
@@ -192,7 +186,7 @@ final class ASProgram
}
struct Value
{
{
ASType vkind;
union
{
@@ -244,7 +238,7 @@ final class ASProgram
Instance instance;
string toString()
override string toString()
{
return instance.name.toString();
}
@@ -266,6 +260,9 @@ final class ASProgram
Instruction[] instructions;
Exception[] exceptions;
Trait[] traits;
string error;
ubyte[] rawBytes;
}
struct Instruction
@@ -584,6 +581,8 @@ private final class ABCtoAS
e.varName = multinames[exc.varName];
}
n.traits = convertTraits(vbody.traits);
n.error = vbody.error;
n.rawBytes = vbody.rawBytes;
return n;
}
@@ -594,7 +593,7 @@ private final class ABCtoAS
r.arguments.length = instruction.arguments.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -642,9 +641,6 @@ private final class ABCtoAS
case OpcodeArgumentType.SwitchTargets:
r.arguments[i].switchTargets = instruction.arguments[i].switchTargets;
break;
default:
assert(0);
}
return r;
}
@@ -732,9 +728,24 @@ private final class AStoABC
return value == T.init;
}
static void move(T)(T[] array, size_t from, size_t to)
{
assert(from<array.length && to<array.length);
if (from == to)
return;
T t = array[from];
if (from < to)
memmove(array.ptr+from, array.ptr+from+1, (to-from)*T.sizeof);
else
memmove(array.ptr+to+1, array.ptr+to, (from-to)*T.sizeof);
array[to] = t;
}
/// Maintain an unordered set of values; sort/index by usage count
struct ConstantPool(T, bool haveNull = true)
{
alias immutable(T) I;
struct Entry
{
uint hits;
@@ -743,7 +754,7 @@ private final class AStoABC
mixin AutoCompare;
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
mixin(addAutoField("hits", true));
@@ -752,17 +763,17 @@ private final class AStoABC
}
}
Entry[T] pool;
Entry[immutable(T)] pool;
T[] values;
bool add(T value) // return true if added
{
if (haveNull && isNull(value))
return false;
auto cp = value in pool;
auto cp = cast(I)value in pool;
if (cp is null)
{
pool[value] = Entry(1, value);
pool[cast(I)value] = Entry(1, value);
return true;
}
else
@@ -774,7 +785,7 @@ private final class AStoABC
bool notAdded(T value)
{
auto ep = value in pool;
auto ep = cast(I)value in pool;
if (ep)
ep.hits++;
return !((haveNull && isNull(value)) || ep);
@@ -788,7 +799,7 @@ private final class AStoABC
values.length = all.length + NullOffset;
foreach (i, ref c; all)
{
pool[c.value].index = i + NullOffset;
pool[cast(I)c.value].index = i + NullOffset;
values[i + NullOffset] = c.value;
}
}
@@ -797,7 +808,7 @@ private final class AStoABC
{
if (haveNull && isNull(value))
return 0;
return pool[value].index;
return pool[cast(I)value].index;
}
}
@@ -811,17 +822,8 @@ private final class AStoABC
uint addIndex, index;
void*[] parents;
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;
}
mixin AutoToString;
mixin ProcessAllData;
}
Entry[void*] pool;
@@ -871,61 +873,37 @@ private final class AStoABC
void finalize()
{
// assign unique index
// create array
auto all = new Entry*[pool.length];
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;
all[i++] = &e;
// sort
//all.sort; // sort preserving topological integrity demands compared items to always be adjacent
done = false;
while (!done)
{
done = true;
sort!q{a.hits > b.hits || (a.hits == b.hits && a.addIndex < b.addIndex)}(all);
for (int j=0; j<all.length-1; j++)
if (all[j] > &all[j+1])
// topographical sort
topSort:
// update indices
foreach (j, e; all)
e.index = j;
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 = all[j];
all[j] = all[j+1];
all[j+1] = t;
done = false;
move(all, pb.index, a.index);
goto topSort;
}
}
}
objects.length = i;
foreach (j, ref e; all)
{
pool[e.object].index = j;
foreach (j, e; all)
objects[j] = cast(T)e.object;
}
}
uint get(T obj)
@@ -996,7 +974,7 @@ private final class AStoABC
throw new .Exception("Unknown Multiname kind");
}
bool r = multinames.add(multiname);
assert(r);
assert(r, "Recursive multiname reference");
}
}
@@ -1095,7 +1073,7 @@ private final class AStoABC
visitInstance(vclass.instance);
bool r = classes.add(vclass);
assert(r);
assert(r, "Recursive class reference");
}
}
@@ -1110,7 +1088,7 @@ private final class AStoABC
strings.add(name);
foreach (ref value; options)
visitValue(value);
foreach (name; paramNames)
foreach (name; paramNames)
strings.add(name);
if (vbody)
@@ -1122,7 +1100,7 @@ private final class AStoABC
{
foreach (ref instruction; vbody.instructions)
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to visit OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1161,9 +1139,6 @@ private final class AStoABC
case OpcodeArgumentType.SwitchDefaultTarget:
case OpcodeArgumentType.SwitchTargets:
break;
default:
assert(0);
}
foreach (ref exception; vbody.exceptions)
@@ -1474,7 +1449,7 @@ private final class AStoABC
r.arguments.length = instruction.arguments.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1522,9 +1497,6 @@ private final class AStoABC
case OpcodeArgumentType.SwitchTargets:
r.arguments[i].switchTargets = instruction.arguments[i].switchTargets;
break;
default:
assert(0);
}
return r;
}
+37 -54
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -22,6 +22,7 @@ import std.file;
import std.string;
import std.conv;
import std.path;
import std.exception;
import abcfile;
import asprogram;
@@ -44,8 +45,8 @@ final class Assembler
{
string filename;
string buf;
char* pos;
char* end;
immutable(char)* pos;
immutable(char)* end;
string[] arguments;
string basePath;
@@ -53,7 +54,7 @@ final class Assembler
{
return fromFile(filename, cast(string)read(filename), arguments);
}
static File fromFile(string filename, string data, string[] arguments = null)
{
return fromData(filename, data, arguments, getDirName(filename));
@@ -61,7 +62,7 @@ final class Assembler
static File fromData(string name, string data, string[] arguments = null, string basePath = null)
{
data ~= \0; data = data[0..$-1]; // hack to prevent readWord etc. from checking for end-of-file on every character
data ~= "\0"; data = data[0..$-1]; // hack to prevent readWord etc. from checking for end-of-file on every character
return File(name, data, data.ptr, data.ptr + data.length, arguments, basePath);
}
@@ -74,7 +75,7 @@ final class Assembler
}
string positionStr()
{
{
auto lines = splitlines(buf);
foreach (i, line; lines)
if (pos <= line.ptr + line.length)
@@ -93,16 +94,16 @@ final class Assembler
return file.basePath;
return null;
}
string convertFilename(string filename)
{
if (filename.length == 0)
throw new Exception("Empty filename");
filename = filename.dup;
foreach (ref c; filename)
auto buf = filename.dup;
foreach (ref c; buf)
if (c == '\\')
c = '/';
return std.path.join(getBasePath, filename);
return std.path.join(getBasePath, assumeUnique(buf));
}
void skipWhitespace()
@@ -126,7 +127,7 @@ final class Assembler
do {} while (*++files[0].pos != '\n');
}
else
return;
return;
}
}
@@ -190,7 +191,7 @@ final class Assembler
foreach (ref file; files[0..fileCount])
if (file.arguments.length)
{
uint index = .toUint(name)-1;
uint index = .to!uint(name)-1;
if (index >= file.arguments.length)
throw new Exception("Argument index out-of-bounds");
string value = file.arguments[index];
@@ -211,7 +212,7 @@ final class Assembler
static bool isWordChar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.'; // TODO: use lookup table?
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.';
}
string readWord()
@@ -249,12 +250,12 @@ final class Assembler
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default:
default:
throw new Exception("Malformed hex digit " ~ x);
}
}
void pushFile(ref File file)
void pushFile(File file)
{
if (fileCount == files.length)
throw new Exception("Recursion limit exceeded");
@@ -264,7 +265,7 @@ final class Assembler
}
/// For restoring the position of an error
void setFile(ref File file)
void setFile(File file)
{
files[0] = file;
fileCount = -1;
@@ -357,7 +358,7 @@ final class Assembler
static const char[16] hexDigits = "0123456789ABCDEF";
// TODO: optimize
string s = \";
string s = "\"";
foreach (c; str)
if (c == 0x0A)
s ~= `\n`;
@@ -422,7 +423,7 @@ final class Assembler
return v;
}
ubyte readFlag(string[] names)
ubyte readFlag(const string[] names)
{
auto word = readWord();
ubyte f = 1;
@@ -490,7 +491,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_INT;
return toInt(w);
return to!int(w);
}
ulong readUInt()
@@ -498,7 +499,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_UINT;
return toUint(w);
return to!uint(w);
}
double readDouble()
@@ -506,7 +507,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_DOUBLE;
return toDouble(w);
return to!double(w);
}
string readString()
@@ -539,8 +540,8 @@ final class Assembler
default: s ~= *files[0].pos;
}
break;
default:
s ~= *files[0].pos;
default:
s ~= *files[0].pos;
}
}
@@ -967,16 +968,16 @@ final class Assembler
if (c=='-' || c=='+')
{
name = label[0..i];
offset = .toInt(label[i..$]);
offset = to!int(label[i..$]);
break;
}
auto lp = name in labels;
if (lp is null)
throw new Exception("Unknown label " ~ name);
return ABCFile.Label(*lp, offset);
}
ASProgram.Instruction[] readInstructions(ref uint[string] _labels)
{
ASProgram.Instruction[] instructions;
@@ -1009,7 +1010,7 @@ final class Assembler
instruction.arguments.length = argTypes.length;
foreach (i, type; argTypes)
{
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to assemble OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1060,9 +1061,6 @@ final class Assembler
foreach (li, s; switchTargetLabels)
switchFixups ~= LocalFixup(files[0].position, instructions.length, i, s, li);
break;
default:
assert(0);
}
if (i < argTypes.length-1)
expectChar(',');
@@ -1073,24 +1071,14 @@ final class Assembler
foreach (ref f; jumpFixups)
{
try
instructions[f.ii].arguments[f.ai].jumpTarget = parseLabel(f.name, labels);
catch (Object o)
{
setFile(f.where.load);
throw o;
}
scope(failure) setFile(f.where.load);
instructions[f.ii].arguments[f.ai].jumpTarget = parseLabel(f.name, labels);
}
foreach (ref f; switchFixups)
{
try
instructions[f.ii].arguments[f.ai].switchTargets[f.si] = parseLabel(f.name, labels);
catch (Object o)
{
setFile(f.where.load);
throw o;
}
scope(failure) setFile(f.where.load);
instructions[f.ii].arguments[f.ai].switchTargets[f.si] = parseLabel(f.name, labels);
}
foreach (ref f; localClassFixups)
@@ -1107,13 +1095,8 @@ final class Assembler
ABCFile.Label readLabel()
{
auto word = readWord();
try
return parseLabel(word, labels);
catch (Object o)
{
backpedal(word.length);
throw o;
}
scope(failure) backpedal(word.length);
return parseLabel(word, labels);
}
ASProgram.Exception e;
@@ -1213,15 +1196,15 @@ final class Assembler
*f.ptr = *mp;
}
}
catch (Object o)
catch (Exception e)
{
string s = files[0].positionStr ~ ": " ~ o.toString();
string s = files[0].positionStr ~ ": ";
if (fileCount == -1)
s ~= "\n\t(inclusion context unavailable)";
else
foreach (ref f; files[1..fileCount])
s ~= "\n\t(included from " ~ f.positionStr ~ ")";
throw new Exception(s);
throw new Exception(s, e);
}
classFixups = null;
+86 -81
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -19,61 +19,67 @@
module autodata;
import murmurhash2a;
import std2.traits;
import std.traits;
string addAutoField(string name, bool reverseSort = false)
{
//return `mixin(handler.process!(typeof(` ~ name ~ `), "` ~ name ~ `")());`; // doesn't work due to DMD bug 3959
return `{ static const _AutoDataStr = handler.process!(typeof(this.` ~ name ~ `), "` ~ name ~ `", ` ~ (reverseSort ? "true" : "false") ~`)(); mixin(_AutoDataStr); }`;
return `mixin(typeof(handler).getMixin!(typeof(` ~ name ~ `), "` ~ name ~ `", ` ~ (reverseSort ? "true" : "false") ~`));`;
}
template AutoCompare()
{
hash_t toHash()
static if (is(typeof(this)==class))
{
alias typeof(this) _AutoDataTypeReference;
alias Object _AutoDataOtherTypeReference;
override hash_t toHash() const { return _AutoDataHash(); }
override bool opEquals(Object o) const { return _AutoDataEquals(o); }
override int opCmp(Object o) const { return _AutoDataCmp(o); }
}
else // struct
{
alias const(typeof(this)*) _AutoDataTypeReference;
alias const(typeof(this)*) _AutoDataOtherTypeReference;
hash_t toHash() const { return _AutoDataHash(); }
bool opEquals(ref const typeof(this) s) const { return _AutoDataEquals(&s); }
int opCmp(ref const typeof(this) s) const { return _AutoDataCmp(&s); }
}
private hash_t _AutoDataHash() const
{
HashDataHandler handler;
handler.hasher.Begin();
processData!(void, "", "")(handler);
processData!(void, q{}, q{})(handler);
return handler.hasher.End();
}
static if (is(typeof(this)==class))
alias Object _AutoDataOtherType;
else
alias typeof(this) _AutoDataOtherType;
int opEquals(_AutoDataOtherType other)
private bool _AutoDataEquals(_AutoDataOtherTypeReference other) const
{
EqualsDataHandler!(typeof(this)) handler;
static if (is(typeof(this)==class))
{
handler.other = cast(typeof(this)) other;
if (handler.other is null)
return false;
}
else
handler.other = other;
return processData!(bool, "auto _AutoDataOther = handler.other;", "return true;")(handler);
auto handler = EqualsDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other);
if (handler.other is null)
return false;
return processData!(bool, q{auto _AutoDataOther = handler.other;}, q{return true;})(handler);
}
int opCmp(_AutoDataOtherType other)
private int _AutoDataCmp(_AutoDataOtherTypeReference other) const
{
CmpDataHandler!(typeof(this)) handler;
static if (is(typeof(this)==class))
{
handler.other = cast(typeof(this)) other;
if (handler.other is null)
return -1;
}
else
handler.other = other;
return processData!(int, "auto _AutoDataOther = handler.other;", "return 0;")(handler);
auto handler = CmpDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other);
if (handler.other is null)
return false;
return processData!(int, q{auto _AutoDataOther = handler.other;}, "return 0;")(handler);
}
}
template AutoToString()
{
string toString()
static if (is(typeof(this)==class))
override string toString() { return _AutoDataToString(); }
else // struct
string toString() { return _AutoDataToString(); }
string _AutoDataToString() const
{
ToStringDataHandler handler;
return processData!(string, "string _AutoDataResult;", "return _AutoDataResult;")(handler);
@@ -82,20 +88,11 @@ template AutoToString()
template ProcessAllData()
{
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
foreach (i, T; this.tupleof)
{
//mixin(addAutoField(T.stringof)); // doesn't work
static if (this.tupleof[i].stringof == typeof(this.tupleof[i]).stringof)
static assert(0, "DMD bug 2881 detected - can't use enums with ProcessAllData");
else
static if (is (typeof(this) == class))
mixin(addAutoField(this.tupleof[i].stringof[5..$])); // remove "this."
else
mixin(addAutoField(this.tupleof[i].stringof[8..$])); // remove "(*this)."
}
mixin(addAutoField(this.tupleof[i].stringof[5..$])); // remove "this."
mixin(epilog);
}
}
@@ -103,29 +100,27 @@ template ProcessAllData()
/// For data handlers that only need to look at the raw data (currently only HashDataHandler)
template RawDataHandlerWrapper()
{
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
return processRecursive!(T, "this." ~ name, "");
enum getMixin = getMixinRecursive!(T, "this." ~ name, "");
}
static string processRecursive(T, string name, string loopDepth)()
template getMixinRecursive(T, string name, string loopDepth)
{
static if (!hasAliasing!(T))
return processRaw("&" ~ name, name ~ ".sizeof");
else
static if (is(T U : U[]))
{
string s = "{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ processRaw("&_AutoDataNullTest", "bool.sizeof") ~ "}";
static if (!hasAliasing!(U))
s ~= processRaw(name ~ ".ptr", name ~ ".length");
else
s ~= "foreach (ref _AutoDataArrayItem" ~ loopDepth ~ "; " ~ name ~ ") {" ~ processRecursive!(U, "_AutoDataArrayItem" ~ loopDepth, loopDepth~"Item")() ~ "}";
return s;
}
enum getMixinRecursive =
"{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ getRawMixin!("&_AutoDataNullTest", "bool.sizeof") ~ "}" ~
(!hasAliasing!(U) ?
getRawMixin!(name ~ ".ptr", name ~ ".length")
:
"foreach (ref _AutoDataArrayItem" ~ loopDepth ~ "; " ~ name ~ ") {" ~ getMixinRecursive!(U, "_AutoDataArrayItem" ~ loopDepth, loopDepth~"Item") ~ "}"
);
else
static if (is(typeof((new T).toHash())))
//static assert(0, "aoeu: " ~ T.stringof);
return name ~ ".processData!(void, ``, ``)(handler);";
static if (!hasAliasing!(T))
enum getMixinRecursive = getRawMixin!("&" ~ name, name ~ ".sizeof");
else
static if (is(typeof(this)==struct) || is(typeof(this)==class))
enum getMixinRecursive = name ~ ".processData!(void, ``, ``)(handler);";
else
static assert(0, "Don't know how to process type: " ~ T.stringof);
}
@@ -137,9 +132,9 @@ struct HashDataHandler
MurmurHash2A hasher;
static string processRaw(string ptr, string len)
template getRawMixin(string ptr, string len)
{
return "handler.hasher.Add(" ~ ptr ~ ", " ~ len ~ ");";
enum getRawMixin = "handler.hasher.Add(" ~ ptr ~ ", " ~ len ~ ");";
}
}
@@ -147,13 +142,17 @@ struct EqualsDataHandler(O)
{
O other;
static string process(T, string name, bool reverseSort)()
template nullCheck(T, string name)
{
string s;
static if (is(T U : U[]))
s ~= " if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;";
s ~= "if (this." ~ name ~ " != _AutoDataOther." ~ name ~ ") return false;";
return s;
enum nullCheck = "if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;";
else
enum nullCheck = "";
}
template getMixin(T, string name, bool reverseSort)
{
enum getMixin = nullCheck!(T, name) ~ "if (this." ~ name ~ " != _AutoDataOther." ~ name ~ ") return false;";
}
}
@@ -161,32 +160,38 @@ struct CmpDataHandler(O)
{
O other;
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
string reverseStr = reverseSort ? "-" : "";
string s;
enum getMixin = getMixinComposite!(T, name, reverseSort).code;
}
template getMixinComposite(T, string name, bool reverseSort)
{
enum reverseStr = reverseSort ? "-" : "";
static if (is(T U : U[]))
s ~= "{ int _AutoDataCmp = cast(int)(this." ~ name ~ " !is null) - cast(int)(_AutoDataOther." ~ name ~ " !is null); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum arrCode = "{ int _AutoDataCmp = cast(int)(this." ~ name ~ " !is null) - cast(int)(_AutoDataOther." ~ name ~ " !is null); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
enum arrCode = "";
static if (is(T == string) && is(std.string.cmp))
s ~= "{ int _AutoDataCmp = std.string.cmp(this." ~ name ~ ", _AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum dataCode = "{ int _AutoDataCmp = std.string.cmp(this." ~ name ~ ", _AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
static if (is(T == int))
s ~= "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long?
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long?
else
static if (is(typeof(T.opCmp)))
s ~= "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
s ~= "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
"if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);";
return s;
enum dataCode = "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
"if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);";
enum code = arrCode ~ dataCode;
}
}
struct ToStringDataHandler
{
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
return "_AutoDataResult ~= format(`%s = %s `, `" ~ name ~ "`, this." ~ name ~ ");";
enum getMixin = "_AutoDataResult ~= format(`%s = %s `, `" ~ name ~ "`, this." ~ name ~ ");";
}
}
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
/// 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.
module build_rabcdasm;
version(D_Version2)
{ /* All OK */ }
else
static assert(false, "Unsupported D version.\nThis software requires a D2 ( http://www.digitalmars.com/d/2.0/ ) compiler to build.");
version(DigitalMars)
const DEFAULT_COMPILER = "dmd";
else
const DEFAULT_COMPILER = "gdmd";
const DEFAULT_FLAGS = "-O -inline";
import std.process;
import std.string;
string[][string] programs;
static this()
{
programs["rabcasm" ] = ["abcfile", "asprogram", "assembler", "autodata", "murmurhash2a"];
programs["rabcdasm" ] = ["abcfile", "asprogram", "disassembler", "autodata", "murmurhash2a"];
programs["abcexport" ] = ["swffile", "zlibx"];
programs["abcreplace" ] = ["swffile", "zlibx"];
programs["swfbinexport" ] = ["swffile", "zlibx"];
programs["swfbinreplace"] = ["swffile", "zlibx"];
programs["swfdecompress"] = ["swffile", "zlibx"];
programs["swf7zcompress"] = ["swffile", "zlibx"];
}
int main()
{
string compiler = getenv("DC");
if (compiler is null)
compiler = DEFAULT_COMPILER;
string flags = getenv("DCFLAGS");
if (flags is null)
flags = DEFAULT_FLAGS;
foreach (program, modules; programs)
{
int ret = system(format("%s %s %s %s", compiler, flags, program, join(modules, " ")));
if (ret)
return ret;
}
return 0;
}
+509 -206
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -31,7 +31,7 @@ public:
m_size = 0;
}
void Add ( void * vdata, int len )
void Add ( const(void) * vdata, int len )
{
ubyte * data = cast(ubyte*)vdata;
m_size += len;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -32,7 +32,7 @@ void main(string[] args)
{
scope abc = ABCFile.read(cast(ubyte[])read(arg));
scope as = ASProgram.fromABC(abc);
scope disassembler = new Disassembler(as, getName(getBaseName(arg)));
scope disassembler = new Disassembler(as, getName(arg), getName(getBaseName(arg)));
disassembler.disassemble();
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
module swfbinexport;
import std.file;
import std.path;
import std.string;
import std.stdio;
import std.exception;
import swffile;
void main(string[] args)
{
if (args.length == 1)
throw new Exception("No file specified");
foreach (arg; args[1..$])
try
{
scope swf = SWFFile.read(cast(ubyte[])read(arg));
bool found;
foreach (ref tag; swf.tags)
if (tag.type == TagType.DefineBinaryData)
{
found = true;
enforce(tag.data.length >= 6);
ushort id = *cast(short*)tag.data.ptr;
ubyte[] bin = tag.data[6..$];
std.file.write(format("%s-%d.bin", getName(arg), id), bin);
}
enforce(found, "No DefineBinaryData tags found");
}
catch (Exception e)
writefln("Error while processing %s: %s", arg, e);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
module swfbinreplace;
import std.file;
import std.conv;
import swffile;
void main(string[] args)
{
if (args.length != 4)
throw new Exception("Bad arguments. Usage: swfbinreplace file.swf id data.bin");
auto swf = SWFFile.read(cast(ubyte[])read(args[1]));
auto id = to!ushort(args[2]);
foreach (ref tag; swf.tags)
if (tag.type == TagType.DefineBinaryData && tag.data.length >= 6 && *cast(short*)tag.data.ptr == id)
{
auto bin = cast(ubyte[])read(args[3]);
tag.data = tag.data[0..6] ~ bin;
write(args[1], swf.write());
return;
}
throw new Exception("DefineBinaryData tag with specified ID not found in file");
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -21,8 +21,8 @@ module swffile;
import std.zlib;
import zlibx;
/**
* Implements a shallow representation of a .swf file.
/**
* Implements a shallow representation of a .swf file.
* Loading and saving a .swf file using this class should produce
* output identical to the input (aside zlib compression differences).
*/
@@ -230,7 +230,7 @@ private final class SWFWriter
buf ~= swf.frameSize.bytes;
buf ~= toArray(swf.frameRate);
buf ~= toArray(swf.frameCount);
foreach (ref tag; swf.tags)
{
ushort u = cast(ushort)(tag.type << 6);
+2 -2
View File
@@ -13,7 +13,7 @@ ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
auto destbuf = new ubyte[destlen];
uint err;
zs.next_in = srcbuf.ptr;
zs.avail_in = srcbuf.length;
@@ -37,7 +37,7 @@ ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
}
if (zs.avail_out != 0)
throw new Exception("Too little data in stream");
err = etc.c.zlib.inflateEnd(&zs);
if (err != Z_OK)
goto Lerr;