AS3 direct editation

This commit is contained in:
Jindra Petk
2014-04-19 16:52:01 +02:00
parent 7460114d10
commit 1fa9e0e547
10 changed files with 238 additions and 30 deletions

View File

@@ -46,7 +46,7 @@ public abstract class AVM2Item extends GraphTargetItem {
}
protected GraphTextWriter formatProperty(GraphTextWriter writer, GraphTargetItem object, GraphTargetItem propertyName, LocalData localData) throws InterruptedException {
boolean empty = false;
boolean empty = object instanceof FindPropertyAVM2Item;
if (object instanceof LocalRegAVM2Item) {
if (((LocalRegAVM2Item) object).computedValue != null) {
if (((LocalRegAVM2Item) object).computedValue.getThroughNotCompilable() instanceof FindPropertyAVM2Item) {
@@ -55,6 +55,13 @@ public abstract class AVM2Item extends GraphTargetItem {
}
}
if(object instanceof FindPropertyAVM2Item){
FindPropertyAVM2Item fp=(FindPropertyAVM2Item)object;
if(fp.propertyName instanceof FullMultinameAVM2Item){
propertyName = fp.propertyName;
}
}
if (!empty) {
if (object.getPrecedence() > PRECEDENCE_PRIMARY) {
writer.append("(");
@@ -70,7 +77,7 @@ public abstract class AVM2Item extends GraphTargetItem {
}
}
if (empty) {
if (empty) {
return propertyName.toString(writer, localData);
}
if (propertyName instanceof FullMultinameAVM2Item) {

View File

@@ -2017,6 +2017,7 @@ public class ActionScriptParser {
if (s.type != SymbolType.CURLY_OPEN) {
expected(s, lexer.yyline(), SymbolType.IDENTIFIER);
name = s.value.toString();
s = lex();
}
while (s.type != SymbolType.CURLY_OPEN) {
expected(s, lexer.yyline(), SymbolType.DOT);
@@ -2097,7 +2098,6 @@ public class ActionScriptParser {
}
public PackageAVM2Item packageFromString(String str, String fileName) throws ParseException, IOException, CompilationException {
this.constantPool = constantPool;
lexer = new ActionScriptLexer(new StringReader(str));
PackageAVM2Item ret = parsePackage(fileName);
@@ -2132,6 +2132,20 @@ public class ActionScriptParser {
this.otherABCs = otherABCs;
}
public static void compile(String src, ABC abc, boolean documentClass,String fileName) throws ParseException, IOException, InterruptedException, CompilationException {
SWC swc = new SWC(new FileInputStream(Configuration.getPlayerSWC()));
SWF swf = new SWF(swc.getSWF("library.swf"), true);
List<ABC> playerABCs = new ArrayList<>();
for (Tag t : swf.tags) {
if (t instanceof ABCContainerTag) {
playerABCs.add(((ABCContainerTag) t).getABC());
}
}
ActionScriptParser parser = new ActionScriptParser(abc, playerABCs);
parser.addScript(src, documentClass, fileName);
}
public static void compile(String src, String dst) {
System.err.println("WARNING: AS3 compiler is not finished yet. This is only used for debuggging!");
try {

View File

@@ -96,7 +96,11 @@ public abstract class Trait implements Serializable {
}
}
if (isStatic) {
ret += " static";
if((this instanceof TraitSlotConst)&&((TraitSlotConst)this).isNamespace()){
//static is automatic
}else{
ret += " static";
}
}
if ((kindFlags & ATTR_Final) > 0) {
if (!isStatic) {

View File

@@ -74,11 +74,11 @@ public class TraitClass extends Trait implements TraitWithSlot {
name = "*";
}
String newimport = ns.getName(abc.constants);
if ((ns.kind != Namespace.KIND_PACKAGE)
/*if ((ns.kind != Namespace.KIND_PACKAGE)
&& (ns.kind != Namespace.KIND_NAMESPACE)
&& (ns.kind != Namespace.KIND_STATIC_PROTECTED)) {
return false;
}
}*/
/*if (ns.kind == Namespace.KIND_NAMESPACE)*/ {
String oldimport = newimport;
newimport = null;
@@ -118,7 +118,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
if (ns.kind == Namespace.KIND_PACKAGE) {
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
if(!pkg.equals("__AS3__.vec")){ //Automatic import
imports.add(newimport);
}
}
}
if (ns.kind == Namespace.KIND_NAMESPACE) {
@@ -159,6 +161,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
if (!imports.contains(newimport)) {
String pkg = newimport.substring(0, newimport.lastIndexOf('.'));
if(pkg.equals("__AS3__.vec")){ //special case - is imported always
return;
}
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
}

View File

@@ -595,32 +595,42 @@ public class Configuration {
return ret;
}
public static File getPlayerSWC() {
public static File getFlashLibPath() {
try {
String home = getFFDecHome();
File libsdir = new File(home + "flashlib");
if (libsdir.exists()) {
File libs[] = libsdir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().startsWith("playerglobal");
}
});
List<String> libnames = new ArrayList<>();
for (File f : libs) {
libnames.add(f.getName());
}
Collections.sort(libnames);
if (!libnames.isEmpty()) {
return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1));
} else {
return null;
}
if (!libsdir.exists()) {
libsdir.mkdirs();
}
return libsdir;
} catch (IOException ex) {
return null;
}
}
public static File getPlayerSWC() {
File libsdir = getFlashLibPath();
if (libsdir!=null && libsdir.exists()) {
File libs[] = libsdir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().startsWith("playerglobal");
}
});
List<String> libnames = new ArrayList<>();
for (File f : libs) {
libnames.add(f.getName());
}
Collections.sort(libnames);
if (!libnames.isEmpty()) {
return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1));
} else {
return null;
}
}
return null;
}
}

View File

@@ -26,6 +26,8 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal0Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
import com.jpexs.decompiler.flash.abc.avm2.parser.ParseException;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScriptParser;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
@@ -55,7 +57,10 @@ import com.jpexs.decompiler.flash.gui.abc.tablemodels.UIntTableModel;
import com.jpexs.decompiler.flash.helpers.Freed;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.SymbolClassTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.treenodes.TreeNode;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
@@ -71,6 +76,9 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -90,6 +98,7 @@ import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
@@ -123,6 +132,15 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
private NewTraitDialog newTraitDialog;
public JLabel scriptNameLabel;
static final String ACTION_SAVE_DECOMPILED = "SAVEDECOMPILED";
static final String ACTION_EDIT_DECOMPILED = "EDITDECOMPILED";
static final String ACTION_CANCEL_DECOMPILED = "CANCELDECOMPILED";
public JLabel experimentalLabel = new JLabel(AppStrings.translate("action.edit.experimental"));
public JButton editDecompiledButton = new JButton(AppStrings.translate("button.edit"), View.getIcon("edit16"));
public JButton saveDecompiledButton = new JButton(AppStrings.translate("button.save"), View.getIcon("save16"));
public JButton cancelDecompiledButton = new JButton(AppStrings.translate("button.cancel"), View.getIcon("cancel16"));
static final String ACTION_ADD_TRAIT = "ADDTRAIT";
public boolean search(String txt, boolean ignoreCase, boolean regexp) {
@@ -361,10 +379,34 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
iconDecPanel.add(scriptNameLabel);
iconDecPanel.add(iconsPanel);
iconDecPanel.add(decompiledScrollPane);
JPanel decButtonsPan = new JPanel(new FlowLayout());
decButtonsPan.setBorder(new BevelBorder(BevelBorder.RAISED));
decButtonsPan.add(editDecompiledButton);
decButtonsPan.add(experimentalLabel);
decButtonsPan.add(saveDecompiledButton);
decButtonsPan.add(cancelDecompiledButton);
editDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
saveDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
cancelDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
saveDecompiledButton.addActionListener(this);
saveDecompiledButton.setActionCommand(ACTION_SAVE_DECOMPILED);
editDecompiledButton.addActionListener(this);
editDecompiledButton.setActionCommand(ACTION_EDIT_DECOMPILED);
cancelDecompiledButton.addActionListener(this);
cancelDecompiledButton.setActionCommand(ACTION_CANCEL_DECOMPILED);
saveDecompiledButton.setVisible(false);
cancelDecompiledButton.setVisible(false);
decButtonsPan.setAlignmentX(0);
JPanel decPanel = new JPanel(new BorderLayout());
decPanel.add(searchPanel, BorderLayout.NORTH);
decPanel.add(iconDecPanel, BorderLayout.CENTER);
decPanel.add(decButtonsPan, BorderLayout.SOUTH);
detailPanel = new DetailPanel(this);
JPanel panB = new JPanel();
panB.setLayout(new BorderLayout());
@@ -380,7 +422,9 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
Configuration.guiAvm2SplitPaneDividerLocation.set((int) pce.getNewValue());
if(!directEditing){
Configuration.guiAvm2SplitPaneDividerLocation.set((int) pce.getNewValue());
}
}
});
decompiledTextArea.setContentType("text/actionscript");
@@ -543,9 +587,124 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
searchPanel.showQuickFindDialog(decompiledTextArea);
}
public String lastDecompiled = null;
public boolean directEditing = false;
private int detWidth = 0;
private int detsp = 0;
public void setDecompiledEditMode(boolean val) {
if (val) {
lastDecompiled = decompiledTextArea.getText();
decompiledTextArea.setEditable(true);
saveDecompiledButton.setVisible(true);
editDecompiledButton.setVisible(false);
experimentalLabel.setVisible(false);
cancelDecompiledButton.setVisible(true);
decompiledTextArea.getCaret().setVisible(true);
decLabel.setIcon(View.getIcon("editing16"));
directEditing = true;
detWidth = detailPanel.getWidth();
detsp = splitPane.getDividerLocation();
detailPanel.setVisible(false);
} else {
decompiledTextArea.setText(lastDecompiled);
decompiledTextArea.setEditable(false);
saveDecompiledButton.setVisible(false);
editDecompiledButton.setVisible(true);
experimentalLabel.setVisible(true);
cancelDecompiledButton.setVisible(false);
decompiledTextArea.getCaret().setVisible(true);
decLabel.setIcon(null);
directEditing = false;
detailPanel.setVisible(true);
detailPanel.setSize(detailPanel.getHeight(), detWidth);
splitPane.setDividerLocation(detsp);
}
decompiledTextArea.ignoreCarret = directEditing;
decompiledTextArea.requestFocusInWindow();
}
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case ACTION_EDIT_DECOMPILED:
File swc = Configuration.getPlayerSWC();
final String adobePage = "http://www.adobe.com/support/flashplayer/downloads.html";
if(swc == null){
if(View.showConfirmDialog(this, AppStrings.translate("message.action.playerglobal.needed").replace("%adobehomepage%",adobePage),AppStrings.translate("message.action.playerglobal.title"),JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE)==JOptionPane.OK_OPTION){
java.awt.Desktop desktop = null;
if (java.awt.Desktop.isDesktopSupported()) {
desktop = java.awt.Desktop.getDesktop();
if (desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
try {
java.net.URI uri = new java.net.URI(adobePage);
desktop.browse(uri);
} catch (URISyntaxException | IOException ex) {
}
} else {
desktop = null;
}
}
int ret = 0;
do{
ret = View.showConfirmDialog(this, AppStrings.translate("message.action.playerglobal.place").replace("%libpath%", Configuration.getFlashLibPath().getAbsolutePath()),AppStrings.translate("message.action.playerglobal.title"),JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
swc = Configuration.getPlayerSWC();
}while(ret == JOptionPane.OK_OPTION && swc == null);
if(ret == JOptionPane.OK_OPTION){
setDecompiledEditMode(true);
}
}
}else{
setDecompiledEditMode(true);
}
break;
case ACTION_CANCEL_DECOMPILED:
setDecompiledEditMode(false);
break;
case ACTION_SAVE_DECOMPILED:
ScriptPack pack = decompiledTextArea.getScriptLeaf();
String scriptName = pack.getPathScriptName()+".as";
int oldIndex = pack.scriptIndex;
int newIndex = abc.script_info.size();
String documentClass = "";
loopt:for (Tag t : swf.tags) {
if (t instanceof SymbolClassTag) {
SymbolClassTag sc = (SymbolClassTag) t;
for (int i = 0; i < sc.tags.length; i++) {
if (sc.tags[i] == 0) {
documentClass = sc.names[i];
break loopt;
}
}
}
}
boolean isDocumentClass = documentClass.equals(pack.getPath().toString());
try {
ActionScriptParser.compile(decompiledTextArea.getText(), abc,isDocumentClass, scriptName);
//Move newly added script to its position
abc.script_info.set(oldIndex, abc.script_info.get(newIndex));
abc.script_info.remove(newIndex);
((Tag)abc.parentTag).setModified(true);
lastDecompiled = decompiledTextArea.getText();
decompiledTextArea.setClassIndex(-1);
View.showMessageDialog(this, AppStrings.translate("message.action.saved"));
setDecompiledEditMode(false);
reload();
} catch (ParseException ex) {
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
decompiledTextArea.gotoLine((int)ex.line);
} catch (CompilationException ex) {
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
decompiledTextArea.gotoLine((int)ex.line);
} catch (IOException|InterruptedException ex) {
//ignore
}
break;
case ACTION_ADD_TRAIT:
int class_index = decompiledTextArea.getClassIndex();
if (class_index < 0) {

View File

@@ -54,7 +54,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL
private ABC abc;
private ScriptPack script;
public int lastTraitIndex = 0;
private boolean ignoreCarret = false;
public boolean ignoreCarret = false;
private boolean reset = false;
private final ABCPanel abcPanel;
private int classIndex = -1;

View File

@@ -739,6 +739,7 @@ public class ActionPanel extends JPanel implements ActionListener, SearchListene
} catch (IOException ex) {
} catch (ParseException ex) {
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
editor.gotoLine((int)ex.line);
}
break;
case ACTION_EDIT_DECOMPILED:

View File

@@ -464,3 +464,7 @@ error.sound.invalid = Invalid sound.
button.prev = Previous
button.next = Next
message.action.playerglobal.title = PlayerGlobal library needed
message.action.playerglobal.needed = For ActionScript 3 direct editation, a library called "PlayerGlobal.swc" needs to be downloaded from Adobe homepage.\r\n%adobehomepage%\r\nPress OK to go to the download page.
message.action.playerglobal.place = Download the library called PlayerGlobal(.swc), and place it to directory\r\n%libpath%\r\n Press OK to continue.

View File

@@ -459,4 +459,8 @@ filter.sounds = Podporovan\u00e9 zvukov\u00e9 form\u00e1ty (*.wav, *.mp3)
filter.sounds.wav = Wave form\u00e1t (*.wav)
filter.sounds.mp3 = MP3 komprimovan\u00fd form\u00e1t (*.mp3)
error.sound.invalid = Neplatn\u00fd zvuk.
error.sound.invalid = Neplatn\u00fd zvuk.
message.action.playerglobal.title = Vy\u017eadov\u00e1na knihovna PlayerGlobal
message.action.playerglobal.needed = Pro p\u0159\u00edmou editaci ActionScriptu 3 je pot\u0159eba knihovna "PlayerGlobal.swc", kterou lze stahnout ze str\u00e1nek Adobe\r\n%adobehomepage%\r\nStiskn\u011bte OK pro p\u0159echod na stahovac\u00ed str\u00e1nku.
message.action.playerglobal.place = St\u00e1hn\u011bte knihovnu nazvanou PlayerGlobal(.swc), a um\u00edst\u011bte j\u00ed do adres\u00e1\u0159e\r\n%libpath%\r\n Stiskn\u011bte OK pro pokra\u010dov\u00e1n\u00ed.