diff --git a/src/main/java/com/alterdekim/flash/decompiler/Main.java b/src/main/java/com/alterdekim/flash/decompiler/Main.java index eabc70b..81e99b8 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/Main.java +++ b/src/main/java/com/alterdekim/flash/decompiler/Main.java @@ -12,7 +12,7 @@ import java.io.File; public class Main { public static void main(String[] args) throws Exception { 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() .stream() diff --git a/src/main/java/com/alterdekim/flash/decompiler/item/ActionPushType.java b/src/main/java/com/alterdekim/flash/decompiler/item/ActionPushType.java index be99bad..24506fc 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/item/ActionPushType.java +++ b/src/main/java/com/alterdekim/flash/decompiler/item/ActionPushType.java @@ -15,7 +15,9 @@ public enum ActionPushType { // these types are internal (used for decompiler's purposes) // they are not exist - INIT_OBJECT(-1); + INIT_OBJECT(-1), + GET_VARIABLE(-2), + GET_MEMBER(-3); public final int type; diff --git a/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetMemberItem.java b/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetMemberItem.java new file mode 100644 index 0000000..15563d4 --- /dev/null +++ b/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetMemberItem.java @@ -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 hierarchy; + + @Override + public ActionPushType getType() { + return ActionPushType.GET_MEMBER; + } + + @Override + public ArrayDeque getValue() { + return hierarchy; + } +} diff --git a/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetVariableItem.java b/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetVariableItem.java new file mode 100644 index 0000000..3bf01a9 --- /dev/null +++ b/src/main/java/com/alterdekim/flash/decompiler/item/internal/GetVariableItem.java @@ -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; + } +} diff --git a/src/main/java/com/alterdekim/flash/decompiler/item/internal/InitObjectItem.java b/src/main/java/com/alterdekim/flash/decompiler/item/internal/InitObjectItem.java index a6db696..3da72e8 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/item/internal/InitObjectItem.java +++ b/src/main/java/com/alterdekim/flash/decompiler/item/internal/InitObjectItem.java @@ -3,9 +3,11 @@ 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.HashMap; +@ToString @AllArgsConstructor public class InitObjectItem extends ByteCodeItem { diff --git a/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java b/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java index cefb015..63625d9 100644 --- a/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java +++ b/src/main/java/com/alterdekim/flash/decompiler/translator/Flash2Java.java @@ -3,9 +3,10 @@ package com.alterdekim.flash.decompiler.translator; import com.alterdekim.flash.decompiler.action.ActionPush; import com.alterdekim.flash.decompiler.item.*; 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.tag.DoAction; -import com.alterdekim.flash.decompiler.util.ActionField; import lombok.extern.slf4j.Slf4j; import java.util.*; @@ -16,7 +17,7 @@ public class Flash2Java { private final List pool; private final List actions; private final Stack stack; // ByteCodeAction - private final Map vars; + private final Map vars; public Flash2Java(DoAction doAction) { this.pool = doAction.getActionPool(); @@ -25,12 +26,15 @@ public class Flash2Java { this.vars = new HashMap<>(); } - public Map convert() { - // abolish the activeness of variable inside of an HashMap. Use stack instead. + public Map convert() { + // abolish the activeness of variable inside a HashMap. Use stack instead. for (ByteCodeAction action : actions) { // try { //log.info("Action type: " + action.getType().toString()); switch (action.getType()) { + case DefineLocal2: + defineLocalWithoutAssign(); + break; case DefineLocal: defineLocal(); break; @@ -66,11 +70,11 @@ public class Flash2Java { } private void initObject() { - Integer numberOfEntries = (Integer) this.stack.pop().getValue(); + Integer numberOfEntries = (int) Double.parseDouble(this.stack.pop().getValue()+""); // harsh way HashMap obj = new HashMap<>(); for( int i = 0; i < numberOfEntries; i++ ) { Object val = valConverter( this.stack.pop() ); - String key = (String) valConverter( this.stack.pop() ); + String key = valToString( this.stack.pop() ); obj.put(key, val); } this.stack.push(new InitObjectItem(obj)); @@ -96,36 +100,62 @@ public class Flash2Java { } private void getMember() { - Object val = this.stack.pop().getValue(); - String name = (String) valConverter( this.stack.pop() ); - log.info("SetMember: {}", name); - String key = this.vars.keySet().stream().filter(k -> this.vars.get(k).isActive()).findFirst().get(); - HashMap g = (HashMap) 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() { + log.info("GetMember: {}", this.stack); + String property = valToString( this.stack.pop() ); ByteCodeItem val = this.stack.pop(); - - if( this.stack.isEmpty() && this.hasActiveVariable() ) { - String var = getActiveVarKey(); - + if( val.getType() == ActionPushType.GET_MEMBER ) { + ArrayDeque l = (ArrayDeque) val.getValue(); + l.add(property); + this.stack.push(new GetMemberItem(l)); return; } - Integer index = (Integer) this.stack.pop().getValue(); - String var = this.vars.keySet().stream().filter(k -> this.vars.get(k).isActive()).findFirst().get(); - Map m = (Map) 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) + String key = valToString(val); + this.stack.push(new GetMemberItem(new ArrayDeque<>(List.of(key, property)))); + } + + 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 m = (Map) this.vars.get(valToString( varOrMember )); + m.put(index, val.getValue()); + this.vars.put(valToString(varOrMember), m); + return; + } + // GetMemberItem recursive + Map m = recursiveGet((ArrayDeque) varOrMember.getValue()); + m.put(index, val.getValue()); + } + + private Map recursiveGet(Deque l) { + Map m = this.vars; + Iterator i = l.iterator(); + while(i.hasNext()) { + m = (HashMap) 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) { @@ -139,29 +169,24 @@ public class Flash2Java { private void setVariable() { Object val = this.stack.pop().getValue(); - String variableName = (String) valConverter( this.stack.pop() ); - vars.put(variableName, new FlashVar(false, val)); + String variableName = valToString( this.stack.pop() ); + vars.put(variableName, val); } private void getVariable() { - String variableName = (String) valConverter( this.stack.pop() ); - vars.keySet().forEach(k -> { - FlashVar fv = vars.get(k); - fv.setActive(false); - vars.put(k, fv); - }); - FlashVar v = vars.get(variableName); - v.setActive(true); - vars.put(variableName, v); + String variableName = valToString( this.stack.pop() ); + this.stack.push(new GetVariableItem(variableName)); + } + + private void defineLocalWithoutAssign() { + String variableName = valToString( this.stack.pop() ); } private void defineLocal() { 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) - vars.put(name, - new FlashVar(false, val.getValue()) - ); + vars.put(name, val.getValue()); } private String fromPool(int index) {