From 4f35fd8e28c543a71abc96cce08c44db426041df Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Wed, 8 Jul 2015 21:55:46 +0200 Subject: [PATCH] #958 Remove and Replace character tag of items from CLI --- .../src/com/jpexs/decompiler/flash/SWF.java | 14 ++ .../deobfuscation/AVM2DeobfuscatorSimple.java | 2 +- .../console/CommandLineArgumentParser.java | 180 ++++++++++++++++++ .../flash/gui/tagtree/TagTreeContextMenu.java | 11 +- 4 files changed, 196 insertions(+), 11 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 1c5ac2384..31c740482 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -2854,6 +2854,20 @@ public final class SWF implements SWFContainerItem, Timelined { } } + public void replaceCharacterTags(CharacterTag characterTag, int newCharacterId) { + int characterId = characterTag.getCharacterId(); + CharacterTag newCharacter = getCharacter(newCharacterId); + newCharacter.setCharacterId(characterId); + characterTag.setCharacterId(newCharacterId); + newCharacter.setModified(true); + characterTag.setModified(true); + + assignExportNamesToSymbols(); + assignClassesToSymbols(); + clearImageCache(); + updateCharacters(); + } + @Override public String toString() { return getShortFileName(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index debcd3230..0e19a9271 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -422,7 +422,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException { AVM2Code code = body.getCode(); - //code.fixJumps(body); + code.fixJumps(body); removeUnreachableActions(code, cpool, trait, minfo, body); removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, new ArrayList<>()); removeZeroJumps(code, body); diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index f6e46376e..81b23c604 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -131,6 +131,7 @@ import java.io.PrintStream; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -319,6 +320,12 @@ public class CommandLineArgumentParser { out.println(" ...methodBodyIndexN parameter should be specified if and only if the imported entity is an AS3 P-Code"); out.println(" " + (cnt++) + ") -replaceAlpha [ ]..."); out.println(" ...replaces the alpha channel of the specified JPEG3 or JPEG4 tag"); + out.println(" " + (cnt++) + ") -replaceCharacter [ ]..."); + out.println(" ...replaces a character tag with another chatacter tag from the same SWF"); + out.println(" " + (cnt++) + ") -remove []..."); + out.println(" ...removes a tag from the SWF"); + out.println(" " + (cnt++) + ") -removeCharacter[WithDependencies] []..."); + out.println(" ...removes a character tag from the SWF"); out.println(" " + (cnt++) + ") -deobfuscate "); out.println(" ...Deobfuscates AS3 P-code in and saves result to "); out.println(" ... can be one of: controlflow/3/max, traps/2, deadcode/1"); @@ -496,6 +503,14 @@ public class CommandLineArgumentParser { parseReplace(args); } else if (command.equals("replacealpha")) { parseReplaceAlpha(args); + } else if (command.equals("replacecharacter")) { + parseReplaceCharacter(args); + } else if (command.equals("remove")) { + parseRemove(args); + } else if (command.equals("removecharacter")) { + parseRemoveCharacter(args, false); + } else if (command.equals("removecharacterwithdependencies")) { + parseRemoveCharacter(args, true); } else if (command.equals("as3compiler")) { ActionScript3Parser.compile(null /*?*/, args.pop(), args.pop(), 0); } else if (nextParam.equals("-help") || nextParam.equals("--help") || nextParam.equals("/?") || nextParam.equals("\\_") /* /? translates as this on windows */) { @@ -1910,6 +1925,171 @@ public class CommandLineArgumentParser { } } + private static void parseReplaceCharacter(Stack args) { + if (args.size() < 4) { + badArguments(); + } + + File inFile = new File(args.pop()); + File outFile = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(inFile)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + while (true) { + String objectToReplace = args.pop(); + + int characterId = 0; + try { + characterId = Integer.parseInt(objectToReplace); + } catch (NumberFormatException nfe) { + System.err.println("CharacterId should be integer"); + System.exit(1); + } + if (!swf.getCharacters().containsKey(characterId)) { + System.err.println("CharacterId does not exist"); + System.exit(1); + } + + CharacterTag characterTag = swf.getCharacter(characterId); + String newCharacterIdStr = args.pop(); + + int newCharacterId = 0; + try { + newCharacterId = Integer.parseInt(newCharacterIdStr); + } catch (NumberFormatException nfe) { + System.err.println("NewCharacterId should be integer"); + System.exit(1); + } + if (!swf.getCharacters().containsKey(newCharacterId)) { + System.err.println("NewCharacterId does not exist"); + System.exit(1); + } + + swf.replaceCharacterTags(characterTag, newCharacterId); + + if (args.isEmpty() || args.peek().startsWith("-")) { + break; + } + } + + try { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { + swf.saveTo(fos); + } + } catch (IOException e) { + System.err.println("I/O error during writing"); + System.exit(2); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + + private static void parseRemove(Stack args) { + if (args.size() < 3) { + badArguments(); + } + + File inFile = new File(args.pop()); + File outFile = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(inFile)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + List tagNumbersToRemove = new ArrayList<>(); + while (true) { + String tagNoToRemoveStr = args.pop(); + + int tagNo = 0; + try { + tagNo = Integer.parseInt(tagNoToRemoveStr); + } catch (NumberFormatException nfe) { + System.err.println("Tag number should be integer"); + System.exit(1); + } + if (swf.tags.size() >= tagNo) { + System.err.println("Tag number does not exist. Last tag number is: " + (swf.tags.size() - 1)); + System.exit(1); + } + + if (!tagNumbersToRemove.contains(tagNo)) { + tagNumbersToRemove.add(tagNo); + } + + if (args.isEmpty() || args.peek().startsWith("-")) { + break; + } + } + + Collections.sort(tagNumbersToRemove); + for (int i = tagNumbersToRemove.size() - 1; i >= 0; i--) { + swf.tags.remove(tagNumbersToRemove.get(i)); + } + + try { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { + swf.saveTo(fos); + } + } catch (IOException e) { + System.err.println("I/O error during writing"); + System.exit(2); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + + private static void parseRemoveCharacter(Stack args, boolean removeDependencies) { + if (args.size() < 3) { + badArguments(); + } + + File inFile = new File(args.pop()); + File outFile = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(inFile)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + while (true) { + String objectToRemove = args.pop(); + + int characterId = 0; + try { + characterId = Integer.parseInt(objectToRemove); + } catch (NumberFormatException nfe) { + System.err.println("CharacterId should be integer"); + System.exit(1); + } + if (!swf.getCharacters().containsKey(characterId)) { + System.err.println("CharacterId does not exist"); + System.exit(1); + } + + CharacterTag characterTag = swf.getCharacter(characterId); + swf.removeTag(characterTag, removeDependencies); + + if (args.isEmpty() || args.peek().startsWith("-")) { + break; + } + } + + try { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { + swf.saveTo(fos); + } + } catch (IOException e) { + System.err.println("I/O error during writing"); + System.exit(2); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + private static void replaceAS2PCode(String text, ASMSource src) throws IOException, InterruptedException { System.out.println("Replace AS1/2 PCode"); if (text.trim().startsWith(Helper.hexData)) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 30b08258e..8680c0d2a 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -624,16 +624,7 @@ public class TagTreeContextMenu extends JPopupMenu { ReplaceCharacterDialog replaceCharacterDialog = new ReplaceCharacterDialog(); if (replaceCharacterDialog.showDialog(swf, characterId) == AppDialog.OK_OPTION) { int newCharacterId = replaceCharacterDialog.getCharacterId(); - CharacterTag newCharacter = swf.getCharacter(newCharacterId); - newCharacter.setCharacterId(characterId); - characterTag.setCharacterId(newCharacterId); - newCharacter.setModified(true); - characterTag.setModified(true); - - swf.assignExportNamesToSymbols(); - swf.assignClassesToSymbols(); - swf.clearImageCache(); - swf.updateCharacters(); + swf.replaceCharacterTags(characterTag, newCharacterId); mainPanel.refreshTree(swf); } }