Decompiler improvement, slightly recursive
This commit is contained in:
parent
a06423a6bc
commit
f75c7e0534
@ -12,7 +12,7 @@ import java.io.File;
|
|||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
FlashDecompiler decompiler = new FlashDecompiler();
|
FlashDecompiler decompiler = new FlashDecompiler();
|
||||||
ShockwaveFile file = decompiler.loadFromFile(new File("D:\\Documents\\rtmpSpring\\static\\swf\\cache\\rus\\base[17].swf"));
|
ShockwaveFile file = decompiler.loadFromFile(new File("D:\\Documents\\FlashProjects\\Untitled-2.swf")); // D:\Documents\rtmpSpring\static\swf\cache\rus\base[17].swf
|
||||||
|
|
||||||
DoAction da = (DoAction) file.getTags()
|
DoAction da = (DoAction) file.getTags()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -15,7 +15,9 @@ public enum ActionPushType {
|
|||||||
// these types are internal (used for decompiler's purposes)
|
// these types are internal (used for decompiler's purposes)
|
||||||
// they are not exist
|
// they are not exist
|
||||||
|
|
||||||
INIT_OBJECT(-1);
|
INIT_OBJECT(-1),
|
||||||
|
GET_VARIABLE(-2),
|
||||||
|
GET_MEMBER(-3);
|
||||||
|
|
||||||
public final int type;
|
public final int type;
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.alterdekim.flash.decompiler.item.internal;
|
||||||
|
|
||||||
|
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
||||||
|
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GetMemberItem extends ByteCodeItem {
|
||||||
|
|
||||||
|
private final ArrayDeque<String> hierarchy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionPushType getType() {
|
||||||
|
return ActionPushType.GET_MEMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayDeque<String> getValue() {
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.alterdekim.flash.decompiler.item.internal;
|
||||||
|
|
||||||
|
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
||||||
|
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GetVariableItem extends ByteCodeItem {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionPushType getType() {
|
||||||
|
return ActionPushType.GET_VARIABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,11 @@ package com.alterdekim.flash.decompiler.item.internal;
|
|||||||
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
import com.alterdekim.flash.decompiler.item.ActionPushType;
|
||||||
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
import com.alterdekim.flash.decompiler.item.ByteCodeItem;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ToString
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class InitObjectItem extends ByteCodeItem {
|
public class InitObjectItem extends ByteCodeItem {
|
||||||
|
|
||||||
|
@ -3,9 +3,10 @@ package com.alterdekim.flash.decompiler.translator;
|
|||||||
import com.alterdekim.flash.decompiler.action.ActionPush;
|
import com.alterdekim.flash.decompiler.action.ActionPush;
|
||||||
import com.alterdekim.flash.decompiler.item.*;
|
import com.alterdekim.flash.decompiler.item.*;
|
||||||
import com.alterdekim.flash.decompiler.action.ByteCodeAction;
|
import com.alterdekim.flash.decompiler.action.ByteCodeAction;
|
||||||
|
import com.alterdekim.flash.decompiler.item.internal.GetMemberItem;
|
||||||
|
import com.alterdekim.flash.decompiler.item.internal.GetVariableItem;
|
||||||
import com.alterdekim.flash.decompiler.item.internal.InitObjectItem;
|
import com.alterdekim.flash.decompiler.item.internal.InitObjectItem;
|
||||||
import com.alterdekim.flash.decompiler.tag.DoAction;
|
import com.alterdekim.flash.decompiler.tag.DoAction;
|
||||||
import com.alterdekim.flash.decompiler.util.ActionField;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -16,7 +17,7 @@ public class Flash2Java {
|
|||||||
private final List<String> pool;
|
private final List<String> pool;
|
||||||
private final List<ByteCodeAction> actions;
|
private final List<ByteCodeAction> actions;
|
||||||
private final Stack<ByteCodeItem> stack; // ByteCodeAction
|
private final Stack<ByteCodeItem> stack; // ByteCodeAction
|
||||||
private final Map<String, FlashVar> vars;
|
private final Map<String, Object> vars;
|
||||||
|
|
||||||
public Flash2Java(DoAction doAction) {
|
public Flash2Java(DoAction doAction) {
|
||||||
this.pool = doAction.getActionPool();
|
this.pool = doAction.getActionPool();
|
||||||
@ -25,12 +26,15 @@ public class Flash2Java {
|
|||||||
this.vars = new HashMap<>();
|
this.vars = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, FlashVar> convert() {
|
public Map<String, Object> convert() {
|
||||||
// abolish the activeness of variable inside of an HashMap. Use stack instead.
|
// abolish the activeness of variable inside a HashMap. Use stack instead.
|
||||||
for (ByteCodeAction action : actions) {
|
for (ByteCodeAction action : actions) {
|
||||||
// try {
|
// try {
|
||||||
//log.info("Action type: " + action.getType().toString());
|
//log.info("Action type: " + action.getType().toString());
|
||||||
switch (action.getType()) {
|
switch (action.getType()) {
|
||||||
|
case DefineLocal2:
|
||||||
|
defineLocalWithoutAssign();
|
||||||
|
break;
|
||||||
case DefineLocal:
|
case DefineLocal:
|
||||||
defineLocal();
|
defineLocal();
|
||||||
break;
|
break;
|
||||||
@ -66,11 +70,11 @@ public class Flash2Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initObject() {
|
private void initObject() {
|
||||||
Integer numberOfEntries = (Integer) this.stack.pop().getValue();
|
Integer numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way
|
||||||
HashMap<String, Object> obj = new HashMap<>();
|
HashMap<String, Object> obj = new HashMap<>();
|
||||||
for( int i = 0; i < numberOfEntries; i++ ) {
|
for( int i = 0; i < numberOfEntries; i++ ) {
|
||||||
Object val = valConverter( this.stack.pop() );
|
Object val = valConverter( this.stack.pop() );
|
||||||
String key = (String) valConverter( this.stack.pop() );
|
String key = valToString( this.stack.pop() );
|
||||||
obj.put(key, val);
|
obj.put(key, val);
|
||||||
}
|
}
|
||||||
this.stack.push(new InitObjectItem(obj));
|
this.stack.push(new InitObjectItem(obj));
|
||||||
@ -96,36 +100,62 @@ public class Flash2Java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void getMember() {
|
private void getMember() {
|
||||||
Object val = this.stack.pop().getValue();
|
log.info("GetMember: {}", this.stack);
|
||||||
String name = (String) valConverter( this.stack.pop() );
|
String property = valToString( this.stack.pop() );
|
||||||
log.info("SetMember: {}", name);
|
|
||||||
String key = this.vars.keySet().stream().filter(k -> this.vars.get(k).isActive()).findFirst().get();
|
|
||||||
HashMap<String, Object> g = (HashMap<String, Object>) this.vars.get(key).getVal();
|
|
||||||
g.put(name, val);
|
|
||||||
this.vars.put(key, new FlashVar(true, g));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasActiveVariable() {
|
|
||||||
return this.vars.keySet().stream().anyMatch(k -> this.vars.get(k).isActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getActiveVarKey() {
|
|
||||||
return this.vars.keySet().stream().filter(k -> this.vars.get(k).isActive()).findFirst().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setMember() {
|
|
||||||
ByteCodeItem val = this.stack.pop();
|
ByteCodeItem val = this.stack.pop();
|
||||||
|
if( val.getType() == ActionPushType.GET_MEMBER ) {
|
||||||
if( this.stack.isEmpty() && this.hasActiveVariable() ) {
|
ArrayDeque<String> l = (ArrayDeque<String>) val.getValue();
|
||||||
String var = getActiveVarKey();
|
l.add(property);
|
||||||
|
this.stack.push(new GetMemberItem(l));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Integer index = (Integer) this.stack.pop().getValue();
|
String key = valToString(val);
|
||||||
String var = this.vars.keySet().stream().filter(k -> this.vars.get(k).isActive()).findFirst().get();
|
this.stack.push(new GetMemberItem(new ArrayDeque<>(List.of(key, property))));
|
||||||
Map<String, Object> m = (Map<String, Object>) this.vars.get(var).getVal();
|
}
|
||||||
m.put(String.valueOf(index), val.getValue());
|
|
||||||
this.vars.put(var, new FlashVar(false, m)); // this may cause a bug (false in FlashVar arg)
|
private void setMember() { // make recursive assignment.
|
||||||
|
log.info("SetMember: {}", this.stack);
|
||||||
|
ByteCodeItem val = this.stack.pop();
|
||||||
|
String index = valToString( this.stack.pop() );
|
||||||
|
ByteCodeItem varOrMember = this.stack.pop();
|
||||||
|
if( varOrMember.getType() == ActionPushType.GET_VARIABLE ) {
|
||||||
|
Map<String, Object> m = (Map<String, Object>) this.vars.get(valToString( varOrMember ));
|
||||||
|
m.put(index, val.getValue());
|
||||||
|
this.vars.put(valToString(varOrMember), m);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// GetMemberItem recursive
|
||||||
|
Map<String, Object> m = recursiveGet((ArrayDeque<String>) varOrMember.getValue());
|
||||||
|
m.put(index, val.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> recursiveGet(Deque<String> l) {
|
||||||
|
Map<String, Object> m = this.vars;
|
||||||
|
Iterator<String> i = l.iterator();
|
||||||
|
while(i.hasNext()) {
|
||||||
|
m = (HashMap<String, Object>) m.get(i.next());
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetMemberItem toGetMember(ByteCodeItem item) {
|
||||||
|
switch (item.getType()) {
|
||||||
|
case GET_MEMBER:
|
||||||
|
return (GetMemberItem) item;
|
||||||
|
case STRING:
|
||||||
|
case POOL_INDEX:
|
||||||
|
default:
|
||||||
|
return new GetMemberItem(new ArrayDeque<>(List.of(valToString(item))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String valToString(ByteCodeItem item) {
|
||||||
|
if ( item.getType() == ActionPushType.POOL_INDEX ) {
|
||||||
|
return fromPool( (Integer) item.getValue() );
|
||||||
|
} else if ( item.getType() == ActionPushType.STRING ) {
|
||||||
|
return (String) item.getValue();
|
||||||
|
}
|
||||||
|
return String.valueOf( item.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object valConverter(ByteCodeItem item) {
|
private Object valConverter(ByteCodeItem item) {
|
||||||
@ -139,29 +169,24 @@ public class Flash2Java {
|
|||||||
|
|
||||||
private void setVariable() {
|
private void setVariable() {
|
||||||
Object val = this.stack.pop().getValue();
|
Object val = this.stack.pop().getValue();
|
||||||
String variableName = (String) valConverter( this.stack.pop() );
|
String variableName = valToString( this.stack.pop() );
|
||||||
vars.put(variableName, new FlashVar(false, val));
|
vars.put(variableName, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getVariable() {
|
private void getVariable() {
|
||||||
String variableName = (String) valConverter( this.stack.pop() );
|
String variableName = valToString( this.stack.pop() );
|
||||||
vars.keySet().forEach(k -> {
|
this.stack.push(new GetVariableItem(variableName));
|
||||||
FlashVar fv = vars.get(k);
|
}
|
||||||
fv.setActive(false);
|
|
||||||
vars.put(k, fv);
|
private void defineLocalWithoutAssign() {
|
||||||
});
|
String variableName = valToString( this.stack.pop() );
|
||||||
FlashVar v = vars.get(variableName);
|
|
||||||
v.setActive(true);
|
|
||||||
vars.put(variableName, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void defineLocal() {
|
private void defineLocal() {
|
||||||
ByteCodeItem val = this.stack.pop();
|
ByteCodeItem val = this.stack.pop();
|
||||||
String name = (String) valConverter( this.stack.pop() );
|
String name = valToString( this.stack.pop() );
|
||||||
// todo: implement assignment ability (from one value to another)
|
// todo: implement assignment ability (from one value to another)
|
||||||
vars.put(name,
|
vars.put(name, val.getValue());
|
||||||
new FlashVar(false, val.getValue())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fromPool(int index) {
|
private String fromPool(int index) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user