Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ed623a322 | ||
|
|
ed130fe1b0 | ||
|
|
a2d18a1a72 | ||
|
|
f455e29deb | ||
|
|
03b13d0c87 | ||
|
|
cdbac56b21 | ||
|
|
a5153c7d22 | ||
|
|
7818a79009 | ||
|
|
656c2e01f4 | ||
|
|
0d2c02af46 | ||
|
|
086ee07659 | ||
|
|
efdde9271c | ||
|
|
f7c28ac340 | ||
|
|
17a70c6c9b | ||
|
|
8454abf95e | ||
|
|
d68e7a1f7f | ||
|
|
62f13d4bab | ||
|
|
c1adeddbea | ||
|
|
37131650e5 | ||
|
|
68f6fa241c | ||
|
|
77b5366ada | ||
|
|
59a0b2c167 | ||
|
|
9bd1c698b5 | ||
|
|
e01cff3f24 | ||
|
|
988b17a401 | ||
|
|
3ed3fb1a27 | ||
|
|
1e7cbaca9b | ||
|
|
9b6dfe13b3 | ||
|
|
dc01be0604 | ||
|
|
5e7b2ea4e7 | ||
|
|
8ab69fc6b7 | ||
|
|
576294f949 | ||
|
|
21650d2056 | ||
|
|
0983145a0d | ||
|
|
62c8fce63b | ||
|
|
7097774834 |
+18
@@ -0,0 +1,18 @@
|
||||
*.exe
|
||||
*.dll
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.exp
|
||||
*.lib
|
||||
*.suo
|
||||
|
||||
/build_rabcdasm
|
||||
/rabcasm
|
||||
/rabcdasm
|
||||
/abcexport
|
||||
/abcreplace
|
||||
/swfbinexport
|
||||
/swfbinreplace
|
||||
/swfdecompress
|
||||
/swf7zcompress
|
||||
/swflzmacompress
|
||||
@@ -1,6 +1,32 @@
|
||||
RABCDAsm Changelog
|
||||
==================
|
||||
|
||||
RABCDAsm v1.19 (????.??.??)
|
||||
---------------------------
|
||||
|
||||
* Ignore duplicate class names during dependency registration
|
||||
* Make over-estimation of uncompressed SWF size non-fatal
|
||||
* Improve robustness of zlib decompression
|
||||
* Disassemble type `0x00` as `Undefined` instead of `Void`
|
||||
- This matches the terminology used in the AVM specification.
|
||||
- `Void` continues to be recognized as a synonym for `Undefined`.
|
||||
|
||||
RABCDAsm v1.18 (2016.01.16)
|
||||
---------------------------
|
||||
|
||||
* Fix disassembly of `pushbyte` instructions (the AVM specification
|
||||
incorrectly lists the argument as unsigned).
|
||||
* Bump `#version` directive of new disassemblies to 4:
|
||||
- Versions below 4 treat `pushbyte` as unsigned, and throw an exception if
|
||||
the argument is outside the range `0` ... `255`.
|
||||
- Versions 4 and above treat `pushbyte` as signed, and throw an exception
|
||||
if the argument is outside the range `-128` ... `127`.
|
||||
* Fix buffer reuse bugs when using macros
|
||||
* Dump floating-point numbers in hex notation if necessary to ensure precision
|
||||
* Cease emitting a number in a comment after opening `script` tags
|
||||
* Detect a known DMD bug in `build_rabcdasm`
|
||||
* Ignore invalid file size in header
|
||||
|
||||
RABCDAsm v1.17 (2014.09.10)
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@ 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-archive/actionscript/articles/avm2overview.pdf
|
||||
[avm2i]: http://www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html
|
||||
[avm2]: https://www.adobe.com/content/dam/acom/en/devnet/pdf/avm2overview.pdf
|
||||
[avm2i]: https://web.archive.org/web/20160215185222/www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014, 2021 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -237,6 +237,7 @@ class ABCFile
|
||||
Opcode opcode;
|
||||
union Argument
|
||||
{
|
||||
byte bytev;
|
||||
ubyte ubytev;
|
||||
long intv;
|
||||
ulong uintv;
|
||||
@@ -268,8 +269,8 @@ class ABCFile
|
||||
|
||||
enum ASType : ubyte
|
||||
{
|
||||
Void = 0x00, // not actually interned
|
||||
Undefined = Void,
|
||||
Undefined = 0x00,
|
||||
Void = Undefined, // not actually interned
|
||||
Utf8 = 0x01,
|
||||
Decimal = 0x02,
|
||||
Integer = 0x03,
|
||||
@@ -301,7 +302,7 @@ enum ASType : ubyte
|
||||
}
|
||||
|
||||
string[ASType.Max] ASTypeNames = [
|
||||
"Void",
|
||||
"Undefined",
|
||||
"Utf8",
|
||||
"Decimal",
|
||||
"Integer",
|
||||
@@ -339,6 +340,7 @@ static this()
|
||||
{
|
||||
foreach (t, n; ASTypeNames)
|
||||
ASTypeByName[n] = cast(ASType)t;
|
||||
ASTypeByName["Void"] = ASType.Void;
|
||||
ASTypeByName = ASTypeByName.rehash;
|
||||
}
|
||||
|
||||
@@ -543,7 +545,7 @@ enum Opcode : ubyte
|
||||
OP_getglobalscope = 0x64,
|
||||
OP_getscopeobject = 0x65,
|
||||
OP_getproperty = 0x66,
|
||||
OP_getpropertylate = 0x67,
|
||||
OP_getouterscope = 0x67,
|
||||
OP_initproperty = 0x68,
|
||||
OP_setpropertylate = 0x69,
|
||||
OP_deleteproperty = 0x6A,
|
||||
@@ -641,6 +643,7 @@ enum OpcodeArgumentType
|
||||
{
|
||||
Unknown,
|
||||
|
||||
ByteLiteral,
|
||||
UByteLiteral,
|
||||
IntLiteral,
|
||||
UIntLiteral,
|
||||
@@ -702,7 +705,7 @@ const OpcodeInfo[256] opcodeInfo = [
|
||||
/* 0x21 */ {"pushundefined", []},
|
||||
/* 0x22 */ {"pushuninitialized", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x23 */ {"nextvalue", []},
|
||||
/* 0x24 */ {"pushbyte", [OpcodeArgumentType.UByteLiteral]},
|
||||
/* 0x24 */ {"pushbyte", [OpcodeArgumentType.ByteLiteral]},
|
||||
/* 0x25 */ {"pushshort", [OpcodeArgumentType.IntLiteral]},
|
||||
/* 0x26 */ {"pushtrue", []},
|
||||
/* 0x27 */ {"pushfalse", []},
|
||||
@@ -769,7 +772,7 @@ const OpcodeInfo[256] opcodeInfo = [
|
||||
/* 0x64 */ {"getglobalscope", []},
|
||||
/* 0x65 */ {"getscopeobject", [OpcodeArgumentType.UByteLiteral]},
|
||||
/* 0x66 */ {"getproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x67 */ {"getpropertylate", []},
|
||||
/* 0x67 */ {"getouterscope", [OpcodeArgumentType.UIntLiteral]},
|
||||
/* 0x68 */ {"initproperty", [OpcodeArgumentType.Multiname]},
|
||||
/* 0x69 */ {"setpropertylate", []},
|
||||
/* 0x6A */ {"deleteproperty", [OpcodeArgumentType.Multiname]},
|
||||
@@ -1378,6 +1381,9 @@ private final class ABCReader
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to decode OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
instruction.arguments[i].bytev = readU8();
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
instruction.arguments[i].ubytev = readU8();
|
||||
break;
|
||||
@@ -1933,6 +1939,9 @@ private final class ABCWriter
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to encode OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
writeU8(instruction.arguments[i].bytev);
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
writeU8(instruction.arguments[i].ubytev);
|
||||
break;
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
</keywords>
|
||||
|
||||
<keywords ignorecase="no" region="ASType">
|
||||
<word name="Undefined"/>
|
||||
<word name="Void"/>
|
||||
<word name="Utf8"/>
|
||||
<word name="Decimal"/>
|
||||
@@ -240,7 +241,7 @@
|
||||
<word name="getglobalscope"/>
|
||||
<word name="getscopeobject"/>
|
||||
<word name="getproperty"/>
|
||||
<word name="getpropertylate"/>
|
||||
<word name="getouterscope"/>
|
||||
<word name="initproperty"/>
|
||||
<word name="setpropertylate"/>
|
||||
<word name="deleteproperty"/>
|
||||
|
||||
+12
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -269,6 +269,7 @@ final class ASProgram
|
||||
Opcode opcode;
|
||||
union Argument
|
||||
{
|
||||
byte bytev;
|
||||
ubyte ubytev;
|
||||
|
||||
long intv;
|
||||
@@ -598,6 +599,9 @@ private final class ABCtoAS
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
r.arguments[i].bytev = instruction.arguments[i].bytev;
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
r.arguments[i].ubytev = instruction.arguments[i].ubytev;
|
||||
break;
|
||||
@@ -831,7 +835,8 @@ private final class AStoABC : ASVisitor
|
||||
// sort
|
||||
static if (is(T == double))
|
||||
{
|
||||
static ulong repr(double d) { static assert(double.sizeof == ulong.sizeof); return *cast(ulong*)(&d); }
|
||||
// Need ref to work around https://issues.dlang.org/show_bug.cgi?id=13998
|
||||
static ulong repr(ref double d) { static assert(double.sizeof == ulong.sizeof); return *cast(ulong*)(&d); }
|
||||
static bool sortPred(Entry* a, Entry* b) { return a.hits > b.hits || (a.hits == b.hits && repr(a.value) < repr(b.value)); }
|
||||
}
|
||||
else
|
||||
@@ -976,7 +981,7 @@ private final class AStoABC : ASVisitor
|
||||
ASProgram.Class[] classObjects = classes.getPreliminaryValues();
|
||||
foreach (c; classObjects)
|
||||
{
|
||||
assert(!(c.instance.name in classByName), "Duplicate class name " ~ c.instance.name.toString());
|
||||
//assert(!(c.instance.name in classByName), "Duplicate class name " ~ c.instance.name.toString());
|
||||
classByName[c.instance.name] = c;
|
||||
}
|
||||
|
||||
@@ -1239,6 +1244,9 @@ private final class AStoABC : ASVisitor
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
r.arguments[i].bytev = instruction.arguments[i].bytev;
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
r.arguments[i].ubytev = instruction.arguments[i].ubytev;
|
||||
break;
|
||||
@@ -1524,6 +1532,7 @@ class ASVisitor : ASTraitsVisitor
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to visit OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
case OpcodeArgumentType.IntLiteral:
|
||||
case OpcodeArgumentType.UIntLiteral:
|
||||
|
||||
+66
-47
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -25,6 +25,7 @@ import std.path;
|
||||
import std.range;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import std.typecons;
|
||||
|
||||
import abcfile;
|
||||
import asprogram;
|
||||
@@ -34,10 +35,10 @@ final class Assembler
|
||||
{
|
||||
static struct Position
|
||||
{
|
||||
File file;
|
||||
SourceFile file;
|
||||
ulong offset;
|
||||
|
||||
File load()
|
||||
SourceFile load()
|
||||
{
|
||||
assert(file.ptr == file.end);
|
||||
file.filePosition = offset;
|
||||
@@ -45,14 +46,14 @@ final class Assembler
|
||||
}
|
||||
}
|
||||
|
||||
static final class File
|
||||
static final class SourceFile
|
||||
{
|
||||
string name;
|
||||
string[] arguments;
|
||||
string data;
|
||||
@property bool isVirtual() { return data ! is null; }
|
||||
|
||||
File parent;
|
||||
SourceFile parent;
|
||||
|
||||
const(char)* ptr, end;
|
||||
|
||||
@@ -63,7 +64,7 @@ final class Assembler
|
||||
|
||||
ulong filePosition; // File position of buffer.ptr
|
||||
sizediff_t shift; // Error location adjustment
|
||||
std.stdio.File f;
|
||||
File f;
|
||||
|
||||
this(string name, string data = null, string[] arguments = null)
|
||||
{
|
||||
@@ -73,7 +74,7 @@ final class Assembler
|
||||
if (data)
|
||||
{
|
||||
createBuffer(data.length);
|
||||
buffer[] = data[];
|
||||
buffer[0..data.length] = data[];
|
||||
ptr = buffer.ptr;
|
||||
end = ptr + data.length;
|
||||
}
|
||||
@@ -84,6 +85,12 @@ final class Assembler
|
||||
}
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
if (f.isOpen)
|
||||
f.close();
|
||||
}
|
||||
|
||||
bool loadNextChunk()
|
||||
{
|
||||
if (!f.isOpen)
|
||||
@@ -120,6 +127,7 @@ final class Assembler
|
||||
{
|
||||
buffer = usedBuffers[0];
|
||||
usedBuffers = usedBuffers[1..$];
|
||||
buffer[size..bufferSize] = 0;
|
||||
}
|
||||
else
|
||||
buffer = new char[bufferSize];
|
||||
@@ -167,7 +175,7 @@ final class Assembler
|
||||
@property char front()
|
||||
{
|
||||
char c;
|
||||
return (c = *ptr) != 0 ? c : (loadNextChunk(), *ptr);
|
||||
return (c = *ptr) != 0 ? c : { loadNextChunk(); return *ptr; }();
|
||||
}
|
||||
|
||||
void popFront()
|
||||
@@ -176,7 +184,7 @@ final class Assembler
|
||||
}
|
||||
}
|
||||
|
||||
File currentFile;
|
||||
SourceFile currentFile;
|
||||
|
||||
string getBasePath()
|
||||
{
|
||||
@@ -233,17 +241,17 @@ final class Assembler
|
||||
switch (word)
|
||||
{
|
||||
case "mixin":
|
||||
pushFile(new File("#mixin", readImmString()));
|
||||
pushFile(new SourceFile("#mixin", readImmString()));
|
||||
break;
|
||||
case "call": // #mixin with arguments
|
||||
pushFile(new File("#call", readImmString(), readList!('(', ')', readImmString, false)()));
|
||||
pushFile(new SourceFile("#call", readImmString(), readList!('(', ')', readImmString, false)()));
|
||||
break;
|
||||
case "include":
|
||||
pushFile(new File(convertFilename(readString())));
|
||||
pushFile(new SourceFile(convertFilename(readString())));
|
||||
break;
|
||||
case "get":
|
||||
auto filename = convertFilename(readString());
|
||||
pushFile(new File(filename, toStringLiteral(cast(string)read(longPath(filename)))));
|
||||
pushFile(new SourceFile(filename, toStringLiteral(cast(string)read(longPath(filename)))));
|
||||
break;
|
||||
case "set":
|
||||
vars[readWord()] = readImmString();
|
||||
@@ -258,7 +266,7 @@ final class Assembler
|
||||
break;
|
||||
case "version":
|
||||
sourceVersion = readUInt().to!uint();
|
||||
enforce(sourceVersion >= 1 && sourceVersion <= 3, "Invalid/unknown #version");
|
||||
enforce(sourceVersion >= 1 && sourceVersion <= 4, "Invalid/unknown #version");
|
||||
break;
|
||||
default:
|
||||
backpedal(word.length);
|
||||
@@ -292,7 +300,7 @@ final class Assembler
|
||||
if (index >= f.arguments.length)
|
||||
throw new Exception("Argument index out-of-bounds");
|
||||
string value = f.arguments[index];
|
||||
pushFile(new File('$' ~ name.assumeUnique(), asStringLiteral ? toStringLiteral(value) : value));
|
||||
pushFile(new SourceFile('$' ~ name.assumeUnique(), asStringLiteral ? toStringLiteral(value) : value));
|
||||
return;
|
||||
}
|
||||
throw new Exception("No arguments in context");
|
||||
@@ -303,7 +311,7 @@ final class Assembler
|
||||
if (pvalue is null)
|
||||
throw new Exception("variable %s is not defined".format(name));
|
||||
string value = *pvalue;
|
||||
pushFile(new File('$' ~ name.assumeUnique(), asStringLiteral ? toStringLiteral(value) : value));
|
||||
pushFile(new SourceFile('$' ~ name.assumeUnique(), asStringLiteral ? toStringLiteral(value) : value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,14 +364,14 @@ final class Assembler
|
||||
}
|
||||
}
|
||||
|
||||
void pushFile(File file)
|
||||
void pushFile(SourceFile file)
|
||||
{
|
||||
file.parent = currentFile;
|
||||
currentFile = file;
|
||||
}
|
||||
|
||||
/// For restoring the position of an error
|
||||
void setFile(File file)
|
||||
void setFile(SourceFile file)
|
||||
{
|
||||
currentFile = file;
|
||||
}
|
||||
@@ -1163,6 +1171,12 @@ final class Assembler
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to assemble OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
if (sourceVersion < 4)
|
||||
instruction.arguments[i].bytev = to!ubyte(readInt());
|
||||
else
|
||||
instruction.arguments[i].bytev = to!byte(readInt());
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
instruction.arguments[i].ubytev = to!ubyte(readUInt());
|
||||
break;
|
||||
@@ -1324,45 +1338,50 @@ final class Assembler
|
||||
|
||||
void assemble(string mainFilename)
|
||||
{
|
||||
pushFile(new File(mainFilename));
|
||||
auto mainFile = scoped!SourceFile(mainFilename);
|
||||
pushFile(mainFile);
|
||||
|
||||
try
|
||||
{
|
||||
readProgram();
|
||||
|
||||
foreach (ref f; classFixups)
|
||||
if (f.name is null)
|
||||
*f.ptr = null;
|
||||
else
|
||||
{
|
||||
auto cp = f.name in classesByID;
|
||||
if (cp is null)
|
||||
{
|
||||
setFile(f.where.load());
|
||||
throw new Exception("Unknown class refid: " ~ f.name);
|
||||
}
|
||||
*f.ptr = *cp;
|
||||
}
|
||||
|
||||
foreach (ref f; methodFixups)
|
||||
if (f.name is null)
|
||||
*f.ptr = null;
|
||||
else
|
||||
{
|
||||
auto mp = f.name in methodsByID;
|
||||
if (mp is null)
|
||||
{
|
||||
setFile(f.where.load());
|
||||
throw new Exception("Unknown method refid: " ~ f.name);
|
||||
}
|
||||
*f.ptr = *mp;
|
||||
}
|
||||
applyFixups();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.msg = "\n%s\n%s".format(context(), e.msg);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void applyFixups()
|
||||
{
|
||||
foreach (ref f; classFixups)
|
||||
if (f.name is null)
|
||||
*f.ptr = null;
|
||||
else
|
||||
{
|
||||
auto cp = f.name in classesByID;
|
||||
if (cp is null)
|
||||
{
|
||||
setFile(f.where.load());
|
||||
throw new Exception("Unknown class refid: " ~ f.name);
|
||||
}
|
||||
*f.ptr = *cp;
|
||||
}
|
||||
|
||||
foreach (ref f; methodFixups)
|
||||
if (f.name is null)
|
||||
*f.ptr = null;
|
||||
else
|
||||
{
|
||||
auto mp = f.name in methodsByID;
|
||||
if (mp is null)
|
||||
{
|
||||
setFile(f.where.load());
|
||||
throw new Exception("Unknown method refid: " ~ f.name);
|
||||
}
|
||||
*f.ptr = *mp;
|
||||
}
|
||||
|
||||
classFixups = null;
|
||||
methodFixups = null;
|
||||
|
||||
+29
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -35,7 +35,7 @@ else
|
||||
const DEFAULT_COMPILER = "gdmd";
|
||||
|
||||
const DEFAULT_FLAGS = "-O -inline";
|
||||
const LZMA_FLAGS = "-version=HAVE_LZMA";
|
||||
const LZMA_FLAGS = ["-version=HAVE_LZMA"];
|
||||
|
||||
import std.exception;
|
||||
import std.file;
|
||||
@@ -43,44 +43,51 @@ import std.process;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
string compiler, flags;
|
||||
string compiler;
|
||||
string[] flags;
|
||||
|
||||
void compile(string program)
|
||||
{
|
||||
stderr.writeln("* Building ", program);
|
||||
enforce(system(format("rdmd --build-only --compiler=%s %s %s", compiler, flags, program)) == 0, "Compilation of " ~ program ~ " failed");
|
||||
enforce(spawnProcess(["rdmd", "--build-only", "--compiler=" ~ compiler] ~ flags ~ program).wait() == 0, "Compilation of " ~ program ~ " failed");
|
||||
}
|
||||
|
||||
void test(string code, string extraFlags=null)
|
||||
void test(string code, in string[] extraFlags=null)
|
||||
{
|
||||
const BASE = "build_rabcdasm_buildtest";
|
||||
const FN = BASE ~ ".d";
|
||||
std.file.write(FN, code);
|
||||
scope(exit) foreach (de; dirEntries(".", BASE ~ "*", SpanMode.shallow)) remove(de.name);
|
||||
enforce(system(format("rdmd --force --compiler=%s -od. %s %s %s", compiler, flags, extraFlags, FN)) == 0, "Test failed");
|
||||
enforce(spawnProcess(["rdmd", "--force", "--compiler=" ~ compiler, "-od."] ~ flags ~ extraFlags ~ FN).wait() == 0, "Test failed");
|
||||
stderr.writeln(" >>> OK");
|
||||
}
|
||||
|
||||
void testBug(string description, int bugId, string code)
|
||||
{
|
||||
stderr.writefln("* Checking for compiler bug %d...", bugId);
|
||||
scope(failure)
|
||||
{
|
||||
stderr.writefln("Compiler bug detected: %s ( https://issues.dlang.org/show_bug.cgi?id=%d ).", description, bugId);
|
||||
stderr.writeln("Try again with a different D compiler, compiler version, or build flags (DCFLAGS environment variable)");
|
||||
}
|
||||
test(code);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
flags = getenv("DCFLAGS");
|
||||
if (flags is null)
|
||||
flags = DEFAULT_FLAGS;
|
||||
compiler = environment.get("DC", DEFAULT_COMPILER);
|
||||
flags = environment.get("DCFLAGS", DEFAULT_FLAGS).split(" ");
|
||||
|
||||
string[] optionArgs, programArgs;
|
||||
foreach (arg; args[1..$])
|
||||
(arg.startsWith("-") ? optionArgs : programArgs) ~= arg;
|
||||
|
||||
if (optionArgs.length)
|
||||
flags = optionArgs.join(" ");
|
||||
flags = optionArgs;
|
||||
if (programArgs.length)
|
||||
programs = programArgs;
|
||||
|
||||
@@ -89,6 +96,13 @@ int main(string[] args)
|
||||
void main() {}
|
||||
`);
|
||||
|
||||
testBug("[REG 2.064] Wrong code with -O on x86_64 for char comparisons", 11508, `
|
||||
import assembler; int main() { foreach (c; "_") if (!Assembler.isWordChar(c)) return 1; return 0; }
|
||||
`);
|
||||
testBug("[REG 2.069] Wrong double-to-string conversion with -O", 15861, `
|
||||
import std.format; int main() { return format("%.18g", 4286853117.0) == "4286853117" ? 0 : 1; }
|
||||
`);
|
||||
|
||||
bool haveLZMA;
|
||||
|
||||
stderr.writeln("* Checking for LZMA...");
|
||||
@@ -114,7 +128,7 @@ int main(string[] args)
|
||||
stderr.writeln(" >>> LZMA not found, building without LZMA support.");
|
||||
|
||||
if (haveLZMA)
|
||||
flags ~= " " ~ LZMA_FLAGS;
|
||||
flags ~= LZMA_FLAGS;
|
||||
|
||||
foreach (program; programs)
|
||||
compile(program);
|
||||
|
||||
@@ -223,7 +223,7 @@ struct lzma_index_iter
|
||||
size_t s;
|
||||
lzma_vli v;
|
||||
}
|
||||
InternalData internal[6];
|
||||
InternalData[6] internal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+40
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014, 2015 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -89,6 +89,9 @@ final class StringBuilder
|
||||
buf[pos++] = c;
|
||||
}
|
||||
|
||||
void opOpAssign(string op : "~", V)(V s) {
|
||||
put(s);
|
||||
}
|
||||
alias put opCatAssign;
|
||||
|
||||
void write(T)(T v)
|
||||
@@ -535,7 +538,7 @@ final class RefBuilder : ASTraitsVisitor
|
||||
if (obj !in contexts)
|
||||
getContext(refs, obj);
|
||||
|
||||
foreach (obj; contexts.keys.sort)
|
||||
foreach (obj; contexts.keys.sort())
|
||||
{
|
||||
auto context = contexts[obj];
|
||||
auto bname = refs.contextToString(context, false);
|
||||
@@ -1012,6 +1015,7 @@ final class Disassembler
|
||||
ASProgram as;
|
||||
string name, dir;
|
||||
RefBuilder refs;
|
||||
bool dumpRaw = true;
|
||||
|
||||
void newInclude(StringBuilder mainsb, string filename, void delegate(StringBuilder) callback, bool doInline = true)
|
||||
{
|
||||
@@ -1051,7 +1055,7 @@ final class Disassembler
|
||||
|
||||
StringBuilder sb = new StringBuilder(dir ~ "/" ~ name ~ ".main.asasm");
|
||||
|
||||
sb ~= "#version 3";
|
||||
sb ~= "#version 4";
|
||||
sb.newLine();
|
||||
|
||||
sb ~= "program";
|
||||
@@ -1146,17 +1150,33 @@ final class Disassembler
|
||||
static double forceDouble(double d) { static double n; n = d; return n; }
|
||||
if (s != "nan" && s != "inf" && s != "-inf")
|
||||
{
|
||||
foreach_reverse (i; 1..s.length)
|
||||
if (s[i]>='0' && s[i]<='8')
|
||||
{
|
||||
s[i]++;
|
||||
if (forceDouble(to!double(s[0..i+1]))==v)
|
||||
s = s[0..i+1];
|
||||
else
|
||||
s[i]--;
|
||||
}
|
||||
while (s.length>2 && s[$-1]!='.' && forceDouble(to!double(s[0..$-1]))==v)
|
||||
s = s[0..$-1];
|
||||
if (forceDouble(to!double(s)) == v)
|
||||
{
|
||||
foreach_reverse (i; 1..s.length)
|
||||
if (s[i]>='0' && s[i]<='8')
|
||||
{
|
||||
s[i]++;
|
||||
if (forceDouble(to!double(s[0..i+1]))==v)
|
||||
s = s[0..i+1];
|
||||
else
|
||||
s[i]--;
|
||||
}
|
||||
while (s.length>2 && s[$-1]!='.' && forceDouble(to!double(s[0..$-1]))==v)
|
||||
s = s[0..$-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.pos = 0;
|
||||
formattedWrite(&buf, "%.13a", v);
|
||||
s = buf.data();
|
||||
auto n = forceDouble(to!double(s));
|
||||
assert(n == v,
|
||||
"Can't print precise representation of double: %(%02X %) (%.18g) => %s => %(%02X %) (%.18g)".format(
|
||||
cast(ubyte[])cast(void[])[v], v,
|
||||
s,
|
||||
cast(ubyte[])cast(void[])[n], n,
|
||||
));
|
||||
}
|
||||
}
|
||||
sb ~= s;
|
||||
}
|
||||
@@ -1545,8 +1565,7 @@ final class Disassembler
|
||||
|
||||
void dumpScript(StringBuilder sb, ASProgram.Script script, uint index)
|
||||
{
|
||||
sb ~= "script ; ";
|
||||
sb.write(index);
|
||||
sb ~= "script";
|
||||
sb.indent++; sb.newLine();
|
||||
dumpMethod(sb, script.sinit, "sinit");
|
||||
dumpTraits(sb, script.traits, true);
|
||||
@@ -1666,7 +1685,8 @@ final class Disassembler
|
||||
|
||||
if (instruction.opcode == Opcode.OP_raw)
|
||||
{
|
||||
sb ~= "; 0x%02X".format(instruction.arguments[0].ubytev);
|
||||
if (dumpRaw)
|
||||
sb ~= "; 0x%02X".format(instruction.arguments[0].ubytev);
|
||||
sb.newLine();
|
||||
continue;
|
||||
}
|
||||
@@ -1684,6 +1704,9 @@ final class Disassembler
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to disassemble OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.ByteLiteral:
|
||||
sb.write(instruction.arguments[i].bytev);
|
||||
break;
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
sb.write(instruction.arguments[i].ubytev);
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2012, 2013, 2014, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -23,6 +23,7 @@ version(HAVE_LZMA) {} else static assert(0, "LZMA is not available (HAVE_LZMA ve
|
||||
import deimos.lzma;
|
||||
import std.conv;
|
||||
import std.exception;
|
||||
import std.string : format;
|
||||
|
||||
version (Windows)
|
||||
{ pragma(lib, "liblzma"); }
|
||||
@@ -40,21 +41,30 @@ static assert(LZMAHeader.sizeof == 13);
|
||||
|
||||
ubyte[] lzmaDecompress(LZMAHeader header, in ubyte[] compressedData)
|
||||
{
|
||||
enforce(header.decompressedSize > 0, "Decompression with unknown size is unsupported");
|
||||
|
||||
lzma_stream strm;
|
||||
lzmaEnforce(lzma_alone_decoder(&strm, ulong.max), "lzma_alone_decoder");
|
||||
scope(exit) lzma_end(&strm);
|
||||
|
||||
auto outBuf = new ubyte[to!size_t(header.decompressedSize)];
|
||||
strm.next_out = outBuf.ptr;
|
||||
strm.avail_out = outBuf.length;
|
||||
auto outBuf = new ubyte[1024];
|
||||
size_t pos = 0;
|
||||
|
||||
void decompress(in ubyte[] chunk)
|
||||
{
|
||||
strm.next_in = chunk.ptr;
|
||||
strm.avail_in = chunk.length;
|
||||
lzmaEnforce!true(lzma_code(&strm, lzma_action.LZMA_RUN), "lzma_code (LZMA_RUN)");
|
||||
strm.next_in = chunk.ptr;
|
||||
strm.avail_in = chunk.length;
|
||||
|
||||
again:
|
||||
strm.next_out = outBuf.ptr + pos;
|
||||
strm.avail_out = outBuf.length - pos;
|
||||
auto ret = lzma_code(&strm, lzma_action.LZMA_RUN);
|
||||
pos = strm.next_out - outBuf.ptr;
|
||||
|
||||
if (ret == lzma_ret.LZMA_OK && strm.avail_in && !strm.avail_out)
|
||||
{
|
||||
outBuf.length = outBuf.length * 2;
|
||||
goto again;
|
||||
}
|
||||
lzmaEnforce!true(ret, "lzma_code (LZMA_RUN)");
|
||||
enforce(strm.avail_in == 0, "Not all data was read");
|
||||
}
|
||||
|
||||
@@ -65,7 +75,13 @@ ubyte[] lzmaDecompress(LZMAHeader header, in ubyte[] compressedData)
|
||||
|
||||
lzmaEnforce!true(lzma_code(&strm, lzma_action.LZMA_FINISH), "lzma_code (LZMA_FINISH)");
|
||||
|
||||
enforce(strm.avail_out == 0, "Decompressed size mismatch");
|
||||
// enforce(strm.avail_out == 0,
|
||||
// "Decompressed size mismatch (expected %d/0x%X, got %d/0x%X)".format(
|
||||
// outBuf.length, outBuf.length,
|
||||
// outBuf.length - strm.avail_out, outBuf.length - strm.avail_out,
|
||||
// ));
|
||||
|
||||
outBuf = outBuf[0..pos];
|
||||
|
||||
return outBuf;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -71,7 +71,7 @@ void main(string[] args)
|
||||
if (header.fileLength != data.length + 8)
|
||||
throw new Exception("Incorrect file length in file header");
|
||||
write(arg ~ ".tempdata", data);
|
||||
if (system(`7z a -tgzip -mx=9 -mfb=258 "` ~ arg ~ `.tempdata.gz" "` ~ arg ~ `.tempdata"`) || !exists(arg ~ ".tempdata.gz"))
|
||||
if (spawnProcess(["7z", "a", "-tgzip", "-mx=9", "-mfb=258", arg ~ ".tempdata.gz", arg ~ ".tempdata"]).wait() || !exists(arg ~ ".tempdata.gz"))
|
||||
throw new Exception("7-Zip failed");
|
||||
remove(arg ~ ".tempdata");
|
||||
auto gzipdata = cast(ubyte[])read(arg ~ ".tempdata.gz");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2016 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -20,6 +20,7 @@ module swffile;
|
||||
|
||||
import std.conv;
|
||||
import std.exception;
|
||||
import std.string : format;
|
||||
import std.zlib;
|
||||
import zlibx;
|
||||
version (HAVE_LZMA) import lzma;
|
||||
@@ -115,7 +116,9 @@ private final class SWFReader
|
||||
else
|
||||
enforce(false, "This version was built without LZMA support");
|
||||
}
|
||||
enforce(swf.header.fileLength == buf.length, "Incorrect file length in file header");
|
||||
//enforce(swf.header.fileLength == buf.length,
|
||||
// "Incorrect file length in file header (expected %d, got %d)"
|
||||
// .format(swf.header.fileLength , buf.length));
|
||||
swf.frameSize = readRect();
|
||||
swf.frameRate = readU16();
|
||||
swf.frameCount = readU16();
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
module zlibx;
|
||||
|
||||
import core.memory;
|
||||
import std.string : format;
|
||||
import std.zlib, etc.c.zlib, std.conv;
|
||||
static import etc.c.zlib;
|
||||
alias std.zlib.Z_SYNC_FLUSH Z_SYNC_FLUSH;
|
||||
debug import std.stdio : stderr;
|
||||
|
||||
/// Avoid bug(?) in D zlib implementation with 7zip-generated zlib streams
|
||||
ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
|
||||
@@ -23,24 +26,59 @@ ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
|
||||
err = etc.c.zlib.inflateInit2(&zs, 15);
|
||||
if (err)
|
||||
{
|
||||
delete destbuf;
|
||||
GC.free(destbuf.ptr);
|
||||
throw new ZlibException(err);
|
||||
}
|
||||
|
||||
err = etc.c.zlib.inflate(&zs, Z_SYNC_FLUSH);
|
||||
if (err != Z_OK && err != Z_STREAM_END)
|
||||
while (true)
|
||||
{
|
||||
Lerr:
|
||||
delete destbuf;
|
||||
etc.c.zlib.inflateEnd(&zs);
|
||||
throw new ZlibException(err);
|
||||
err = etc.c.zlib.inflate(&zs, Z_SYNC_FLUSH);
|
||||
if (err != Z_OK && err != Z_STREAM_END)
|
||||
{
|
||||
Lerr:
|
||||
GC.free(destbuf.ptr);
|
||||
etc.c.zlib.inflateEnd(&zs);
|
||||
throw new ZlibException(err);
|
||||
}
|
||||
|
||||
if (err == Z_STREAM_END)
|
||||
break;
|
||||
else
|
||||
if (zs.avail_out == 0)
|
||||
{
|
||||
debug stderr.writefln("Wrong uncompressed file length (read %d/%d bytes and wrote %d/%d bytes)",
|
||||
srcbuf .length - zs.avail_in , srcbuf .length,
|
||||
destlen - zs.avail_out, destlen);
|
||||
auto out_pos = zs.next_out - destbuf.ptr;
|
||||
destbuf.length = 1024 + destbuf.length * 2;
|
||||
zs.next_out = destbuf.ptr + out_pos;
|
||||
zs.avail_out = to!uint(destbuf.length - out_pos);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (zs.avail_in == 0)
|
||||
{
|
||||
debug stderr.writefln("Unterminated Zlib stream (read %d/%d bytes and wrote %d/%d bytes)",
|
||||
srcbuf .length - zs.avail_in , srcbuf .length,
|
||||
destlen - zs.avail_out, destlen);
|
||||
break;
|
||||
}
|
||||
else
|
||||
throw new Exception(format("Unexpected zlib state (err=%d, avail_in == %d, avail_out = %d)",
|
||||
err, zs.avail_in , zs.avail_out));
|
||||
}
|
||||
if (zs.avail_out != 0)
|
||||
throw new Exception("Too little data in stream");
|
||||
|
||||
if (zs.avail_in != 0 || zs.avail_out != 0)
|
||||
debug stderr.writefln("Zlib stream incongruity (read %d/%d bytes and wrote %d/%d bytes)",
|
||||
srcbuf .length - zs.avail_in , srcbuf .length,
|
||||
destlen - zs.avail_out, destlen);
|
||||
|
||||
err = etc.c.zlib.inflateEnd(&zs);
|
||||
if (err != Z_OK)
|
||||
goto Lerr;
|
||||
|
||||
return destbuf;
|
||||
if (zs.avail_out != 0)
|
||||
debug stderr.writefln("Too little data in zlib stream: expected %d, got %d", destlen, destlen - zs.avail_out);
|
||||
|
||||
return destbuf[0..$-zs.avail_out];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user