/* * Copyright (C) 2010-2016 JPEXS, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ package com.jpexs.decompiler.flash.abc.avm2.parser.script; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NanAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.decompiler.graph.model.UnboundedTypeItem; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * * @author JPEXS */ public class NameAVM2Item extends AssignableAVM2Item { private String variableName; private boolean definition; private int nsKind = -1; public List<NamespaceItem> openedNamespaces; public int line; public GraphTargetItem type; private GraphTargetItem ns = null; private int regNumber = -1; public boolean unresolved = false; private int slotNumber = -1; private int slotScope = 0; public GraphTargetItem redirect; @Override public AssignableAVM2Item copy() { NameAVM2Item c = new NameAVM2Item(type, line, variableName, assignedValue, definition, openedNamespaces); c.setNs(ns); c.regNumber = regNumber; c.unresolved = unresolved; c.nsKind = nsKind; return c; } public void setSlotScope(int slotScope) { this.slotScope = slotScope; } public int getSlotScope() { return slotScope; } public void setNs(GraphTargetItem ns) { this.ns = ns; } public void setRegNumber(int regNumber) { this.regNumber = regNumber; } public int getSlotNumber() { return slotNumber; } public void setSlotNumber(int slotNumber) { this.slotNumber = slotNumber; } public int getRegNumber() { return regNumber; } public GraphTargetItem getNs() { return ns; } public void appendName(String name) { this.variableName += "." + name; } public void setDefinition(boolean definition) { this.definition = definition; } public void setNsKind(int nsKind) { this.nsKind = nsKind; } public int getNsKind() { return nsKind; } public String getVariableName() { return variableName; } public NameAVM2Item(GraphTargetItem type, int line, String variableName, GraphTargetItem storeValue, boolean definition, List<NamespaceItem> openedNamespaces) { super(storeValue); this.variableName = variableName; this.assignedValue = storeValue; this.definition = definition; this.line = line; this.type = type; this.openedNamespaces = openedNamespaces; } public boolean isDefinition() { return definition; } public GraphTargetItem getStoreValue() { return assignedValue; } @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { return writer; } public static GraphTargetItem getDefaultValue(String type) { switch (type) { case "*": return new UndefinedAVM2Item(null, null); case "int": return new IntegerValueAVM2Item(null, null, 0L); case "Number": return new NanAVM2Item(null, null); default: return new NullAVM2Item(null, null); } } public static AVM2Instruction generateCoerce(SourceGeneratorLocalData localData, SourceGenerator generator, GraphTargetItem ttype) throws CompilationException { if (ttype instanceof UnresolvedAVM2Item) { ttype = ((UnresolvedAVM2Item) ttype).resolved; } AVM2Instruction ins; if (ttype instanceof UnboundedTypeItem) { ins = ins(AVM2Instructions.CoerceA); } else { switch (ttype.toString()) { case "int": ins = ins(AVM2Instructions.ConvertI); break; case "*": ins = ins(AVM2Instructions.CoerceA); break; case "String": ins = ins(AVM2Instructions.CoerceS); break; case "Boolean": ins = ins(AVM2Instructions.ConvertB); break; case "uint": ins = ins(AVM2Instructions.ConvertU); break; default: int type_index = AVM2SourceGenerator.resolveType(localData, ttype, ((AVM2SourceGenerator) generator).abcIndex); ins = ins(AVM2Instructions.Coerce, type_index); break; } } return ins; } private List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator, boolean needsReturn) throws CompilationException { if (variableName != null && regNumber == -1 && slotNumber == -1 && ns == null) { throw new CompilationException("No register or slot set for " + variableName, line); } if (definition && assignedValue == null) { return new ArrayList<>(); } String name = variableName; boolean attr = false; if (name != null && name.startsWith("@")) { //name = name.substring(1); attr = true; } AVM2SourceGenerator g = (AVM2SourceGenerator) generator; Reference<Integer> ns_temp = new Reference<>(-1); Reference<Integer> index_temp = new Reference<>(-1); Reference<Integer> ret_temp = new Reference<>(-1); if (assignedValue != null) { List<String> basicTypes = Arrays.asList("int", "Number"); if (slotNumber > -1) { return toSourceMerge(localData, generator, ins(AVM2Instructions.GetScopeObject, slotScope), assignedValue, !(("" + assignedValue.returnType()).equals("" + type) && (basicTypes.contains("" + type))) ? generateCoerce(localData, generator, type) : null, needsReturn ? dupSetTemp(localData, generator, ret_temp) : null, generateSetLoc(regNumber), slotNumber > -1 ? ins(AVM2Instructions.SetSlot, slotNumber) : null, needsReturn ? getTemp(localData, generator, ret_temp) : null, killTemp(localData, generator, Arrays.asList(ret_temp))); } else { return toSourceMerge(localData, generator, assignedValue, !(("" + assignedValue.returnType()).equals("" + type) && (basicTypes.contains("" + type))) ? generateCoerce(localData, generator, type) : null, needsReturn ? ins(AVM2Instructions.Dup) : null, generateSetLoc(regNumber)); } } else { return toSourceMerge(localData, generator, generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), needsReturn ? null : ins(AVM2Instructions.Pop)); } } @Override public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { if (redirect != null) { return redirect.toSource(localData, generator); } return toSource(localData, generator, true); } @Override public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { if (redirect != null) { return redirect.toSourceIgnoreReturnValue(localData, generator); } return toSource(localData, generator, false); } @Override public boolean hasReturnValue() { return !definition; } @Override public boolean needsSemicolon() { return definition; } @Override public String toString() { return variableName; } @Override public GraphTargetItem returnType() { if (type == null) { return TypeItem.UNBOUNDED; } return type; } @Override public List<GraphSourceItem> toSourceChange(SourceGeneratorLocalData localData, SourceGenerator generator, boolean post, boolean decrement, boolean needsReturn) throws CompilationException { if (redirect != null) { return ((AssignableAVM2Item) redirect).toSourceChange(localData, generator, post, decrement, needsReturn); } AVM2SourceGenerator g = (AVM2SourceGenerator) generator; Reference<Integer> ns_temp = new Reference<>(-1); Reference<Integer> name_temp = new Reference<>(-1); Reference<Integer> index_temp = new Reference<>(-1); Reference<Integer> ret_temp = new Reference<>(-1); boolean isInteger = returnType().toString().equals("int"); /* */ if (!needsReturn) { if (slotNumber > -1) { return toSourceMerge(localData, generator, ins(AVM2Instructions.GetScopeObject, slotScope), generateGetSlot(slotScope, slotNumber), (decrement ? ins(isInteger ? AVM2Instructions.DecrementI : AVM2Instructions.Decrement) : ins(isInteger ? AVM2Instructions.IncrementI : AVM2Instructions.Increment)), ins(AVM2Instructions.SetSlot, slotNumber) ); } else { return toSourceMerge(localData, generator, (decrement ? ins(isInteger ? AVM2Instructions.DecLocalI : AVM2Instructions.DecLocal, regNumber) : ins(isInteger ? AVM2Instructions.IncLocalI : AVM2Instructions.IncLocal, regNumber))); } } return toSourceMerge(localData, generator, slotNumber > -1 ? ins(AVM2Instructions.GetScopeObject, slotScope) : null, //Start get original generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), //End get original //!isInteger ? ins(AVM2Instructions.ConvertD) : null, //End get original (!post) ? (decrement ? ins(isInteger ? AVM2Instructions.DecrementI : AVM2Instructions.Decrement) : ins(isInteger ? AVM2Instructions.IncrementI : AVM2Instructions.Increment)) : null, needsReturn ? ins(AVM2Instructions.Dup) : null, (post) ? (decrement ? ins(isInteger ? AVM2Instructions.DecrementI : AVM2Instructions.Decrement) : ins(isInteger ? AVM2Instructions.IncrementI : AVM2Instructions.Increment)) : null, generateCoerce(localData, generator, returnType()), generateSetLoc(regNumber), slotNumber > -1 ? ins(AVM2Instructions.SetSlot, slotNumber) : null ); } }