stream reading improvements, collecting dump infos can be disabled

This commit is contained in:
honfika
2014-06-28 22:09:14 +02:00
parent af42bb3f7d
commit 53714b0450
9 changed files with 239 additions and 491 deletions

View File

@@ -512,11 +512,13 @@ public final class SWF implements TreeItem, Timelined {
SWFInputStream sis = new SWFInputStream(this, uncompressedData);
dumpInfo = new DumpInfoSwfNode(this, "rootswf", "", null, 0, 0);
sis.dumpInfo = dumpInfo;
if (Configuration.dumpInfoCollecting.get()) {
sis.dumpInfo = dumpInfo;
}
sis.readBytesEx(3, "signature"); // skip siganture
version = sis.readUI8("version");
fileSize = sis.readUI32("fileSize");
sis.dumpInfo.lengthBytes = fileSize;
dumpInfo.lengthBytes = fileSize;
if (listener != null) {
sis.addPercentListener(listener);
}

View File

@@ -310,6 +310,18 @@ public class SWFInputStream implements AutoCloseable {
}
}
private void informListeners() {
if (listeners.size() > 0 && percentMax > 0) {
int percent = (int) (getPos() * 100 / percentMax);
if (lastPercent != percent) {
for (ProgressListener pl : listeners) {
pl.progress(percent);
}
lastPercent = percent;
}
}
}
public void setPercentMax(long percentMax) {
this.percentMax = percentMax;
}
@@ -410,15 +422,7 @@ public class SWFInputStream implements AutoCloseable {
private int lastPercent = -1;
private int readNoBitReset() throws IOException, EndOfStreamException {
if (listeners.size() > 0 && percentMax > 0) {
int percent = (int) (getPos() * 100 / percentMax);
if (lastPercent != percent) {
for (ProgressListener pl : listeners) {
pl.progress(percent);
}
lastPercent = percent;
}
}
informListeners();
int r = is.read();
if (r == -1) {
throw new EndOfStreamException();
@@ -694,10 +698,14 @@ public class SWFInputStream implements AutoCloseable {
if (count <= 0) {
return new byte[0];
}
informListeners();
bitPos = 0;
byte[] ret = new byte[(int) count];
for (int i = 0; i < count; i++) {
ret[i] = (byte) readEx();
if (is.read(ret) != count) {
throw new EndOfStreamException();
}
return ret;
}
@@ -960,7 +968,7 @@ public class SWFInputStream implements AutoCloseable {
public Tag call() throws Exception {
try {
Tag t = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
if (t != null) {
if (dumpInfo!= null && t != null) {
dumpInfo.name = t.getName();
}
return t;
@@ -1004,7 +1012,7 @@ public class SWFInputStream implements AutoCloseable {
tag = null;
}
DumpInfo di = dumpInfo;
if (tag != null) {
if (di != null && tag != null) {
di.name = tag.getName();
}
endDumpLevel(tag == null ? null : tag.getId());

View File

@@ -94,6 +94,10 @@ public class Configuration {
@ConfigurationCategory("display")
public static final ConfigurationItem<Boolean> dumpView = null;
@ConfigurationDefaultBoolean(true)
@ConfigurationCategory("display")
public static final ConfigurationItem<Boolean> dumpInfoCollecting = null;
@ConfigurationDefaultBoolean(false)
@ConfigurationCategory("ui")
public static final ConfigurationItem<Boolean> gotoMainClassOnStartup = null;

View File

@@ -1,86 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
/**
*
* @author JPEXS
*/
public class DumpTree extends JTree {
public class DumpTreeCellRenderer extends DefaultTreeCellRenderer {
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
//DumpInfo dumpInfo = (DumpInfo) value;
setUI(new BasicLabelUI());
setOpaque(false);
setBackgroundNonSelectionColor(Color.white);
return this;
}
}
DumpTree(DumpTreeModel treeModel) {
super(treeModel);
setCellRenderer(new DumpTreeCellRenderer());
setRootVisible(false);
setBackground(Color.white);
setUI(new BasicTreeUI() {
@Override
public void paint(Graphics g, JComponent c) {
setHashColor(Color.gray);
super.paint(g, c);
}
});
}
@Override
public void setModel(TreeModel tm) {
super.setModel(tm);
if (tm != null) {
int rowCount = tm.getChildCount(tm.getRoot());
for (int i = rowCount - 1; i >= 0; i--) {
expandRow(i);
}
}
}
}

View File

@@ -1,84 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.treeitems.SWFList;
import java.util.List;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
*
* @author JPEXS
*/
public class DumpTreeModel implements TreeModel {
private final DumpInfo root;
public DumpTreeModel(List<SWFList> swfs) {
DumpInfo root = new DumpInfo("root", "", null, 0, 0);
for (SWFList swfList : swfs) {
for (SWF swf : swfList) {
swf.dumpInfo.name = swf.getFileTitle();
root.childInfos.add(swf.dumpInfo);
}
}
this.root = root;
}
@Override
public Object getRoot() {
return root;
}
@Override
public Object getChild(Object o, int i) {
return ((DumpInfo) o).childInfos.get(i);
}
@Override
public int getChildCount(Object o) {
return ((DumpInfo) o).childInfos.size();
}
@Override
public boolean isLeaf(Object o) {
return ((DumpInfo) o).childInfos.isEmpty();
}
@Override
public void valueForPathChanged(TreePath tp, Object o) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public int getIndexOfChild(Object o, Object o1) {
return ((DumpInfo) o).childInfos.indexOf(o1);
}
@Override
public void addTreeModelListener(TreeModelListener tl) {
}
@Override
public void removeTreeModelListener(TreeModelListener tl) {
}
}

View File

@@ -1,98 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* @author JPEXS
*/
public class DumpViewPanel extends JPanel {
private final JLabel dumpViewLabel;
private final HexView dumpViewHexTable;
public DumpViewPanel() {
super(new BorderLayout());
dumpViewLabel = new JLabel();
dumpViewLabel.setMinimumSize(new Dimension(100, 20));
add(dumpViewLabel, BorderLayout.SOUTH);
dumpViewHexTable = new HexView();
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<DumpInfo> dumpInfos = new ArrayList<>();
DumpInfo di = dumpInfo;
while (di.parent != null) {
dumpInfos.add(di);
di = di.parent;
}
long[] highlightStarts = new long[dumpInfos.size()];
long[] highlightEnds = new long[dumpInfos.size()];
for (int i = 0; i < dumpInfos.size(); i++) {
DumpInfo di2 = dumpInfos.get(highlightStarts.length - i - 1);
highlightStarts[i] = di2.startByte;
highlightEnds[i] = getEndIndex(di2);
}
dumpViewHexTable.setData(data, highlightStarts, highlightEnds);
if (dumpInfo.lengthBytes != 0 || dumpInfo.lengthBits != 0) {
int selectionStart = (int) dumpInfo.startByte;
int selectionEnd = getEndIndex(dumpInfo);
dumpViewHexTable.scrollToByte(dumpInfo.startByte);
setLabelText("startByte: " + dumpInfo.startByte
+ " startBit: " + dumpInfo.startBit
+ " lengthBytes: " + dumpInfo.lengthBytes
+ " lengthBits: " + dumpInfo.lengthBits
+ " selectionStart: " + selectionStart
+ " selectionEnd: " + selectionEnd);
}
repaint();
}
public void setLabelText(String text) {
dumpViewLabel.setText(text);
}
}

View File

@@ -61,7 +61,7 @@ public class LoadingPanel extends JPanel {
private synchronized void redrawImage(int size) {
if (drawTimer != null) {
drawTimer.cancel();;
drawTimer.cancel();
drawTimer = null;
}
BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
@@ -105,12 +105,14 @@ public class LoadingPanel extends JPanel {
@Override
public void run() {
double rot2 = rotation - Math.PI * 2 / segments;
if (rot2 < 0) {
rot2 += Math.PI * 2;
if (isVisible()) {
double rot2 = rotation - Math.PI * 2 / segments;
if (rot2 < 0) {
rot2 += Math.PI * 2;
}
setRotation(rot2);
repaint();
}
setRotation(rot2);
repaint();
}
}, idelay, idelay);
}

View File

@@ -1,189 +1,190 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.player;
import com.jpexs.decompiler.flash.AppStrings;
import com.jpexs.decompiler.flash.gui.View;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
/**
*
* @author JPEXS
*/
public class PlayerControls extends JPanel implements ActionListener {
static final String ACTION_PAUSE = "PAUSE";
static final String ACTION_STOP = "STOP";
private final JButton pauseButton;
private boolean paused = false;
private MediaDisplay display;
private JProgressBar progress;
private final Timer timer;
private final JLabel timeLabel;
private final JLabel totalTimeLabel;
private static final Icon pauseIcon = View.getIcon("pause16");
private static final Icon playIcon = View.getIcon("play16");
public PlayerControls(MediaDisplay display) {
this.display = display;
JPanel controlPanel = new JPanel(new BorderLayout());
timeLabel = new JLabel("00:00.00");
totalTimeLabel = new JLabel("00:00.00");
controlPanel.add(timeLabel, BorderLayout.WEST);
controlPanel.add(totalTimeLabel, BorderLayout.EAST);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(new FlowLayout());
pauseButton = new JButton(AppStrings.translate("preview.pause"), pauseIcon);
pauseButton.setMargin(new Insets(0, 0, 0, 0));
pauseButton.setActionCommand(ACTION_PAUSE);
pauseButton.addActionListener(this);
JButton stopButton = new JButton(AppStrings.translate("preview.stop"), View.getIcon("stop16"));
stopButton.setMargin(new Insets(0, 0, 0, 0));
stopButton.setActionCommand(ACTION_STOP);
stopButton.addActionListener(this);
buttonsPanel.add(pauseButton);
buttonsPanel.add(stopButton);
controlPanel.add(buttonsPanel, BorderLayout.CENTER);
progress = new JProgressBar();
Dimension pref = progress.getPreferredSize();
pref.height = 20;
progress.setPreferredSize(pref);
final PlayerControls t = this;
progress.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int frame = (int) Math.floor(e.getX() * t.display.getTotalFrames() / (double) progress.getWidth());
boolean p = t.display.isPlaying();
t.display.gotoFrame(frame);
if (p) {
t.display.play();
}
}
});
add(progress);
add(controlPanel);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
update();
}
}, 100, 100);
}
private String formatMs(long ms) {
long s = ms / 1000;
ms %= 1000;
long m = s / 60;
s %= 60;
long h = m / 60;
m %= 60;
return "" + (h > 0 ? h + ":" : "") + pad(m) + ":" + pad(s) + "." + pad(ms / 10);
}
private String pad(long t) {
String ret = "" + t;
while (ret.length() < 2) {
ret = "0" + ret;
}
return ret;
}
public void setMedia(MediaDisplay media) {
this.display = media;
}
private void update() {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
if (!display.isLoaded()) {
return;
}
int totalFrames = display.getTotalFrames();
int currentFrame = display.getCurrentFrame();
int frameRate = display.getFrameRate();
if (totalFrames == 0) {
progress.setIndeterminate(true);
} else {
progress.setMaximum(totalFrames - 1);
progress.setMinimum(0);
progress.setValue(currentFrame);
progress.setIndeterminate(false);
}
if (frameRate != 0) {
timeLabel.setText(formatMs((currentFrame * 1000) / frameRate));
totalTimeLabel.setText(formatMs(((totalFrames - 1) * 1000) / frameRate));
}
if (totalFrames <= 1 && isVisible()) {
setVisible(false);
}
if (totalFrames > 1 && !isVisible()) {
setVisible(true);
}
if (display.isPlaying() == paused) {
paused = !paused;
if (paused) {
pauseButton.setText(AppStrings.translate("preview.play"));
pauseButton.setIcon(playIcon);
} else {
pauseButton.setText(AppStrings.translate("preview.pause"));
pauseButton.setIcon(pauseIcon);
}
}
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case ACTION_PAUSE:
if (paused) {
display.play();
} else {
display.pause();
}
break;
case ACTION_STOP:
display.pause();
display.rewind();
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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.player;
import com.jpexs.decompiler.flash.AppStrings;
import com.jpexs.decompiler.flash.gui.View;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
/**
*
* @author JPEXS
*/
public class PlayerControls extends JPanel implements ActionListener {
static final String ACTION_PAUSE = "PAUSE";
static final String ACTION_STOP = "STOP";
private final JButton pauseButton;
private boolean paused = false;
private MediaDisplay display;
private JProgressBar progress;
private final Timer timer;
private final JLabel timeLabel;
private final JLabel totalTimeLabel;
private static final Icon pauseIcon = View.getIcon("pause16");
private static final Icon playIcon = View.getIcon("play16");
public PlayerControls(MediaDisplay display) {
this.display = display;
JPanel controlPanel = new JPanel(new BorderLayout());
timeLabel = new JLabel("00:00.00");
totalTimeLabel = new JLabel("00:00.00");
controlPanel.add(timeLabel, BorderLayout.WEST);
controlPanel.add(totalTimeLabel, BorderLayout.EAST);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(new FlowLayout());
pauseButton = new JButton(AppStrings.translate("preview.pause"), pauseIcon);
pauseButton.setMargin(new Insets(0, 0, 0, 0));
pauseButton.setActionCommand(ACTION_PAUSE);
pauseButton.addActionListener(this);
JButton stopButton = new JButton(AppStrings.translate("preview.stop"), View.getIcon("stop16"));
stopButton.setMargin(new Insets(0, 0, 0, 0));
stopButton.setActionCommand(ACTION_STOP);
stopButton.addActionListener(this);
buttonsPanel.add(pauseButton);
buttonsPanel.add(stopButton);
controlPanel.add(buttonsPanel, BorderLayout.CENTER);
progress = new JProgressBar();
Dimension pref = progress.getPreferredSize();
pref.height = 20;
progress.setPreferredSize(pref);
final PlayerControls t = this;
progress.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int frame = (int) Math.floor(e.getX() * t.display.getTotalFrames() / (double) progress.getWidth());
boolean p = t.display.isPlaying();
t.display.gotoFrame(frame);
if (p) {
t.display.play();
}
}
});
add(progress);
add(controlPanel);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
update();
}
}, 100, 100);
}
private String formatMs(long ms) {
long s = ms / 1000;
ms %= 1000;
long m = s / 60;
s %= 60;
long h = m / 60;
m %= 60;
return "" + (h > 0 ? h + ":" : "") + pad(m) + ":" + pad(s) + "." + pad(ms / 10);
}
private String pad(long t) {
String ret = "" + t;
while (ret.length() < 2) {
ret = "0" + ret;
}
return ret;
}
public void setMedia(MediaDisplay media) {
this.display = media;
}
private void update() {
if (!display.isLoaded()) {
return;
}
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
int totalFrames = display.getTotalFrames();
int currentFrame = display.getCurrentFrame();
int frameRate = display.getFrameRate();
if (totalFrames == 0) {
progress.setIndeterminate(true);
} else {
progress.setMaximum(totalFrames - 1);
progress.setMinimum(0);
progress.setValue(currentFrame);
progress.setIndeterminate(false);
}
if (frameRate != 0) {
timeLabel.setText(formatMs((currentFrame * 1000) / frameRate));
totalTimeLabel.setText(formatMs(((totalFrames - 1) * 1000) / frameRate));
}
if (totalFrames <= 1 && isVisible()) {
setVisible(false);
}
if (totalFrames > 1 && !isVisible()) {
setVisible(true);
}
if (display.isPlaying() == paused) {
paused = !paused;
if (paused) {
pauseButton.setText(AppStrings.translate("preview.play"));
pauseButton.setIcon(playIcon);
} else {
pauseButton.setText(AppStrings.translate("preview.pause"));
pauseButton.setIcon(pauseIcon);
}
}
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case ACTION_PAUSE:
if (paused) {
display.play();
} else {
display.pause();
}
break;
case ACTION_STOP:
display.pause();
display.rewind();
break;
}
}
}

View File

@@ -27,7 +27,6 @@ public class MemoryInputStream extends SeekableInputStream {
private final byte[] buffer;
private long pos;
private int count;
private int startPos;
private int maxLength;
@@ -51,10 +50,6 @@ public class MemoryInputStream extends SeekableInputStream {
}
}
public int getCount() {
return count;
}
public byte[] getAllRead() {
return buffer;
}
@@ -75,11 +70,7 @@ public class MemoryInputStream extends SeekableInputStream {
@Override
public int read() throws IOException {
if (pos > count) {
count = (int) pos;
}
if (pos < length()) {
if (pos < maxLength) {
int ret = buffer[(int) pos + startPos] & 0xff;
pos++;
return ret;
@@ -88,10 +79,18 @@ public class MemoryInputStream extends SeekableInputStream {
return -1;
}
private int length() {
return maxLength;
@Override
public int read(byte[] bytes) throws IOException {
if (pos < maxLength) {
int toRead = Math.min(available(), bytes.length);
System.arraycopy(buffer, (int) pos + startPos, bytes, 0, toRead);
pos += toRead;
return toRead;
}
return -1;
}
@Override
public int available() throws IOException {
return maxLength - (int) pos;