Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe93f5e764 | ||
|
|
0fbfba1186 | ||
|
|
6bdf6dae39 | ||
|
|
62ef183d95 | ||
|
|
f6eb080be7 | ||
|
|
a17a03e6f6 | ||
|
|
0486c1a54a | ||
|
|
a2d22e7606 | ||
|
|
6568793aaf | ||
|
|
b0bdb250c5 | ||
|
|
99e49a9385 | ||
|
|
6313739b5e | ||
|
|
8ed3295199 | ||
|
|
31ad8dcef7 |
@@ -1,6 +1,21 @@
|
||||
RABCDAsm Changelog
|
||||
==================
|
||||
|
||||
RABCDAsm v1.17 (2014.09.10)
|
||||
---------------------------
|
||||
|
||||
* Do not attempt to disassemble unreachable code
|
||||
* Improve handling of disassembly errors:
|
||||
methods will be partially disassembled as far as possible.
|
||||
* Fix LZMA errors with uncompressable data.
|
||||
|
||||
RABCDAsm v1.16 (2014.04.21)
|
||||
---------------------------
|
||||
|
||||
* Fix handling of TypeName-kind Multinames with null parameters
|
||||
* Fix v1.15 regression in handling very long paths on Windows
|
||||
(DMD 2.066 is required when building from source for this to work)
|
||||
|
||||
RABCDAsm v1.15 (2014.01.11)
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -72,12 +72,16 @@ Substitute `dmd` with `gdmd` if you're using gdc. You can use the `DC` and
|
||||
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.
|
||||
to have the [liblzma library][] and development files installed on your system.
|
||||
|
||||
Note: DMD 2.066 is required for long path support on Windows since RABCDAsm
|
||||
1.16.
|
||||
|
||||
[d2]: http://dlang.org/
|
||||
[dmd]: http://www.digitalmars.com/d/download.html
|
||||
[gdc]: http://bitbucket.org/goshawk/gdc/
|
||||
[git]: http://git-scm.com/
|
||||
[liblzma library]: http://tukaani.org/xz/
|
||||
|
||||
Pre-compiled binaries
|
||||
---------------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -208,8 +208,7 @@ class ABCFile
|
||||
ExceptionInfo[] exceptions;
|
||||
TraitsInfo[] traits;
|
||||
|
||||
string error;
|
||||
ubyte[] rawBytes;
|
||||
Error[] errors;
|
||||
}
|
||||
|
||||
/// Destination for a jump or exception block boundary
|
||||
@@ -219,13 +218,20 @@ class ABCFile
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint index; /// instruction index
|
||||
int offset; /// signed offset relative to said instruction
|
||||
uint index = uint.max; /// instruction index
|
||||
int offset = int.max; /// signed offset relative to said instruction
|
||||
}
|
||||
private ptrdiff_t absoluteOffset; /// internal temporary value used during reading and writing
|
||||
}
|
||||
}
|
||||
|
||||
/// Disassembly/decoding error
|
||||
struct Error
|
||||
{
|
||||
Label loc;
|
||||
string msg;
|
||||
}
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
Opcode opcode;
|
||||
@@ -439,6 +445,7 @@ const string[4] TraitAttributeNames = ["FINAL", "OVERRIDE", "METADATA", "0x08"];
|
||||
|
||||
enum Opcode : ubyte
|
||||
{
|
||||
OP_raw = 0x00, /// Used internally by RABCDAsm
|
||||
OP_bkpt = 0x01,
|
||||
OP_nop = 0x02,
|
||||
OP_throw = 0x03,
|
||||
@@ -659,7 +666,7 @@ struct OpcodeInfo
|
||||
}
|
||||
|
||||
const OpcodeInfo[256] opcodeInfo = [
|
||||
/* 0x00 */ {"0x00", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x00 */ {"db", [OpcodeArgumentType.UByteLiteral]},
|
||||
/* 0x01 */ {"bkpt", [OpcodeArgumentType.Unknown]},
|
||||
/* 0x02 */ {"nop", []},
|
||||
/* 0x03 */ {"throw", []},
|
||||
@@ -926,6 +933,16 @@ static this()
|
||||
OpcodeByName = OpcodeByName.rehash;
|
||||
}
|
||||
|
||||
bool[256] genLookup(Opcode[] opcodes)
|
||||
{
|
||||
bool[256] result;
|
||||
foreach (op; opcodes)
|
||||
result[op] = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
const bool[256] stopsExecution = genLookup([Opcode.OP_returnvalue, Opcode.OP_returnvoid, Opcode.OP_throw, Opcode.OP_jump, Opcode.OP_lookupswitch]);
|
||||
|
||||
private final class ABCReader
|
||||
{
|
||||
ubyte[] buf;
|
||||
@@ -1291,8 +1308,194 @@ private final class ABCReader
|
||||
r.instructions = null;
|
||||
|
||||
size_t len = readU30();
|
||||
size_t start = pos;
|
||||
size_t end = pos + len;
|
||||
|
||||
pos = end;
|
||||
r.exceptions.length = readU30();
|
||||
foreach (ref value; r.exceptions)
|
||||
value = readExceptionInfo();
|
||||
|
||||
size_t postExceptions = pos;
|
||||
|
||||
enum TraceState : ubyte
|
||||
{
|
||||
unexplored,
|
||||
pending,
|
||||
instruction,
|
||||
instructionBody,
|
||||
error,
|
||||
}
|
||||
|
||||
auto traceState = new TraceState[len];
|
||||
auto instructions = new ABCFile.Instruction[len];
|
||||
|
||||
@property size_t offset() { return pos - start; }
|
||||
|
||||
bool havePending;
|
||||
|
||||
void queue(size_t traceOffset)
|
||||
{
|
||||
if (traceOffset < len && traceState[traceOffset] == TraceState.unexplored)
|
||||
{
|
||||
traceState[traceOffset] = TraceState.pending;
|
||||
havePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
queue(0);
|
||||
|
||||
foreach (ref value; r.exceptions)
|
||||
queue(value.target.absoluteOffset);
|
||||
|
||||
while (havePending)
|
||||
{
|
||||
havePending = false;
|
||||
pos = start;
|
||||
while (pos < end)
|
||||
{
|
||||
if (traceState[offset] == TraceState.pending)
|
||||
{
|
||||
size_t instructionOffset;
|
||||
|
||||
try
|
||||
{
|
||||
while (pos < end)
|
||||
{
|
||||
instructionOffset = offset;
|
||||
|
||||
enforce(traceState[instructionOffset] != TraceState.instructionBody, "Overlapping instruction");
|
||||
if (traceState[instructionOffset] == TraceState.instruction)
|
||||
break; // already decoded
|
||||
|
||||
ABCFile.Instruction instruction;
|
||||
instruction.opcode = cast(Opcode)readU8();
|
||||
enforce(instruction.opcode != Opcode.OP_raw, "Null opcode");
|
||||
instruction.arguments.length = opcodeInfo[instruction.opcode].argumentTypes.length;
|
||||
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
|
||||
final switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to decode OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
instruction.arguments[i].ubytev = readU8();
|
||||
break;
|
||||
case OpcodeArgumentType.IntLiteral:
|
||||
instruction.arguments[i].intv = readS32();
|
||||
break;
|
||||
case OpcodeArgumentType.UIntLiteral:
|
||||
instruction.arguments[i].uintv = readU32();
|
||||
break;
|
||||
|
||||
case OpcodeArgumentType.Int:
|
||||
case OpcodeArgumentType.UInt:
|
||||
case OpcodeArgumentType.Double:
|
||||
case OpcodeArgumentType.String:
|
||||
case OpcodeArgumentType.Namespace:
|
||||
case OpcodeArgumentType.Multiname:
|
||||
case OpcodeArgumentType.Class:
|
||||
case OpcodeArgumentType.Method:
|
||||
{
|
||||
auto index = readU30();
|
||||
size_t length;
|
||||
switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.Int: length = abc.ints .length; break;
|
||||
case OpcodeArgumentType.UInt: length = abc.uints .length; break;
|
||||
case OpcodeArgumentType.Double: length = abc.doubles .length; break;
|
||||
case OpcodeArgumentType.String: length = abc.strings .length; break;
|
||||
case OpcodeArgumentType.Namespace: length = abc.namespaces.length; break;
|
||||
case OpcodeArgumentType.Multiname: length = abc.multinames.length; break;
|
||||
case OpcodeArgumentType.Class: length = abc.classes .length; break;
|
||||
case OpcodeArgumentType.Method: length = abc.methods .length; break;
|
||||
default: assert(false);
|
||||
}
|
||||
enforce(index < length, "Out-of-bounds constant index");
|
||||
instruction.arguments[i].index = index;
|
||||
break;
|
||||
}
|
||||
|
||||
case OpcodeArgumentType.JumpTarget:
|
||||
{
|
||||
auto delta = readS24();
|
||||
auto target = offset + delta;
|
||||
instruction.arguments[i].jumpTarget.absoluteOffset = target;
|
||||
queue(target);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpcodeArgumentType.SwitchDefaultTarget:
|
||||
{
|
||||
auto target = instructionOffset + readS24();
|
||||
instruction.arguments[i].jumpTarget.absoluteOffset = target;
|
||||
queue(target);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpcodeArgumentType.SwitchTargets:
|
||||
instruction.arguments[i].switchTargets.length = readU30()+1;
|
||||
foreach (ref label; instruction.arguments[i].switchTargets)
|
||||
{
|
||||
label.absoluteOffset = instructionOffset + readS24();
|
||||
queue(label.absoluteOffset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
enforce(offset <= len, "Out-of-bounds code read error");
|
||||
|
||||
instructions[instructionOffset] = instruction;
|
||||
traceState[instructionOffset] = TraceState.instruction;
|
||||
traceState[instructionOffset+1..offset] = TraceState.instructionBody;
|
||||
|
||||
if (stopsExecution[instruction.opcode])
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
traceState[instructionOffset] = TraceState.error;
|
||||
ABCFile.Label loc;
|
||||
loc.absoluteOffset = instructionOffset;
|
||||
r.errors ~= ABCFile.Error(loc, e.msg);
|
||||
|
||||
pos = start + instructionOffset + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t[] instructionOffsets;
|
||||
auto instructionAtOffset = new uint[len];
|
||||
r.rawBytes = buf[pos..pos+len];
|
||||
instructionAtOffset[] = uint.max;
|
||||
|
||||
void addInstruction(ref ABCFile.Instruction i, size_t offset)
|
||||
{
|
||||
instructionAtOffset[offset] = to!uint(r.instructions.length);
|
||||
r.instructions ~= i;
|
||||
instructionOffsets ~= offset;
|
||||
}
|
||||
|
||||
foreach (o, state; traceState)
|
||||
{
|
||||
assert(state != TraceState.pending);
|
||||
if (state == TraceState.instruction)
|
||||
addInstruction(instructions[o], o);
|
||||
else
|
||||
if (state == TraceState.unexplored || state == TraceState.error)
|
||||
{
|
||||
ABCFile.Instruction instruction;
|
||||
instruction.opcode = Opcode.OP_raw;
|
||||
instruction.arguments.length = 1;
|
||||
instruction.arguments[0].ubytev = buf[start + o];
|
||||
addInstruction(instruction, o);
|
||||
}
|
||||
else
|
||||
assert(state == TraceState.instructionBody);
|
||||
}
|
||||
|
||||
void translateLabel(ref ABCFile.Label label)
|
||||
{
|
||||
@@ -1322,105 +1525,37 @@ private final class ABCReader
|
||||
label.offset = to!int(absoluteOffset-instructionOffset);
|
||||
}
|
||||
|
||||
size_t start = pos;
|
||||
size_t end = pos + len;
|
||||
// convert jump target offsets to instruction indices
|
||||
foreach (ii, ref instruction; r.instructions)
|
||||
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
|
||||
switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.JumpTarget:
|
||||
case OpcodeArgumentType.SwitchDefaultTarget:
|
||||
translateLabel(instruction.arguments[i].jumpTarget);
|
||||
break;
|
||||
case OpcodeArgumentType.SwitchTargets:
|
||||
foreach (ref x; instruction.arguments[i].switchTargets)
|
||||
translateLabel(x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@property size_t offset() { return pos - start; }
|
||||
// convert error offsets to instruction indices
|
||||
foreach (ref e; r.errors)
|
||||
translateLabel(e.loc);
|
||||
|
||||
try
|
||||
{
|
||||
instructionAtOffset[] = uint.max;
|
||||
size_t[] instructionOffsets;
|
||||
while (pos < end)
|
||||
{
|
||||
auto instructionOffset = offset;
|
||||
scope(failure) pos = start + instructionOffset;
|
||||
instructionAtOffset[instructionOffset] = to!uint(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)
|
||||
final switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.Unknown:
|
||||
throw new Exception("Don't know how to decode OP_" ~ opcodeInfo[instruction.opcode].name);
|
||||
|
||||
case OpcodeArgumentType.UByteLiteral:
|
||||
instruction.arguments[i].ubytev = readU8();
|
||||
break;
|
||||
case OpcodeArgumentType.IntLiteral:
|
||||
instruction.arguments[i].intv = readS32();
|
||||
break;
|
||||
case OpcodeArgumentType.UIntLiteral:
|
||||
instruction.arguments[i].uintv = readU32();
|
||||
break;
|
||||
|
||||
case OpcodeArgumentType.Int:
|
||||
case OpcodeArgumentType.UInt:
|
||||
case OpcodeArgumentType.Double:
|
||||
case OpcodeArgumentType.String:
|
||||
case OpcodeArgumentType.Namespace:
|
||||
case OpcodeArgumentType.Multiname:
|
||||
case OpcodeArgumentType.Class:
|
||||
case OpcodeArgumentType.Method:
|
||||
instruction.arguments[i].index = readU30();
|
||||
break;
|
||||
|
||||
case OpcodeArgumentType.JumpTarget:
|
||||
int delta = readS24();
|
||||
instruction.arguments[i].jumpTarget.absoluteOffset = offset + delta;
|
||||
break;
|
||||
|
||||
case OpcodeArgumentType.SwitchDefaultTarget:
|
||||
instruction.arguments[i].jumpTarget.absoluteOffset = instructionOffset + readS24();
|
||||
break;
|
||||
|
||||
case OpcodeArgumentType.SwitchTargets:
|
||||
instruction.arguments[i].switchTargets.length = readU30()+1;
|
||||
foreach (ref label; instruction.arguments[i].switchTargets)
|
||||
label.absoluteOffset = instructionOffset + readS24();
|
||||
break;
|
||||
}
|
||||
r.instructions ~= instruction;
|
||||
instructionOffsets ~= instructionOffset;
|
||||
}
|
||||
|
||||
if (pos > end)
|
||||
throw new Exception("Out-of-bounds code read error");
|
||||
|
||||
// convert jump target offsets to instruction indices
|
||||
foreach (ii, ref instruction; r.instructions)
|
||||
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
|
||||
switch (type)
|
||||
{
|
||||
case OpcodeArgumentType.JumpTarget:
|
||||
case OpcodeArgumentType.SwitchDefaultTarget:
|
||||
translateLabel(instruction.arguments[i].jumpTarget);
|
||||
break;
|
||||
case OpcodeArgumentType.SwitchTargets:
|
||||
foreach (ref x; instruction.arguments[i].switchTargets)
|
||||
translateLabel(x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
r.instructions = null;
|
||||
r.error = e.msg;
|
||||
instructionAtOffset[] = 0;
|
||||
}
|
||||
pos = end;
|
||||
|
||||
r.exceptions.length = readU30();
|
||||
// convert exception offsets to instruction indices
|
||||
foreach (ref value; r.exceptions)
|
||||
{
|
||||
value = readExceptionInfo();
|
||||
translateLabel(value.from);
|
||||
translateLabel(value.to);
|
||||
translateLabel(value.target);
|
||||
}
|
||||
|
||||
pos = postExceptions;
|
||||
|
||||
r.traits.length = readU30();
|
||||
foreach (ref value; r.traits)
|
||||
value = readTrait();
|
||||
|
||||
+12
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -261,8 +261,7 @@ final class ASProgram
|
||||
Exception[] exceptions;
|
||||
Trait[] traits;
|
||||
|
||||
string error;
|
||||
ubyte[] rawBytes;
|
||||
ABCFile.Error[] errors;
|
||||
}
|
||||
|
||||
struct Instruction
|
||||
@@ -583,8 +582,7 @@ private final class ABCtoAS
|
||||
e.varName = multinames[exc.varName];
|
||||
}
|
||||
n.traits = convertTraits(vbody.traits);
|
||||
n.error = vbody.error;
|
||||
n.rawBytes = vbody.rawBytes;
|
||||
n.errors = vbody.errors;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -747,12 +745,18 @@ private final class AStoABC : ASVisitor
|
||||
{
|
||||
static if (byRef)
|
||||
alias void* Key;
|
||||
else
|
||||
static if (is(T == double))
|
||||
alias ulong Key; // https://issues.dlang.org/show_bug.cgi?id=13420
|
||||
else
|
||||
alias immutable(T) Key;
|
||||
|
||||
Key toKey(T value)
|
||||
{
|
||||
return cast(Key)value;
|
||||
static if (is(T == double))
|
||||
return *cast(ulong*)&value;
|
||||
else
|
||||
return cast(Key)value;
|
||||
}
|
||||
|
||||
struct Entry
|
||||
@@ -994,7 +998,8 @@ private final class AStoABC : ASVisitor
|
||||
{
|
||||
multinames.registerDependency(m, m.vTypeName.name);
|
||||
foreach (t; m.vTypeName.params)
|
||||
multinames.registerDependency(m, t);
|
||||
if (t)
|
||||
multinames.registerDependency(m, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -80,7 +80,7 @@ final class Assembler
|
||||
else
|
||||
{
|
||||
createBuffer(BUF_SIZE);
|
||||
f.open(name, "rb");
|
||||
f = openFile(name, "rb");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ final class Assembler
|
||||
dataSource = (cast(ubyte[])data).only.inputRangeObject;
|
||||
else
|
||||
{
|
||||
f.open(name, "rb");
|
||||
f = openFile(name, "rb");
|
||||
dataSource = f.byChunk(BUF_SIZE).inputRangeObject;
|
||||
}
|
||||
scope(exit) if (!isVirtual) f.close();
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -222,8 +222,8 @@ struct ToStringDataHandler
|
||||
_AutoDataResult ~= to!string(" ~ name ~ ");
|
||||
";
|
||||
*/
|
||||
static if (is(typeof(T.init.toString())))
|
||||
enum getMixinSingle = "_AutoDataResult ~= " ~ name ~ ".toString();";
|
||||
static if (is(typeof(T.init is null)))
|
||||
enum getMixinSingle = "_AutoDataResult ~= " ~ name ~ " ? to!string(" ~ name ~ ") : `null`;";
|
||||
else
|
||||
enum getMixinSingle = "_AutoDataResult ~= to!string(" ~ name ~ ");";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2012, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
module common;
|
||||
|
||||
import std.path;
|
||||
import std.string;
|
||||
import std.array;
|
||||
import std.path;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
string longPath(string s)
|
||||
{
|
||||
@@ -34,3 +35,56 @@ string longPath(string s)
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
File openFile(string fn, string mode)
|
||||
{
|
||||
File f;
|
||||
static if (is(typeof(&f.windowsHandleOpen)))
|
||||
{
|
||||
import core.sys.windows.windows;
|
||||
|
||||
import std.exception;
|
||||
import std.utf;
|
||||
import std.windows.syserror;
|
||||
|
||||
string winMode;
|
||||
foreach (c; mode)
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
case 'w':
|
||||
case 'a':
|
||||
case '+':
|
||||
winMode ~= c;
|
||||
break;
|
||||
case 'b':
|
||||
case 't':
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unknown character in mode");
|
||||
}
|
||||
DWORD access, creation;
|
||||
bool append;
|
||||
switch (winMode)
|
||||
{
|
||||
case "r" : access = GENERIC_READ ; creation = OPEN_EXISTING; break;
|
||||
case "r+": access = GENERIC_READ | GENERIC_WRITE; creation = OPEN_EXISTING; break;
|
||||
case "w" : access = GENERIC_WRITE; creation = OPEN_ALWAYS ; break;
|
||||
case "w+": access = GENERIC_READ | GENERIC_WRITE; creation = OPEN_ALWAYS ; break;
|
||||
case "a" : access = GENERIC_WRITE; creation = OPEN_ALWAYS ; append = true; break;
|
||||
case "a+": assert(false, "Not implemented"); // requires two file pointers
|
||||
default: assert(false, "Bad file mode: " ~ mode);
|
||||
}
|
||||
|
||||
auto pathW = toUTF16z(longPath(fn));
|
||||
auto h = CreateFileW(pathW, access, FILE_SHARE_READ, null, creation, 0, HANDLE.init);
|
||||
enforce(h != INVALID_HANDLE_VALUE, "Failed to open file \"" ~ fn ~ "\": " ~ sysErrorString(GetLastError()));
|
||||
|
||||
assert(!append, "'a' mode not implemented");
|
||||
|
||||
f.windowsHandleOpen(h, mode);
|
||||
}
|
||||
else
|
||||
f.open(fn, mode);
|
||||
return f;
|
||||
}
|
||||
|
||||
+24
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2010, 2011, 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -58,7 +58,7 @@ final class StringBuilder
|
||||
if (subdir.length && !exists(longPath(subdir)))
|
||||
mkdir(longPath(subdir));
|
||||
}
|
||||
file.open(longPath(filename), "wb");
|
||||
file = openFile(filename, "wb");
|
||||
assert(!pos, "Opening new file with unflushed buffer");
|
||||
}
|
||||
|
||||
@@ -1129,6 +1129,7 @@ final class Disassembler
|
||||
T[size] buf;
|
||||
size_t pos;
|
||||
void put(T v) { buf[pos++] = v; }
|
||||
void put(in T[] v) { buf[pos..pos+v.length] = v[]; pos+=v.length; }
|
||||
T[] data() { return buf[0..pos]; }
|
||||
}
|
||||
|
||||
@@ -1574,13 +1575,6 @@ final class Disassembler
|
||||
|
||||
void dumpMethodBody(StringBuilder sb, ASProgram.MethodBody mbody)
|
||||
{
|
||||
if (mbody.error)
|
||||
{
|
||||
sb ~= "; Error while disassembling method: " ~ mbody.error;
|
||||
sb.newLine();
|
||||
sb.linePrefix = "; ";
|
||||
}
|
||||
|
||||
sb ~= "body";
|
||||
sb.indent++; sb.newLine();
|
||||
dumpUIntField(sb, "maxstack", mbody.maxStack);
|
||||
@@ -1596,17 +1590,7 @@ final class Disassembler
|
||||
labels[e.from.index] = labels[e.to.index] = labels[e.target.index] = true;
|
||||
|
||||
sb.indent++;
|
||||
if (mbody.error)
|
||||
foreach (i, b; mbody.rawBytes)
|
||||
{
|
||||
sb ~= format("0x%02X", b);
|
||||
if (i%16==15 || i==mbody.rawBytes.length-1)
|
||||
sb.newLine();
|
||||
else
|
||||
sb ~= " ";
|
||||
}
|
||||
else
|
||||
dumpInstructions(sb, mbody.instructions, labels);
|
||||
dumpInstructions(sb, mbody.instructions, labels, mbody.errors);
|
||||
sb.indent--;
|
||||
|
||||
sb ~= "end ; code";
|
||||
@@ -1631,7 +1615,7 @@ final class Disassembler
|
||||
sb.linePrefix = null;
|
||||
}
|
||||
|
||||
void dumpInstructions(StringBuilder sb, ASProgram.Instruction[] instructions, bool[] labels)
|
||||
void dumpInstructions(StringBuilder sb, ASProgram.Instruction[] instructions, bool[] labels, ABCFile.Error[] errors)
|
||||
{
|
||||
foreach (ref instruction; instructions)
|
||||
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
|
||||
@@ -1661,6 +1645,10 @@ final class Disassembler
|
||||
}
|
||||
}
|
||||
|
||||
string[] iErrors = new string[instructions.length + 1];
|
||||
foreach (ref error; errors)
|
||||
iErrors[error.loc.index] = error.msg;
|
||||
|
||||
bool extraNewLine = false;
|
||||
foreach (uint ii, ref instruction; instructions)
|
||||
{
|
||||
@@ -1669,6 +1657,20 @@ final class Disassembler
|
||||
extraNewLine = newLineAfter[instruction.opcode];
|
||||
checkLabel(ii);
|
||||
|
||||
if (iErrors[ii])
|
||||
{
|
||||
sb ~= "; Error: ";
|
||||
sb ~= iErrors[ii];
|
||||
sb.newLine();
|
||||
}
|
||||
|
||||
if (instruction.opcode == Opcode.OP_raw)
|
||||
{
|
||||
sb ~= "; 0x%02X".format(instruction.arguments[0].ubytev);
|
||||
sb.newLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
sb ~= opcodeInfo[instruction.opcode].name;
|
||||
auto argTypes = opcodeInfo[instruction.opcode].argumentTypes;
|
||||
if (argTypes.length)
|
||||
@@ -1802,6 +1804,7 @@ static this()
|
||||
Opcode.OP_si32,
|
||||
Opcode.OP_sf32,
|
||||
Opcode.OP_sf64,
|
||||
Opcode.OP_throw,
|
||||
])
|
||||
newLineAfter[o] = true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, 2013 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* Copyright 2012, 2013, 2014 Vladimir Panteleev <vladimir@thecybershadow.net>
|
||||
* This file is part of RABCDAsm.
|
||||
*
|
||||
* RABCDAsm is free software: you can redistribute it and/or modify
|
||||
@@ -79,7 +79,7 @@ ubyte[] lzmaCompress(in ubyte[] decompressedData, LZMAHeader* header)
|
||||
lzmaEnforce(lzma_alone_encoder(&strm, &opts), "lzma_alone_encoder");
|
||||
scope(exit) lzma_end(&strm);
|
||||
|
||||
auto outBuf = new ubyte[decompressedData.length + 1024];
|
||||
auto outBuf = new ubyte[decompressedData.length * 11 / 10 + 1024];
|
||||
strm.next_out = outBuf.ptr;
|
||||
strm.avail_out = outBuf.length;
|
||||
strm.next_in = decompressedData.ptr;
|
||||
|
||||
Reference in New Issue
Block a user