flash.swf.tools.Disassembler Maven / Gradle / Ivy
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package flash.swf.tools;
import flash.swf.Action;
import flash.swf.ActionHandler;
import flash.swf.ActionConstants;
import flash.swf.actions.Branch;
import flash.swf.actions.ConstantPool;
import flash.swf.actions.DefineFunction;
import flash.swf.actions.GetURL;
import flash.swf.actions.GetURL2;
import flash.swf.actions.GotoFrame;
import flash.swf.actions.GotoFrame2;
import flash.swf.actions.GotoLabel;
import flash.swf.actions.Label;
import flash.swf.actions.Push;
import flash.swf.actions.SetTarget;
import flash.swf.actions.StoreRegister;
import flash.swf.actions.StrictMode;
import flash.swf.actions.Try;
import flash.swf.actions.Unknown;
import flash.swf.actions.WaitForFrame;
import flash.swf.actions.With;
import flash.swf.debug.DebugModule;
import flash.swf.debug.LineRecord;
import flash.swf.debug.RegisterRecord;
import flash.swf.types.ActionList;
import flash.util.FieldFormat;
import java.io.PrintWriter;
import java.util.HashMap;
/**
* This utility supports printing AS2 byte codes.
*/
public class Disassembler extends ActionHandler
{
protected ConstantPool cpool;
protected int start;
protected int offset;
protected final PrintWriter out;
private boolean showOffset = false;
private boolean showDebugSource = false;
private boolean showLineRecord = true;
private RegisterRecord registerRecord = null;
private int indent;
private int initialIndent;
private String comment;
private String format;
public Disassembler(PrintWriter out, ConstantPool cpool, String comment)
{
this(out, false, 0);
this.cpool = cpool;
this.comment = comment;
}
public Disassembler(PrintWriter out, boolean showOffset, int indent)
{
this.out = out;
this.showOffset = showOffset;
this.indent = indent;
this.initialIndent = indent;
this.comment = "";
}
public void setComment(String comment)
{
this.comment = comment;
}
public void setFormat(String format)
{
this.format = format;
}
public void setShowDebugSource(boolean b)
{
this.showDebugSource = b;
}
public void setShowLineRecord(boolean b)
{
this.showLineRecord = b;
}
public static void disassemble(ActionList list, ConstantPool pool, int startIndex, int endIndex, PrintWriter out)
{
Disassembler d = new Disassembler(out, pool, " ");
d.setFormat(" 0x%08O %a");
d.setShowLineRecord(false);
// probe backward for a register record if any to set up register to variable name mapping
int at = list.lastIndexOf(ActionList.sactionRegisterRecord, startIndex);
if (at > -1)
d.registerRecord = (RegisterRecord)list.getAction(at);
// now dump the contents of our request
list.visit(d, startIndex, endIndex);
out.flush();
}
protected void print(Action action)
{
start(action);
out.println();
}
public void setActionOffset(int offset, Action a)
{
if (this.offset == 0)
{
this.start = offset;
}
this.offset = offset;
}
protected void indent()
{
for (int i=0; i < initialIndent; i++)
out.print(" ");
out.print(comment);
for (int i=initialIndent; i < indent; i++)
out.print(" ");
}
public void registerRecord(RegisterRecord record)
{
// set the active record
registerRecord = record;
}
protected String variableNameForRegister(int regNbr)
{
int at = (registerRecord == null) ? -1 : registerRecord.indexOf(regNbr);
if (at > -1)
return registerRecord.variableNames[at];
else
return null;
}
public void lineRecord(LineRecord line)
{
if (!showLineRecord)
;
else if (showDebugSource)
{
printLines(line, out);
}
else
{
start(line);
out.println(" "+line.module.name +":"+line.lineno);
}
}
public void printLines(LineRecord lr, PrintWriter out)
{
DebugModule script = lr.module;
if (script != null)
{
int lineno = lr.lineno;
if (lineno > 0)
{
while (lineno-1 > 0 && script.offsets[lineno-1] == 0)
{
lineno--;
}
if (lineno == 1)
{
indent();
out.println(script.name);
}
int off = script.index[lineno-1];
int len = script.index[lr.lineno] - off;
out.write(script.text, off, len);
}
}
}
protected void start(Action action)
{
String actionName;
if ((action.code < 0) || (action.code > actionNames.length))
{
actionName = "Unknown";
}
else
{
actionName = actionNames[action.code];
}
if (showOffset)
{
indent();
out.print("absolute=" + offset + ",relative=" + (offset-start) +
",code=" + action.code + "\t" + actionName);
}
else
{
if (format == null)
{
indent();
out.print(actionName);
}
else
{
startFormatted(actionName);
}
}
}
protected void startFormatted(String action)
{
StringBuilder sb = new StringBuilder();
boolean leadingZeros = false;
int width = -1;
for(int i=0; i
{
private static final long serialVersionUID = -7907644739362458461L;
LabelEntry getLabelEntry(Label l)
{
LabelEntry entry = get(l);
if (entry == null)
{
entry = new LabelEntry(null,null);
put(l, entry);
}
return entry;
}
}
private LabelMap labels = new LabelMap();
int labelCount = 0;
public void ifAction(Branch action)
{
printBranch(action);
}
public void jump(Branch action)
{
printBranch(action);
}
protected void printBranch(Branch action)
{
start(action);
LabelEntry entry = labels.getLabelEntry(action.target);
if (entry.name == null)
entry.name = "L"+String.valueOf(labelCount++);
entry.source = action;
out.println(" " + entry.name);
}
public void label(Label label)
{
LabelEntry entry = labels.getLabelEntry(label);
if (entry.source == null)
{
// have not seen any actions that target this label yet, and that
// means the source can only be a backwards branch
entry.name = "L"+String.valueOf(labelCount++);
indent();
out.println(entry.name + ":");
}
else
{
switch (entry.source.code)
{
case ActionConstants.sactionTry:
Try t = (Try) entry.source;
indent--;
indent();
out.println("}");
indent();
if (label == t.endTry && t.hasCatch())
{
out.println("catch("+
(t.hasRegister()?"$"+t.catchReg:t.catchName) +
") {");
indent++;
}
else if ((label == t.endTry || label == t.endCatch) && t.hasFinally())
{
out.println("finally {");
indent++;
}
break;
case ActionConstants.sactionWaitForFrame:
case ActionConstants.sactionWaitForFrame2:
case ActionConstants.sactionWith:
// end of block
indent--;
indent();
out.println("}");
break;
case ActionConstants.sactionIf:
case ActionConstants.sactionJump:
indent();
out.println(entry.name + ":");
break;
default:
assert (false);
break;
}
}
}
public void call(Action action)
{
print(action);
}
public void gotoFrame2(GotoFrame2 action)
{
start(action);
out.println(" " + action.playFlag);
}
public void quickTime(Action action)
{
print(action);
}
public void unknown(Unknown action)
{
print(action);
}
public static String quoteString(String s, char qc)
{
StringBuilder b = new StringBuilder(s.length() + 2);
b.append(qc);
for (int i=0; i < s.length(); i++)
{
char c = s.charAt(i);
switch (c)
{
case 8: b.append("\\v"); break;
case '\f' : b.append("\\f"); break;
case '\r' : b.append("\\r"); break;
case '\t' : b.append("\\t"); break;
case '\n' : b.append("\\n"); break;
case '"' : b.append("\\\""); break;
case '\'' : b.append("\\'"); break;
default: b.append(c); break;
}
}
b.append(qc);
return b.toString();
}
static final public String[] actionNames = {
// 00 0000----
"0x00",
"0x01",
"0x02",
"0x03",
"next", // sactionNextFrame
"prev", // sactionPrevFrame
"play", // sactionPlay
"stop", // sactionStop
"toggle", // sactionToggleQuality
"stopsound", // sactionStopSounds
"add", // sactionAdd
"sub", // sactionSubtract
"mul", // sactionMultiply
"div", // sactionDivide
"eq", // sactionEquals
"lt", // sactionLess
// 0x10 0001----
"and", // sactionAnd
"or", // sactionOr
"not", // sactionNot
"seq", // sactionStringEquals
"slen", // sactionStringLength
"substr", // sactionStringExtract
"0x16",
"pop", // sactionPop
"toint", // sactionToInteger
"0x19",
"0x1A",
"0x1B",
"get", // sactionGetVariable
"set", // sactionGetVariable
"0x1E",
"0x1F",
//0x20 0010----
"settarget2", //sactionSetTarget2
"sadd", // sactionStringAdd
"getprop", // sactionGetProperty
"setprop", // sactoinSetProperty
"csprite", // sactionCloneSprite
"rsprite", // sactionRemoveSprite
"trace", // sactionTrace
"sdrag", // sactionStartDrag
"edrag", // sactionEndDragg
"slt", // sactionStringLess
"0x2A",
"0x2B",
"0x2C",
"0x2D",
"0x2E",
"0x2F",
// 0x30 0011----
"rand", // sactionRandomNumber
"wslen", // sactionMbStringLength
"c2a", // sactionCharToAscii
"a2c", // sactionAscii2Char
"time", // sactionGetTime
"wsubstr", // sactionMBStringExtract
"wc2a", // sactionMbCharToAscii
"wa2c", // sactionMbAsciiToChar
"0x38",
"0x39",
"del", // sactionDelete
"del2", // sactionDelete2
"var", // sactionDefineLoc
"callfun", // sactionCallFunction
"return", // sactionReturn
"mod", // sactionMod
// 0x40 0100----
"newobj", // sactionNewObject
"var2", // sactionDefineLocal2
"initarr", // sactionInitArray
"initobj", // sactionInitObject
"typeof", // sactionTypeOf
"target", // sactionTargetPath
"enum", // sactionEnumerate
"add2", // sactionAdd2
"lt2", // sactionLess2
"eq2", // sactionEquals2
"tonum", // sactionToNumber
"tostr", // sactionToString
"dup", // sactionPushDuplicate
"swap", // sactionStackSwap
"getmem", // sactionGetMember
"setmem", // sactionSetMember
// 0x50 0101----
"inc", // sactionIncrement
"dec", // sactionDecrement
"callmethod", // sactionCallMethod
"newmethod", // sactionNewMethod
"instanceof", // sactionInstanceOf
"enum2", // sactionEnumerate2
"0x56",
"0x57",
"0x58",
"0x59",
"0x5A",
"0x5B",
"0x5C",
"0x5D",
"0x5E",
"halt", // sactionHalt
// 0x60 0110----
"band", // sactionBitAnd
"bor", // sactionBitOr
"bxor", // sactionBitXor
"bls", // sactionBitLShift
"brs", // sactionBitRShift
"burs", // sactionBitURShift
"eqs", // sactionStrictEquals
"gt", // sactionGreater
"sgt", // sactionStringGreater
"extends", // sactionExtends
"0x6A",
"0x6B",
"0x6C",
"0x6D",
"0x6E",
"0x6F",
// 0x70 0111----
"0x70",
"0x71",
"0x72",
"0x73",
"0x74",
"0x75",
"0x76",
"nop", // sactionNop
"0x78",
"0x79",
"0x7A",
"0x7B",
"0x7C",
"0x7D",
"0x7E",
"0x7F",
// 0x80 1000----
"0x80",
"gotoframe", // sactionGotoFrame
"0x82",
"geturl", // sactionGetUrl
"0x84",
"0x85",
"0x86",
"store", // sactionStoreRegister
"cpool", // sactionConstantPool
"strict", // sactionStrictMode
"wait", // sactionWaitForFrame
"settarget", // sactionSetTarget
"gotolabel", // sactoinGotoLabel
"wait2", // sactionWaitForFrame2
"function2", // sactionDefineFunction2
"try", // sactionTry
// 0x90 1001----
"0x90",
"0x91",
"0x92",
"0x93",
"with", // sactionWith
"0x95",
"push", // sactionPush
"0x97",
"0x98",
"jump", // sactionJump
"geturl2", // sactionGetUrl2
"function", // sactionDefineFunction
"0x9C",
"if", // sactionIf
"call", // sactionCall
"gotof2", // sactionGotoFrame2
// 0xA0 1010----
"0xA0",
"0xA1",
"0xA2",
"0xA3",
"0xA4",
"0xA5",
"0xA6",
"0xA7",
"0xA8",
"0xA9",
"quicktime", // sactionQuickTime
"0xAB",
"0xAC",
"0xAD",
"0xAE",
"0xAF",
// 0xB0 1011----
"0xB0",
"0xB1",
"0xB2",
"0xB3",
"0xB4",
"0xB5",
"0xB6",
"0xB7",
"0xB8",
"0xB9",
"0xBA",
"0xBB",
"0xBC",
"0xBD",
"0xBE",
"0xBF",
// 0xC0 1100----
"0xC0",
"0xC1",
"0xC2",
"0xC3",
"0xC4",
"0xC5",
"0xC6",
"0xC7",
"0xC8",
"0xC9",
"0xCA",
"0xCB",
"0xCC",
"0xCD",
"0xCE",
"0xCF",
// 0xD0 1101----
"0xD0",
"0xD1",
"0xD2",
"0xD3",
"0xD4",
"0xD5",
"0xD6",
"0xD7",
"0xD8",
"0xD9",
"0xDA",
"0xDB",
"0xDC",
"0xDD",
"0xDE",
"0xDF",
// 0xE0 1110----
"0xE0",
"0xE1",
"0xE2",
"0xE3",
"0xE4",
"0xE5",
"0xE6",
"0xE7",
"0xE8",
"0xE9",
"0xEA",
"0xEB",
"0xEC",
"0xED",
"0xEE",
"0xEF",
"0xF0",
// 0xF0 1111----
"0xF1",
"0xF2",
"0xF3",
"0xF4",
"0xF5",
"0xF6",
"0xF7",
"0xF8",
"0xF9",
"0xFA",
"0xFB",
"0xFC",
"0xFD",
"0xFE",
"0xFF",
// these are not valid bytecodes, but we use them internally
"label", // 0x100
"line", // 0x101
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy