/* * Copyright (C) 2010-2014 JPEXS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.jpexs.decompiler.flash.action.swf7; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.model.FunctionActionItem; import com.jpexs.decompiler.flash.action.parser.ParseException; import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.helpers.Helper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; public class ActionDefineFunction2 extends Action implements GraphSourceItemContainer { public String functionName; public String replacedFunctionName; public List paramNames = new ArrayList<>(); public List replacedParamNames; public List paramRegisters = new ArrayList<>(); public boolean preloadParentFlag; public boolean preloadRootFlag; public boolean suppressSuperFlag; public boolean preloadSuperFlag; public boolean suppressArgumentsFlag; public boolean preloadArgumentsFlag; public boolean suppressThisFlag; public boolean preloadThisFlag; public int reserved; public boolean preloadGlobalFlag; public int registerCount; public int codeSize; //public List code; private int version; public List constantPool; private long hdrSize; public ActionDefineFunction2(String functionName, boolean preloadParentFlag, boolean preloadRootFlag, boolean suppressSuperFlag, boolean preloadSuperFlag, boolean suppressArgumentsFlag, boolean preloadArgumentsFlag, boolean suppressThisFlag, boolean preloadThisFlag, boolean preloadGlobalFlag, int registerCount, int codeSize, int version, List paramNames, List paramRegisters) { super(0x8E, 0); this.functionName = functionName; this.preloadParentFlag = preloadParentFlag; this.preloadRootFlag = preloadRootFlag; this.suppressSuperFlag = suppressSuperFlag; this.preloadSuperFlag = preloadSuperFlag; this.suppressArgumentsFlag = suppressArgumentsFlag; this.preloadArgumentsFlag = preloadArgumentsFlag; this.suppressThisFlag = suppressThisFlag; this.preloadThisFlag = preloadThisFlag; this.preloadGlobalFlag = preloadGlobalFlag; this.registerCount = registerCount; this.codeSize = codeSize; this.version = version; this.paramNames = paramNames; this.paramRegisters = paramRegisters; } public ActionDefineFunction2(int actionLength, SWFInputStream sis, int version) throws IOException { super(0x8E, actionLength); long posBef = sis.getPos(); this.version = version; functionName = sis.readString("functionName"); int numParams = sis.readUI16("numParams"); registerCount = sis.readUI8("registerCount"); preloadParentFlag = sis.readUB(1, "preloadParentFlag") == 1; preloadRootFlag = sis.readUB(1, "preloadRootFlag") == 1; suppressSuperFlag = sis.readUB(1, "suppressSuperFlag") == 1; preloadSuperFlag = sis.readUB(1, "preloadSuperFlag") == 1; suppressArgumentsFlag = sis.readUB(1, "suppressArgumentsFlag") == 1; preloadArgumentsFlag = sis.readUB(1, "preloadArgumentsFlag") == 1; suppressThisFlag = sis.readUB(1, "suppressThisFlag") == 1; preloadThisFlag = sis.readUB(1, "preloadThisFlag") == 1; reserved = (int) sis.readUB(7, "reserved"); preloadGlobalFlag = sis.readUB(1, "preloadGlobalFlag") == 1; for (int i = 0; i < numParams; i++) { paramRegisters.add(sis.readUI8("paramRegister")); paramNames.add(sis.readString("paramName")); } codeSize = sis.readUI16("codeSize"); long posAfter = sis.getPos(); hdrSize = posAfter - posBef; //code = new ArrayList(); //int posBef2 = (int) rri.getPos(); //code = sis.readActionList(rri.getPos(), getFileAddress() + hdrSize, rri, codeSize); //rri.setPos(posBef2 + codeSize); } public ActionDefineFunction2(FlasmLexer lexer) throws IOException, ParseException { super(0x8E, -1); functionName = lexString(lexer); int numParams = (int) lexLong(lexer); registerCount = (int) lexLong(lexer); preloadParentFlag = lexBoolean(lexer); preloadRootFlag = lexBoolean(lexer); suppressSuperFlag = lexBoolean(lexer); preloadSuperFlag = lexBoolean(lexer); suppressArgumentsFlag = lexBoolean(lexer); preloadArgumentsFlag = lexBoolean(lexer); suppressThisFlag = lexBoolean(lexer); preloadThisFlag = lexBoolean(lexer); preloadGlobalFlag = lexBoolean(lexer); for (int i = 0; i < numParams; i++) { paramRegisters.add((int) lexLong(lexer)); paramNames.add(lexString(lexer)); } lexBlockOpen(lexer); } @Override public long getHeaderSize() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); SWFOutputStream sos = new SWFOutputStream(baos, version); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); try { sos.writeString(functionName); sos.writeUI16(paramNames.size()); sos.writeUI8(registerCount); sos.writeUB(1, preloadParentFlag ? 1 : 0); sos.writeUB(1, preloadRootFlag ? 1 : 0); sos.writeUB(1, suppressSuperFlag ? 1 : 0); sos.writeUB(1, preloadSuperFlag ? 1 : 0); sos.writeUB(1, suppressArgumentsFlag ? 1 : 0); sos.writeUB(1, preloadArgumentsFlag ? 1 : 0); sos.writeUB(1, suppressThisFlag ? 1 : 0); sos.writeUB(1, preloadThisFlag ? 1 : 0); sos.writeUB(7, reserved); sos.writeUB(1, preloadGlobalFlag ? 1 : 0); for (int i = 0; i < paramNames.size(); i++) { sos.writeUI8(paramRegisters.get(i)); sos.writeString(paramNames.get(i)); } sos.writeUI16(0); sos.close(); baos2.write(surroundWithAction(baos.toByteArray(), version)); } catch (IOException e) { } return baos2.toByteArray().length; } @Override public byte[] getBytes(int version) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); SWFOutputStream sos = new SWFOutputStream(baos, version); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); try { sos.writeString(functionName); sos.writeUI16(paramNames.size()); sos.writeUI8(registerCount); sos.writeUB(1, preloadParentFlag ? 1 : 0); sos.writeUB(1, preloadRootFlag ? 1 : 0); sos.writeUB(1, suppressSuperFlag ? 1 : 0); sos.writeUB(1, preloadSuperFlag ? 1 : 0); sos.writeUB(1, suppressArgumentsFlag ? 1 : 0); sos.writeUB(1, preloadArgumentsFlag ? 1 : 0); sos.writeUB(1, suppressThisFlag ? 1 : 0); sos.writeUB(1, preloadThisFlag ? 1 : 0); sos.writeUB(7, 0); sos.writeUB(1, preloadGlobalFlag ? 1 : 0); for (int i = 0; i < paramNames.size(); i++) { sos.writeUI8(paramRegisters.get(i)); sos.writeString(paramNames.get(i)); } //byte[] codeBytes = Action.actionsToBytes(code, false, version); sos.writeUI16(codeSize);//codeBytes.length); sos.close(); baos2.write(surroundWithAction(baos.toByteArray(), version)); //baos2.write(codeBytes); } catch (IOException e) { } return baos2.toByteArray(); } private long getPreLen(int version) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); SWFOutputStream sos = new SWFOutputStream(baos, version); try { sos.writeString(functionName); sos.writeUI16(paramNames.size()); sos.writeUI8(registerCount); sos.writeUB(1, preloadParentFlag ? 1 : 0); sos.writeUB(1, preloadRootFlag ? 1 : 0); sos.writeUB(1, suppressSuperFlag ? 1 : 0); sos.writeUB(1, preloadSuperFlag ? 1 : 0); sos.writeUB(1, suppressArgumentsFlag ? 1 : 0); sos.writeUB(1, preloadArgumentsFlag ? 1 : 0); sos.writeUB(1, suppressThisFlag ? 1 : 0); sos.writeUB(1, preloadThisFlag ? 1 : 0); sos.writeUB(7, 0); sos.writeUB(1, preloadGlobalFlag ? 1 : 0); for (int i = 0; i < paramNames.size(); i++) { sos.writeUI8(paramRegisters.get(i)); sos.writeString(paramNames.get(i)); } sos.writeUI16(0); sos.close(); } catch (IOException e) { } return surroundWithAction(baos.toByteArray(), version).length; } @Override public GraphTextWriter getASMSourceReplaced(List container, List knownAddreses, List constantPool, ScriptExportMode exportMode, GraphTextWriter writer) { List oldParamNames = paramNames; if (replacedParamNames != null) { paramNames = replacedParamNames; } String oldFunctionName = functionName; if (replacedFunctionName != null) { functionName = replacedFunctionName; } String ret = getASMSource(container, knownAddreses, constantPool, exportMode); paramNames = oldParamNames; functionName = oldFunctionName; writer.appendNoHilight(ret); return writer; } @Override public String getASMSource(List container, List knownAddreses, List constantPool, ScriptExportMode exportMode) { StringBuilder paramStr = new StringBuilder(); for (int i = 0; i < paramNames.size(); i++) { paramStr.append(paramRegisters.get(i)).append(" \"").append(Helper.escapeString(paramNames.get(i))).append("\" "); } return ("DefineFunction2 \"" + Helper.escapeString(functionName) + "\" " + paramRegisters.size() + " " + registerCount + " " + preloadParentFlag + " " + preloadRootFlag + " " + suppressSuperFlag + " " + preloadSuperFlag + " " + suppressArgumentsFlag + " " + preloadArgumentsFlag + " " + suppressThisFlag + " " + preloadThisFlag + " " + preloadGlobalFlag).trim() + " " + paramStr + " {" + (codeSize == 0 ? "\r\n}" : "");// + "\r\n" + Action.actionsToString(getAddress() + getHeaderLength(), getItems(container), knownAddreses, constantPool, version, hex, getFileAddress() + hdrSize) + "}"; } @Override public String toString() { return "DefineFunction2"; } public int getFirstRegister() { int pos = 1; if (preloadThisFlag) { pos++; } if (preloadArgumentsFlag) { pos++; } if (preloadSuperFlag) { pos++; } if (preloadRootFlag) { pos++; } if (preloadParentFlag) { pos++; } if (preloadGlobalFlag) { pos++; } return pos; } @Override public void translate(Stack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { } @Override public HashMap getRegNames() { HashMap funcRegNames = new HashMap<>(); for (int f = 0; f < paramNames.size(); f++) { int reg = paramRegisters.get(f); if (reg != 0) { funcRegNames.put(reg, paramNames.get(f)); } } int pos = 1; if (preloadThisFlag) { funcRegNames.put(pos, "this"); pos++; } if (preloadArgumentsFlag) { funcRegNames.put(pos, "arguments"); pos++; } if (preloadSuperFlag) { funcRegNames.put(pos, "super"); pos++; } if (preloadRootFlag) { funcRegNames.put(pos, "_root"); pos++; } if (preloadParentFlag) { funcRegNames.put(pos, "_parent"); pos++; } if (preloadGlobalFlag) { funcRegNames.put(pos, "_global"); pos++; } return funcRegNames; } @Override public void translateContainer(List> content, Stack stack, List output, HashMap regNames, HashMap variables, HashMap functions) { FunctionActionItem fti = new FunctionActionItem(this, functionName, paramNames, content.get(0), constantPool, getFirstRegister(), new ArrayList()); functions.put(functionName, fti); stack.push(fti); } @Override public List getContainerSizes() { List ret = new ArrayList<>(); ret.add((Long) (long) codeSize); return ret; } @Override public void setContainerSize(int index, long size) { if (index == 0) { codeSize = (int) size; } else { throw new IllegalArgumentException("Index must be 0."); } } @Override public boolean parseDivision(long size, FlasmLexer lexer) { codeSize = (int) (size - getHeaderSize()); return false; } @Override public String getASMSourceBetween(int pos) { return ""; } @Override public String getName() { return "function"; } }