- Recalculating dependencies in the loop (now only on change)
- Dependencies handling
This commit is contained in:
Jindra Petřík
2022-11-12 18:14:59 +01:00
parent 4baa14084d
commit 2b6816daec
21 changed files with 206 additions and 58 deletions

View File

@@ -28,6 +28,8 @@ All notable changes to this project will be documented in this file.
- [#1865] ConcurrentModificationException on SWF close
- NullPointerException on expanding needed/dependent characters on basic tag info
- Copy/Move with dependencies should copy mapped tags too
- Recalculating dependencies in the loop (now only on change)
- Dependencies handling
## [16.2.0] - 2022-11-08
### Added

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -124,4 +125,9 @@ public class CSMTextSettingsTag extends Tag implements CharacterIdTag {
public String toString() {
return super.toString() + " (" + textID + ")";
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(textID);
}
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -97,4 +98,9 @@ public class DefineButtonCxformTag extends Tag implements CharacterIdTag {
public String toString() {
return super.toString() + " (" + buttonId + ")";
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(buttonId);
}
}

View File

@@ -155,6 +155,7 @@ public class DefineButtonSoundTag extends Tag implements CharacterIdTag {
if (buttonSoundChar3 != 0) {
needed.add(buttonSoundChar3);
}
needed.add(buttonId);
}
@Override

View File

@@ -31,6 +31,7 @@ import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -116,4 +117,9 @@ public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag {
public String toString() {
return super.toString() + " (" + fontID + ")";
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(fontID);
}
}

View File

@@ -30,6 +30,7 @@ import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -189,4 +190,9 @@ public class DefineFontInfo2Tag extends FontInfoTag {
public boolean isShiftJIS() {
return fontFlagsShiftJIS;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(fontID);
}
}

View File

@@ -29,6 +29,7 @@ import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -191,4 +192,9 @@ public class DefineFontInfoTag extends FontInfoTag {
public boolean isAnsi() {
return fontFlagsANSI;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(fontID);
}
}

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -94,4 +95,9 @@ public class DefineFontNameTag extends Tag implements CharacterIdTag {
public String toString() {
return super.toString() + " (" + fontId + ")";
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(fontId);
}
}

View File

@@ -37,6 +37,7 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -214,5 +215,10 @@ public class DefineScalingGridTag extends Tag implements CharacterIdTag {
public String toString() {
return super.toString() + " (" + characterId + ")";
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(characterId);
}
}

View File

@@ -456,10 +456,12 @@ public class DefineSpriteTag extends DrawableTag implements Timelined {
}
@Override
public Set<Integer> getMissingNeededCharacters() {
public Set<Integer> getMissingNeededCharacters(Set<Integer> needed) {
Set<Integer> ret = new LinkedHashSet<>();
for (Tag tag : getTags()) {
Set<Integer> sub = tag.getMissingNeededCharacters();
Set<Integer> subNeeded = new HashSet<>();
tag.getNeededCharactersDeep(subNeeded);
Set<Integer> sub = tag.getMissingNeededCharacters(subNeeded);
ret.addAll(sub);
}
return ret;

View File

@@ -38,6 +38,7 @@ import com.jpexs.helpers.Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -264,4 +265,9 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource {
public Tag getTag() {
return null; //?
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(spriteId);
}
}

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -82,4 +83,9 @@ public class FreeCharacterTag extends Tag implements CharacterIdTag {
public void setCharacterId(int characterId) {
this.characterId = characterId;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(characterId);
}
}

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -91,4 +92,9 @@ public class NameCharacterTag extends Tag implements CharacterIdTag {
public void setCharacterId(int characterId) {
this.characterId = characterId;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(characterId);
}
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
* Removes the specified character
@@ -105,4 +106,9 @@ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag {
public void setCharacterId(int characterId) {
this.characterId = characterId;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(characterId);
}
}

View File

@@ -34,6 +34,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -263,4 +264,6 @@ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag {
public String toString() {
return getName() + (virtualCharacterId > 0 ? " (" + virtualCharacterId + ")" : "");
}
//getNeededCharacters intentionally not defined
}

View File

@@ -35,6 +35,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -273,4 +274,13 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag {
public String toString() {
return getName() + (virtualCharacterId > 0 ? " (" + virtualCharacterId + ")" : "");
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
if (virtualCharacterId > 0) {
needed.add(virtualCharacterId);
}
}
//getNeededCharacters intentionally not defined
}

View File

@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
import com.jpexs.decompiler.flash.amf.amf3.ListSet;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
@@ -599,15 +600,14 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
public void getNeededCharacters(Set<Integer> needed) {
}
public Set<Integer> getMissingNeededCharacters() {
Set<Integer> needed = new LinkedHashSet<>();
getNeededCharacters(needed);
if (needed.isEmpty()) {
return needed;
public Set<Integer> getMissingNeededCharacters(Set<Integer> needed) {
Set<Integer> needed2 = new ListSet<>(needed);
if (needed2.isEmpty()) {
return new LinkedHashSet<>();
}
Timelined tim = getTimelined();
if (tim == null) {
return needed;
return needed2;
}
ReadOnlyTagList tags = tim.getTags();
for (int i = tags.indexOf(this) - 1; i >= -1; i--) {
@@ -624,13 +624,13 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
}
if (tags.get(i) instanceof CharacterTag) {
int charId = ((CharacterTag) tags.get(i)).getCharacterId();
needed.remove(charId);
if (needed.isEmpty()) {
return needed;
needed2.remove(charId);
if (needed2.isEmpty()) {
return needed2;
}
}
}
return needed;
return needed2;
}
@Override
@@ -725,7 +725,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
bounds.getHeight() / SWF.unitDivisor));
}
Set<Integer> needed = new LinkedHashSet<>();
/*Set<Integer> needed = new LinkedHashSet<>();
getNeededCharactersDeep(needed);
if (needed.size() > 0) {
@@ -745,7 +745,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
if(dependent2 != null && dependent2.size() > 0) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
}
}
}*/
}
public String getCharset() {

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.util.Set;
/**
*
@@ -96,4 +97,9 @@ public class VideoFrameTag extends Tag implements CharacterIdTag {
public void setCharacterId(int characterId) {
this.streamID = characterId;
}
@Override
public void getNeededCharacters(Set<Integer> needed) {
needed.add(streamID);
}
}

View File

@@ -70,11 +70,6 @@ public abstract class ButtonTag extends DrawableTag implements Timelined {
for (BUTTONRECORD r : getRecords()) {
needed.add(r.characterId);
}
DefineButtonSoundTag sounds = getSounds();
if (sounds != null) {
sounds.getNeededCharacters(needed);
}
}
@Override

View File

@@ -1369,6 +1369,7 @@ public class Main {
mainFrame.getPanel().tagTree.setExpandPathString(resourcesPathStr);
mainFrame.getPanel().tagListTree.setExpandPathString(tagListPathStr);
}
mainFrame.getPanel().updateMissingNeededCharacters();
}
if (executeAfterOpen != null) {

View File

@@ -31,9 +31,9 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AbcMultiNameCollisionFixer;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.amf.amf3.ListSet;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration;
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
@@ -124,6 +124,7 @@ import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
@@ -197,7 +198,6 @@ import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
@@ -228,7 +228,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
@@ -238,6 +237,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
@@ -253,12 +253,9 @@ import javax.swing.Icon;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
@@ -270,11 +267,9 @@ import javax.swing.event.DocumentListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.basic.BasicScrollPaneUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import jsyntaxpane.DefaultSyntaxKit;
/**
@@ -394,9 +389,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private static final Logger logger = Logger.getLogger(MainPanel.class.getName());
private Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
private Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
private Thread calculateMissingNeededThread;
private CalculateMissingNeededThread calculateMissingNeededThread;
private List<WeakReference<TreeItem>> orderedClipboard = new ArrayList<>();
private Map<TreeItem, Boolean> clipboard = new WeakHashMap<>();
@@ -1146,23 +1142,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
//Opening files with drag&drop to main window
enableDrop(true);
calculateMissingNeededThread = new Thread("calculateMissingNeededThread") {
@Override
public void run() {
while (true) {
try {
calculateMissingNeededCharacters();
} catch (ConcurrentModificationException cme) {
//ignore
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
return;
}
}
}
};
calculateMissingNeededThread = new CalculateMissingNeededThread();
calculateMissingNeededThread.start();
}
@@ -2960,6 +2940,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
swf.clearImageCache();
reload(true);
updateMissingNeededCharacters();
}
}
@@ -3045,6 +3026,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
ViewMessages.showMessageDialog(MainPanel.this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3)));
if (countAs2 != 0 || countAs3 != 0) {
reload(true);
updateMissingNeededCharacters();
}
});
}
@@ -3457,6 +3439,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
reload(true);
updateMissingNeededCharacters();
}
public void refreshDecompiled() {
@@ -4344,7 +4327,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
character.getNeededCharactersDeep(needed);
needed.remove(buttonRecord.characterId);
needed.add(buttonRecord.characterId);
for (int n : needed) {
CharacterTag neededCharacter;
try {
@@ -4354,10 +4337,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
return;
}
neededCharacter.setSwf(swf);
neededCharacter.setTimelined(swf);
neededCharacter.setTimelined(swf);
swf.addTag(neededCharacter);
}
PlaceObject2Tag placeTag = new PlaceObject2Tag(swf, false, 1, buttonRecord.characterId, buttonRecord.placeMatrix, buttonRecord.colorTransform, 0, null, -1, null);
swf.addTag(placeTag);
placeTag.setTimelined(swf);
@@ -4460,6 +4443,36 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
Tag tag = (Tag) treeItem;
TagInfo tagInfo = new TagInfo(treeItem.getSwf());
tag.getTagInfo(tagInfo);
Set<Integer> needed;
if (neededCharacters.containsKey(treeItem)) {
needed = neededCharacters.get(treeItem);
} else {
needed = new LinkedHashSet<>();
tag.getNeededCharactersDeep(needed);
neededCharacters.put(treeItem, needed);
}
if (needed.size() > 0) {
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
}
if (tag instanceof CharacterTag) {
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> dependent = tag.getSwf().getDependentCharacters(characterId);
if (dependent != null) {
if (dependent.size() > 0) {
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
}
}
Set<Integer> dependent2 = tag.getSwf().getDependentFrames(characterId);
if(dependent2 != null && dependent2.size() > 0) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
}
}
if (!tagInfo.isEmpty()) {
tagInfoPanel.setTagInfos(tagInfo);
showDetail(DETAILCARDTAGINFO);
@@ -4941,29 +4954,78 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
Helper.emptyObject(this);
}
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> missingNeededCharacters, Timelined tim) {
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> neededMap, Map<TreeItem, Set<Integer>> missingNeededCharacters, Timelined tim) {
List<Tag> tags = tim.getTags().toArrayList();
for (Tag t : tags) {
missingNeededCharacters.put(t, t.getMissingNeededCharacters());
Set<Integer> needed = new LinkedHashSet<>();
t.getNeededCharactersDeep(needed);
neededMap.put(t, needed);
missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed));
if (t instanceof DefineSpriteTag) {
calculateMissingNeededCharacters(missingNeededCharacters, (DefineSpriteTag) t);
calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t);
}
}
}
public void calculateMissingNeededCharacters() {
public void updateMissingNeededCharacters() {
if (calculateMissingNeededThread != null) {
calculateMissingNeededThread.recalculate();
}
}
private void calculateMissingNeededCharacters() {
Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
List<SWFList> swfsLists = new ArrayList<>(swfs);
for (SWFList swfList : swfsLists) {
for (SWF swf : swfList) {
calculateMissingNeededCharacters(missingNeededCharacters, swf);
calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, swf);
}
}
if (!missingNeededCharacters.equals(this.missingNeededCharacters)) {
this.missingNeededCharacters = missingNeededCharacters;
tagTree.setMissingNeededCharacters(missingNeededCharacters);
tagListTree.setMissingNeededCharacters(missingNeededCharacters);
}
this.neededCharacters = neededCharacters;
this.missingNeededCharacters = missingNeededCharacters;
tagTree.setMissingNeededCharacters(missingNeededCharacters);
tagListTree.setMissingNeededCharacters(missingNeededCharacters);
}
class CalculateMissingNeededThread extends Thread {
public CalculateMissingNeededThread() {
super("calculateMissingNeededThread");
}
private boolean recalculate = false;
public synchronized void recalculate() {
this.recalculate = true;
this.notify();
}
@Override
public void run() {
while (true) {
synchronized (this) {
recalculate = false;
}
try {
calculateMissingNeededCharacters();
} catch (ConcurrentModificationException cme) {
//ignore
}
synchronized (this) {
if (recalculate) {
continue;
}
try {
wait();
} catch (InterruptedException ex) {
return;
}
}
}
}
}
}