Added #2260 GFX - Configure path resolving dialog for file paths that use prefixes like data:

This commit is contained in:
Jindra Petřík
2024-07-31 21:06:20 +02:00
parent 5654497a52
commit 45199d043f
10 changed files with 219 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ All notable changes to this project will be documented in this file.
- [PR194] Support for XDG base directory specification (env variable `XDG_CONFIG_HOME`)
- FLA export - ImportAssets/2 tag support
- FLA export - export in frame 1 flag support
- [#2260] GFX - Configure path resolving dialog for file paths that use prefixes like `data:`
### Fixed
- Debugger - getting children of top level variables

View File

@@ -29,4 +29,5 @@ public class CustomConfigurationKeys {
public static final String KEY_LOADED_IMPORT_ASSETS = "loadedImportAssets";
public static final String KEY_ABC_DEPENDENCIES = "abcDependencies";
public static final String KEY_BREAKPOINTS = "breakpoints";
public static final String KEY_PATH_RESOLVING = "pathResolving";
}

View File

@@ -17,6 +17,9 @@
package com.jpexs.decompiler.flash.tags.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
import com.jpexs.decompiler.flash.gfx.TgaSupport;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.gfx.enums.FileFormatType;
@@ -24,6 +27,7 @@ import com.jpexs.helpers.ByteArrayRange;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
@@ -47,9 +51,50 @@ public abstract class AbstractGfxImageTag extends ImageTag {
}
protected BufferedImage getExternalBufferedImage(String fileName, int bitmapFormat) {
Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName));
Path imagePath = null;
try {
imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName));
} catch (InvalidPathException ip) {
//ignore
}
if (imagePath == null || !imagePath.toFile().exists()) {
return null;
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(getSwf().getShortPathTitle());
if (cc == null) {
return null;
}
String paths = cc.getCustomData(CustomConfigurationKeys.KEY_PATH_RESOLVING, "");
if (paths.trim().isEmpty()) {
return null;
}
String[] rows = paths.trim().split("\r\n");
boolean found = false;
for (String row : rows) {
String prefix = "";
String searchPath;
if (row.contains("|")) {
prefix = row.substring(0, row.indexOf("|"));
searchPath = row.substring(row.indexOf("|") + 1);
} else {
searchPath = row;
}
String fileNameNoPrefix = fileName;
if (!prefix.isEmpty() && fileName.startsWith(prefix)) {
fileNameNoPrefix = fileName.substring(prefix.length());
}
if (!searchPath.isEmpty()) {
Path newImagePath = Paths.get(searchPath).resolve(fileNameNoPrefix);
if (newImagePath.toFile().exists()) {
found = true;
imagePath = newImagePath;
break;
}
}
}
if (!found) {
return null;
}
}
byte[] imageData;

View File

@@ -172,7 +172,7 @@ public class DefineExternalImage extends AbstractGfxImageTag {
if (shortFormat) {
//Just guessing how this may work...
return exportName + "." + FileFormatType.fileFormatExtension(bitmapFormat);
}
}
return fileName;
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2010-2024 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* @author JPEXS
*/
public class PathResolvingDialog extends AppDialog {
private final JEditorPane editor;
private final JButton okButton = new JButton(translate("button.ok"));
private final JButton cancelButton = new JButton(translate("button.cancel"));
private int result = ERROR_OPTION;
private final SWF swf;
public PathResolvingDialog(SWF swf, Window owner) {
super(owner);
setTitle(translate("dialog.title"));
setDefaultCloseOperation(HIDE_ON_CLOSE);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
cnt.add(new JLabel("<html>" + translate("info") + "</html>"), BorderLayout.NORTH);
editor = new JEditorPane();
cnt.add(new JScrollPane(editor), BorderLayout.CENTER);
editor.setContentType("text/plain");
okButton.addActionListener(this::okButtonActionPerformed);
cancelButton.addActionListener(this::cancelButtonActionPerformed);
JPanel buttonsPanel = new JPanel(new FlowLayout());
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(swf.getShortPathTitle());
String pathResolving = "";
if (cc != null) {
pathResolving = cc.getCustomData(CustomConfigurationKeys.KEY_PATH_RESOLVING, "");
}
editor.setText(pathResolving);
setSize(800, 600);
View.centerScreen(this);
View.setWindowIcon(this);
getRootPane().setDefaultButton(okButton);
setModal(true);
this.swf = swf;
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
SwfSpecificCustomConfiguration cc = Configuration.getOrCreateSwfSpecificCustomConfiguration(swf.getShortPathTitle());
String txt = editor.getText();
txt = txt.replace("\r\n", "\n");
txt = txt.replace("\n", "\r\n");
cc.setCustomData(CustomConfigurationKeys.KEY_PATH_RESOLVING, txt);
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public int showDialog() {
setVisible(true);
return result;
}
}

View File

@@ -1269,4 +1269,6 @@ warning.cleanAbc = This action will remove items from ABC which have zero usages
Some kinds of obfuscated SWFs could be damaged this way.\r\n\
Use it at your own risk. Do you want to continue?
tagInfo.idType = Type of the id
tagInfo.idType = Type of the id
contextmenu.configurePathResolving = Configure path resolving...

View File

@@ -1244,4 +1244,6 @@ warning.cleanAbc = Tato akce odstran\u00ed z ABC polo\u017eky, kter\u00e9 maj\u0
N\u011bkter\u00e9 druhy obfuskovan\u00fdch SWF to m\u016f\u017ee po\u0161kodit.\r\n\
Pou\u017e\u00edvejte ji na vlastn\u00ed riziko. Chcete pokra\u010dovat?
tagInfo.idType = Typ id
tagInfo.idType = Typ id
contextmenu.configurePathResolving = Nastavit resolvov\u00e1n\u00ed cest...

View File

@@ -0,0 +1,22 @@
# Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
dialog.title = Path resolving
info = Set directories where assets will be searched when not found in SWFs path.\r\n\
You can use pipe "|" to separate prefix that the path must have, like "data:|C:\\MyData\\Dir"\
when you have paths starting with "data:" prefix.\r\nOne path per line. This is currently used only in GFX tags.
button.ok = OK
button.cancel = Cancel

View File

@@ -0,0 +1,22 @@
# Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
dialog.title = Resolvov\u00e1n\u00ed cest
info = Nastav\u00ed slo\u017eky kde budou hled\u00e1ny assety, kter\u00e9 se nepoda\u0159\u00ed nal\u00e9zt v cest\u011b SWF.\r\n\
M\u016f\u017eete pou\u017e\u00edt rouru "|" pro odd\u011blen\u00ed p\u0159edpony, kterou cesta mus\u00ed m\u00edt jako "data:|C:\\MyData\\Dir"\
pokud chcete m\u00edt cesty za\u010d\u00ednaj\u00edc\u00ed p\u0159edponou "data:". Co cesta to jeden \u0159\u00e1dek. Toto se moment\u00e1ln\u011b pou\u017e\u00edv\u00e1 jen v GFX taz\u00edch.
button.ok = OK
button.cancel = Storno

View File

@@ -40,6 +40,7 @@ import com.jpexs.decompiler.flash.gui.ClipboardType;
import com.jpexs.decompiler.flash.gui.CollectDepthAsSpritesDialog;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.PathResolvingDialog;
import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
import com.jpexs.decompiler.flash.gui.SelectFramePositionDialog;
import com.jpexs.decompiler.flash.gui.SelectTagPositionDialog;
@@ -171,6 +172,8 @@ public class TagTreeContextMenu extends JPopupMenu {
private final MainPanel mainPanel;
private JMenuItem configurePathResolvingMenuItem;
private JMenuItem setClassToCharacterMappingMenuItem;
private JMenuItem expandRecursiveMenuItem;
@@ -368,6 +371,12 @@ public class TagTreeContextMenu extends JPopupMenu {
}
add(changeCharsetMenu);
configurePathResolvingMenuItem = new JMenuItem(mainPanel.translate("contextmenu.configurePathResolving"));
configurePathResolvingMenuItem.addActionListener(this::configurePathResolvingActionPerformed);
configurePathResolvingMenuItem.setIcon(View.getIcon("settings16"));
add(configurePathResolvingMenuItem);
removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove") + " (DEL)");
removeMenuItem.addActionListener((ActionEvent e) -> {
removeItemActionPerformed(e, false);
@@ -1125,6 +1134,7 @@ public class TagTreeContextMenu extends JPopupMenu {
unpinAllMenuItem.setVisible(false);
unpinOthersMenuItem.setVisible(false);
configurePathResolvingMenuItem.setVisible(false);
removeMenuItem.setVisible(canRemove);
removeWithDependenciesMenuItem.setVisible(canRemove && !allDoNotHaveDependencies);
cloneMenuItem.setVisible(allSelectedIsTagOrFrame && allSelectedSameParent);
@@ -1404,6 +1414,9 @@ public class TagTreeContextMenu extends JPopupMenu {
abcExplorerMenuItem.setVisible(true);
cleanAbcMenuItem.setVisible(true);
}
if (swf.gfx) {
configurePathResolvingMenuItem.setVisible(true);
}
}
if (firstItem instanceof Tag) {
@@ -5315,6 +5328,13 @@ public class TagTreeContextMenu extends JPopupMenu {
mainPanel.repaintTree();
}
public void configurePathResolvingActionPerformed(ActionEvent evt) {
SWF item = (SWF) getCurrentItem();
PathResolvingDialog dialog = new PathResolvingDialog(item, Main.getDefaultDialogsOwner());
dialog.showDialog();
}
public void changeCharsetActionPerformed(ActionEvent evt) {
SWF item = (SWF) getCurrentItem();
String newCharset = ((JMenuItem) evt.getSource()).getText();