From b65244c618d3cd3479c04bd8d05e3301e987c96e Mon Sep 17 00:00:00 2001 From: honfika Date: Fri, 15 Aug 2014 13:49:31 +0200 Subject: [PATCH] allow to save data range in dumpview to file (e.g. for exporting ABC data) --- .../flash/action/ActionListReader.java | 30 +- .../decompiler/flash/dumpview/DumpInfo.java | 14 + .../flash/gui/LoadFromCacheFrame.java | 581 +++++++++--------- .../flash/gui/LoadFromMemoryFrame.java | 3 +- src/com/jpexs/decompiler/flash/gui/Main.java | 3 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 3 +- .../flash/gui/dumpview/DumpTree.java | 42 ++ .../flash/gui/dumpview/DumpViewPanel.java | 18 +- .../flash/gui/locales/MainFrame.properties | 2 + .../flash/gui/locales/MainFrame_hu.properties | 2 + 10 files changed, 362 insertions(+), 336 deletions(-) diff --git a/src/com/jpexs/decompiler/flash/action/ActionListReader.java b/src/com/jpexs/decompiler/flash/action/ActionListReader.java index 1a59d1067..a86beb86e 100644 --- a/src/com/jpexs/decompiler/flash/action/ActionListReader.java +++ b/src/com/jpexs/decompiler/flash/action/ActionListReader.java @@ -152,11 +152,11 @@ public class ActionListReader { } // remove nulls - index = getNextAddress(addresses, index); + index = getNearAddress(addresses, index, true); while (index > -1) { Action action = actionMap.get(index); long nextOffset = nextOffsets.get(index); - long nextIndex = getNextAddress(addresses, index + 1); + long nextIndex = getNearAddress(addresses, index + 1, true); actions.add(action); if (nextIndex != -1 && nextOffset != nextIndex) { if (!action.isExit() && !(action instanceof ActionJump)) { @@ -280,7 +280,7 @@ public class ActionListReader { return reta; } - private static long getNextAddress(List addresses, long address) { + private static long getNearAddress(List addresses, long address, boolean next) { int min = 0; int max = addresses.size() - 1; @@ -295,25 +295,9 @@ public class ActionListReader { max = mid - 1; } - return min < addresses.size() ? addresses.get(min) : -1; - } - - private static long getPrevAddress(List addresses, long address) { - int min = 0; - int max = addresses.size() - 1; - - while (max >= min) { - int mid = (min + max) / 2; - long midValue = addresses.get(mid); - if(midValue == address) - return address; - else if (midValue < address) - min = mid + 1; - else - max = mid - 1; - } - - return max > 0 ? addresses.get(max) : -1; + return next + ? (min < addresses.size() ? addresses.get(min) : -1) + : (max > 0 ? addresses.get(max) : -1); } private static Map actionListToMap(List actions) { @@ -371,7 +355,7 @@ public class ActionListReader { List lasts = new ArrayList<>(sizes.size()); for (long size : sizes) { endAddress += size; - long lastActionIndex = getPrevAddress(addresses, endAddress - 1); + long lastActionIndex = getNearAddress(addresses, endAddress - 1, false); Action lastAction = null; if (lastActionIndex != -1) { lastAction = actionMap.get(lastActionIndex); diff --git a/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java b/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java index 77ab2caf5..eb8ac775e 100644 --- a/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java +++ b/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java @@ -75,6 +75,20 @@ public class DumpInfo { return childInfos; } + public long getEndByte() { + int end = (int) startByte; + if (lengthBytes != 0) { + end += lengthBytes; + } else { + int bits = startBit + lengthBits; + end += bits / 8; + if (bits % 8 != 0) { + end++; + } + } + return end - 1; + } + @Override public String toString() { String value = previewValue == null ? "" : previewValue.toString(); diff --git a/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java b/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java index 7c8c87440..797e09829 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java @@ -1,291 +1,290 @@ -/* - * 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.gui; - -import com.jpexs.browsers.cache.CacheEntry; -import com.jpexs.browsers.cache.CacheImplementation; -import com.jpexs.browsers.cache.CacheReader; -import com.jpexs.decompiler.flash.AppStrings; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.ReReadableInputStream; -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.FlowLayout; -import java.awt.Image; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JProgressBar; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.SwingWorker; -import javax.swing.filechooser.FileFilter; - -/** - * - * @author JPEXS - */ -public class LoadFromCacheFrame extends AppFrame implements ActionListener { - - static final String ACTION_OPEN = "OPEN"; - static final String ACTION_SAVE = "SAVE"; - static final String ACTION_REFRESH = "REFRESH"; - - private final JList list; - private final JTextField searchField; - private List caches; - private List entries; - private final JProgressBar progressBar; - JButton saveButton; - JButton refreshButton; - JButton openButton; - - public LoadFromCacheFrame() { - setSize(900, 600); - View.setWindowIcon(this); - View.centerScreen(this); - setTitle(translate("dialog.title")); - setDefaultCloseOperation(HIDE_ON_CLOSE); - Container cnt = getContentPane(); - list = new JList<>(); - list.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() > 1) { - openSWF(); - } - } - }); - searchField = new JTextField(); - searchField.addKeyListener(new KeyListener() { - @Override - public void keyTyped(KeyEvent e) { - filter(); - } - - @Override - public void keyPressed(KeyEvent e) { - } - - @Override - public void keyReleased(KeyEvent e) { - } - }); - cnt.setLayout(new BorderLayout()); - cnt.add(searchField, BorderLayout.NORTH); - cnt.add(new JScrollPane(list), BorderLayout.CENTER); - - JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); - - JPanel buttonsPanel = new JPanel(new FlowLayout()); - - openButton = new JButton(translate("button.open")); - openButton.setActionCommand(ACTION_OPEN); - openButton.addActionListener(this); - buttonsPanel.add(openButton); - - saveButton = new JButton(translate("button.save")); - saveButton.setActionCommand(ACTION_SAVE); - saveButton.addActionListener(this); - buttonsPanel.add(saveButton); - - refreshButton = new JButton(translate("button.refresh")); - refreshButton.setActionCommand(ACTION_REFRESH); - refreshButton.addActionListener(this); - buttonsPanel.add(refreshButton); - - JPanel browsersPanel = new JPanel(new FlowLayout()); - browsersPanel.add(new JLabel(translate("supported.browsers"))); - JLabel chromeLabel = new JLabel("Google Chrome", View.getIcon("chrome16"), JLabel.CENTER); - JLabel firefoxLabel = new JLabel("Mozilla Firefox*", View.getIcon("firefox16"), JLabel.CENTER); - browsersPanel.add(chromeLabel); - browsersPanel.add(firefoxLabel); - buttonsPanel.setAlignmentX(0.5f); - - progressBar = new JProgressBar(); - progressBar.setAlignmentX(0.5f); - progressBar.setIndeterminate(true); - bottomPanel.add(progressBar); - bottomPanel.add(buttonsPanel); - browsersPanel.setAlignmentX(0.5f); - bottomPanel.add(browsersPanel); - JLabel infoLabel = new JLabel(translate("info.closed")); - infoLabel.setAlignmentX(0.5f); - bottomPanel.add(infoLabel); - cnt.add(bottomPanel, BorderLayout.SOUTH); - progressBar.setVisible(false); - openButton.setEnabled(false); - saveButton.setEnabled(false); - - java.util.List images = new ArrayList<>(); - images.add(View.loadImage("loadcache16")); - images.add(View.loadImage("loadcache32")); - setIconImages(images); - refresh(); - } - - private void refresh() { - progressBar.setVisible(true); - openButton.setEnabled(false); - saveButton.setEnabled(false); - refreshButton.setEnabled(false); - new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - if (caches == null) { - caches = new ArrayList<>(); - for (String b : CacheReader.availableBrowsers()) { - caches.add(CacheReader.getBrowserCache(b)); - } - } else { - for (CacheImplementation c : caches) { - c.refresh(); - } - } - entries = new ArrayList<>(); - for (CacheImplementation c : caches) { - List list = c.getEntries(); - if (list != null) { - for (CacheEntry en : c.getEntries()) { - String contentType = en.getHeader("Content-Type"); - if ("application/x-shockwave-flash".equals(contentType)) { - entries.add(en); - } - } - } - } - filter(); - - return null; - } - - @Override - protected void done() { - openButton.setEnabled(true); - saveButton.setEnabled(true); - refreshButton.setEnabled(true); - progressBar.setVisible(false); - } - }.execute(); - - } - - private void filter() { - String search = searchField.getText(); - List filtered = new ArrayList<>(); - for (CacheEntry en : entries) { - if (search.isEmpty() || en.getRequestURL().contains(search)) { - filtered.add(en); - } - } - list.setListData(new Vector<>(filtered)); - } - - private static String entryToFileName(CacheEntry en) { - String ret = en.getRequestURL(); - //Strip parameters - if (ret.contains("?")) { - ret = ret.substring(0, ret.indexOf('?')); - } - //Strip path - if (ret.contains("/")) { - ret = ret.substring(ret.lastIndexOf('/') + 1); - } - return ret; - } - - private void openSWF() { - CacheEntry en = list.getSelectedValue(); - if (en != null) { - ReReadableInputStream str = new ReReadableInputStream(en.getResponseDataStream()); - SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, entryToFileName(en)); - Main.openFile(sourceInfo); - } - } - - @Override - public void actionPerformed(ActionEvent e) { - switch (e.getActionCommand()) { - case ACTION_REFRESH: - refresh(); - break; - case ACTION_OPEN: - openSWF(); - break; - case ACTION_SAVE: - List selected = list.getSelectedValuesList(); - if (!selected.isEmpty()) { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); - if (selected.size() > 1) { - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - } else { - fc.setSelectedFile(new File(Configuration.lastSaveDir.get(), entryToFileName(selected.get(0)))); - fc.setFileFilter(new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }); - } - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showSaveDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = Helper.fixDialogFile(fc.getSelectedFile()); - try { - if (selected.size() == 1) { - Helper.saveStream(selected.get(0).getResponseDataStream(), file); - } else { - for (CacheEntry sel : selected) { - Helper.saveStream(sel.getResponseDataStream(), new File(file, entryToFileName(sel))); - } - } - Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); - } catch (IOException ex) { - View.showMessageDialog(null, translate("error.file.write")); - } - } - } - break; - } - } -} +/* + * 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.gui; + +import com.jpexs.browsers.cache.CacheEntry; +import com.jpexs.browsers.cache.CacheImplementation; +import com.jpexs.browsers.cache.CacheReader; +import com.jpexs.decompiler.flash.AppStrings; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.ReReadableInputStream; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.SwingWorker; +import javax.swing.filechooser.FileFilter; + +/** + * + * @author JPEXS + */ +public class LoadFromCacheFrame extends AppFrame implements ActionListener { + + static final String ACTION_OPEN = "OPEN"; + static final String ACTION_SAVE = "SAVE"; + static final String ACTION_REFRESH = "REFRESH"; + + private final JList list; + private final JTextField searchField; + private List caches; + private List entries; + private final JProgressBar progressBar; + JButton saveButton; + JButton refreshButton; + JButton openButton; + + public LoadFromCacheFrame() { + setSize(900, 600); + View.setWindowIcon(this); + View.centerScreen(this); + setTitle(translate("dialog.title")); + setDefaultCloseOperation(HIDE_ON_CLOSE); + Container cnt = getContentPane(); + list = new JList<>(); + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + openSWF(); + } + } + }); + searchField = new JTextField(); + searchField.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + filter(); + } + + @Override + public void keyPressed(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + } + }); + cnt.setLayout(new BorderLayout()); + cnt.add(searchField, BorderLayout.NORTH); + cnt.add(new JScrollPane(list), BorderLayout.CENTER); + + JPanel bottomPanel = new JPanel(); + bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + + openButton = new JButton(translate("button.open")); + openButton.setActionCommand(ACTION_OPEN); + openButton.addActionListener(this); + buttonsPanel.add(openButton); + + saveButton = new JButton(translate("button.save")); + saveButton.setActionCommand(ACTION_SAVE); + saveButton.addActionListener(this); + buttonsPanel.add(saveButton); + + refreshButton = new JButton(translate("button.refresh")); + refreshButton.setActionCommand(ACTION_REFRESH); + refreshButton.addActionListener(this); + buttonsPanel.add(refreshButton); + + JPanel browsersPanel = new JPanel(new FlowLayout()); + browsersPanel.add(new JLabel(translate("supported.browsers"))); + JLabel chromeLabel = new JLabel("Google Chrome", View.getIcon("chrome16"), JLabel.CENTER); + JLabel firefoxLabel = new JLabel("Mozilla Firefox*", View.getIcon("firefox16"), JLabel.CENTER); + browsersPanel.add(chromeLabel); + browsersPanel.add(firefoxLabel); + buttonsPanel.setAlignmentX(0.5f); + + progressBar = new JProgressBar(); + progressBar.setAlignmentX(0.5f); + progressBar.setIndeterminate(true); + bottomPanel.add(progressBar); + bottomPanel.add(buttonsPanel); + browsersPanel.setAlignmentX(0.5f); + bottomPanel.add(browsersPanel); + JLabel infoLabel = new JLabel(translate("info.closed")); + infoLabel.setAlignmentX(0.5f); + bottomPanel.add(infoLabel); + cnt.add(bottomPanel, BorderLayout.SOUTH); + progressBar.setVisible(false); + openButton.setEnabled(false); + saveButton.setEnabled(false); + + java.util.List images = new ArrayList<>(); + images.add(View.loadImage("loadcache16")); + images.add(View.loadImage("loadcache32")); + setIconImages(images); + refresh(); + } + + private void refresh() { + progressBar.setVisible(true); + openButton.setEnabled(false); + saveButton.setEnabled(false); + refreshButton.setEnabled(false); + new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + if (caches == null) { + caches = new ArrayList<>(); + for (String b : CacheReader.availableBrowsers()) { + caches.add(CacheReader.getBrowserCache(b)); + } + } else { + for (CacheImplementation c : caches) { + c.refresh(); + } + } + entries = new ArrayList<>(); + for (CacheImplementation c : caches) { + List list = c.getEntries(); + if (list != null) { + for (CacheEntry en : c.getEntries()) { + String contentType = en.getHeader("Content-Type"); + if ("application/x-shockwave-flash".equals(contentType)) { + entries.add(en); + } + } + } + } + filter(); + + return null; + } + + @Override + protected void done() { + openButton.setEnabled(true); + saveButton.setEnabled(true); + refreshButton.setEnabled(true); + progressBar.setVisible(false); + } + }.execute(); + + } + + private void filter() { + String search = searchField.getText(); + List filtered = new ArrayList<>(); + for (CacheEntry en : entries) { + if (search.isEmpty() || en.getRequestURL().contains(search)) { + filtered.add(en); + } + } + list.setListData(new Vector<>(filtered)); + } + + private static String entryToFileName(CacheEntry en) { + String ret = en.getRequestURL(); + //Strip parameters + if (ret.contains("?")) { + ret = ret.substring(0, ret.indexOf('?')); + } + //Strip path + if (ret.contains("/")) { + ret = ret.substring(ret.lastIndexOf('/') + 1); + } + return ret; + } + + private void openSWF() { + CacheEntry en = list.getSelectedValue(); + if (en != null) { + ReReadableInputStream str = new ReReadableInputStream(en.getResponseDataStream()); + SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, entryToFileName(en)); + Main.openFile(sourceInfo); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + switch (e.getActionCommand()) { + case ACTION_REFRESH: + refresh(); + break; + case ACTION_OPEN: + openSWF(); + break; + case ACTION_SAVE: + List selected = list.getSelectedValuesList(); + if (!selected.isEmpty()) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); + if (selected.size() > 1) { + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } else { + fc.setSelectedFile(new File(Configuration.lastSaveDir.get(), entryToFileName(selected.get(0)))); + fc.setFileFilter(new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }); + } + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { + File file = Helper.fixDialogFile(fc.getSelectedFile()); + try { + if (selected.size() == 1) { + Helper.saveStream(selected.get(0).getResponseDataStream(), file); + } else { + for (CacheEntry sel : selected) { + Helper.saveStream(sel.getResponseDataStream(), new File(file, entryToFileName(sel))); + } + } + Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); + } catch (IOException ex) { + View.showMessageDialog(null, translate("error.file.write")); + } + } + } + break; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java index bac8c0ba8..d44826f13 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java @@ -434,8 +434,7 @@ public class LoadFromMemoryFrame extends AppFrame implements ActionListener { fc.setAcceptAllFileFilterUsed(false); JFrame f = new JFrame(); View.setWindowIcon(f); - int returnVal = fc.showSaveDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { File file = Helper.fixDialogFile(fc.getSelectedFile()); try { if (selected.length == 1) { diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 5af9610df..fde069389 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -584,8 +584,7 @@ public class Main { fc.setAcceptAllFileFilterUsed(false); JFrame f = new JFrame(); View.setWindowIcon(f); - int returnVal = fc.showSaveDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { File file = Helper.fixDialogFile(fc.getSelectedFile()); FileFilter selFilter = fc.getFileFilter(); try { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index ef2e1cebb..4e211dc94 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1414,8 +1414,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec fc.setAcceptAllFileFilterUsed(false); JFrame f = new JFrame(); View.setWindowIcon(f); - int returnVal = fc.showSaveDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); File sf = Helper.fixDialogFile(fc.getSelectedFile()); diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java index d68e2da32..3913d923c 100644 --- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java +++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui.dumpview; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; import com.jpexs.decompiler.flash.gui.Main; @@ -29,7 +30,15 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTree; @@ -48,6 +57,7 @@ public class DumpTree extends JTree implements ActionListener { private static final String ACTION_CLOSE_SWF = "CLOSESWF"; private static final String ACTION_EXPAND_RECURSIVE = "EXPANDRECURSIVE"; + private static final String ACTION_SAVE_TO_FILE = "SAVETOFILE"; private final MainPanel mainPanel; @@ -100,6 +110,11 @@ public class DumpTree extends JTree implements ActionListener { expandRecursiveMenuItem.setActionCommand(ACTION_EXPAND_RECURSIVE); contextPopupMenu.add(expandRecursiveMenuItem); + final JMenuItem saveToFileMenuItem = new JMenuItem(mainPanel.translate("contextmenu.saveToFile")); + saveToFileMenuItem.addActionListener(this); + saveToFileMenuItem.setActionCommand(ACTION_SAVE_TO_FILE); + contextPopupMenu.add(saveToFileMenuItem); + final JMenuItem closeSelectionMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf")); closeSelectionMenuItem.setActionCommand(ACTION_CLOSE_SWF); closeSelectionMenuItem.addActionListener(this); @@ -122,6 +137,7 @@ public class DumpTree extends JTree implements ActionListener { } closeSelectionMenuItem.setVisible(false); expandRecursiveMenuItem.setVisible(false); + saveToFileMenuItem.setVisible(false); if (paths.length == 1) { DumpInfo treeNode = (DumpInfo) paths[0].getLastPathComponent(); @@ -129,6 +145,10 @@ public class DumpTree extends JTree implements ActionListener { if (treeNode instanceof DumpInfoSwfNode) { closeSelectionMenuItem.setVisible(true); } + + if (treeNode.getEndByte() - treeNode.startByte > 3) { + saveToFileMenuItem.setVisible(true); + } TreeModel model = getModel(); expandRecursiveMenuItem.setVisible(model.getChildCount(treeNode) > 0); @@ -151,6 +171,28 @@ public class DumpTree extends JTree implements ActionListener { View.expandTreeNodesRecursive(this, path, true); } break; + case ACTION_SAVE_TO_FILE: { + TreePath[] paths = getSelectionPaths(); + DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent(); + JFileChooser fc = new JFileChooser(); + String selDir = Configuration.lastOpenDir.get(); + fc.setCurrentDirectory(new File(selDir)); + if (!selDir.endsWith(File.separator)) { + selDir += File.separator; + } + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { + File sf = Helper.fixDialogFile(fc.getSelectedFile()); + try (FileOutputStream fos = new FileOutputStream(sf)) { + byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().uncompressedData; + fos.write(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1)); + } catch (IOException ex) { + Logger.getLogger(DumpTree.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + break; case ACTION_CLOSE_SWF: { Main.closeFile(mainPanel.getCurrentSwfList()); } diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java index 4b5d32c92..76f4b57aa 100644 --- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java @@ -46,20 +46,6 @@ public class DumpViewPanel extends JPanel { add(new JScrollPane(dumpViewHexTable), BorderLayout.CENTER); } - private int getEndIndex(DumpInfo dumpInfo) { - int end = (int) dumpInfo.startByte; - if (dumpInfo.lengthBytes != 0) { - end += dumpInfo.lengthBytes; - } else { - int bits = dumpInfo.startBit + dumpInfo.lengthBits; - end += bits / 8; - if (bits % 8 != 0) { - end++; - } - } - return end - 1; - } - public void setData(byte[] data, DumpInfo dumpInfo) { List dumpInfos = new ArrayList<>(); DumpInfo di = dumpInfo; @@ -72,13 +58,13 @@ public class DumpViewPanel extends JPanel { for (int i = 0; i < dumpInfos.size(); i++) { DumpInfo di2 = dumpInfos.get(highlightStarts.length - i - 1); highlightStarts[i] = di2.startByte; - highlightEnds[i] = getEndIndex(di2); + highlightEnds[i] = di2.getEndByte(); } dumpViewHexTable.setData(data, highlightStarts, highlightEnds); if (dumpInfo.lengthBytes != 0 || dumpInfo.lengthBits != 0) { int selectionStart = (int) dumpInfo.startByte; - int selectionEnd = getEndIndex(dumpInfo); + int selectionEnd = (int) dumpInfo.getEndByte(); dumpViewHexTable.scrollToByte(highlightStarts, highlightEnds); diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index c6c46cd7a..d88cf6bdf 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -508,3 +508,5 @@ header.framecount = Frame count: header.displayrect = Display rect: header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels + +contextmenu.saveToFile = Save to File diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties index 41c9bab03..0169867f8 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties @@ -508,3 +508,5 @@ header.framecount = Keret sz\u00e1m: header.displayrect = Megjelen\u00edt\u00e9si t\u00e9glalap: header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twip header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% k\u00e9ppont + +contextmenu.saveToFile = Ment\u00e9s f\u00e1jlba