diff --git a/src/com/jpexs/decompiler/flash/SWFInputStream.java b/src/com/jpexs/decompiler/flash/SWFInputStream.java index 2441d76ea..6e2d173cc 100644 --- a/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -383,7 +383,7 @@ public class SWFInputStream implements AutoCloseable { } DumpInfo di = new DumpInfo(name, type, null, startByte, bitPos, 0, 0); di.parent = dumpInfo; - dumpInfo.childInfos.add(di); + dumpInfo.getChildInfos().add(di); dumpInfo = di; } } diff --git a/src/com/jpexs/decompiler/flash/SWFSearch.java b/src/com/jpexs/decompiler/flash/SWFSearch.java index 9d3c32fa0..37db1180b 100644 --- a/src/com/jpexs/decompiler/flash/SWFSearch.java +++ b/src/com/jpexs/decompiler/flash/SWFSearch.java @@ -1,151 +1,152 @@ -/* - * Copyright (C) 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; - -import com.jpexs.helpers.MemoryInputStream; -import com.jpexs.helpers.PosMarkedInputStream; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.Searchable; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class SWFSearch { - - protected Searchable s; - private final boolean noCheck; - private final SearchMode searchMode; - private boolean processed = false; - private final Set listeners = new HashSet<>(); - private final Map swfStreams = new HashMap<>(); - - public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) { - this.s = s; - this.noCheck = noCheck; - this.searchMode = searchMode; - } - - public void addProgressListener(ProgressListener l) { - listeners.add(l); - } - - public void removeProgressListener(ProgressListener l) { - listeners.remove(l); - } - - private void setProgress(int p) { - for (ProgressListener l : listeners) { - l.progress(p); - } - } - - public void process() { - Map ret = new HashMap<>(); - ret = s.search(new ProgressListener() { - @Override - public void progress(int p) { - setProgress(p); - } - }, - "FWS".getBytes(), //Uncompressed Flash - "CWS".getBytes(), //ZLib compressed Flash - "ZWS".getBytes(), //LZMA compressed Flash - "GFX".getBytes(), //Uncompressed ScaleForm GFx - "CFX".getBytes()); //Compressed ScaleForm GFx - int pos = 0; - long biggestSize = 0; - long smallestSize = Long.MAX_VALUE; - addressLoop: - for (Long addr : ret.keySet()) { - setProgress(pos * 100 / ret.size()); - pos++; - try { - MemoryInputStream mis = (MemoryInputStream) ret.get(addr); - mis.reset(); - PosMarkedInputStream pmi = new PosMarkedInputStream(mis); - SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, false, true); - boolean valid = swf.fileSize > 0 - && swf.version > 0 - && (!swf.tags.isEmpty() || noCheck) - && swf.version < 25; // Needs to be fixed when SWF versions reaches this value - if (valid) { - long limit = pmi.getPos(); - MemoryInputStream is = new MemoryInputStream(mis.getAllRead(), (int) (long) addr, (int) limit); - switch (searchMode) { - case ALL: - swfStreams.put(addr, is); - break; - case BIGGEST: - if (limit > biggestSize) { - biggestSize = limit; - swfStreams.clear(); - swfStreams.put(addr, is); - } - break; - case SMALLEST: - if (limit < smallestSize) { - smallestSize = limit; - swfStreams.clear(); - swfStreams.put(addr, is); - } - break; - case FIRST: - swfStreams.put(addr, is); - break addressLoop; - case LAST: - swfStreams.clear(); - swfStreams.put(addr, is); - break; - } - } - } catch (OutOfMemoryError ome) { - System.gc(); - } catch (Exception | Error ex) { - } - } - setProgress(100); - processed = true; - } - - public MemoryInputStream get(ProgressListener listener, long address) throws IOException { - if (!processed) { - return null; - } - if (!swfStreams.containsKey(address)) { - return null; - } - return swfStreams.get(address); - } - - public Set getAddresses() { - return swfStreams.keySet(); - } - - public int length() { - if (!processed) { - return 0; - } - return swfStreams.size(); - } -} +/* + * Copyright (C) 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; + +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.MemoryInputStream; +import com.jpexs.helpers.PosMarkedInputStream; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.Searchable; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class SWFSearch { + + protected Searchable s; + private final boolean noCheck; + private final SearchMode searchMode; + private boolean processed = false; + private final Set listeners = new HashSet<>(); + private final Map swfStreams = new HashMap<>(); + + public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) { + this.s = s; + this.noCheck = noCheck; + this.searchMode = searchMode; + } + + public void addProgressListener(ProgressListener l) { + listeners.add(l); + } + + public void removeProgressListener(ProgressListener l) { + listeners.remove(l); + } + + private void setProgress(int p) { + for (ProgressListener l : listeners) { + l.progress(p); + } + } + + public void process() { + Map ret = new HashMap<>(); + ret = s.search(new ProgressListener() { + @Override + public void progress(int p) { + setProgress(p); + } + }, + "FWS".getBytes(), //Uncompressed Flash + "CWS".getBytes(), //ZLib compressed Flash + "ZWS".getBytes(), //LZMA compressed Flash + "GFX".getBytes(), //Uncompressed ScaleForm GFx + "CFX".getBytes()); //Compressed ScaleForm GFx + int pos = 0; + long biggestSize = 0; + long smallestSize = Long.MAX_VALUE; + addressLoop: + for (Long addr : ret.keySet()) { + setProgress(pos * 100 / ret.size()); + pos++; + try { + MemoryInputStream mis = (MemoryInputStream) ret.get(addr); + mis.reset(); + PosMarkedInputStream pmi = new PosMarkedInputStream(mis); + SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, false, true); + boolean valid = swf.fileSize > 0 + && swf.version > 0 + && (!swf.tags.isEmpty() || noCheck) + && swf.version < 25; // Needs to be fixed when SWF versions reaches this value + if (valid) { + long limit = pmi.getPos(); + MemoryInputStream is = new MemoryInputStream(mis.getAllRead(), (int) (long) addr, (int) limit); + switch (searchMode) { + case ALL: + swfStreams.put(addr, is); + break; + case BIGGEST: + if (limit > biggestSize) { + biggestSize = limit; + swfStreams.clear(); + swfStreams.put(addr, is); + } + break; + case SMALLEST: + if (limit < smallestSize) { + smallestSize = limit; + swfStreams.clear(); + swfStreams.put(addr, is); + } + break; + case FIRST: + swfStreams.put(addr, is); + break addressLoop; + case LAST: + swfStreams.clear(); + swfStreams.put(addr, is); + break; + } + } + } catch (OutOfMemoryError ome) { + Helper.freeMem(); + } catch (Exception | Error ex) { + } + } + setProgress(100); + processed = true; + } + + public MemoryInputStream get(ProgressListener listener, long address) throws IOException { + if (!processed) { + return null; + } + if (!swfStreams.containsKey(address)) { + return null; + } + return swfStreams.get(address); + } + + public Set getAddresses() { + return swfStreams.keySet(); + } + + public int length() { + if (!processed) { + return 0; + } + return swfStreams.size(); + } +} diff --git a/src/com/jpexs/decompiler/flash/action/Action.java b/src/com/jpexs/decompiler/flash/action/Action.java index 2b733dafe..de1305fba 100644 --- a/src/com/jpexs/decompiler/flash/action/Action.java +++ b/src/com/jpexs/decompiler/flash/action/Action.java @@ -900,7 +900,7 @@ public class Action implements GraphSourceItem { } catch (OutOfMemoryError | TranslateException | StackOverflowError ex2) { Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error in: " + path, ex2); if (ex2 instanceof OutOfMemoryError) { - System.gc(); + Helper.freeMem(); } out = new ArrayList<>(); out.add(new CommentItem(new String[]{ diff --git a/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java b/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java index 3313db2d2..a339fceb1 100644 --- a/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java +++ b/src/com/jpexs/decompiler/flash/dumpview/DumpInfo.java @@ -40,7 +40,7 @@ public class DumpInfo { public DumpInfo parent; - public List childInfos = new ArrayList<>(); + private List childInfos; public DumpInfo(String name, String type, Object value, long startByte, long lengthBytes) { @@ -62,6 +62,13 @@ public class DumpInfo { this.lengthBits = lengthBits; } + public List getChildInfos() { + if (childInfos == null) { + childInfos = new ArrayList<>(); + } + return childInfos; + } + @Override public String toString() { String value = previewValue == null ? "" : previewValue.toString(); diff --git a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java index 1db9cc0b5..bac8c0ba8 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java @@ -1,463 +1,463 @@ -/* - * 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.decompiler.flash.AppStrings; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.LimitedInputStream; -import com.jpexs.helpers.PosMarkedInputStream; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.ReReadableInputStream; -import com.jpexs.process.ProcessTools; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -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.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.BoxLayout; -import javax.swing.DefaultListCellRenderer; -import javax.swing.DefaultListModel; -import javax.swing.ImageIcon; -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.JSplitPane; -import javax.swing.JTable; -import javax.swing.SwingWorker; -import javax.swing.SwingWorker.StateValue; -import javax.swing.filechooser.FileFilter; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableRowSorter; - -/** - * - * @author petrik - */ -public class LoadFromMemoryFrame extends AppFrame implements ActionListener { - - static final String ACTION_SELECT_PROCESS = "SELECTPROCESS"; - static final String ACTION_REFRESH_PROCESS_LIST = "REFRESHPROCESSLIST"; - static final String ACTION_OPEN_SWF = "OPENSWF"; - static final String ACTION_SAVE = "SAVE"; - - private MainFrame mainFrame; - private List processlist; - private List foundIs; - private List selProcesses; - private JList list; - private DefaultListModel model; - private DefaultTableModel resTableModel; - private final JTable tableRes; - private final JLabel stateLabel; - private boolean processing = false; - private final JProgressBar progress; - - private class SelectProcessWorker extends SwingWorker, Object> { - - private final List procs; - - public SelectProcessWorker(List procs) { - this.procs = procs; - } - - @Override - protected void process(List chunks) { - for (Object s : chunks) { - if (s instanceof com.jpexs.process.Process) { - stateLabel.setText(s.toString()); - } - if (s instanceof SwfInMemory) { - SwfInMemory swf = (SwfInMemory) s; - addResultRow(swf); - } - } - } - - @Override - protected List doInBackground() throws Exception { - Map ret = new HashMap<>(); - List swfStreams = new ArrayList<>(); - for (com.jpexs.process.Process proc : procs) { - publish(proc); - ret = proc.search(new ProgressListener() { - @Override - public void progress(int p) { - setProgress(p); - } - }, "CWS".getBytes(), "FWS".getBytes(), "ZWS".getBytes()); - int pos = 0; - for (Long addr : ret.keySet()) { - setProgress(pos * 100 / ret.size()); - pos++; - try { - PosMarkedInputStream pmi = new PosMarkedInputStream(ret.get(addr)); - ReReadableInputStream is = new ReReadableInputStream(pmi); - SWF swf = new SWF(is, null, false, true); - long limit = pmi.getPos(); - is.seek(0); - is = new ReReadableInputStream(new LimitedInputStream(is, limit)); - if (swf.fileSize > 0 && swf.version > 0 && !swf.tags.isEmpty() && swf.version < 25/*Needs to be fixed when SWF versions reaches this value*/) { - SwfInMemory s = new SwfInMemory(is, swf.version, swf.fileSize, proc); - String p = translate("swfitem").replace("%version%", "" + swf.version).replace("%size%", "" + swf.fileSize); - publish(s); - swfStreams.add(s); - } - - } catch (OutOfMemoryError ome) { - System.gc(); - } catch (Exception | Error ex) { - } - - } - setProgress(100); - } - if (swfStreams.isEmpty()) { - return null; - } - return swfStreams; - } - } - - private void addResultRow(SwfInMemory swf) { - if (swf != null) { - com.jpexs.process.Process process = swf.process; - resTableModel.addRow(new Object[]{swf.version, swf.fileSize, process.getPid(), process.getFileName()}); - } else { - String notFound = translate("notfound"); - resTableModel.addRow(new Object[]{notFound, 0, "", ""}); - } - } - - private void refreshList() { - model.clear(); - processlist = ProcessTools.listProcesses(); - Collections.sort(processlist); - for (com.jpexs.process.Process p : processlist) { - model.addElement(p); - } - } - - private void openSWF() { - if (foundIs == null) { - return; - } - int index = tableRes.getRowSorter().convertRowIndexToModel(tableRes.getSelectedRow()); - if (index > -1) { - SwfInMemory swf = foundIs.get(index); - ReReadableInputStream str = swf.is; - try { - str.seek(0); - } catch (IOException ex) { - Logger.getLogger(LoadFromMemoryFrame.class.getName()).log(Level.SEVERE, null, ex); - return; - } - str.mark(Integer.MAX_VALUE); - SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, swf.process + " [" + (index + 1) + "]"); - Main.openFile(sourceInfo); - } - } - - private void selectProcess() { - if (processing) { - return; - } - selProcesses = list.getSelectedValuesList(); - if (!selProcesses.isEmpty()) { - processing = true; - tableRes.setEnabled(false); - resTableModel.getDataVector().removeAllElements(); - resTableModel.fireTableDataChanged(); - foundIs = null; - progress.setIndeterminate(true); - progress.setString(translate("searching")); - progress.setStringPainted(true); - progress.setVisible(true); - final SelectProcessWorker wrk = new SelectProcessWorker(selProcesses); - wrk.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - switch (evt.getPropertyName()) { - case "progress": - progress.setIndeterminate(false); - progress.setStringPainted(false); - progress.setValue((Integer) evt.getNewValue()); - break; - case "state": - if (((StateValue) evt.getNewValue()) == StateValue.DONE) { - try { - foundIs = wrk.get(); - } catch (InterruptedException | ExecutionException ex) { - Logger.getLogger(LoadFromMemoryFrame.class.getName()).log(Level.SEVERE, null, ex); - } - if (foundIs == null) { - addResultRow(null); - } - tableRes.setEnabled(foundIs != null); - progress.setVisible(false); - processing = false; - } - } - - } - }); - wrk.execute(); - } - } - - public LoadFromMemoryFrame(final MainFrame mainFrame) { - setSize(800, 600); - //setAlwaysOnTop(true); - setTitle(translate("dialog.title")); - - this.mainFrame = mainFrame; - - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - if (!mainFrame.isVisible()) { - mainFrame.setVisible(true); - } - } - }); - model = new DefaultListModel<>(); - - resTableModel = new DefaultTableModel() { - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case 0: - return Integer.class; - case 1: - return Integer.class; - case 2: - return String.class; - case 3: - return String.class; - } - return null; - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - }; - resTableModel.addColumn(translate("column.version")); - resTableModel.addColumn(translate("column.fileSize")); - resTableModel.addColumn(translate("column.pid")); - resTableModel.addColumn(translate("column.processName")); - tableRes = new JTable(resTableModel); - TableRowSorter sorter = new TableRowSorter<>(resTableModel); - tableRes.setRowSorter(sorter); - list = new JList<>(model); - list.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == 10) { //Enter pressed - selectProcess(); - } - } - }); - list.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() > 1) { - selectProcess(); - } - } - }); - tableRes.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() > 1) { - openSWF(); - } - } - }); - tableRes.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == 10) { //Enter pressed - openSWF(); - } - } - }); - list.setCellRenderer(new DefaultListCellRenderer() { - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - - JLabel label = (JLabel) super.getListCellRendererComponent(list, - value, index, isSelected, cellHasFocus); - - if (value instanceof com.jpexs.process.Process) { - if (((com.jpexs.process.Process) value).getIcon() != null) { - label.setIcon(new ImageIcon(((com.jpexs.process.Process) value).getIcon())); - } - } - if (!isSelected) { - label.setBackground(Color.white); - } - return label; - } - }); - refreshList(); - Container cnt = getContentPane(); - cnt.setLayout(new BorderLayout()); - - JPanel leftPanel = new JPanel(new BorderLayout()); - leftPanel.add(new JScrollPane(list), BorderLayout.CENTER); - JPanel leftButtonsPanel = new JPanel(new FlowLayout()); - JButton selectButton = new JButton(translate("button.select")); - selectButton.setActionCommand(ACTION_SELECT_PROCESS); - selectButton.addActionListener(this); - JButton refreshButton = new JButton(translate("button.refresh")); - refreshButton.setActionCommand(ACTION_REFRESH_PROCESS_LIST); - refreshButton.addActionListener(this); - leftButtonsPanel.add(selectButton); - leftButtonsPanel.add(refreshButton); - leftPanel.add(leftButtonsPanel, BorderLayout.SOUTH); - - JPanel rightPanel = new JPanel(new BorderLayout()); - rightPanel.add(new JScrollPane(tableRes), BorderLayout.CENTER); - JPanel rightButtonsPanel = new JPanel(new FlowLayout()); - JButton openButton = new JButton(translate("button.open")); - openButton.setActionCommand(ACTION_OPEN_SWF); - openButton.addActionListener(this); - - JButton saveButton = new JButton(translate("button.save")); - saveButton.setActionCommand(ACTION_SAVE); - saveButton.addActionListener(this); - - rightButtonsPanel.add(openButton); - rightButtonsPanel.add(saveButton); - rightPanel.add(rightButtonsPanel, BorderLayout.SOUTH); - - JPanel statePanel = new JPanel(); - statePanel.setLayout(new BoxLayout(statePanel, BoxLayout.Y_AXIS)); - - stateLabel = new JLabel(translate("noprocess")); - statePanel.add(stateLabel); - progress = new JProgressBar(0, 100); - statePanel.add(progress); - progress.setVisible(false); - rightPanel.add(statePanel, BorderLayout.NORTH); - - cnt.add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel), BorderLayout.CENTER); - View.setWindowIcon(this); - View.centerScreen(this); - java.util.List images = new ArrayList<>(); - images.add(View.loadImage("loadmemory16")); - images.add(View.loadImage("loadmemory32")); - setIconImages(images); - } - - @Override - public void actionPerformed(ActionEvent e) { - switch (e.getActionCommand()) { - case ACTION_SELECT_PROCESS: - selectProcess(); - break; - case ACTION_OPEN_SWF: - openSWF(); - break; - case ACTION_REFRESH_PROCESS_LIST: - refreshList(); - break; - case ACTION_SAVE: - if (foundIs == null) { - return; - } - int[] selected = tableRes.getSelectedRows(); - if (selected.length > 0) { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); - if (selected.length > 1) { - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - } else { - fc.setSelectedFile(new File(Configuration.lastSaveDir.get(), "movie.swf")); - 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.length == 1) { - SwfInMemory swf = foundIs.get(tableRes.getRowSorter().convertRowIndexToModel(selected[0])); - ReReadableInputStream bis = swf.is; - bis.seek(0); - Helper.saveStream(bis, file); - } else { - for (int sel : selected) { - SwfInMemory swf = foundIs.get(tableRes.getRowSorter().convertRowIndexToModel(sel)); - ReReadableInputStream bis = swf.is; - bis.seek(0); - Helper.saveStream(bis, new File(file, "movie" + sel + ".swf")); - } - } - 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.decompiler.flash.AppStrings; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.LimitedInputStream; +import com.jpexs.helpers.PosMarkedInputStream; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.ReReadableInputStream; +import com.jpexs.process.ProcessTools; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +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.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.BoxLayout; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +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.JSplitPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.SwingWorker.StateValue; +import javax.swing.filechooser.FileFilter; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableRowSorter; + +/** + * + * @author petrik + */ +public class LoadFromMemoryFrame extends AppFrame implements ActionListener { + + static final String ACTION_SELECT_PROCESS = "SELECTPROCESS"; + static final String ACTION_REFRESH_PROCESS_LIST = "REFRESHPROCESSLIST"; + static final String ACTION_OPEN_SWF = "OPENSWF"; + static final String ACTION_SAVE = "SAVE"; + + private MainFrame mainFrame; + private List processlist; + private List foundIs; + private List selProcesses; + private JList list; + private DefaultListModel model; + private DefaultTableModel resTableModel; + private final JTable tableRes; + private final JLabel stateLabel; + private boolean processing = false; + private final JProgressBar progress; + + private class SelectProcessWorker extends SwingWorker, Object> { + + private final List procs; + + public SelectProcessWorker(List procs) { + this.procs = procs; + } + + @Override + protected void process(List chunks) { + for (Object s : chunks) { + if (s instanceof com.jpexs.process.Process) { + stateLabel.setText(s.toString()); + } + if (s instanceof SwfInMemory) { + SwfInMemory swf = (SwfInMemory) s; + addResultRow(swf); + } + } + } + + @Override + protected List doInBackground() throws Exception { + Map ret = new HashMap<>(); + List swfStreams = new ArrayList<>(); + for (com.jpexs.process.Process proc : procs) { + publish(proc); + ret = proc.search(new ProgressListener() { + @Override + public void progress(int p) { + setProgress(p); + } + }, "CWS".getBytes(), "FWS".getBytes(), "ZWS".getBytes()); + int pos = 0; + for (Long addr : ret.keySet()) { + setProgress(pos * 100 / ret.size()); + pos++; + try { + PosMarkedInputStream pmi = new PosMarkedInputStream(ret.get(addr)); + ReReadableInputStream is = new ReReadableInputStream(pmi); + SWF swf = new SWF(is, null, false, true); + long limit = pmi.getPos(); + is.seek(0); + is = new ReReadableInputStream(new LimitedInputStream(is, limit)); + if (swf.fileSize > 0 && swf.version > 0 && !swf.tags.isEmpty() && swf.version < 25/*Needs to be fixed when SWF versions reaches this value*/) { + SwfInMemory s = new SwfInMemory(is, swf.version, swf.fileSize, proc); + String p = translate("swfitem").replace("%version%", "" + swf.version).replace("%size%", "" + swf.fileSize); + publish(s); + swfStreams.add(s); + } + + } catch (OutOfMemoryError ome) { + Helper.freeMem(); + } catch (Exception | Error ex) { + } + + } + setProgress(100); + } + if (swfStreams.isEmpty()) { + return null; + } + return swfStreams; + } + } + + private void addResultRow(SwfInMemory swf) { + if (swf != null) { + com.jpexs.process.Process process = swf.process; + resTableModel.addRow(new Object[]{swf.version, swf.fileSize, process.getPid(), process.getFileName()}); + } else { + String notFound = translate("notfound"); + resTableModel.addRow(new Object[]{notFound, 0, "", ""}); + } + } + + private void refreshList() { + model.clear(); + processlist = ProcessTools.listProcesses(); + Collections.sort(processlist); + for (com.jpexs.process.Process p : processlist) { + model.addElement(p); + } + } + + private void openSWF() { + if (foundIs == null) { + return; + } + int index = tableRes.getRowSorter().convertRowIndexToModel(tableRes.getSelectedRow()); + if (index > -1) { + SwfInMemory swf = foundIs.get(index); + ReReadableInputStream str = swf.is; + try { + str.seek(0); + } catch (IOException ex) { + Logger.getLogger(LoadFromMemoryFrame.class.getName()).log(Level.SEVERE, null, ex); + return; + } + str.mark(Integer.MAX_VALUE); + SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, swf.process + " [" + (index + 1) + "]"); + Main.openFile(sourceInfo); + } + } + + private void selectProcess() { + if (processing) { + return; + } + selProcesses = list.getSelectedValuesList(); + if (!selProcesses.isEmpty()) { + processing = true; + tableRes.setEnabled(false); + resTableModel.getDataVector().removeAllElements(); + resTableModel.fireTableDataChanged(); + foundIs = null; + progress.setIndeterminate(true); + progress.setString(translate("searching")); + progress.setStringPainted(true); + progress.setVisible(true); + final SelectProcessWorker wrk = new SelectProcessWorker(selProcesses); + wrk.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + switch (evt.getPropertyName()) { + case "progress": + progress.setIndeterminate(false); + progress.setStringPainted(false); + progress.setValue((Integer) evt.getNewValue()); + break; + case "state": + if (((StateValue) evt.getNewValue()) == StateValue.DONE) { + try { + foundIs = wrk.get(); + } catch (InterruptedException | ExecutionException ex) { + Logger.getLogger(LoadFromMemoryFrame.class.getName()).log(Level.SEVERE, null, ex); + } + if (foundIs == null) { + addResultRow(null); + } + tableRes.setEnabled(foundIs != null); + progress.setVisible(false); + processing = false; + } + } + + } + }); + wrk.execute(); + } + } + + public LoadFromMemoryFrame(final MainFrame mainFrame) { + setSize(800, 600); + //setAlwaysOnTop(true); + setTitle(translate("dialog.title")); + + this.mainFrame = mainFrame; + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + if (!mainFrame.isVisible()) { + mainFrame.setVisible(true); + } + } + }); + model = new DefaultListModel<>(); + + resTableModel = new DefaultTableModel() { + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return Integer.class; + case 1: + return Integer.class; + case 2: + return String.class; + case 3: + return String.class; + } + return null; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + }; + resTableModel.addColumn(translate("column.version")); + resTableModel.addColumn(translate("column.fileSize")); + resTableModel.addColumn(translate("column.pid")); + resTableModel.addColumn(translate("column.processName")); + tableRes = new JTable(resTableModel); + TableRowSorter sorter = new TableRowSorter<>(resTableModel); + tableRes.setRowSorter(sorter); + list = new JList<>(model); + list.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == 10) { //Enter pressed + selectProcess(); + } + } + }); + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + selectProcess(); + } + } + }); + tableRes.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + openSWF(); + } + } + }); + tableRes.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == 10) { //Enter pressed + openSWF(); + } + } + }); + list.setCellRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + + JLabel label = (JLabel) super.getListCellRendererComponent(list, + value, index, isSelected, cellHasFocus); + + if (value instanceof com.jpexs.process.Process) { + if (((com.jpexs.process.Process) value).getIcon() != null) { + label.setIcon(new ImageIcon(((com.jpexs.process.Process) value).getIcon())); + } + } + if (!isSelected) { + label.setBackground(Color.white); + } + return label; + } + }); + refreshList(); + Container cnt = getContentPane(); + cnt.setLayout(new BorderLayout()); + + JPanel leftPanel = new JPanel(new BorderLayout()); + leftPanel.add(new JScrollPane(list), BorderLayout.CENTER); + JPanel leftButtonsPanel = new JPanel(new FlowLayout()); + JButton selectButton = new JButton(translate("button.select")); + selectButton.setActionCommand(ACTION_SELECT_PROCESS); + selectButton.addActionListener(this); + JButton refreshButton = new JButton(translate("button.refresh")); + refreshButton.setActionCommand(ACTION_REFRESH_PROCESS_LIST); + refreshButton.addActionListener(this); + leftButtonsPanel.add(selectButton); + leftButtonsPanel.add(refreshButton); + leftPanel.add(leftButtonsPanel, BorderLayout.SOUTH); + + JPanel rightPanel = new JPanel(new BorderLayout()); + rightPanel.add(new JScrollPane(tableRes), BorderLayout.CENTER); + JPanel rightButtonsPanel = new JPanel(new FlowLayout()); + JButton openButton = new JButton(translate("button.open")); + openButton.setActionCommand(ACTION_OPEN_SWF); + openButton.addActionListener(this); + + JButton saveButton = new JButton(translate("button.save")); + saveButton.setActionCommand(ACTION_SAVE); + saveButton.addActionListener(this); + + rightButtonsPanel.add(openButton); + rightButtonsPanel.add(saveButton); + rightPanel.add(rightButtonsPanel, BorderLayout.SOUTH); + + JPanel statePanel = new JPanel(); + statePanel.setLayout(new BoxLayout(statePanel, BoxLayout.Y_AXIS)); + + stateLabel = new JLabel(translate("noprocess")); + statePanel.add(stateLabel); + progress = new JProgressBar(0, 100); + statePanel.add(progress); + progress.setVisible(false); + rightPanel.add(statePanel, BorderLayout.NORTH); + + cnt.add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel), BorderLayout.CENTER); + View.setWindowIcon(this); + View.centerScreen(this); + java.util.List images = new ArrayList<>(); + images.add(View.loadImage("loadmemory16")); + images.add(View.loadImage("loadmemory32")); + setIconImages(images); + } + + @Override + public void actionPerformed(ActionEvent e) { + switch (e.getActionCommand()) { + case ACTION_SELECT_PROCESS: + selectProcess(); + break; + case ACTION_OPEN_SWF: + openSWF(); + break; + case ACTION_REFRESH_PROCESS_LIST: + refreshList(); + break; + case ACTION_SAVE: + if (foundIs == null) { + return; + } + int[] selected = tableRes.getSelectedRows(); + if (selected.length > 0) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); + if (selected.length > 1) { + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } else { + fc.setSelectedFile(new File(Configuration.lastSaveDir.get(), "movie.swf")); + 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.length == 1) { + SwfInMemory swf = foundIs.get(tableRes.getRowSorter().convertRowIndexToModel(selected[0])); + ReReadableInputStream bis = swf.is; + bis.seek(0); + Helper.saveStream(bis, file); + } else { + for (int sel : selected) { + SwfInMemory swf = foundIs.get(tableRes.getRowSorter().convertRowIndexToModel(sel)); + ReReadableInputStream bis = swf.is; + bis.seek(0); + Helper.saveStream(bis, new File(file, "movie" + sel + ".swf")); + } + } + 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/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index ba19e9921..ac45800fa 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -434,8 +434,7 @@ public class Main { mainFrame.getPanel().closeAll(); } if (Main.sourceInfos.isEmpty()) { - Cache.clearAll(); - System.gc(); + Helper.freeMem(); showModeFrame(); return true; } else { @@ -501,8 +500,7 @@ public class Main { sourceInfos.clear(); mainFrame.getPanel().closeAll(); mainFrame.setVisible(false); - Cache.clearAll(); - System.gc(); + Helper.freeMem(); } View.execInEventDispatch(new Runnable() { @@ -869,32 +867,12 @@ public class Main { UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); } - /** - * This may help to free some memory when not needed (maybe?) - */ - private static void startFreeMemThread() { - new Thread() { - @Override - public void run() { - try { - while (true) { - Thread.sleep(5000); - System.gc(); - } - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - }.start(); - } - /** * @param args the command line arguments * @throws IOException */ public static void main(String[] args) throws IOException { AppStrings.setResourceClass(MainFrame.class); - startFreeMemThread(); initLogging(Configuration.debugMode.get()); initLang(); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index eaf70060c..0bb368704 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -202,7 +202,6 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se } } - System.gc(); Main.stopWork(); searchPanel.setSearchText(txt); diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTreeModel.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTreeModel.java index 93957a3db..62789f675 100644 --- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTreeModel.java @@ -37,7 +37,7 @@ public class DumpTreeModel implements TreeModel { for (SWFList swfList : swfs) { for (SWF swf : swfList) { swf.dumpInfo.name = swf.getFileTitle(); - root.childInfos.add(swf.dumpInfo); + root.getChildInfos().add(swf.dumpInfo); } } this.root = root; @@ -50,17 +50,17 @@ public class DumpTreeModel implements TreeModel { @Override public Object getChild(Object o, int i) { - return ((DumpInfo) o).childInfos.get(i); + return ((DumpInfo) o).getChildInfos().get(i); } @Override public int getChildCount(Object o) { - return ((DumpInfo) o).childInfos.size(); + return ((DumpInfo) o).getChildInfos().size(); } @Override public boolean isLeaf(Object o) { - return ((DumpInfo) o).childInfos.isEmpty(); + return ((DumpInfo) o).getChildInfos().isEmpty(); } @Override @@ -70,7 +70,7 @@ public class DumpTreeModel implements TreeModel { @Override public int getIndexOfChild(Object o, Object o1) { - return ((DumpInfo) o).childInfos.indexOf(o1); + return ((DumpInfo) o).getChildInfos().indexOf(o1); } @Override